1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """ps
15 Interpret the output from the ps command and provide performance data for
16 CPU utilization, total RSS and the number of processes that match the
17 /Process tree definitions.
18 """
19
20 import re
21 import logging
22 log = logging.getLogger("zen.ps")
23
24 import Globals
25 from Products.ZenRRD.CommandParser import CommandParser
26 from Products.ZenEvents.ZenEventClasses import Status_OSProcess
27
28
29 AllPids = {}
30 emptySet = set()
31
32 -class ps(CommandParser):
33
41
47
48 - def getMatches(self, matchers, procName, cmdAndArgs):
62
64 """
65 Process the non-empyt ps and return back the
66 standard info.
67
68 @parameter line: one line of ps output
69 @type line: text
70 @return: pid, rss, cpu, cmdAndArgs (ie full process name)
71 @rtype: tuple
72 """
73 pid, rss, cpu, cmdAndArgs = line.split(None, 3)
74 return pid, rss, cpu, cmdAndArgs
75
77 """
78 Group processes per datapoint
79 """
80 dpsToProcs = {}
81 for line in output.split('\n')[1:]:
82 if not line:
83 continue
84
85 try:
86 pid, rss, cpu, cmdAndArgs = self.getProcInfo(line)
87 log.debug("line '%s' -> pid=%s " \
88 "rss=%s cpu=%s cmdAndArgs=%s",
89 line, pid, rss, cpu, cmdAndArgs)
90
91 except (SystemExit, KeyboardInterrupt): raise
92 except:
93 log.warn("Unable to parse entry '%s'", line)
94 continue
95
96 try:
97 procName = cmdAndArgs.split()[0]
98 matches = self.getMatches(matchers, procName, cmdAndArgs)
99
100 if not matches:
101 continue
102
103 days = 0
104 if cpu.find('-') > -1:
105 days, cpu = cpu.split('-')
106 days = int(days)
107 cpu = map(int, cpu.split(':'))
108 if len(cpu) == 3:
109 cpu = (days * 24 * 60 * 60 +
110 cpu[0] * 60 * 60 +
111 cpu[1] * 60 +
112 cpu[2])
113 elif len(cpu) == 2:
114 cpu = (days * 24 * 60 * 60 +
115 cpu[0] * 60 +
116 cpu[1])
117
118 rss = int(rss)
119 pid = int(pid)
120
121 for dp in matches:
122 procInfo = dict(procName=procName,
123 cmdAndArgs=cmdAndArgs, rss=0.0, cpu=0.0,
124 pids=set())
125 procInfo = dpsToProcs.setdefault(dp, procInfo)
126 procInfo['rss'] += rss
127 procInfo['cpu'] += cpu
128 procInfo['pids'].add(pid)
129
130 except (SystemExit, KeyboardInterrupt): raise
131 except:
132 log.exception("Unable to convert entry data pid=%s " \
133 "rss=%s cpu=%s cmdAndArgs=%s",
134 pid, rss, cpu, cmdAndArgs)
135 continue
136 return dpsToProcs
137
138
140
141
142 matchers = {}
143 for dp in cmd.points:
144 matchers[dp] = re.compile(re.escape(dp.data['processName']))
145
146 dpsToProcs = self.groupProcs(matchers, cmd.result.output)
147
148
149 for dp in cmd.points:
150 process = dp.data['processName']
151 failSeverity = dp.data['failSeverity']
152 procInfo = dpsToProcs.get(dp, None)
153 if not procInfo:
154 self.sendEvent(results,
155 summary='Process not running: ' + process,
156 component=process,
157 severity=failSeverity)
158 log.debug("device:%s, command: %s, procInfo: %r, failSeverity: %r, process: %s, dp: %r",
159 cmd.deviceConfig.device,
160 cmd.command,
161 procInfo,
162 failSeverity,
163 process,
164 dp)
165 else:
166 if 'cpu' in dp.id:
167 results.values.append( (dp, procInfo['cpu']) )
168 if 'mem' in dp.id:
169 results.values.append( (dp, procInfo['rss']) )
170 if 'count' in dp.id:
171 results.values.append( (dp, len(procInfo['pids'])) )
172
173
174
175
176 device = cmd.deviceConfig.device
177 before = AllPids.get( (device, process), emptySet)
178 after = set()
179 if procInfo:
180 after = procInfo['pids']
181
182 alertOnRestart = dp.data['alertOnRestart']
183
184 if before != after:
185 if len(before) > len(after) and alertOnRestart:
186 pids = ', '.join(map(str, before - after))
187 self.sendEvent(results,
188 summary='Pid(s) %s stopped: %s' % (pids, process),
189 component=process,
190 severity=failSeverity)
191 if len(before) == len(after) and alertOnRestart:
192
193 pids = ', '.join(map(str, before - after))
194 self.sendEvent(results,
195 summary='Pid(s) %s restarted: %s' % (pids, process),
196 component=process,
197 severity=failSeverity)
198 if len(before) < len(after):
199 if len(before) == 0:
200 self.sendEvent(results,
201 summary='Process running: %s' % process,
202 component=process,
203 severity=0)
204
205 AllPids[device, process] = after
206