文章目录
一、前言
python通过fllow读取文件,需求是可以监控log文件,当文件行数增加的话,就写入到数据库,也可以读取历史log文件,写入到数据库,因此我们通过给脚本添加参数的方式来区分是否监控log文件。
可是当执行python的时候,明明log文件没有新增数据,但是发现每隔60s,python就会读取log文件的旧数据,并插入到数据库。这当然是不符合需求的,正常来说,log文件无变化,fllow不应该再去读取文件才对。
二、读取fllow源码
遇到文件就读源码,码中自有黄金屋,码中自有颜如玉。
1、fllow读取文件代码
thefile = follow.Follow(filename, False)
fllow的Follow函数如下:
class Follow(object):
def __init__(self, fname, start=False, new_file_check=60, *open_args):
可以看到参数中有个new_file_check =60,这个参数会不会就是罪魁祸首呢?
2、跟踪new_file_check 函数
def _preread(self):
if not self.f:
self._reopen(False)
return
t = time.time()
if t >= self.stat_time + self.stat_time_min: # 这部分用到了
nstat = os.stat(self.fname)
self.stat_time = t
if nstat.st_dev != self.stat.st_dev or \
nstat.st_ino != self.stat.st_ino:
# start at top of new file
self._reopen(True)
return
# should clear previous EOF condition
self.f.seek(self.pos)
代码的语意是:
当60s之后,脚本会重新获取文件的相关属性,并对比文件的相关参数,若参数不一致则重新读取文件。
看来问题就出在了这个对比属性上,下面先看看这些属性都是什么意思
3、python的stat函数
根据if条件左边的代码格式,我们知道是用os.stat()函数的返回值进行对比的。
根据if条件右边的代码格式,我们可追踪代码,最终锁定在os.fstat()函数
手册解析:
https://www.runoob.com/python/os-stat.html
os.stat() 方法用于在给定的路径上执行一个系统 stat 的调用。
https://www.runoob.com/python/os-fstat.html
os.fstat() 方法用于返回文件描述符fd的状态,类似 stat()。Unix,Windows上可用。
根据这个教程,我们发现
os.stat返回的结果有:
st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。 等
os.fstat返回的结果有:
st_dev: 设备信息
st_ino: 文件的i-node值
4、分析出错代码
if nstat.st_dev != self.stat.st_dev or \
nstat.st_ino != self.stat.st_ino:
# start at top of new file
self._reopen(True)
return
首先是对比: inode 驻留的设备 != 设备信息
其次是对比:inode 节点号 != 文件的i-node值
两次对比有一次不同则重新读取文件,也就是造成我们上面的bug。
三、windows下对比inode 节点号
1、windows下打印这几个参数
print nstat.st_dev
print self.stat.st_dev
print nstat.st_ino
print self.stat.st_ino
结果:
0
0
0
73746443898579758
OK,根据结果已经知道是文件的inode值不同,所以造成了重新读取文件的bug。那么为什么文件属性会发生变化呢,本地数据量又没有增加。而且既然这个文件是常用的读取文件脚本,那么怎么可能会有这明显的bug
2、os.start() 与 os.fstat()
首先明确一点,两个函数都能在windows下正常运行。函数含义也有些相似,唯一不一样的一点就是inode的值,关于inode,听说最多的就是linux文件系统的inode了,那么会不会是windows下的inode和linux的inode不一样,或者windows不够稳定呢
3、linux文件的inode会保持不变吗?
答案:
inode在文件的生命周期里是不改变的,除非,你把文件删除重建。而你删除文件前100行的动作,实际上是新建一个临时文件,把旧文件第100行以后的东西输出到临时文件里,删掉旧文件,把临时文件的文件名重命名成旧文件的名字。也就是说你删前100行的时候,文件已经经历了删除-重建的过程,inode号也就改变了。
作者:北极
链接:https://www.zhihu.com/question/26127845/answer/32214159
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4、windows文件的inode会保持不变吗?
通过搜索我们发现,对于windows来说,它有类似于inode的概念,比如通过卷序列号/ FileId组合等来标识目录文件,但是windows下并没有直接的inode概念,所以在windows下通过inode对比文件是不稳定且不精准的。
关于windows的inode,有兴趣的可以参考:
http://zgserver.com/windowsinode.html
http://cn.voidcc.com/question/p-nvmqdzhb-vo.html
这样一对比,答案就很明显了,windows下问题奇葩问题多,怪不得大佬们都用mac电脑开发呢,大佬们果然诚不我欺。
四、解决方案
通过以上的分析,可以知道这个锅算是windows的锅,怪不得py脚本在windows下那么多的bug,因为windows和linux在某些函数调用上还是有一些差距的,建议是到linux服务器上跑一跑看看。
因此上传py脚本到linux,在linux上测试,发现完美实现监控日志文件的目的,文件有更新则写入到数据库,无更新则持续读取。
五、总结
通过这篇文章的分析,对博主对打的触动就是:windows环境果然是坑。 怪不得大佬们都是用mac电脑,天天在linux下开发呢,博主本来在windows下开发php开发的不亦乐乎,只可惜以后始终是要用到编译型语言的,早晚都要完全在linux下开发啊。。
行吧,解决问题的过程永远是复杂的,查找的过程永远是享受,通过这个问题博主又学到了很多python的知识,整体来说还是很赞的。
我是铁柱,我为自己代言!
end
转载:https://blog.csdn.net/LJFPHP/article/details/102545525