当前位置: 首页 > 代码生活 > 正文

遇到一个日志文件变化带来的文件句柄问题

正在进行的项目中有个系统调试日志存储的功能,需要存储打印信息。测试部反馈了一个bug:调试日志文件有时候不更新。对照代码,项目用的代码和之前项目的代码是一样的。感觉没什么问题,我自己测试没发现有不更新的情况,但测试部已经反馈过几次了,肯定有问题。项目deadline很快到了(按计划,应该是本文发表前4天已经是deadline了),——也正因为如此,开始了本年第一次周末加班。项目经理不放过这个问题,经分析代码,最终算是解决了问题。

事情起因于linux的syslog日志服务和我们所采用的日志分析机制。我们通过syslog函数将日志存放到syslog服务指定的文件(通过配置文件来指定,如/var/log/syslog),人为地规定日志等级,就可以从中分析这些日志来分门别类存储。以前所有的项目,linux系统都是基于内存的ramdisk,一旦断电,系统产生的东西将不复存在。虽然有项目使用了nand flash,但鉴于技术掌握的问题,还是采用内存系统。当时,linux根文件系统使用busybox来构建,很多工具和服务无法和桌面版如ubuntu/fedora匹敌,也正因为如此,系统级别的工具都是针对某一特定功能来移植、剪裁,比如syslog。

上面提到的问题,其实一开始已经遇到了,当时我对syslog配置没什么研究——我根本就不能接触内核和根文件系统这一块,负责上层应用程序的日志模块的同事说有问题,在某个时刻就不能从syslog文件讲到数据了,因为打开该文件的句柄无效了。我查了发现存储的日志容量达到10MB后就会备份,原来的文件会被改名甚至压缩来备份。虽然表面上文件名称不变,但文件已经变化了,句柄自然无效。后来我查到可以通过参数将syslog文件回滚,始终保持一个文件。这样解决了句柄问题,鉴于使用内存系统,这样做也没问题。当时我没有接触上层应用程序,不知他们已经在代码中解决句柄问题(用stat函数来读取并判断新旧文件节点是否一致)。那时我所在的负责linux底层的部门,要不断适应应用程序不好解决的问题,通过修改系统来适应。

后来日志模块使用了新的技术,使用通道函数popen来打开查询日志的命令(但没有对文件句柄作判断),当然,系统级别的syslog配置还是和以前一样。

这个项目中的很多东西和以前不一样,在项目初期没人去评估。我一来被bios和构建适合的系统等事情烦扰,二来本着不在其位不谋其政的态度,对此问题没有过多关注,现在来看,最终的苦果扔给了自己。由于使用了较大容量的硬盘作为存储介质,不再像之前用flash介质那样能省就省。我直接使用ubuntu作为系统的基本版本加上自定义的剪裁,而日志服务,变成了强大的rsyslogd,经过配置,在存储日志体积和时间上达到我认为的平衡点,既不占用太多的硬盘,也能存储约10天的日志信息(对于运维来说,信息实在太可怜了)。因为linux系统中用syslog来记录、备份日志是十分正常的事,我也以为其它同事也此认识。

但我还是没有意识到那个句柄的问题:因为代码沿用以前的,而日志文件机制变化了。于是,测试人员发现这个bug。这个还是项目经理告诉我的,我对公司的架构还不十分熟悉,很多模块没什么文档,之前还有遇到一个问题是因为别人把本该用冒号的地方用逗号而找了好几天,这类的坑,让新手很郁闷。

在保留日志模块用新的方式下修改,发现会影响其它的日志小模块,几经测试,发现不成功,于是改用回旧的方法,经过几次测试,发现没问题,算是解决了。

各有各的错,应用程序人员不应太依赖不变的系统,总想着不动代码,系统自然会适应,大部分人不会让日志信息只存在一个相同的文件而不进行备份的。系统人员不应不了解上层使用而改动某些机制。前者让人觉得换了一个平台上层代码又得改,不符合架构的设计本意;后者觉得不更改,就会固步自封,不能进步。总之,各有各的理,用之前和同事争吵时的话来说:让英明的领导来决断吧。

1.26 周一 PS:
上班时,对这个问题还是不死心,继续研究。代码使用了tail -f来读取日志文件末尾的内容,看了下tail的用法,选项有-f和-F。-F表示“-F same as –follow=name –retry”,因为有retry,会保证文件变化了,继续跟踪内容。当日志文件因为时间或容量到达rotate时,也不怕内容丢失了。

因此,本文遇到的问题,将代码的“-f”改为“-F”即可解决。——又是一个只改动个别字符就解决的bug。当时思路没打开,没往这个方向走,浪费了不少时间。

李迟 2015年1月25日 周日 下午

本文固定链接: http://www.latelee.org/code-life/tail-problem.html

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter