我们可能会遇到这样的问题:即写出的代码可能需要编译成动态连接库并在不同运行环境下运行,而这些运行环境下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, , 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 = ; i < ; ++i)
{
DEMO_FILE_DEBUG("hello world %d", i);
sleep();
}
return ;
}

这样,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()

linux基于file的logger的更多相关文章

  1. Linux -- 基于zookeeper的java api(二)

    Linux -- 基于zookeeper的java api(二) 写一个关于基于集群的zookeeper的自定义实现HA 基于客户端和监控器:使用监控的方法查看每个注册过的节点的状态来做出操作. Wa ...

  2. Linux -- 基于zookeeper的java api(一)

    Linux -- 基于zookeeper的java api 首先启动你所有的 zkService.sh 查看状态:检查是否启动正确 [root@hu-hadoop2 ~]# zkServer.sh s ...

  3. linux -- 基于zookeeper搭建yarn的HA高可用集群

    linux -- 基于zookeeper搭建yarn的HA高可用集群 实现方式:配置yarn-site.xml配置文件 <configuration> <property> & ...

  4. linux C file format analysis

    c语言文件格式 source file file.c C source, ASCII text pretreatment 预处理文件 file.i C source, ASCII text assem ...

  5. linux move file / folder bash command

    linux move file / folder bash command mv $ which mv $ man mv # mv [-f] source target/ target folder ...

  6. Linux基于Docker的Redis主从复制、哨兵模式搭建

    本教程基于CentOS7,开始本教程前,请确保您的Linux系统已安装Docker. 1.使用docker下载redis镜像 docker pull redis 安装完成后,使用docker imag ...

  7. 基于File NIO写的一个文件新增内容监控器

    基于File NIO写的一个文件新增内容监控器 需求说明 监控一个文件,如果文件有新增内容,则在控制台打印出新增内容. 代码示例 FileMoniter文件监控器类 package com.black ...

  8. 嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示

    在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们 ...

  9. Linux Kernel File IO Syscall Kernel-Source-Code Analysis(undone)

    目录 . 引言 . open() syscall . close() syscall 0. 引言 在linux的哲学中,所有的磁盘文件.目录.外设设备.驱动设备全部被抽象为了"文件" ...

随机推荐

  1. activemq 的小实验

    package ch02.chat; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms ...

  2. CenOS中下载RPM包

    在实施部署时,往往服务器环境无外网或无法访问国外网址.这是可以在本机虚拟机的CentOS环境中下载RPM. 方法一:yum yum命令本身就可以用来下载一个RPM包,标准的yum命令提供了--down ...

  3. 50道经典的JAVA编程题 (6-10)

    50道经典的JAVA编程题 (6-10),今晚做了10道了,累死了...感觉难度不是很大,就是不知道是不是最好的实现方法啊!希望大神们能给指点哈... [程序6]GCDAndLCM.java 题目:输 ...

  4. ubuntu 13.04下sublime text 3使用中文输入法

    主要思路参考 http://blog.yanwen.org/archives/1955.html libsublime-imfix.so 这个库自己编译和从他这下载的 md5一样.可以不用编译了.直接 ...

  5. [C语言 - 11] 语言编译执行

    使用gcc编译器 1.预编译 gcc -E Hello.c -o Hello.i 2.汇编 gcc -S Hello.i -o Hello.s   3.编译 gcc -c Hello.s -o Hel ...

  6. [Objective-c 基础 - 2.9] 类的本质

    A.概念 类对象:类也是一个对象,是Class类型的对象 实例对象:创建的对象,有一个isa指针指向类   B.操作 获取内存中的内对象 1. 使用实例对象获取 Class c = [p class] ...

  7. 使用Redis bitmaps进行快速、简单、实时统计

    原文:Fast, easy, realtime metrics using Redis bitmaps (http://blog.getspool.com/2011/11/29/fast-easy-r ...

  8. Windows下环境变量配置

    JAVA_HOME=C:\Program Files\Java\jdk1.6.0_33   PATH+=%JAVA_HOME%\bin;   CLASSPATH=.;%JAVA_HOME%\lib\d ...

  9. DotNET 开发常用工具汇集

    开发用专业软件已经很多了,来说说开发用的辅助软件把--分享我常使用的辅助软件 个人工具清单 .NET 程序员十种必备工具 新.net开发十大必备工具 .NET开发不可错过的25款必备工具 我的生活必备 ...

  10. xps13 关机充电 右边的usb口

    bios里设置了 usb powershare但关机的时候还是不能充电 度娘了一下,发现不解决问题,只能放狗了.果然谷歌里搜到答案,是windows的电源策略. I figured it out. A ...