【问题标题】:Boost logging class attribute提升日志记录类属性
【发布时间】:2014-07-30 16:01:40
【问题描述】:

我正在尝试为我的应用程序记录日志。我想添加一个属性,这样我就知道日志在哪个类中。我已经开始测试它是否有效:

#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/common.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/syslog_backend.hpp>

enum severity_levels
{
    debug,
    info,
    warning,
    error
};

typedef boost::log::sinks::synchronous_sink< boost::log::sinks::syslog_backend > SinkSysLogBackEnd;
typedef boost::log::sources::severity_logger< severity_levels > BoostLogger;

std::ostream& operator<< (std::ostream& strm, severity_levels level)
{
    static const char* strings[] =
    {
        "debug",
        "info",
        "warning",
        "error"
    };

    if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
        strm << strings[level];
    else
        strm << static_cast< int >(level);

    return strm;
}

BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_levels)
BOOST_LOG_ATTRIBUTE_KEYWORD(executable, "Executable", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(className, "Class name", std::string)

void init_syslog()
{
    // Create a backend
    boost::shared_ptr< SinkSysLogBackEnd > sink(new SinkSysLogBackEnd());

    // We'll have to map our custom levels to the syslog levels
    boost::log::sinks::syslog::custom_severity_mapping< severity_levels > mapping("Severity");
    mapping[info] = boost::log::sinks::syslog::info;
    mapping[warning] = boost::log::sinks::syslog::warning;
    mapping[error] = boost::log::sinks::syslog::error;

    sink->set_formatter(
        boost::log::expressions::stream
        // line id will be written in hex, 8-digits, zero-filled
        << executable << " <" << severity
        << "> : " << boost::log::expressions::smessage);

    sink->locked_backend()->set_severity_mapper(mapping);

    // Set the remote address to sent syslog messages to
    sink->locked_backend()->set_target_address("localhost");

    // Wrap it into the frontend and register in the core.
    // The backend requires synchronization in the frontend.
    boost::log::core::get()->add_sink(sink);
}

class Cls1
{
    BoostLogger m_lg;
public:
    Cls1()
    {
        // set the class name to Cls1
    }

    void foo()
    {
        // print log that has "Class Name" attribute set to "Cls1"
    }
};

class Cls2
{
    BoostLogger m_lg;
public:
    Cls2()
    {
        // set the class name to Cls2
    }


    void foo()
    {
        // print log that has "Class Name" attribute set to "Cls2"
    }
};

int main(int argc, char** argv)
{
    init_syslog();

    Cls1 o1;
    o1.foo();
    Cls2 o2;
    o2.foo();

    return 0;
}

现在我被卡住了......

  1. 怎么做会更好?
  2. 如何将属性设置为想要的值?
  3. 我应该将 BoostLogger 成员设为静态吗?

感谢您的任何建议。我看过提升日志属性教程(link1link2link3),但我还没有找到有用的东西……

【问题讨论】:

    标签: c++ logging boost


    【解决方案1】:

    下面是我编写的一个示例:

    Logger.hpp:

    #ifndef LOGGER_HPP
    #define LOGGER_HPP
    
    #include <ostream>
    #include <fstream>
    
    #include <boost/shared_ptr.hpp>
    #include <boost/log/common.hpp>
    #include <boost/log/expressions.hpp>
    #include <boost/log/attributes.hpp>
    #include <boost/log/sources/logger.hpp>
    #include <boost/log/sinks/async_frontend.hpp>
    #include <boost/log/sinks/text_ostream_backend.hpp>
    #include <boost/utility/empty_deleter.hpp>
    
    class Logger
    {
    public:
    
        typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_ostream_backend> text_sink;
    
        Logger();
    
        ~Logger();
    
        void    Initialize();
    
        void    Finalize();
    
        void    addStream(boost::shared_ptr<std::ostream>& stream);
    
        template< typename T >
        Logger& operator<<(const T& value)
        {
            BOOST_LOG(my_logger::get()) << value;
            return *this;
        }
    
        typedef Logger& (*LoggerManipulator)(Logger&);
    
        Logger& operator<<(LoggerManipulator manip)
        {
            return manip(*this);
        }
    
        static Logger& endl(Logger& stream)
        {
            std::cout << std::endl;
            return stream;
        }
    
    
        typedef std::basic_ostream<char, std::char_traits<char>> CoutType;
    
        typedef CoutType& (*StandardEndLine)(CoutType&);
    
        Logger& operator<<(StandardEndLine manip)
        {
            manip(std::cout);
            return *this;
        }
    
    private:
    
        boost::log::sources::logger_mt m_lg;
    
        boost::shared_ptr<text_sink> m_sink;
    
    };
    
    #endif LOGGER_HPP
    

    Logger.cpp:

        #include <boost/date_time/posix_time/posix_time.hpp>
    
        #include "Logger.hpp"
    
        Logger::Logger()
            :
            m_sink(new text_sink),
            m_lg()
        {
        }
    
        Logger::~Logger()
        {
        }
    
        void    Logger::Initialize()
        {
            m_sink->locked_backend()->auto_flush(true);
    
        m_sink->set_formatter
            (
            boost::log::expressions::format("[%1%] - %2%")
            % boost::log::expressions::attr< boost::posix_time::ptime >("TimeStamp")
            % boost::log::expressions::smessage
            );
    
        boost::log::core::get()->add_sink(m_sink);
    
        boost::log::core::get()->add_global_attribute("TimeStamp",boost::log::attributes::local_clock());
    }
    
    void    Logger::Finalize()
    {
    }
    
    void    Logger::addStream(boost::shared_ptr<std::ostream>& stream)
    {
        m_sink->locked_backend()->add_stream(stream);
    }
    

    main.cpp:

    int main
    {
        boost::shared_ptr<std::ostream> stream_out(&std::clog, boost::empty_deleter());
        boost::shared_ptr<std::ostream> stream_file(new std::ofstream(ProgramName + ".log", std::ostream::app));
    
        Logger logger;
    
        logger.addStream(stream_out);
        logger.addStream(stream_file);
        logger.Initialize();
    
        logger << "Sample";
    
    return 0;
    }
    

    【讨论】:

    • 你在你的代码中拥有的是我在我的(或多或少)中拥有的,但我有 2 个不同的类,每个类都有一个记录器成员;我想要的是,在每个类中,记录器的“类名”属性都有不同的值。如何做到这一点,而不是如何拥有一个记录器?
    • 这个问题明确要求将类名记录为属性,而您对此只字未提?!
    【解决方案2】:

    我已经为每个类使用静态记录器并使用初始化它们的方法解决了这个问题。像这样的:

    BoostLogger setClassNameAttribute(const std::string& classNameIn)
    {
        BoostLogger lg;
        lg.add_attribute("ClassName", boost::log::attributes::constant<std::string>(classNameIn));
        return lg;
    }
    

    class Cls1
    {
        static BoostLogger sm_lg;
    public:
        Cls1()
        {
            // set the class name to Cls1
        }
    
        void foo()
        {
            // print log that has "Class Name" attribute set to "Cls1"
        }
    };
    
    BoostLogger Cls1::sm_lg = setClassNameAttribute("Cls1");
    

    class Cls2
    {
        static BoostLogger sm_lg;
    public:
        Cls2()
        {
            // set the class name to Cls2
        }
    
    
        void foo()
        {
            // print log that has "Class Name" attribute set to "Cls2"
        }
    };
    
    BoostLogger Cls2::sm_lg = setClassNameAttribute("Cls2");
    

    【讨论】:

    • 哈哈哇!我们一定同时在编写我们的解决方案!干得好
    【解决方案3】:

    我已经修改了 attributesformatting 上文档中的代码,以解决这个问题。我从我的程序中提取了所有相关位以创建下面的示例代码;它不会编译,但应该给你一个明确的指示。

    粗略解释:

    • 在格式化程序的某处使用expressions::attr&lt;string&gt;("ClassName")
    • 为每个类创建一个静态记录器,类型如severity_logger&lt;severity_level&gt;
    • 使用技术described by EFraim(或其他技术)创建一个静态初始化器,将类名属性添加到记录器,如下所示:logger.add_attribute("ClassName", attrs::constant&lt;string&gt;("Foo"));
    • 像这样使用记录器:BOOST_LOG_SEV(logger, trace) &lt;&lt; "Hello there";

    我遗漏了很多包含和“使用命名空间”的内容 - 如果您找不到某些内容的来源,请告诉我。

    // I have this in my stdafx.h for convenience
    typedef boost::log::sources::severity_logger<boost::log::trivial::severity_level> Logger;
    
    // foo.h
    class Foo
    {
        private:
            static Logger logger;
    
            static class _Init
            {
            public:
                _Init()
                {
                    logger.add_attribute("ClassName", boost::log::attributes::constant<std::string>("Foo"));
                }
            } _initializer;
    
        public:
            Foo();
    }
    
    // foo.cpp
    Logger Foo::logger;                     // initialize the static variables
    Foo::_Init Foo::_initializer;
    
    Foo::Foo()
    {
        BOOST_LOG_SEV(logger, trace) << "Hello there";
    }
    
    
    // main.cpp
    int main(int argc, char *argv[])
    {
        using namespace boost::log;
    
        // Set up our sink and formatting
        boost::log::add_file_log(
            boost::log::keywords::file_name = "MyApp_%3N.log",
            boost::log::keywords::rotation_size = 1 * 1024 * 1024,
            boost::log::keywords::max_size = 20 * 1024 * 1024,
            boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
            boost::log::keywords::format = 
            (
                expressions::stream 
                << expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S,%f") << "|"
                << expressions::attr<std::string>("ClassName") << "|"
                << trivial::severity << "|"
                << expressions::message 
            ),
            boost::log::keywords::auto_flush = true
            );
    
        boost::log::add_common_attributes();
    
        boost::log::core::get()->set_filter(
            boost::log::trivial::severity >= boost::log::trivial::trace
            );
    
        Foo* foo = new Foo();
    }
    

    输出看起来像

    2014-08-26 19:16:19,006726|Foo|trace|你好

    (我已经这样格式化了,因为我使用的日志查看器喜欢这样)

    现在您应该可以按类名对日志消息进行排序了。 :)

    【讨论】:

    • 我之前没用过Program::,能给个链接吗?
    • 抱歉——它的意思是“Foo”,我从我的应用程序中复制了代码,该应用程序有一个名为“Program”的类
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多