【问题标题】:Programmaticaly parse journalctl to initiate an action以编程方式解析 journalctl 以启动操作
【发布时间】:2022-02-10 20:58:21
【问题描述】:

当我的 3d 打印机用完灯丝时,它会暂停而不发送任何警报消息。我能找到的唯一条目是 journalctl 上的一条消息,如下所示: Jan 22 04:36:39 ultimakersystem-flipflop_wsgi.py[2884]: INF - root:80 - PrintJobStatus updated! 6e408dcf-9887, paused

当打印机暂停时,我绝对需要得到提醒,否则打印将被破坏。有没有办法以编程方式轮询/解析 journalctl,例如通过 bash 或 python 脚本,并根据需要发送电子邮件?

【问题讨论】:

    标签: logging cron systemd-journald


    【解决方案1】:

    可能还有其他方法可以比轮询更优雅,但 FWIW:

    1. journalctl 可以对其输出进行时间过滤;例如查看最近 30 分钟的活动:
    journalctl --since "30 min ago" --until "now"
    
    1. cron 可以不同间隔运行作业;例如要每 30 分钟运行一次上述 journalctl 作业,请将此行放入您的 crontab
    0,30 * * * * /bin/journalctl --since "30 min ago" --until "now"
    
    1. 必须检查上面的journalctl 输出是否与感兴趣的日志条目匹配。从您发布的错误消息中,我不知道究竟是什么关键词提示空灯丝箱,但我们现在假设它们是ultimakersystempausedawk 提供了一种可扩展的方式来查找匹配的单词和短语:awk '/pattern1/ && /pattern2/' 当两个模式出现在journalctl 输出的同一行时匹配,因此将pipejournalctl 输出添加到awk;上面的cron作业修改如下:
    0,30 * * * * /bin/journalctl --since "30 min ago" --until "now" | awk '/ultimakersystem/ && /paused/'
    
    1. 最后一步是测试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 awksystem 函数 REF 提供对系统命令库的访问。

    在更改此配方的许多其他可能性中,日期时间戳可以通过将 cat warn.txt 替换为 date 并将邮件发送给其他人来插入电子邮件正文比$USER。请参阅man mail,或您的电子邮件客户端的文档。

    【讨论】:

      【解决方案2】:

      我已经用 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()
      

      【讨论】:

      • 好节目!我不擅长使用 Python,所以我想知道您是否可以回答一个问题:我收集提示代码检查来自 APPEND 事件的每个新日志条目。您知道如何该事件是生成的吗?我想知道这是否在 systemd 单元中完成?
      • 顺便说一句:您应该向 ultimaker 制造商许可。考虑到影响,他们似乎疏忽了没有内置警报系统。如果料斗中没有咖啡豆,即使是我的 Capressa 豆到杯咖啡机也不会尝试冲泡咖啡!哈哈
      • 是的,我困扰了他们 3 年,当打印机遇到问题时,他们必须构建某种推送消息。他们不理我,所以我自己动手……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多