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()

 

posted on 2017-01-09 10:11  闻冥  阅读(162)  评论(0编辑  收藏  举报

导航