背景

项目代码的打印函数,有的用printf,有的用std::cout,风格不统一,也不方便查看,因此需要编写一个统一的函数接口。

需求及实现

  • 时间戳

该打印函数需要有时间戳,精确到毫秒。这样能直观观察程序运行时间。获取时间使用localtime函数,毫秒的获取使用gettimeofday函数。获取时间戳函数get_timestamp没有使用静态局部变量,使用4线程测试,时间戳没有错误情况发生。

  • 打印等级

函数需要有打印等级,目前分为ERROR、WARNING、INFO、DEBUG几种,等级越高,数字越小。在使用时需要根据实际情况,出错的情况使用ERROR。为代码简洁起见,使用gcc扩展语法。

代码如下:

static const char* s_loginfo[] = {[ERROR] = "ERROR",[WARN]  = "WARN",[INFO]  = "INFO",[DEBUG] = "DEBUG",
};

这样通过s_loginfo数组即可获取等级对应的字符串。注意,这种语法只能在C语言中使用,C++代码编译报错。

  • 附加信息

打印时,要附带文件名、行号信息(当然,也可打印函数名称),此举在于方便定位代码。由于Makefile可能不与实现文件在同一目录,因此,文件名可能会带有路径信息,需要用strrchr查找“/”,达到保留文件名的目的。详细参考代码。

  • 检查参数

代码实现需要严谨,传入参数需要严格检查。这里再次使用gcc扩展语法:__attribute__((format(printf,N,M)));这样的好处是,能避免参数不一致。比如字符串使用%d打印时,会提示编译警告。

扩展(未完事宜)

  • 打印等级控制没有很好实现,只是在代码中固定定义一个宏,理论上应该在Makefile中定义,这样无须修改代码。另外,也可以通过配置文件的形式,在执行程序时手动配置等级。

  • 没有添加syslog,因为考虑到docker部署,也考虑到调试权限问题,所以未添加。

  • 处理不同的等级,如ERROR等级的,需要写入EEPROM或flash指定分区文件,以方便长久保存。

完整代码

头文件声明如下:

#ifndef LOG_H_
#define LOG_H_#ifdef __cplusplus
extern "C" {
#endifenum LogLevel
{ ERROR = 1, WARN  = 2, INFO  = 3, DEBUG = 4,
};void mylog1(const char* filename, int line, enum LogLevel level, const char* fmt, ...) __attribute__((format(printf,4,5)));#define mylog(level, format, ...) mylog1(__FILE__, __LINE__, level, format, ## __VA_ARGS__)#ifdef __cplusplus
};
#endif#endif

实现代码如下:

/**
日志打印示例。
使用:
mylog(DEBUG, "This is debug info\n");
结果:
[2018-07-22 23:37:27:172] [DEBUG] [main.cpp:5] This is debug info
默认打印当前时间(精确到毫秒)、文件名称、行号。
*/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>#include "log.h"#ifndef LOGLEVEL
#define LOGLEVEL DEBUG
#endif// 使用了GNU C扩展语法,只在gcc(C语言)生效,
// g++的c++版本编译不通过
static const char* s_loginfo[] = {[ERROR] = "ERROR",[WARN]  = "WARN",[INFO]  = "INFO",[DEBUG] = "DEBUG",
};static void get_timestamp(char *buffer)
{time_t t;struct tm *p;struct timeval tv;int len;int millsec;t = time(NULL);p = localtime(&t);gettimeofday(&tv, NULL);millsec = (int)(tv.tv_usec / 1000);/* 时间格式:[2011-11-15 12:47:34:888] */len = snprintf(buffer, 32, "[%04d-%02d-%02d %02d:%02d:%02d:%03d] ",p->tm_year+1900, p->tm_mon+1,p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, millsec);buffer[len] = '\0';
}void mylog1(const char* filename, int line, enum LogLevel level, const char* fmt, ...)
{if(level > LOGLEVEL)return;va_list arg_list;char buf[1024];memset(buf, 0, 1024);va_start(arg_list, fmt);vsnprintf(buf, 1024, fmt, arg_list);char time[32] = {0};// 去掉*可能*存在的目录路径,只保留文件名const char* tmp = strrchr(filename, '/');if (!tmp) tmp = filename;else tmp++;get_timestamp(time);printf("%s[%s] [%s:%d] %s\n", time, s_loginfo[level], tmp, line, buf);va_end(arg_list);
}

注:本文所示代码可随意使用。代码不是最终应用到实际项目版本。

李迟 2017.7.25 夜

Linux C简单日志打印代码示例相关推荐

  1. python画折线图代码-python绘制简单折线图代码示例

    1.画最简单的直线图 代码如下: import numpy as np import matplotlib.pyplot as plt x=[0,1] y=[0,1] plt.figure() plt ...

  2. python画折线图详解-python绘制简单折线图代码示例

    1.画最简单的直线图 代码如下: import numpy as np import matplotlib.pyplot as plt x=[0,1] y=[0,1] plt.figure() plt ...

  3. html5自动打印图片,html2canvas生成清晰的图片实现打印代码示例

    本篇文章小编给大家分享一下html2canvas生成清晰的图片实现打印代码示例,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 基本用法 处理模糊问题 细节问题-压缩base ...

  4. python画折线图虚线_python绘制简单折线图代码示例

    1.画最简单的直线图 代码如下: import numpy as np import matplotlib.pyplot as plt x=[0,1] y=[0,1] plt.figure() plt ...

  5. python画折线图-python绘制简单折线图代码示例

    1.画最简单的直线图 代码如下: import numpy as np import matplotlib.pyplot as plt x=[0,1] y=[0,1] plt.figure() plt ...

  6. java占位符打印_java简单日志打印规范小记

    个人认为,如果公司一些基础类库不做约束,很可能"埋坑",形成技术债务,最终为此付出代价.本文讲解一个最基本的日志打印规范. 1. 日志打印组件 日志组件有很多,日志门面的选择有:S ...

  7. 一段简单的打印代码(c#)

    代码  1 //数据流     2 System.IO.StringReader sr;  3       //要打印的字符串  4         private void redstr()  5  ...

  8. qtp xml联合xsl输出html报表,通过xml和xsl实现数据和页面展示模板的解耦(简单完整网站代码示例)...

    一.示例简介 该示例通过xml配置数据源,在其xsl样式模板中配置数据源的展示模板,从而达到数据和页面模板解耦,降低前端和后端开发的依赖,相比于传统的HTML+CSS的实现页面模板展示,数据和模板解耦 ...

  9. Linux之poll/select/epoll代码示例

    Linux poll and epoll poll 问题:假如应用需要根据IO的状态来读或写多个IO,如何处理?如果是一个进程处理,一个一个IO的处理,那么就势必会出现阻塞等待某个IO的过程,此时就可 ...

最新文章

  1. 开启ubuntu的SSH服务,使用终端远程控制
  2. 锁Lock 那点事儿
  3. 直播「拯救」互联网?
  4. 从菜鸟到专家的五步编程语言学习法
  5. C0302 将一个代码块中的内容保存在文件中, 查看一个rpm包是否可以安装
  6. android滚动条布局横向,Android自定义ViewGroup实现可滚动的横向布局(2)
  7. C++学习之路 | PTA乙级—— 1021 个位数统计 (15分)(精简)
  8. 信息学奥赛一本通(2032:【例4.18】分解质因数)
  9. 机器学习实战(一)xgboost实战
  10. 电脑软件测试英雄联盟,揭秘英雄联盟的自动化测试
  11. 腾讯企业邮箱申请步骤
  12. 笔记|角度传感器angular transducer
  13. 自己动手实现fft.m函数
  14. 1.65亿融资背后,是时候把「百度」标签从林元庆身上摘下了| 人物特写
  15. 【游戏介绍】aiwi3D疯狂平衡球
  16. CAS、AtomicInteger、synchronized原理
  17. 改进后的A星三维路径规划完整算法(matlab语言)
  18. 人人网登陆之C++版(MFC)
  19. 提高IIS的FTP安全性 管理员的九阴真经
  20. 【IIS服务器】IIS服务器常见漏洞

热门文章

  1. lnmp 下php升级,lnmp nginx和php升级方法
  2. eZ publish 3 安装指南
  3. 这个温州人,是中国开店最多的炸鸡王者
  4. 外媒:特斯拉CEO马斯克加入反对英伟达收购Arm交易行列
  5. 闲鱼的真正用法,其实是找对象
  6. 2020年假期结束!支付宝发布国庆中秋黄金周报告:出行人次、购买力惊人!
  7. Galaxy Note 20新爆料:至少有两款机型,处理器高低配
  8. 三星Galaxy S20系列机模上手视频曝光:不再单独设置Bixby按键
  9. 腾讯32款游戏退市,只因为这个理由!
  10. 2499元!Beats最新降噪耳机Solo Pro来了:加入降噪、通透两种模式