检测日志文件轮换(同时观察日志文件以进行修改)

时间:2017-06-07 08:48:10

标签: python linux logging

我使用以下代码来跟踪ssh登录:

readline()

我注意到这个剧本在几天后突然停止工作。我没有收到任何错误,它没有终止,它只是停止工作,好像echo 'test' >> auth.log.1永远不会返回。

所以我执行了一个auth.log,这确实最终被脚本处理了,因为前一段时间auth.log.1被重命名为{{1}}

如何跟踪何时发生这种日志轮换并进行相应调整?

4 个答案:

答案 0 :(得分:5)

使用e4c5的答案我最终得到了这段代码,这也解决了每秒多次调用readline()的问题。

在第一次调用期间,它会跳到文件末尾并等待修改。移动文件后,它会重新打开文件并读取整个内容,然后开始等待。

import os
import time
import traceback
import threading
import inotify.adapters

logfile = b'/var/log/auth.log'
#logfile = b'logfile.log'

##################################################################

def process(line, history=False):
  if history:
    print '=', line.strip('\n')
  else:
    print '>', line.strip('\n')

##################################################################

from_beginning = False
notifier = inotify.adapters.Inotify()
while True:
  try:
    #------------------------- check
    if not os.path.exists(logfile):
      print 'logfile does not exist'
      time.sleep(1)
      continue
    print 'opening and starting to watch', logfile
    #------------------------- open
    file = open(logfile, 'r')
    if from_beginning:
      for line in file.readlines():
        process(line, history=True)
    else:
      file.seek(0,2)
      from_beginning = True
    #------------------------- watch
    notifier.add_watch(logfile)
    try:
      for event in notifier.event_gen():
        if event is not None:
          (header, type_names, watch_path, filename) = event
          if set(type_names) & set(['IN_MOVE_SELF']): # moved
            print 'logfile moved'
            notifier.remove_watch(logfile)
            file.close()
            time.sleep(1)
            break
          elif set(type_names) & set(['IN_MODIFY']): # modified
            for line in file.readlines():
              process(line, history=False)
    except (KeyboardInterrupt, SystemExit):
      raise
    except:
      notifier.remove_watch(logfile)
      file.close()
      time.sleep(1)
    #-------------------------
  except (KeyboardInterrupt, SystemExit):
    break
  except inotify.calls.InotifyError:
    time.sleep(1)
  except IOError:
    time.sleep(1)
  except:
    traceback.print_exc()
    time.sleep(1)

##################################################################

答案 1 :(得分:2)

最好使用inotify,您不希望继续轮询文件系统,以询问在循环的每次迭代过程中是否有变化。这是浪费了很多IO。发生更改时,inotify通知您。手册中有一个示例,显示了它与日志文件的用法。

答案 2 :(得分:1)

你可以查看文件的inode。

import os
inode = os.stat('/var/log/auth.log').st_ino

当inode更改时,文件已旋转。

答案 3 :(得分:1)

显然,我只有在> = 50的声誉时才能发表评论。

@ daniel-f有一个很棒的例子!我遇到的唯一情况是,当我正在读取的创建循环日志文件的服务重新启动时,它将删除旧文件并创建新文件。

这会导致“通知程序”失去对日志文件的可见性(因为它有所不同)。

由于服务每60秒写入一次日志文件,因此我对for循环进行了快速修改,如下所示:

last_pull = datetime.datetime.now()
while True:
...
...

            for event in notifier.event_gen():
                if event is not None:
                    last_pull = datetime.datetime.now()
                    (header, type_names, watch_path, filename) = event
                    if set(type_names) & set(['IN_MOVE_SELF']): # moved
                        notifier.remove_watch(file_watcher.intput_logfile)
                        file.close()
                        time.sleep(1)
                        break
                    elif set(type_names) & set(['IN_MODIFY']): # modified
                        lines = file.readlines()
                        for line in lines:
                            process(line, file_watcher, history=False)
                else:
                    if (datetime.datetime.now() - last_pull).total_seconds() >= time_to_refresh:
                        last_pull = datetime.datetime.now()
                        notifier.remove_watch(file_watcher.intput_logfile)
                        file.close()
                        break

这将在75秒后重新监视文件而不进行更新。