Boost.Log:如何转发登录源

Boost.Log: How to forward a loging source

本文关键字:转发 登录 Log 何转发 Boost      更新时间:2023-10-16

我正试图弄清楚,在类中使用日志记录源的最佳方式是什么。简单地将其定义为成员(堆栈)变量的直接解决方案有一个很大的缺点,那就是我必须包含Boost.Log头文件,这确实会减慢编译速度。

我想使用严重性通道记录器。因此,我的第一个方法是定义一种新的类型,例如:

#include <boost/log/sources/severity_channel_logger.hpp>
typedef boost::log::sources::severity_channel_logger_mt<SeverityLogLevel, std::string> DefaultLogger;

这种方法只简化了记录器的定义,但我仍然需要包含头文件。

我的下一个想法是创建一个新的类,它对记录器进行子类型化,然后使用这个类的前向声明:

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

但这样做,编译器抱怨MyLogger没有定义二进制"["运算符,也没有定义到预定义运算符可接受的类型的转换

所以,我的问题是,什么是简单地转发记录器定义的好方法?(我正在重构现有代码的日志记录,所以使用PIMPL或类似的模式会带来很多额外的工作。)

谢谢,-Lars

我认为您已经展示了转发声明记录器的最佳方法,尽管我建议将Boost.Log记录器存储为MyLogger的成员,而不是从它派生。Boost.Log日志记录器是使用CRTP设计的,因此从它派生可能会导致意外行为。

您遇到的编译器错误可能是由于代码的某些部分没有根据您所做的更改进行更新造成的——lg不再是记录器,而是指针。

PIMPL是实现您想要的另一种方式,我认为它实际上可能比使用指针更容易。您需要的是为记录器实现一个包装器,该包装器实现一个类似于您使用的Boost.Log记录器的接口。例如,对于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));
}

你应该能够使用Boost.Log宏和这个包装器。你仍然需要在MyLogger.h中包含一些头,但希望这对你来说是一个足够显著的改进。如果您删除对关键字的支持(Boost.Log includes和模板化的open_record重载),它可以得到进一步改进,但您必须在整个代码中定义并使用自己的日志宏。

如果使用其他日志记录功能,例如属性,则可能需要向包装器添加更多转发功能。有关记录器函数的签名,请参阅参考。