a61747a973254fc1edd181cb0369d29fa4361a28
1# -*- coding: utf-8 -*-
2#
3# systemctl.py
4#
5# Get information about running/failed units and boot process
6#
7
8import re
9import subprocess
10
11from logparse import config
12from logparse.formatting import *
13from logparse.load_parsers import Parser
14from logparse.util import resolve
15
16# The following list changes with each systemd version.
17# Run `systemctl --state=help` to view currently implemented states.
18# The numbers correspond to degrees of severity for later formatting.
19BAD_STATES = {"bad": 4, "failed": 4, "not-found": 4, "bad-setting": 2,
20 "error": 3, "masked": 2, "dead": 3, "abandoned": 3}
21SYS_STATUS = {'running': 0, 'initializing': 1, 'starting': 1, 'stopping': 1,
22 'degraded': 3, 'unknown': 4, 'offline': 5}
23
24class Unit():
25
26 def __init__(self, name, loaded, active, sub, description):
27 self.name = name
28 self.loaded = loaded
29 self.active = active
30 self.sub = sub
31 self.description = description
32
33 def status():
34 try:
35 p = subprocess.Popen(["systemctl", "is-active", self.name],
36 stdout=subprocess.PIPE)
37 (output, err) = p.communicate()
38 status = output.decode('utf-8')
39 return status
40 except Exception as e:
41 logger.warning("Failed to get status for unit {0}: {1}".format(
42 self.name, str(e)))
43
44
45class Systemctl(Parser):
46
47 def __init__(self):
48 super().__init__()
49 self.name = "systemctl"
50 self.info = "Information about running/failed units and boot process"
51
52 def parse_log(self):
53
54 logger.debug("Starting systemctl section")
55 section = Section("systemctl")
56
57 try:
58 p = subprocess.Popen(["systemctl", "is-system-running"],
59 stdout = subprocess.PIPE)
60 (output, err) = p.communicate()
61 except Exception as e:
62 logger.warning("Failed to get system status: " + str(e))
63 else:
64 status_raw = str(output.decode('utf-8')).split()[0]
65 section.append_data(Data("System status", [status_raw], severity=SYS_STATUS[status_raw]))
66
67 try:
68 p = subprocess.Popen(
69 ["systemctl", "list-units"], stdout = subprocess.PIPE)
70 (output, err) = p.communicate()
71 except Exception as e:
72 logger.warning("Failed to get list of unit files: " + str(e))
73 units_raw = None
74 else:
75 units_raw = output.decode('utf-8')
76 unit_properties = [Unit(*line.split(maxsplit=4))
77 for line in units_raw.replace("●", " ").splitlines()[1:-7]]
78 unit_states = {}
79
80 for u in unit_properties:
81 if not u.sub in unit_states:
82 unit_states[u.sub] = []
83 unit_states[u.sub].append(u.name)
84
85 ok_data = Data()
86
87 for state, unit_list in unit_states.items():
88 if state in BAD_STATES:
89 logger.debug("Found critical unit {0} with status {1}".format(
90 u.name, u.sub))
91 section.append_data(Data(
92 plural(state + " unit", len(unit_list)), unit_list,
93 severity=BAD_STATES[state])
94 .truncl(config.prefs.getint("logparse", "maxlist")))
95 else:
96 ok_data.items.append(" ".join([str(len(unit_list)), state]))
97
98 if len(ok_data.items) > 0 and config.prefs.getboolean("systemctl", "show-all"):
99 ok_data.subtitle = plural("unit", len(ok_data.items)) \
100 + " in a non-critical state"
101 ok_data.truncl(config.prefs.getint("logparse", "maxlist"))
102 section.append_data(ok_data)
103
104 logger.info("Finished systemctl section")
105 return section
106