zoukankan      html  css  js  c++  java
  • 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, "
    "); 
      } 
      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()
  • 相关阅读:
    30天敏捷结果(26): 如何解决问题
    30天敏捷结果(30):提升敏捷结果
    30天敏捷结果(27):做些有重要意义的事
    STM32笔记A
    嵌入式linux驱动开发入门总结
    2014年个人计划
    迄今为止见过最好的职业规划
    30天敏捷结果(28):撰写你的个人使命
    C语言深度解剖读书笔记
    基于 SQLite 数据库的 C# 实体模型的实现
  • 原文地址:https://www.cnblogs.com/astreye/p/6264158.html
Copyright © 2011-2022 走看看