简体   繁体   English

Boost.Log:如何转发日志源

[英]Boost.Log: How to forward a loging source

I am trying to figure out, what the best way is to use a logging source within a class. 我试图弄清楚,最好的方法是在类中使用日志记录源。 The straight forward solution, simply to define it as a member (stack) variable has the big drawback, that I have to include Boost.Log header files, which really slows down the compilation. 简单的解决方案只是将其定义为成员(堆栈)变量,这有一个很大的缺点,那就是我必须包含Boost.Log头文件,这确实减慢了编译速度。

I'd like to use a severity channel logger. 我想使用严重性通道记录器。 So my first approach was to define a new type, eg: 所以我的第一种方法是定义一个新类型,例如:

#include <boost/log/sources/severity_channel_logger.hpp>

typedef boost::log::sources::severity_channel_logger_mt<SeverityLogLevel, std::string> DefaultLogger;

This approach only simplifies defining a logger, but I still need to include the header file. 这种方法仅简化了记录器的定义,但是我仍然需要包括头文件。

My next idea was to create a new class, which subtypes the logger and then using a forward declaration of this class: 我的下一个想法是创建一个新类,该类将记录器子化,然后使用该类的前向声明:

// MyLogger.h
class MyLogger : public boost::log::sources::severity_channel_logger_mt<SeverityLogLevel, std::string>
{
  public:
    MyLogger(const std::string& name);
};

// MyLoggingClient.h
include <memory>

class MyLogger;

class MyLoggingClient
{
  // Actual implementation

  private:
    std::unique_ptr<MyLogger> lg;

};

But doing this, the compiler complains that MyLogger does not define the binary "[" operator or a conversion to a type acceptable to the predefined operator. 但是这样做,编译器抱怨MyLogger没有定义二进制“ [”运算符,也没有定义为预定义运算符可以接受的类型的转换。

So, my question is, what is a good way of simply forwarding the definition of logger? 因此,我的问题是,简单转发记录器定义的一种好方法是什么? (I am refactoring the logging of existing code, so using the PIMPL or similar pattern, would result in a lot of extra effort.) (我正在重构现有代码的日志记录,因此使用PIMPL或类似的模式会导致很多额外的工作。)

Thanks, - Lars 谢谢,-拉斯

I think you've already showed the best way to forward-declare a logger, although I would suggest to store Boost.Log logger as a member of MyLogger instead of deriving from it. 我想你已经表现出了最好的方式转发,申报记录,但我会建议Boost.Log记录仪存储为成员MyLogger ,而不是从中获取的。 Boost.Log loggers are designed using CRTP , so deriving from it may result in unexpected behavior. Boost.Log记录器是使用CRTP设计的,因此从中导出可能会导致意外行为。

The compiler error you're getting is probably caused by some part of your code which was not updated to account for the change you made - that lg is no longer a logger but a pointer. 您得到的编译器错误可能是由于代码的某些部分未更新而无法解释您所做的更改lg不再是记录器,而是指针。

PIMPL is another way to achieve what you want, and I think it actually might be easier than using a pointer. PIMPL是实现所需目标的另一种方法,我认为它实际上可能比使用指针要容易。 What you need is to implement a wrapper for the logger that implements an interface similar to Boost.Log loggers you use. 您需要为记录器实现一个包装器,该包装器实现与所使用的Boost.Log记录器类似的接口。 For instance, for severity_channel_logger_mt this might suffice: 例如,对于severity_channel_logger_mt这可能就足够了:

// MyLogger.h
#include <string>
#include <boost/log/core/record.hpp>
#include <boost/log/keywords/severity.hpp>
#include <boost/log/keywords/channel.hpp>

enum SeverityLogLevel { ... };

class MyLogger
{
private:
    struct Impl;
    Impl* impl;

public:
    MyLogger();
    MyLogger(MyLogger const&);
    MyLogger(MyLogger&& that) noexcept : impl(that.impl) { that.impl = nullptr; }
    ~MyLogger();

    MyLogger& operator= (MyLogger const&);
    MyLogger& operator= (MyLogger&& that) noexcept
    {
        MyLogger copy(static_cast< MyLogger&& >(that)); // you can use use std::move here and include <utility>
        this->swap(copy);
        return *this;
    }

    boost::log::record open_record();
    boost::log::record open_record(SeverityLogLevel sev, std::string const& chan);
    template< typename Args >
    boost::log::record open_record(Args const& args)
    {
        return open_record(args[boost::log::keywords::severity], args[boost::log::keywords::channel]);
    }

    void push_record(boost::log::record&& rec);

    void swap(MyLogger& that) noexcept
    {
        Impl* p = impl;
        impl = that.impl;
        that.impl = p;
    }
};

// MyLogger.cpp
#include "MyLogger.h"
#include <utility>
#include <boost/log/sources/severity_channel_logger.hpp>

typedef boost::log::sources::severity_channel_logger_mt<
    SeverityLogLevel,
    std::string
> DefaultLogger;

struct MyLogger::Impl
{
    DefaultLogger lg;
};

MyLogger::MyLogger() : impl(new Impl())
{
}

MyLogger::MyLogger(MyLogger const& that) : impl(new Impl(*that.impl))
{
}

MyLogger::~MyLogger()
{
   delete impl;
}

MyLogger& MyLogger::operator= (MyLogger const& that)
{
    MyLogger(that).swap(*this);
    return *this;
}

boost::log::record MyLogger::open_record()
{
    return impl->lg.open_record();
}

boost::log::record MyLogger::open_record(SeverityLogLevel sev, std::string const& chan)
{
    return impl->lg.open_record((boost::log::keywords::severity = sev, boost::log::keywords::channel = chan));
}

void MyLogger::push_record(boost::log::record&& rec)
{
    impl->lg.push_record(std::move(rec));
}

You should be able to use Boost.Log macros with this wrapper as is. 您应该能够按原样将此Boost.Log宏与此包装一起使用。 You still have to include a few headers in MyLogger.h but hopefully this will be an improvement significant enough for you. 您仍然必须在MyLogger.h中包含一些标头,但希望这对您来说是足够重要的改进。 It can be improved further if you remove support for keywords (the Boost.Log includes and the templated open_record overload) but then you will have to define and use your own logging macros throughout the code. 如果删除对关键字的支持(Boost.Log包括和模板化的open_record重载),则可以进一步改进,但是您将必须在整个代码中定义和使用自己的日志记录宏。

If you use other logging features, such as attributes, you may need to add more forwarding functions to the wrapper. 如果使用其他日志记录功能(例如属性),则可能需要向包装器添加更多转发功能。 See Reference for signatures of logger functions. 有关记录器功能的签名,请参见参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM