5

我正在尝试使用 systemd 库 http://www.freedesktop.org/software/systemd/python-systemd/journal.html在 Python 中模拟这个 shell 命令

我实际上是在尝试在 Python 中模拟这个命令。

journalctl --since=-5m --no-pager

我已经看到其他人在 Python 中通过调用日志可执行文件来执行此操作,但这是一种非常糟糕的方法。

我根据上面链接的文档编写了这个简单的脚本

import select
from systemd import journal

j = journal.Reader()
j.log_level(journal.LOG_INFO)
# j.add_match(_SYSTEMD_UNIT="systemd-udevd.service")

j.seek_tail()
j.get_next()

while j.get_next():
    for entry in j:
        if entry['MESSAGE'] != "":
            print(str(entry['__REALTIME_TIMESTAMP'] )+ ' ' + entry['MESSAGE'])

这里有几个问题

  1. 日志似乎从大约 5 天前开始,这意味着 seek_tail 似乎没有工作。
  2. 我在这里收到了很多垃圾,我应该使用一个特定的过滤器来匹配我从问题开头给出的 journalctl 命令中获得的数据吗?

理想情况下,从长远来看,我只想根据一组过滤器/匹配来关注该期刊,以模拟命令“journalctl -f”,但我只需要先解决这个问题。我想结束这样的事情,但它也不起作用。

import select
from systemd import journal

j = journal.Reader()
j.log_level(journal.LOG_INFO)

# j.add_match(_SYSTEMD_UNIT="systemd-udevd.service")
j.seek_tail()

p = select.poll()
p.register(j, j.get_events())
while p.poll():

    while j.get_next():
        for entry in j:
            if entry['MESSAGE'] != "":
                print(str(entry['__REALTIME_TIMESTAMP'] )+ ' ' + entry['MESSAGE'])
4

2 回答 2

11

我也在研究类似的 python 模块。

根据以下链接,我们必须调用sd_journal_previous(在 python systemd 模块中,即journal.Reader().get_previous())。

http://www.freedesktop.org/software/systemd/man/sd_journal_seek_tail.html

https://bugs.freedesktop.org/show_bug.cgi?id=64614

此外,您的示例代码将消耗 80-100% 的 CPU 负载,因为即使在获取条目后阅读器的状态仍保持“可读”,这会导致过多的poll().

根据以下链接,似乎我们必须在每个之后调用sd_journal_process(在 python systemd 模块中,即journal.Reader().process()poll(),以重置文件描述符的可读状态。

http://www.freedesktop.org/software/systemd/man/sd_journal_get_events.html

总之,您的示例代码将是:

import select
from systemd import journal

j = journal.Reader()
j.log_level(journal.LOG_INFO)

# j.add_match(_SYSTEMD_UNIT="systemd-udevd.service")
j.seek_tail()
j.get_previous()
# j.get_next() # it seems this is not necessary.

p = select.poll()
p.register(j, j.get_events())

while p.poll():
    if j.process() != journal.APPEND:
        continue

    # Your example code has too many get_next() (i.e, "while j.get_next()" and "for event in j") which cause skipping entry.
    # Since each iteration of a journal.Reader() object is equal to "get_next()", just do simple iteration.
    for entry in j:
        if entry['MESSAGE'] != "":
            print(str(entry['__REALTIME_TIMESTAMP'] )+ ' ' + entry['MESSAGE'])
于 2014-10-14T08:55:07.650 回答
3

先前的答案有效,并且在 seek_tail() 之后调用 get_next() 的提示确实是必不可少的。

一种更简单的方法是(但显然使用轮询的先前版本在更大的应用程序中更灵活)

import systemd.journal

def main():
  j = systemd.journal.Reader()
  j.seek_tail()
  j.get_previous()
  while True:
    event = j.wait(-1)
    if event == systemd.journal.APPEND:
      for entry in j:
         print entry['MESSAGE']

if __name__ == '__main__':
  main()

如果想详细了解正在发生的事情,支持调试输出的以下版本可能会有所帮助(用一些参数调用它会打开它)

import sys
import systemd.journal

def main(debug):
  j = systemd.journal.Reader()
  j.seek_tail()
  j.get_previous()
  while True:
    event = j.wait(-1)
    if event == systemd.journal.APPEND:
      for entry in j:
         print entry['MESSAGE']
    elif debug and event == systemd.journal.NOP:
      print "DEBUG: NOP"
    elif debug and event == systemd.journal.INVALIDATE:
      print "DEBUG: INVALIDATE"
    elif debug:
      raise ValueError, event   

if __name__ == '__main__':
  main(len(sys.argv) > 1)

对我来说,它总是在开始时导致一个 INVALIDATE。不确定这到底意味着什么。让用作迭代器的东西失效对我来说,我可能会以某种方式重新创建/重新打开/刷新它。但至少在我的基本测试期间,上面的代码可以正常工作。不确定是否有任何竞争条件。实际上,我很难解释该代码如何没有种族。

于 2015-02-17T15:56:39.527 回答