linux基于file的logger
我们可能会遇到这样的问题:即写出的代码可能需要编译成动态连接库并在不同运行环境下运行,而这些运行环境下log的输出方式可能不同,一种运行环境的log方式在另一种运行环境下可能无法输出。而为保证多种运行环境下的运行正确,我们不能在程序中使用特定运行环境的log机制,于是我们需要找到一种能够在多种运行环境下均能使用的log方式。
有两种办法可以解决这个问题,一种是写一个抽象层的log库,用插件的方式在不同运行环境中加载为当时运行环境编写的log适配插件。另一种方式是将log输出到一个各种运行环境都能看到的地方,这里选择了file,之后为特殊运行环境单独写一个log读取器,将log内容重新输出到当时运行环境中。
我这里演示后一种方式:创建一个如下名为demo_file_logger.h的文件
/** * demo_file_logger.h */ #ifndef DEMO_FILE_LOGGER_H #define DEMO_FILE_LOGGER_H #include <sys/file.h> #include <stdio.h> #include <assert.h> class DemoFileLogger { public: static DemoFileLogger& ref() { static DemoFileLogger self; return self; } ~DemoFileLogger() { if (ok()) { fclose(file); file = nullptr; } } FILE* lock() { flock(file->_fileno, LOCK_EX); return file; } void unlock() { flock(file->_fileno, LOCK_UN); } bool ok() { return file != nullptr; } private: DemoFileLogger() { file = fopen(logFileName, "a"); assert(file); } private: static constexpr const char* logFileName { "/tmp/demo_file_log.log" }; FILE* file { nullptr }; }; #define DEMO_FILE_DEBUG(...) if (DemoFileLogger::ref().ok()) { \ auto f = DemoFileLogger::ref().lock(); \ if (f) { \ fseek(f, 0, SEEK_END); \ fprintf(f, __VA_ARGS__);\ fprintf(f, "\r\n"); \ } \ DemoFileLogger::ref().unlock(); } #define DEMO_FILE_INFO DEMO_FILE_DEBUG #define DEMO_FILE_WARNING DEMO_FILE_DEBUG #define DEMO_FILE_ERROR DEMO_FILE_DEBUG #endif /* DEMO_FILE_LOGGER_H */
之后在另一个头文件demo_debug.h中使用开关ENABLE_DEMO_FILE_LOG来开启FILE LOG的功能
/** * demo_debug.h */ #ifndef DEMO_DEBUG_H #define DEMO_DEBUG_H #ifdef ENABLE_DEMO_FILE_LOG #include "demo_debug_file.h" #else // ENABLE_DEMO_FILE_LOG #include "demo_debug_disable.h #endif // ENABLE_DEMO_FILE_LOG #endif // DEMO_DEBUG_H
我们可以在其他程序代码里使用我们的log宏:
/** * main.cpp */ #include <unistd.h> #define ENABLE_DEMO_FILE_LOG #include "demo_debug.h" int main(int argc, char* argv[]) { for (int i = 0; i < 100; ++i) { DEMO_FILE_DEBUG("hello world %d", i); sleep(1); } return 0; }
这样,log就保存到了/tmp/demo_file_log.log中,我们可以用一个log读取器去实时读取这个log,并且清空这个临时文件,以保证其不会占用过多系统资源,下面是一个python写的示例:
#!/usr/bin/env python def __main(): import fcntl import time f = open("/tmp/demo_file_log.log", "a+") if f: while True: f.seek(0, 2) fl = f.tell() f.seek(0) fcntl.flock(f.fileno(), fcntl.LOCK_SH) if fl > 0: reading = True while reading: s = f.read(1024) print(s) if f.tell() >= fl: reading = False fcntl.flock(f.fileno(), fcntl.LOCK_UN) fcntl.flock(f.fileno(), fcntl.LOCK_EX) reading = True curpos = f.tell() f.seek(0, 2) fl = f.tell() f.seek(curpos, 0) if fl - curpos > 0: while reading: s = f.read(1024) print(s) if f.tell() >= fl: reading = False f.truncate(0) fcntl.flock(f.fileno(), fcntl.LOCK_UN) time.sleep(0.01) if __name__ == "__main__": __main()