dmesg
で確認できるログを tail -F
のように末尾更新の監視をするサンプル実装。
dmesg
で出力されるリングバッファは /dev/kmsg
または /proc/kmsg
でファイルとしてオープンできる。
最終行の read
でブロックしてしまうため、読み飛ばしの処理の時のみ O_NONBLOCK
を指定している。
実装
# !/usr/bin/env python2
# cofing: UTF-8
import os
import fcntl
import time
def readLines(path):
with open(path, "r") as fp:
stat = os.stat(path)
fp.seek(stat[6])
where = None
# =================
# seek to last line
# =================
fd = fp.fileno()
flag = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
try:
# FIXME
for last in fp:
pass
except IOError as e:
if e.errno != 11:
raise
fcntl.fcntl(fd, fcntl.F_SETFL, flag)
# =================
# tailf impl
# =================
try:
while True:
where = fp.tell()
line = fp.readline()
yield line
except KeyboardInterrupt:
pass
if __name__ == "__main__":
import sys
for line in readLines("/dev/kmsg"):
if str(line).find("stop tailf") >= 0:
print "### stop watch tailf ###"
break
else:
print line,
※通常のファイルの更新監視の場合は、最終行到達時に fp.readline()
で止まらないため修正が必要
実行とその結果は以下のようになる。
$ ./tailf.py
12,642,9584294872,-;aaa
12,643,9588998703,-;bbb
12,644,9593362017,-;ccc
### stop watch tailf ###
/dev/kmsg
にリダイレクトすることで、擬似的にドライバのログの出力を確認している
$ sudo sh -c "echo aaa > /dev/kmsg"
$ sudo sh -c "echo bbb > /dev/kmsg"
$ sudo sh -c "echo ccc > /dev/kmsg"
$ sudo sh -c "echo stop tailf > /dev/kmsg"
TODO
pythonでファイルの最終行にseekする良い方法がいまいち分からなかったため、最終行まですべて読みだす方法で実装してしまっている。
巨大なファイルの場合、読み飛ばしだけで地味に時間がかかる可能性がある。(リングバッファのサイズを変更している場合等)
# FIXME
for last in fp:
pass
参考
Emerge Technology: Pythonでtailもどき
テキストファイルから指定した文字列を含む行を出力する - Qiita
python - What is the most efficient way to get first and last line of a text file? - Stack Overflow
Get last n lines of a file with Python, similar to tail - Stack Overflow
python Non-block read file - Stack Overflow