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