本文共 2239 字,大约阅读时间需要 7 分钟。
在程序开发中,日志功能是非常重要的。对于开源日志库如 log4j 到 C++ 的 log4cpp,各大公司也都有自己的日志库实现。这些日志库通常支持分离的线程和缓存机制,以减少日志写入操作对程序性能的影响,特别是在不能阻塞的场景下。
为了满足普通项目中对日志功能的需求,我实现了一个文件轮转日志库。这个日志库支持将日志内容轮转到多个文件中,每次文件满写时换新文件,并对旧文件进行编号。例如,日志文件可能按照 my.log
, my.log.1
, my.log.2
等形式轮转。
该日志库的核心功能包括:
代码实现如下:
#ifndef ROTATE_LOG_INC#define ROTATE_LOG_INC#include#include #include #include #include #include #include namespace rotate_log { enum { DEBUG = 0, INFO, WARN, ERROR, ALERT }; class RotateLog { public: RotateLog(); ~RotateLog(); int init(char* basename, int file_size, int file_num, int level = DEBUG); int set_level(int level); int get_level() const; int close(); int reopen(); bool is_too_big(); int check(); int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len); int manage_log(); int shift_file(char* basename, int num); }; #define ROTATE_LOG(log, level, format, ...) \ do { \ if (log.level >= level) { \ log.check(); \ fprintf(log.file_, "%s[%d][%s][%d]: " format "\n", #level, __FILE__, __LINE__); \ } \ } while (0) #define ROTATE_LOG_TO_FILE(log, basename, file_size, file_num) } #endif
除了文件轮转日志库,还实现了一个基于标准错误输出的日志库。这种日志库可以将标准错误输出重定向到文件中,并支持轮转。代码实现如下:
#ifndef STDERR_LOG_INC#define STDERR_LOG_INC#include#include namespace stderr_log { enum { DEBUG = 0, INFO, WARN, ERROR, ALERT }; int __attribute__((weak)) g_log_level = 0; int __attribute__((weak)) g_log_pid = getpid(); void set_level(int level); int get_level() const; void set_pid(pid_t pid); #define STDERR_LOG(level, format, ...) \ do { \ if (stderr_log::level >= stderr_log::g_log_level) { \ fprintf(stderr, "[%s][%d][%s][%d]: " format "\n", #level, __FILE__, __LINE__, __VA_ARGS__); \ } \ } while (0)}#endif
程序何时检测日志是否需要轮转,主要取决于具体应用的需求。为了保证高效性,我采取了“策略于机制分离”的原则。在 CGI 程序中,通常在处理每个请求前进行日志检测。
日志轮转的实现可以灵活配置,支持基于文件大小或文件数量的轮转策略。这种灵活性使得日志管理更加高效,能够适应不同应用场景的需求。
通过以上日志轮转库的实现,可以轻松管理程序的日志输出,确保日志的高效写入和管理。
转载地址:http://igtbz.baihongyu.com/