最早使用过log4cpp,后来项目需要尽量少依赖外部so,并且支持跨平台,源码越少越好;
当时使用log4z,并且对性能做了一个简单的测试,但是最近使用中发现:日志量比较大时候,内存占用波动比较大,原因是其内部使用了8k大小的内存块,存放了200个空闲缓冲,另外如果来不及写盘,链表中的数据也会占用内存,所以简单的测试情况下,内存波动比较大。所以决定放弃了。
今天测试了spdlog,总体速度还可以,普通的云机器,能实现20万条的写入(100-200字节)而且内存波动很小,这个很喜人;
但是旧的代码使用了printf格式的日志,
风格是这样的:
LOGFMTD("debug() handle=%lld, time=%lld ", 1LL, getnSecNow());
LOGFMTE("error() handle=%lld, time=%lld ", 1LL, getnSecNow());
LOGFMTW("test warning: %s ", "it is a warn!!!");
为了减少更改,这里做了一个封装与嫁接:
std::shared_ptr<spdlog::logger> logger = nullptr;
#define MSG_BUF_LEN 20
#define LOGFMTW(...) { if (logger->level() <= SPDLOG_LEVEL_WARN){ \
char buffer[MSG_BUF_LEN]; int len = snprintf(buffer, MSG_BUF_LEN, __VA_ARGS__); \
if (len < MSG_BUF_LEN) logger->warn(buffer);\
else { char * buf = new char[len + 2]; snprintf(buf, len + 2, __VA_ARGS__); logger->warn(buf);delete[] buf;} } }
#define LOGFMTD(...) { if (logger->level() <= SPDLOG_LEVEL_DEBUG) { \
char buffer[MSG_BUF_LEN]; int len = snprintf(buffer, MSG_BUF_LEN, __VA_ARGS__); \
if (len < MSG_BUF_LEN) logger->debug(buffer);\
else { char * buf = new char[len + 2]; snprintf(buf, len + 2, __VA_ARGS__); logger->debug(buf);delete[] buf;} } }
#define LOGFMTE(...) { if (logger->level() <= SPDLOG_LEVEL_ERROR) { \
char buffer[MSG_BUF_LEN]; int len = snprintf(buffer, MSG_BUF_LEN, __VA_ARGS__); \
if (len < MSG_BUF_LEN) logger->error(buffer);\
else { char * buf = new char[len + 2]; snprintf(buf, len + 2, __VA_ARGS__); logger->error(buf);delete[] buf;} } }
基本原理:
1)在栈上开辟4k内存,用传统方式格式化,如果不够了,则新开辟空间,并释放,具体大小根据项目情况估算;
2)使用前初始化logger;
示例如下;
// 100Mb
auto max_size = 1024 * 1024 * 100;
auto max_files = 20;
// spdlog::color_mode::automatic
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);
console_sink->set_pattern("[apm] [%^%l%$] %v");
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("logs/cpp-agent.log", max_size, max_files);
file_sink->set_level(spdlog::level::debug);
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(console_sink);
sinks.push_back(file_sink);
logger = std::make_shared<spdlog::logger>("apm", sinks.begin(), sinks.end());
//logger = spdlog::logger("apm", { console_sink, file_sink });
logger->set_level(spdlog::level::err);
logger->flush_on(spdlog::level::err);
最后,可以使用valgrind测试一下内存使用情况;
valgrind --leak-check=full --show-reachable=yes --log-file=a.log ./testlog