提升日志记录类属性

时间:2014-07-30 16:01:40

标签: c++ logging boost

我正在尝试为我的应用程序做日志。我想添加一个属性,所以我知道在哪个类是日志。我已经开始测试,看它是否有效:

#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成员静态化吗?
  4. 感谢您的任何建议。我看过提升日志属性教程(link1link2link3),但我找不到有用的内容......

3 个答案:

答案 0 :(得分:5)

在我编写的示例下面:

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;
}

答案 1 :(得分:4)

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

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");

答案 2 :(得分:2)

我已经调整了attributesformatting上的文档中的代码来实现此解决方案。我从程序中提取了所有相关位,以创建下面的示例代码;它没有编译,但应该给你一个明确的指示。

粗略的解释:

  • 在格式化程序中使用expressions::attr<string>("ClassName")
  • 为每个类创建一个静态记录器,类型为severity_logger<severity_level>
  • 使用described by EFraim(或其他一些技术)技术创建一个静态初始值设定项,它将类名属性添加到记录器中,如下所示:logger.add_attribute("ClassName", attrs::constant<string>("Foo"));
  • 像这样使用记录器:BOOST_LOG_SEV(logger, trace) << "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 |你好

(我已将其格式化,因为我使用的日志查看器就是这样)

现在,您应该能够按类名对日志消息进行排序。 :)