Python
Linux
dmesg

Linuxでpythonからdmesg(/dev/kmsg)の更新監視

More than 1 year has passed since last update.

dmesg で確認できるログを tail -F のように末尾更新の監視をするサンプル実装。

dmesg で出力されるリングバッファは /dev/kmsg または /proc/kmsg でファイルとしてオープンできる。

最終行の read でブロックしてしまうため、読み飛ばしの処理の時のみ O_NONBLOCK を指定している。


実装


dmesg(/dev/kmsg)の更新監視

#!/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