做服务器开发首要做的事情,就是将日志系统建立起来。这个系统也是方便我们检查服务器的问题。
完整代码可以去这里看:
下载地址
初始化日志系统
这是一个初始化日志系统的代码。我这里是使用了一个配置文件来做boost.log的设置的。所以代码写起来是非常的简洁。
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/from_stream.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/log/utility/setup/filter_parser.hpp>
bool init_log_environment(std::string _cfg)
{
namespace logging = boost::log;
using namespace logging::trivial;
if (!boost::filesystem::exists("./log/"))
{
boost::filesystem::create_directory("./log/");
}
logging::add_common_attributes();
logging::register_simple_formatter_factory<severity_level, char>("Severity");
logging::register_simple_filter_factory<severity_level, char>("Severity");
std::ifstream file(_cfg);
try
{
logging::init_from_stream(file);
}
catch (const std::exception& e)
{
std::cout << "init_logger is fail, read log config file fail. curse: " << e.what() << std::endl;
exit(-2);
}
return true;
}
其实最核心的代码就是logging::init_from_stream这个函数。他能加载你对日志的配置信息。这样比起一般将sink设置,日志级别设置写到代码里面的方式要更加简单。接下来我们来看看配置文件的写法。
配置日志
[Core]
DisableLogging=false
Filter="%Severity% >= trace"
[Sinks.console]
Filter="%Severity% > trace "
Destination=Console
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=false
AutoFlush=true
# trace,
[Sinks.trace]
Filter="%Severity% = trace"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] %Message%"
Asynchronous=false
AutoFlush=true
RotationSize= 31457280
FileName="./log/trace_%03N.log"
# debug,
[Sinks.debug]
Filter="%Severity% = debug"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=false
AutoFlush=true
RotationTimePoint="00:00:00"
FileName="./log/debug_%Y%m%d_%H%M%S.log"
# info,
[Sinks.info]
Filter="%Severity% = info"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=false
AutoFlush=true
RotationTimePoint="00:00:00"
FileName="./log/info_%Y%m%d_%H%M%S.log"
# warning,
[Sinks.warning]
Filter="%Severity% = warning"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=false
AutoFlush=true
RotationTimePoint="00:00:00"
FileName="./log/warning_%Y%m%d_%H%M%S.log"
# error,
[Sinks.error]
Filter="%Severity% = error"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=false
AutoFlush=true
RotationTimePoint="00:00:00"
FileName="./log/erro_%Y%m%d_%H%M%S.log"
# fatal
[Sinks.fatal]
Filter="%Severity% = fatal"
Destination=TextFile
Format="[%TimeStamp%] [%Severity%] [%Channel%] %Message%"
Asynchronous=true
AutoFlush=true
RotationTimePoint="00:00:00"
FileName="./log/fatal_%Y%m%d_%H%M%S.log"
在这个配置文件中,我们可以直接定义logging core的日志输出级别。设置每个级别的日志的格式。比较屌的是他这里可以通过配置来让日志翻滚起来。仔细看里面的日志配置,他里面是能支持按照时间来写日志的。
里面其实还能自己建立对于特定的日志做过滤条件来做分析:
Filter="%Severity% = fatal"
Parameter | Format | Description |
---|---|---|
FileName | File name pattern | The file name pattern for the sink backend. This parameter is mandatory. |
Format | Format string as described here | Log record formatter to be used by the sink. If not specified, the default formatter is used. |
AutoFlush | “true” or “false” | Enables or disables the auto-flush feature of the backend. If not specified, the default value false is assumed. |
RotationSize | Unsigned integer | File size, in bytes, upon which file rotation will be performed. If not specified, no size-based rotation will be made. |
RotationInterval | Unsigned integer | Time interval, in seconds, upon which file rotation will be performed. See also the RotationTimePoint parameter and the note below. |
RotationTimePoint | Time point format string, see below | Time point or a predicate that detects at what moment of time to perform log file rotation. See also the RotationInterval parameter and the note below. |
Target | File system path to a directory | Target directory name, in which the rotated files will be stored. If this parameter is specified, rotated file collection is enabled. Otherwise the feature is not enabled, and all corresponding parameters are ignored. |
MaxSize | Unsigned integer | Total size of files in the target directory, in bytes, upon which the oldest file will be deleted. If not specified, no size-based file cleanup will be performed. |
MinFreeSpace | Unsigned integer | Minimum free space in the target directory, in bytes, upon which the oldest file will be deleted. If not specified, no space-based file cleanup will be performed. |
MaxFiles | Unsigned integer | Total number of files in the target directory, upon which the oldest file will be deleted. If not specified, no count-based file cleanup will be performed. |
ScanForFiles | “All” or “Matching” | Mode of scanning for old files in the target directory, see scan_method. If not specified, no scanning will be performed. |
可以看到不仅仅是能支持RotationTimePoint,我当前例子是用的0点刷新的方式。而且还支持使用间隔时间刷新、文件大小刷新。而且还能指定Rotation文件备份的位置。
如何写日志
头文件中引入
#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
namespace logging = boost::log;
using namespace logging::trivial;
namespace src = boost::log::sources;
//在自己的class里面定义一个日志输出通道对象
src::severity_channel_logger<severity_level, std::string> scl;
cpp文件中的写写法
// 构造函数的时候,初始化日志输出通道对象
xxxx::xxx(void) : scl(keywords::channel = "xxxx_class")
// 按照日志级别写入日志
BOOST_LOG_SEV(scl, debug) << __FUNCTION__ << ":" << __LINE__ << " success, fd: " << fd << ", ip: " << str_addr;
输出结果
[2016-08-25 10:29:18.328592] [debug] [config] config::show_config:53 port:9210
[2016-08-25 10:29:18.333095] [debug] [config] config::show_config:54 name:abelserver
[2016-08-25 10:29:18.335597] [debug] [config] config::show_config:55 log_config:log_conf.ini
[2016-08-25 10:29:18.338599] [debug] [config] config::show_config:56 redis_host:127.0.0.1
[2016-08-25 10:29:18.342104] [debug] [config] config::show_config:57 redis_port:6379
# 输出文件名称:
erro_20160325_145443.log
在做一些调试工作的时候,可能需要将数据dump出来看,就可以使用:
void on_receive(std::vector< unsigned char > const& packet)
{
// Outputs something like "Packet received: 00 01 02 0a 0b 0c"
BOOST_LOG(lg) << "Packet received: " << logging::dump(packet.data(), packet.size());
}
使用起来还是非常简单的。而且已经满足了大多数的需求。boost.log库是能支持自定义的sink,具体可以需要查阅这里