本文适用范围:Linux系统使用语言:C/C++
打log的原则
- 异常分支或错误处理一定要打log
- 重大操作时一定要打log,下面打log场景会讲述
log格式的原则
1、时间戳必须有,最好能够精确到微秒精确到秒的时间戳,相信很多人都熟悉,这能够确认问题的时间和系统uptime的对比,能够进一步还原问题的场景。至于到微秒,在多线程程序下,如果进程停止响应,可以从日志时间看是否死锁。一般格式:
[2017-01-09 12:16:30.541]
2、打log位置的文件名和代码行数这个不用说,用于定位问题根源。其实最重要是防止扯皮。因为程序员大多喜欢copy-paste,如果你不加文件名和行数,某程序员copy了你的代码,修改了点,出错了,到时候把你拉下水。一般格式:
[2017-01-09 12:16:30.541][network.c:541]
3、有进程id有些log机制在进程重启时,不会重新生成一个日志文件,而是直接在同一个日志文件后面添加日志。或者,有时候同一程序的多个进程同时运行,可能也会写入到同一个日志文件。
一般格式:
[2017-01-09 12:16:30.541][network.c:541][pid=15529]
4、有线程id在多线程程序,如果不加线程id,很难追溯程序的行为。
一般格式:
[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345]
5、有日志的级别日志是反映问题的,有不同紧急程序的问题,自然有不同的日志级别。一般采用Error,Warning,Info,Debug。定义不同级别,也可以方便在日志查找问题来源。
一般格式:
[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][Error]
打log的场景1、申请内存时,失败的话,要把申请大小打印出来
以前我申请内存失败也是简单地打印:
[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][Error]Failedtoallocatememory
后来在重构时遇到一个问题:进程跑的时间一久,大概一天多,别的程序向它发消息都会收到失败响应,在日志里就是一大堆内存失败的消息"Failed to allocate memory"。
用"free"命令来看,物理内存还有好几G空闲,而用“top”命令来看,该进程也只是占700M内存。当时我就怀疑是不是内存碎片导致。于是我把申请内存的大小也打印出来,就收到一堆这样的:
[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][Error]Failed to allocate memory of size 65536
[2017-01-09 12:16:30.588][network.c:541][pid=15529][thread=0x12345][Error]Failedtoallocatememoryofsize1048576
当时就看那些代码引用的数据结构,最小也有64K,大的16M都有,基本一个结构包括很多个大数组。当时就把那些数组全改为指针,再进一步申请,代码繁琐了,但这种问题再也不会出现。再看bug系统,原来这个问题存在很多,在其它程序也存在,当时都找不到根因,只是用过一段时间重启进程来解决2、 函数参数非空判断时,要打印日志原因不说,看对比:
之前:
if ( ( pInfo == NULL ) || ( pHandler == NULL ) )
{
log( ERROR, "invalid arguments" );
}
之后:
if ( ( pInfo == NULL ) || ( pHandler == NULL ) )
{
log( ERROR, "invalid arguments:(pInfo, pHandler )=(%p,%p)",
pInfo, pHandler );
}
3、加载和卸载模块,无论是正常还是异常情况都要打印
毕竟这些操作大多都是一次性操作。对性能影响不大。
[2017-01-09 12:16:30.588][modules.c:54][pid=15529][thread=0x12345][Error]Failedtoloadmodulelibftp.so,error=modulealreadyloaded
4、操作文件目录时,失败要把文件名和错误码打印出来
如:
[2017-01-09 12:16:30.588][config.c:120][pid=15529][thread=0x12345][Error]Failedtoopenfileconf/ftp.xml,errno=(13:Permissiondenied)
假设这个错误导致进程初始化失败,且环境在客户那边,维护人员就可以确认并自己解决这个问题。5、操作socket时,把IP,端口号或路径名(Unix socket )和错误码打印出来
如:
[2017-01-09 12:16:30.588][network.c:541][pid=15529][thread=0x12345][Error]Failedtoconnecttohost(10.17.128.10:9981),errno=(111:Connectionrefused)
假设在客户环境出错,维护人员可以根据日志来确认10.17.128.10这台机器是否在线,是否开启了相应的服务,或者服务是开启了,可能只是端口配置错了(这种情况是扯皮最多的)6、操作数据库时,把相应操作的IP,端口,库,用户名,sql语句和错误打印出来
如:
[2017-01-09 12:16:30.588][dbmgr.c:781][pid=15529][thread=0x12345][Error]user tiger failed to operate in host (10.17.128.10:3365) with db test, sql="select * from users", error="no table users exists"
在客户环境下,维护人员可以通过命令行来验证这些问题,来确定问题。可能有人会考虑安全性,毕竟在日志中把IP,端口,库,用户名都暴露出来了,这样好像不妥。但如果是从事过通信行业的网上问题维护,就知道,可维护性比这种细节的安全性还要重要。7、创建新进程时,需要把程序名,参数和错误码打印出来如:
[2017-01-09 12:16:30.588][process.c:154][pid=15529][thread=0x12345][Error]failed to execute program "iptables -L", errno=(2:No such file or directory)
往往在客户环境,由于运维人员水平参差不齐,可能误操作或漏操作,导致文件缺失或权限出错,这种错误在公司的模拟环境根本不会出现。如果日志够详细,能够减少很多工作量。8、解析文件时,需要把文件名,字段,行号打印出来如:
[2017-01-09 12:16:30.588][config.c:120][pid=15529][thread=0x12345][Error]Failed to parse file conf/ftp.xml, line:20, tag <host> is not closed
结语上面的原则,基本是每一条是血的教训。以前在H时见得太多因为日志不全导致的麻烦,前方的客户经理不断向客户恳求宽限时间,维护人员不断地在客户环境找出蛛丝马迹,后方领导也不断地调配资源来跟踪问题,后方测试人员不断地测试,尝试问题复现,后方开发人员就不断地看代码。在Z也见过因为日志不全,导致被客户罚钱次数过多,整个产品都亏损了。像?@帝都铁匠 说的“感觉学会log,程序就算入门了”。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
程序
+关注
关注
116文章
3779浏览量
80896 -
Log
+关注
关注
0文章
14浏览量
11315 -
线程
+关注
关注
0文章
504浏览量
19660
原文标题:感觉学会log,程序就算入门了
文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
FPGA入门容易,关键是怎么进阶!
本帖最后由 hughqfb 于 2013-1-19 17:34 编辑
FPGA总算入门了,但接下来的学习疲软心理让我十分的懊恼。为什么我发现自己学习到一定程度后就不愿意学习了呢?当时学习
发表于 01-19 17:23
教大家如何看懂电路图
本帖最后由 wpf1633 于 2013-12-3 00:09 编辑
本附件适合初学者,包含各个电子元件的符号,以及一些最基本的电路图,弄懂这些电路,你就算入门了
发表于 12-03 00:06
讨论labview如何算入门?
labview 和其他编程语言一样,(最起码都是编程语言)那么怎么才算入门?入门之后怎么去有效率的研究学习呢?当然学无止境,但是 学要有方法,欢迎过来人指点迷津。
发表于 12-07 08:50
总结大佬经验,如何学习STM32?(入门、进阶)
之内的不会的可以查资料,但是一定要要有自己的思想,完成了我觉得就算入门了。------Llinuxu六、关于初学者是否要弄懂底层函数 初学者没必要弄懂底层函数。项目需要用到什么再去研究什么。比如你的项目
发表于 06-10 09:15
单片机开发怎么才算入门了
记得开始学单片机的时候,也很想知道自己到底学的怎样了,到了什么水平,到处问人单片机开发怎么才算入门了,最后老师跟我说:能做一个万年历出来就算入门了
发表于 01-19 06:27
轻松入门开发ARM程序
很多朋友都想自己动手开发ARM 应用程序,却不知从哪儿下手。我们编写本手册的目的就是想帮助这些初学者轻松的入门。应该说,入门学会开发ST ARM 应用
发表于 01-19 22:20
•31次下载
云计算入门指南
云计算入门指南:Sun 公司云计算技术可顺利地扩展您的基础设施,以抓住新的商业机会。
云计算在许多方面只是互联网的一个比喻词,亦即计算和数据资源日益迁移到 Web
发表于 02-10 09:50
•0次下载
LOG112,LOG2112,pdf(Precision Logarithmic and Log Ratio Ampli
The LOG112 and LOG2112 are versatile integrated circuits that compute the logarithm or log ratio
发表于 09-26 01:10
•38次下载
如何让应用程序感觉更快
好的设计实际上可以让时间加快!
......好吧......不,不是真的,但是Luke W确实分享了一些非常聪明的设计技巧,让你的应用程序感觉更快 - 令人着迷
基于Rust的Log日志库介绍
Rust是一门系统级编程语言,因其安全性、高性能和并发性而备受欢迎。在Rust应用程序中,日志记录是一项非常重要的任务,因为它可以帮助开发人员了解应用程序的运行情况并解决问题。Rust的Log库提供
评论