自己很久前整理开发了一个boost线程安全日志库,使用了很久,可放心使用;使用方法如下:
1、代码中添加boost_log.h和boost_log.cpp文件;
2、在程序的入口添加
#ifdef _DEBUG
BoostLog::Init_Release("log", "videolog", debug);
#else
BoostLog::Init_Release("log", "videolog", info);
#endif // _DEBUG
如果需要将信息输出到控制台,则将Init_Release换位Init_Debug,第一个参数为日志目录,第二个参数为日志名称,第三个为日志等级;
日志会自动划分每个文件的大小为10M,而且整个目录大小限制为100M;
3、写日志:
根据日志级别,分别调用如下宏即可:
BOOST_TRACE
BOOST_DEBUG
BOOST_INFO
BOOST_WARNING
BOOST_ERROR
BOOST_FATAL
BOOST_CB
如:
BOOST_ERROR << "open udp port excption :" << "绑定地址失败!";
日志输出格式为:
[2016-11-30 09:41:53.375260]<error>http_client.cpp[31]:open udp port excption :绑定地址失败!
4、退出时,在程序的出口调用:
BoostLog::Uninit()
5、代码如下:
boost_log.h
/*!
* \file Boostlog.hpp
* \author cgb
*
* 封装boost log模块,多线程(同步)写入日志;
*/
#pragma once
#include <string>
#include <iostream>
#ifdef _WIN32
#include <process.h>
#else
#include <unistd.h>
#endif
#ifdef _VS2013
#include <stdint.h>
#endif // _VS2013
#include "boost/log/trivial.hpp"
#include "boost/filesystem.hpp"
#include "boost/log/sources/logger.hpp"
#include "boost/log/sources/record_ostream.hpp"
#include "boost/log/sources/global_logger_storage.hpp"
#include "boost/log/utility/setup/file.hpp"
#include "boost/log/utility/setup/console.hpp"
#include "boost/log/utility/setup/common_attributes.hpp"
#include "boost/log/sinks/text_ostream_backend.hpp"
#include "boost/log/attributes/named_scope.hpp"
#include "boost/log/expressions.hpp"
#include "boost/log/support/date_time.hpp"
#include "boost/log/detail/format.hpp"
#include "boost/log/detail/thread_id.hpp"
#include "boost/log/core/core.hpp"
#include "boost/format.hpp"
#define _CSTDIO_
#define _CSTRING_
#define _CWCHAR_
using std::string;
namespace boost_log = boost::log;
namespace boost_sources = boost::log::sources;
namespace boost_keywords = boost::log::keywords;
namespace boost_sinks = boost::log::sinks;
namespace boost_expressions = boost::log::expressions;
namespace boost_attributes = boost::log::attributes;
namespace boost_trivial = boost::log::trivial;
/*
* 自定义日志等级
*/
enum sign_severity_level {
trace = 0,
debug,
info,
warn,
error,
fatal,
callback
};
#define BOOST_TRACE\
BOOST_LOG_SEV((BoostLog::s_slg), (trace)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_DEBUG\
BOOST_LOG_SEV((BoostLog::s_slg), (debug)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_INFO\
BOOST_LOG_SEV((BoostLog::s_slg), (info)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_WARNING\
BOOST_LOG_SEV((BoostLog::s_slg), (warn)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_ERROR\
BOOST_LOG_SEV((BoostLog::s_slg), (error)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_FATAL\
BOOST_LOG_SEV((BoostLog::s_slg), (fatal)) << __FILE__ << "[" << __LINE__ << "]:"
#define BOOST_CB\
BOOST_LOG_SEV((BoostLog::s_slg), (callback)) << __FILE__ << "[" << __LINE__ << "]:"
#define RUDP_LOG(level, ...) \
BoostLog::Log(level, ...)
// The formatting logic for the severity level
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT >& operator<< (
std::basic_ostream< CharT, TraitsT >& strm, sign_severity_level lvl)
{
static const char* const str[] =
{
"trace",
"debug",
"info",
"warn",
"error",
"fatal",
"callback"
};
if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
strm << str[lvl];
else
strm << static_cast< int >(lvl);
return strm;
}
/*
自定义日志类,在使用之前必须先调用 init方法;
写日志可以调用如下方法:
LOG_DEBUG<<"test string";
也可以用boost 中的宏 BOOST_LOG_TRIVIAL(info)<<"test msg";
*/
class BoostLog
{
public:
BoostLog(){};
~BoostLog(void){ Uninit();}
/*! 在使用此类之前必须先调用此函数进行初始化工作;
* Init_Debug 会添加控制台输出和日志文件输出;
* param@dir : 日志文件存放目录
* param@fileName : 日志文件名前缀
* param@level : 日志过滤等级
* */
static void Init_Debug(const string & dir, const string & fileName, sign_severity_level level)
{
if (_init_flag)
{
return;
}else
{
_init_flag = true;
}
if (boost::filesystem::exists(dir) == false)
{
boost::filesystem::create_directories(dir);
}
//日志名后添加_进程ID,以区分不同进程,防止冲突
string tmp_str = (boost::format("%s_%d") %fileName % getpid()).str();
AddConsoleSink();
AddFileSink(dir, tmp_str);
boost_log::add_common_attributes();
//设置日志过滤等级
SetLogLevel(level);
}
/*! 在使用此类之前必须先调用此函数进行初始化工作;
* Init_Release 添加日志文件输出sink;
* param@dir : 日志文件存放目录
* param@fileName : 日志文件名前缀
* param@level : 日志过滤等级
*/
static void Init_Release(const string & dir, const string & fileName, sign_severity_level level)
{
if (_init_flag)
{
return;
}else
{
_init_flag = true;
}
if (boost::filesystem::exists(dir) == false)
{
boost::filesystem::create_directories(dir);
}
//日志名后添加_进程ID,以区分不同进程,防止冲突
string tmp_str = (boost::format("%s_%d") %fileName % getpid()).str();
AddFileSink(dir, tmp_str);
boost_log::add_common_attributes();
//设置日志过滤等级
SetLogLevel(level);
}
static void Uninit()
{
if (!_init_flag)
{
return;
}else
{
_init_flag = false;
}
boost_log::core::get()->flush();
boost_log::core::get()->remove_all_sinks();
}
static void SetLogLevel(sign_severity_level level)
{
boost_log::core::get()->set_filter(boost_expressions::attr< sign_severity_level >("Severity") >= level);
}
static void Log(sign_severity_level level_, const char* fmt, ...)
{
char str_buf[1024] = {0};
memset(str_buf, 0, sizeof(str_buf));
va_list ap;
va_start(ap, fmt);
vsprintf_s(str_buf, fmt, ap);
va_end(ap);
switch (level_)
{
case trace:
BOOST_TRACE << str_buf;
break;
case debug:
BOOST_DEBUG << str_buf;
break;
case info:
BOOST_INFO << str_buf;
break;
case warn:
BOOST_WARNING << str_buf;
break;
case error:
BOOST_ERROR << str_buf;
break;
case fatal:
BOOST_FATAL << str_buf;
break;
case callback:
BOOST_CB << str_buf;
break;
default:
break;
}
}
protected:
static void Start(){ boost_log::core::get()->set_logging_enabled(true); }
static void Stop(){ boost_log::core::get()->set_logging_enabled(false); }
//打印在控制台
static void AddConsoleSink()
{
boost_log::add_console_log()->set_formatter(
boost_expressions::format("[%1%]<%2%>(%3%): %4%")
% boost_expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f")
% boost_expressions::attr<sign_severity_level>("Severity")
% boost_expressions::attr<boost_attributes::current_thread_id::value_type >("ThreadID")
% boost_expressions::smessage
);
}
//输出至日志文件
static void AddFileSink(const string & dir, const string & fileName)
{
typedef boost_sinks::synchronous_sink< boost_sinks::text_file_backend > sink_t;
boost::shared_ptr< sink_t > pFileSink = boost_log::add_file_log(
boost_keywords::open_mode = std::ios::/*app*/trunc,
boost_keywords::file_name = dir + "/" + fileName + "_%Y-%m-%d(%N).log",
boost_keywords::rotation_size = 10 * 1024 * 1024,
boost_keywords::time_based_rotation = boost_sinks::file::rotation_at_time_point(0, 0, 0), //间隔多长时间自动新建文件
boost_keywords::format =
(
boost_expressions::stream
<< "[" << boost_expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << "]"
<< "<" << boost_expressions::attr<sign_severity_level>("Severity") << ">"
//<< "(" << boost_expressions::attr< boost::log::aux::thread::id >("ThreadID") << ")"
<< boost_expressions::smessage
)
);
pFileSink->locked_backend()->set_file_collector(boost_sinks::file::make_collector(
boost_keywords::target = dir + "/oldlogs", //目标文件夹
boost_keywords::max_size = 100 * 1024 * 1024, //所有日志加起来的最大大小,
boost_keywords::min_free_space = 1000 * 1024 * 1024 //最低磁盘空间限制
));
pFileSink->locked_backend()->auto_flush(true);//使日志实时更新
pFileSink->locked_backend()->scan_for_files();
}
public:
static boost_sources::severity_logger< sign_severity_level> s_slg;
protected:
static bool _init_flag;
};
boost_log.cpp
#include "boost_log.h"
boost_sources::severity_logger< sign_severity_level > BoostLog::s_slg;
bool BoostLog::_init_flag = false;
注意事项:
由于类中均为静态变量,所以一个模块只能写一个日志文件,这也是这个日志类的一个弊端;
不要多个模块同时写同一个名字的文件,否则在对文件进行关闭操作时会导致程序异常;
boost编译为静态库,因boost使用的是动态链接技术,所以在win32代码中不需要手动添加任何静态链接各种lib的代码,只需要在工程中指定库目录即可。