'Programmaticaly parse journalctl to initiate an action

When my 3d printer runs out of filament, it pauses without sending any alert message. The only entry I can find is a message that on journalctl like this one: Jan 22 04:36:39 ultimakersystem-flipflop_wsgi.py[2884]: INF - root:80 - PrintJobStatus updated! 6e408dcf-9887, paused

I absolutely need to be alerted when the printer pauses, or else the print will be ruined. Is there a way to poll/parse journalctl programmatically, e.g. via a bash or python script, and send an email as appropriate?



Solution 1:[1]

I have solved the issue with a python script. I think that it's more efficient that a cronjob because it will react whenever it finds the keyword (in this case the word "pause"), without a need to poll.

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 = "[email protected]"
        toaddrs  = "[email protected]"
        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('[email protected]', 'pw')  # login to our email server

        # send our email message 'msg' to our boss
        smtp.sendmail('[email protected]',
                    '[email protected]',
                    msg)
                    
        smtp.quit()  # finally, don't forget to close the connection
    else:
        print ("Doesn't contain given substring")

if __name__ == '__main__':
    main()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 aag