Boost.Log:如何转发登录源
Boost.Log: How to forward a loging source
我正试图弄清楚,在类中使用日志记录源的最佳方式是什么。简单地将其定义为成员(堆栈)变量的直接解决方案有一个很大的缺点,那就是我必须包含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
重载),它可以得到进一步改进,但您必须在整个代码中定义并使用自己的日志宏。
如果使用其他日志记录功能,例如属性,则可能需要向包装器添加更多转发功能。有关记录器函数的签名,请参阅参考。
- 正在折叠转发引用
- 密码登录程序将永远循环并显示不正确的结果
- 如何检查cURL是否成功登录?c ++
- 将函数参数完美转发到函数指针:按值传递呢?
- 转发变量参数列表以模拟 std::thread
- 在按值调用 (c++) 中转发构造函数参数
- 存储稍后要转发的变量参数
- 如何在 C++ 中转发声明 std::set?
- C++使用默认模板参数键入别名和转发声明
- CNTK:->转发或 ->评估某些电脑上的崩溃,而不是其他电脑上的崩溃
- C++20理念:要求表达和完美转发
- 如何在模板中转发右值和左值引用
- 如何转发声明枚举?
- 使用函数指针转发声明作为 lamba 声明
- CAFFE转发网络在for循环中不起作用
- 如何将迭代器调用转发给类的私有成员?
- 转发复制的 std::tuple
- 完美的转发和构造函数
- 是否可以在不扣除的情况下将模板参数转发到 make_*?
- Boost.Log:如何转发登录源