以编程方式解析 journalctl 以启动操作
Programmaticaly parse journalctl to initiate an action
当我的 3d 打印机耗尽耗材时,它会暂停而不发送任何警告消息。我能找到的唯一条目是在 journalctl 上的一条消息,如下所示:
Jan 22 04:36:39 ultimakersystem-flipflop_wsgi.py[2884]: INF - root:80 - PrintJobStatus updated! 6e408dcf-9887, paused
我绝对需要在打印机暂停时得到提醒,否则打印会被破坏。有没有办法以编程方式 poll/parse journalctl,例如通过 bash 或 python 脚本,并根据需要发送电子邮件?
可能还有其他比轮询更优雅的方法,但是 FWIW:
journalctl
可以time-filter其输出;例如查看最后 30 分钟 activity:
journalctl --since "30 min ago" --until "now"
cron
可以 运行 不同时间间隔的作业;例如每 30 分钟 运行 以上 journalctl
作业,将此行放入您的 crontab
:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now"
- 必须检查上面的
journalctl
输出是否与感兴趣的 日志条目 匹配。从您发布的错误消息中,我不知道 关键字 究竟是什么提示了一个空的灯丝箱,但我们现在假设它们是 ultimakersystem
和 paused
. awk
提供了一种可扩展的方式来查找匹配的单词和短语:当两个模式出现在 journalctl
输出的同一行时,awk '/pattern1/ && /pattern2/'
匹配,因此从 [=] 添加一个 pipe
14=]输出到awk
;上面的 cron
作业修改如下:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now" | awk '/ultimakersystem/ && /paused/'
- 最后一步是测试
awk
是否找到匹配项,如果找到,则向指定用户发送消息。如果有一个或多个匹配,只需要发送一封电子邮件,因此匹配测试将在 END
部分进行。 cron
作业再次更新如下:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now" | awk '/ultimakersystem/ && /paused/ {m=1}; END { if (m == 1){system("cat warn.txt | mail -s FILAMENT_NEEDED $USER")} }'
awk
使用 pattern-action 范式; /ultimakersystem/ && /paused/
是 模式 ,{m=1}
是 动作 。 awk
处理完所有 journalctl
输出后,执行 END
部分。一个简单的 if (m == 1)
测试确定是否出现一个或多个匹配项,如果出现,则调用 mail
命令发送 warn.txt
中定义的消息。 GNU awk
的 system
函数 REF 提供对系统命令库的访问。
在更改此食谱的许多其他可能性中,可以将 date-time 邮票 插入电子邮件正文,方法是将 cat warn.txt
替换为 date
,并向 $USER
以外的人发送邮件。请参阅 man mail
,或您的电子邮件客户端的文档。
我已经用 python 脚本解决了这个问题。我认为它比 cronjob 更有效,因为它会在找到关键字(在本例中为“暂停”一词)时做出反应,而无需轮询。
import systemd.journal
import socket
from time import sleep
import smtplib
from smtplib import SMTP
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'])
alertmail(entry['MESSAGE'])
def alertmail(logEntry):
# returns first occurrence of Substring
trigger_text = 'pause'
result = logEntry.find(trigger_text)
if (logEntry.find(trigger_text) != -1):
print ("Contains '" + trigger_text + "' at index:", result)
fromaddr = "ultimaker@mymailstrasse.com"
toaddrs = "aag@bluewin.ch"
msg = "ultimaker has paused!!! " + logEntry
smtp = smtplib.SMTP('mail.mymailstrasse.com', port='587')
smtp.ehlo() # send the extended hello to our server
smtp.starttls() # tell server we want to communicate with TLS encryption
smtp.login('ultimaker@mail.mymailstrasse.com', 'pw') # login to our email server
# send our email message 'msg' to our boss
smtp.sendmail('ultimaker@mail.mymailstrasse.com',
'aag@bluewin.ch',
msg)
smtp.quit() # finally, don't forget to close the connection
else:
print ("Doesn't contain given substring")
if __name__ == '__main__':
main()
当我的 3d 打印机耗尽耗材时,它会暂停而不发送任何警告消息。我能找到的唯一条目是在 journalctl 上的一条消息,如下所示:
Jan 22 04:36:39 ultimakersystem-flipflop_wsgi.py[2884]: INF - root:80 - PrintJobStatus updated! 6e408dcf-9887, paused
我绝对需要在打印机暂停时得到提醒,否则打印会被破坏。有没有办法以编程方式 poll/parse journalctl,例如通过 bash 或 python 脚本,并根据需要发送电子邮件?
可能还有其他比轮询更优雅的方法,但是 FWIW:
journalctl
可以time-filter其输出;例如查看最后 30 分钟 activity:
journalctl --since "30 min ago" --until "now"
cron
可以 运行 不同时间间隔的作业;例如每 30 分钟 运行 以上journalctl
作业,将此行放入您的crontab
:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now"
- 必须检查上面的
journalctl
输出是否与感兴趣的 日志条目 匹配。从您发布的错误消息中,我不知道 关键字 究竟是什么提示了一个空的灯丝箱,但我们现在假设它们是ultimakersystem
和paused
.awk
提供了一种可扩展的方式来查找匹配的单词和短语:当两个模式出现在journalctl
输出的同一行时,awk '/pattern1/ && /pattern2/'
匹配,因此从 [=] 添加一个pipe
14=]输出到awk
;上面的cron
作业修改如下:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now" | awk '/ultimakersystem/ && /paused/'
- 最后一步是测试
awk
是否找到匹配项,如果找到,则向指定用户发送消息。如果有一个或多个匹配,只需要发送一封电子邮件,因此匹配测试将在END
部分进行。cron
作业再次更新如下:
0,30 * * * * /bin/journalctl --since "30 min ago" --until "now" | awk '/ultimakersystem/ && /paused/ {m=1}; END { if (m == 1){system("cat warn.txt | mail -s FILAMENT_NEEDED $USER")} }'
awk
使用 pattern-action 范式; /ultimakersystem/ && /paused/
是 模式 ,{m=1}
是 动作 。 awk
处理完所有 journalctl
输出后,执行 END
部分。一个简单的 if (m == 1)
测试确定是否出现一个或多个匹配项,如果出现,则调用 mail
命令发送 warn.txt
中定义的消息。 GNU awk
的 system
函数 REF 提供对系统命令库的访问。
在更改此食谱的许多其他可能性中,可以将 date-time 邮票 插入电子邮件正文,方法是将 cat warn.txt
替换为 date
,并向 $USER
以外的人发送邮件。请参阅 man mail
,或您的电子邮件客户端的文档。
我已经用 python 脚本解决了这个问题。我认为它比 cronjob 更有效,因为它会在找到关键字(在本例中为“暂停”一词)时做出反应,而无需轮询。
import systemd.journal
import socket
from time import sleep
import smtplib
from smtplib import SMTP
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'])
alertmail(entry['MESSAGE'])
def alertmail(logEntry):
# returns first occurrence of Substring
trigger_text = 'pause'
result = logEntry.find(trigger_text)
if (logEntry.find(trigger_text) != -1):
print ("Contains '" + trigger_text + "' at index:", result)
fromaddr = "ultimaker@mymailstrasse.com"
toaddrs = "aag@bluewin.ch"
msg = "ultimaker has paused!!! " + logEntry
smtp = smtplib.SMTP('mail.mymailstrasse.com', port='587')
smtp.ehlo() # send the extended hello to our server
smtp.starttls() # tell server we want to communicate with TLS encryption
smtp.login('ultimaker@mail.mymailstrasse.com', 'pw') # login to our email server
# send our email message 'msg' to our boss
smtp.sendmail('ultimaker@mail.mymailstrasse.com',
'aag@bluewin.ch',
msg)
smtp.quit() # finally, don't forget to close the connection
else:
print ("Doesn't contain given substring")
if __name__ == '__main__':
main()