在安卓平台上使用Boost.Log进行日志输出

5
我正在尝试使用Boost.Log(v1.57)将日志写入多个平台,其中包括Android。对于我们拥有的NDK代码,我需要将日志消息发送到__android_log_print
反复阅读文档后(整个系统相当复杂),似乎我需要编写自己的日志后端。或者,似乎我可以使用他们现有的ostream后端并编写自己的流(使用Boost.Iostream)。
问题是,如果您考虑一下,流并不真正适合这种情况。我不一定会有一个我正在存储日志的缓冲区。我只是将它们转发到前面提到的Android NDK函数。
在这里,什么是正确的解决方案?IO流还是自定义日志记录器后端?
1个回答

4
我建议创建一个自定义的sink后端,将日志消息转发到Android日志功能。以下示例代码实现了这一点,并使用了Android日志级别,以便您可以根据日志级别过滤日志消息。当然,您也可以定义自己的日志级别,并添加在您的日志级别和Android日志级别之间的映射。
您需要调用boost_android_logging::init()一次,然后可以在需要时实例化boost_android_logging::Logger并使用BOOST_LOG_SEV发送日志消息。
#include <iostream>

typedef enum android_LogPriority {
    ANDROID_LOG_UNKNOWN = 0,
    ANDROID_LOG_DEFAULT,
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT,
} android_LogPriority;


int fake__android_log_print(int prio, const char *tag, const char *fmt, ...)
{
  std::cout << prio << " " << tag << ": " << fmt << std::endl;
  return 0;
}


#include <boost/log/attributes.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/utility/setup.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/expressions/keyword.hpp>

namespace boost_android_logging
{

  BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", android_LogPriority)
BOOST_LOG_ATTRIBUTE_KEYWORD(module, "Module", std::string)

namespace logging = boost::log;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;

struct android_sink_backend : public sinks::basic_sink_backend<logging::sinks::concurrent_feeding>
{
    void consume(const logging::record_view& rec)
    {
        android_LogPriority log_sev = rec[severity].get();
        const char* log_msg = rec[expr::smessage].get().c_str();

        const char* log_module = "unknown";

        if (rec[module])
        {
            log_module = rec[module].get().c_str();
        }

        // forward to actual logging function
        fake__android_log_print(log_sev, log_module, log_msg);
    }
};

typedef boost::log::sources::severity_logger<android_LogPriority> Logger;

void init()
{
    logging::add_common_attributes();
    typedef sinks::synchronous_sink<android_sink_backend> android_sink;
    boost::shared_ptr<android_sink> sink = boost::make_shared<android_sink>();

    sink->set_filter(severity >= ANDROID_LOG_INFO);
    logging::core::get()->add_sink(sink);
}

void shutdown()
{
    logging::core::get()->remove_all_sinks();
}

} // namespace boost_android_logging


#define SET_MODULE(logger,log_module)  logger.add_attribute(boost_android_logging::module.get_name(), boost::log::attributes::constant<std::string>(#log_module));

struct Demo
{
  Demo()
  {
    SET_MODULE(logger, Demo);
    BOOST_LOG_SEV(logger, ANDROID_LOG_WARN) << "this is a warning"; 
  }

  void test()
  {
    BOOST_LOG_SEV(logger, ANDROID_LOG_FATAL) << "fatal error occured";
  }

  boost_android_logging::Logger logger;
};

int main()
{
  boost_android_logging::init();

  boost_android_logging::Logger logger;
  SET_MODULE(logger, main);

  BOOST_LOG_SEV(logger, ANDROID_LOG_WARN) << "this is a warning";
  BOOST_LOG_SEV(logger, ANDROID_LOG_DEBUG) << "this will be filtered";
  BOOST_LOG_SEV(logger, ANDROID_LOG_FATAL) << "fatal error occured";

  Demo d;
  d.test();
  boost_android_logging::shutdown();
}

live on coliru


你是刚刚写的这个代码还是有通用的安卓解决方案?谢谢! - void.pointer
@void.pointer 我写了这个,我不知道有没有现成的安卓解决方案。 - m.s.
Android的日志打印函数实际上需要4个参数,其中一个是标签。我认为该标签是唯一的模块标识。我不确定如何传递它(可能是一个属性,但这样每次记录时都必须指定它,很麻烦)。 - void.pointer
@void.pointer 我更新了问题,你可以将属性添加到记录器一次。 - m.s.
我不太确定Boost.Log中的'syslog'部分是什么,所以我不确定是否可以使用那些映射对象。文档细节非常稀少。在后端中,使用switch或map处理通用的严重级别似乎更简单。感谢提供信息! - void.pointer
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接