| Trees | Indices | Help |
|
|---|
|
|
1 ###########################################################################
2 #
3 # This program is part of Zenoss Core, an open source monitoring platform.
4 # Copyright (C) 2009, 2010, Zenoss Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License version 2 or (at your
8 # option) any later version as published by the Free Software Foundation.
9 #
10 # For complete information please visit: http://www.zenoss.com/oss/
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 # Keep track of state between runs
29 AllPids = {} # (device, processName)
30 emptySet = set()
31
33
35 id, name, ignoreParams, alertOnRestart, failSeverity = \
36 context.getOSProcessConf()
37 return dict(processName=name,
38 ignoreParams=ignoreParams,
39 alertOnRestart=alertOnRestart,
40 failSeverity=failSeverity)
41
43 results.events.append(dict(
44 eventClass=Status_OSProcess,
45 eventGroup='Process',
46 **kwargs))
47
49 """
50 Get regex matches of processes running on the machine
51 """
52 matches = []
53 for dp, procRegex in matchers.items():
54 if dp.data['ignoreParams']:
55 name = procName
56 else:
57 name = cmdAndArgs
58
59 if procRegex.search(name):
60 matches.append(dp)
61 return matches
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 # map data points by procesName
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 # report any processes that are missing, and post perf data
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 # Report process changes
174 # Note that we can't tell the difference between a
175 # reconfiguration from zenhub and process that goes away.
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 # process restarted
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
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1.1812 on Tue Oct 11 12:51:53 2011 | http://epydoc.sourceforge.net |