-#
-# cron_journald.py
-#
-# List the logged (executed) cron jobs and their commands (uses journald module)
-#
-# TODO: also output a list of scheduled (future) jobs
-#
+# -*- coding: utf-8 -*-
+
+"""
+List the logged (executed) cron jobs and their commands (uses journald/logfile)
+NOTE: If using journald, the log level for cron.service should be at least 2
+(default is 1). This can be changed with `sudo systemctl edit cron --full`,
+and ammend `-L 2` to the ExecStart command.
+TODO: also output a list of scheduled (future) jobs
+"""
from systemd import journal
+import datetime
from logparse import config
from logparse.formatting import *
from logparse.load_parsers import Parser
+from logparse.parsers.cron import CronCommand
+
class CronJournald(Parser):
def __init__(self):
super().__init__()
self.name = "cron_journald"
- self.info = "List the logged (executed) cron jobs and their commands (uses journald module)"
+ self.info = "List the logged (executed) cron jobs and their commands " \
+ "(uses journald module)"
def parse_log(self):
logger.info("Obtaining cron logs")
- messages = [entry["MESSAGE"] for entry in j if "MESSAGE" in entry and " CMD " in entry["MESSAGE"]]
-
- total_jobs = len(messages)
+ records = [entry for entry in j
+ if "MESSAGE" in entry and " CMD " in entry["MESSAGE"]]
- if total_jobs == 0:
+ if len(records) == 0:
logger.warning("Couldn't find any cron commands")
return 1
- logger.info("Found " + str(total_jobs) + " cron jobs")
- section.append_data(Data("Total of " + plural("cron session", total_jobs) + " executed across all users"))
+ logger.info("Found {0} log records".format(len(records)))
logger.debug("Analysing cron commands for each user")
+ command_objects = []
users = {}
+ for record in records:
+ if record["_SOURCE_REALTIME_TIMESTAMP"] < section.period.startdate:
+ logger.warning("Discarding log record from {0} - was "
+ "seek_realtime set properly?".format(
+ record["_SOURCE_REALTIME_TIMESTAMP"]))
+ continue
+ try:
+ cmd_obj = CronCommand(record)
+ if config.prefs.getboolean("cron", "truncate-commands"):
+ cmd_obj.truncate()
+ if not (cmd_obj.match_user(config.prefs.get("cron", "users")
+ .split()) and cmd_obj.match_cmd(config.prefs.get(
+ "cron", "commands").split())):
+ logger.debug("Ignoring cron session by {0} with command "
+ "{1} due to config".format(cmd_obj.user, cmd_obj.cmd))
+ continue
+ command_objects.append(cmd_obj)
+ if not cmd_obj.user in users:
+ users[cmd_obj.user] = []
+ users[cmd_obj.user].append(cmd_obj.cmd)
+ except Exception as e:
+ logger.warning("Malformed cron log message: {0}. "
+ "Error message: {1}".format(record["MESSAGE"], str(e)))
+ continue
+
+ logger.info("Found {0} valid cron sessions".format(len(command_objects)))
+
+ if config.prefs.getboolean("cron", "summary"):
+ summary_data = Data()
+ summary_data.subtitle = "Total of " + plural("cron session",
+ len(command_objects)) + " for " + plural("user",
+ len(users))
+ summary_data.items = ["{}: `{}`".format(c.user, c.cmd)
+ for c in command_objects]
+ summary_data.orderbyfreq()
+ summary_data.truncl(config.prefs.getint("logparse", "maxcmd"))
+ section.append_data(summary_data)
+
+ if config.prefs.getboolean("cron", "list-users"):
+ for user, cmdlist in users.items():
+ user_data = Data()
+ user_data.subtitle = plural("session", len(cmdlist)) \
+ + " for " + user + (" (" + plural("unique command",
+ len(set(cmdlist))) + ")" if len(set(cmdlist)) > 1
+ else "")
+ user_data.items = ["`{0}`".format(cmd) for cmd in cmdlist]
+ user_data.orderbyfreq()
+ user_data.truncl(config.prefs.getint("logparse", "maxcmd"))
+ section.append_data(user_data)
+ logger.debug("Found {0} cron sessions for user {1} "
+ "({2} unique commands): {3}".format(
+ len(cmdlist), user,
+ len(set(cmdlist)), user_data.items))
- for msg in messages:
- usr_cmd = re.search('\((\S+)\) CMD (.*)', msg) # [('user', 'cmd')]
- if usr_cmd:
- if not usr_cmd.group(1) in users:
- users[usr_cmd.group(1)] = []
- users[usr_cmd.group(1)].append(usr_cmd.group(2))
-
- for usr, cmdlist in users.items():
- user_data = Data()
- user_data.subtitle = plural("cron session", len(cmdlist)) + " for " + usr
- user_data.items = ("`{0}`".format(cmd) for cmd in cmdlist)
- user_data.orderbyfreq()
- user_data.truncl(config.prefs.getint("logparse", "maxcmd"))
- section.append_data(user_data)
logger.info("Finished cron section")