40
40
def __cmp__(self, other):
41
41
return cmp(self.cpu, other.cpu)
44
44
return str(self.name + " - " + self.cpu + " - " + self.memory)
50
50
totalkilobytes = None
52
52
def __init__(self, options):
53
53
self.options = options
54
54
self.logger = logging.getLogger(app_name+"."+module_name)
55
55
self.loadConfigData()
57
57
def loadConfigData(self):
60
60
self.config = ProcessInfoConfig()
62
62
if self.options.config != None:
63
63
# load the config based on options passed in from the main app
64
64
configfilepath = self.options.config
66
66
# load plugin config from home directory of the user
67
67
configfilepath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/"+module_name+".config")
69
69
if os.path.exists(configfilepath):
71
71
self.logger.info("Loading config settings from \"%s\""%configfilepath)
73
73
for line in fileinput.input(os.path.expanduser(configfilepath)):
74
74
line = line.strip()
75
75
if len(line) > 0 and line[0:1] != "#": # ignore commented lines or empty ones
77
77
name = line.split("=")[0].strip().upper() # config setting name on the left of =
78
78
value = line.split("=")[1].split("#")[0].strip() # config value on the right of = (minus any trailing comments)
81
81
if name == "HEADERTEMPLATE":
82
self.config.HEADERTEMPLATE = self.getTypedValue(value, "string")
82
self.config.HEADERTEMPLATE = getTypedValue(value, "string")
83
83
elif name == "TEMPLATE":
84
self.config.TEMPLATE = self.getTypedValue(value, "string")
84
self.config.TEMPLATE = getTypedValue(value, "string")
85
85
elif name == "LIMIT":
86
self.config.LIMIT = self.getTypedValue(value, "integer")
86
self.config.LIMIT = getTypedValue(value, "integer")
87
87
elif name == "SORTBY":
88
self.config.SORTBY = self.getTypedValue(value, "string")
88
self.config.SORTBY = getTypedValue(value, "string")
90
90
self.logger.error("Unknown option in config file: " + name)
92
92
self.logger.info("Config data file %s not found, using defaults and setting up config file for next time" % configfilepath)
94
94
userconfigpath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/")
95
95
configsource = os.path.join(app_path, "config/"+module_name+".config")
97
97
if os.path.exists(userconfigpath) == False:
98
98
os.makedirs(userconfigpath)
100
100
shutil.copy(configsource, configfilepath)
102
102
except Exception, e:
103
103
self.logger.error(e.__str__()+"\n"+traceback.format_exc())
105
def getTypedValue(self, value, expectedtype):
108
if len(value.strip(" ")) == 0:
111
elif value.lower() == "true":
112
if expectedtype == "boolean":
115
self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
117
elif value.lower() == "false":
118
if expectedtype == "boolean":
121
self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
123
elif self.isNumeric(value) == True:
124
if expectedtype == "integer":
127
self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
132
except (TypeError, ValueError):
133
self.logger.error("Cannot convert '%s' to expected type of '%s'"%(value,expectedtype))
136
105
def BIGBANGgetOutputData(self):
139
108
processInfoList = statgrab.sg_get_process_stats()
141
110
currentid = os.getpid()
142
111
processInfoDataList = []
143
112
for processInfo in processInfoList:
145
114
id = processInfo['pid']
146
115
cpu = processInfo['cpu_percent']
147
116
memory = processInfo['proc_size']
149
118
if currentid != id: # ignore info on this process
150
119
processInfoData = ProcessInfoData(name,str(id),self.formatCPU(cpu),self.formatMemory(memory))
151
120
processInfoDataList.append(processInfoData)
153
122
if self.config.SORTBY == "CPU":
154
123
processInfoDataList.sort(lambda x, y: cmp(x.cpu, y.cpu))
155
124
elif self.config.SORTBY == "MEM":
156
125
processInfoDataList.sort(lambda x, y: cmp(x.memory, y.memory))
158
127
processInfoDataList.sort()
160
129
processInfoDataList.reverse()
162
131
return processInfoDataList
164
133
except Exception, e:
165
self.logger.error(e.__str__()+"\n"+traceback.format_exc())
134
self.logger.error(e.__str__()+"\n"+traceback.format_exc())
168
137
def BIGBANGformatCPU(self, value, dp=2):
174
143
def BIGBANGformatMemory(self, value):
175
144
return str(value / 1024)+"KB"
177
146
def getOutputData(self):
180
149
processInfoDataList = []
182
151
proc = subprocess.Popen("cat /proc/meminfo | grep MemTotal:", shell=True, stdout=subprocess.PIPE)
183
152
self.totalkilobytes = float(proc.communicate()[0][10:].replace("kB","").strip(" "))
185
154
proc = subprocess.Popen("top -n 1 -b | sed '1,7d'", shell=True, stdout=subprocess.PIPE)
186
lines = proc.communicate()[0].rstrip("\n").split("\n")
155
lines = proc.communicate()[0].rstrip("\n").split("\n")
188
157
for line in lines:
189
158
name = line[61:].strip(" ")
190
159
id = int(line[:6].strip(" "))
191
160
cpu = float(line[43:46].strip(" "))
192
161
memory = float(line[47:50].strip(" "))
194
163
if cpu > 0 or memory > 0:
195
164
processInfoData = ProcessInfoData(name,id,cpu,memory)
196
processInfoDataList.append(processInfoData)
165
processInfoDataList.append(processInfoData)
198
167
if self.config.SORTBY == "CPU":
199
168
processInfoDataList.sort(lambda x, y: cmp(x.cpu, y.cpu))
200
169
elif self.config.SORTBY == "MEM":
201
170
processInfoDataList.sort(lambda x, y: cmp(x.memory, y.memory))
203
172
processInfoDataList.sort()
205
174
processInfoDataList.reverse()
207
176
return processInfoDataList
209
178
except Exception, e:
210
self.logger.error(e.__str__()+"\n"+traceback.format_exc())
179
self.logger.error(e.__str__()+"\n"+traceback.format_exc())
213
182
def formatMemory(self, percent, total):
215
184
size = total * (percent / 100)
219
188
size = size / 1024.0
222
191
return str(round(size,2))+unit
224
193
def formatCPU(self, percent):
225
194
return str(round(percent,2))+"%"
227
196
def getOutputFromTemplate(self, template, name, id, cpu, memory):
231
200
output = template
233
202
if name == None or name.strip() == "":
235
204
output = output.replace("[name]",name)
237
206
if id == None or id.strip() == "":
239
208
output = output.replace("[id]",id)
241
210
if cpu == None or cpu.strip() == "":
243
212
output = output.replace("[cpu]",cpu)
245
214
if memory == None or memory.strip() == "":
247
216
output = output.replace("[memory]",memory)
302
271
inputfile.close()
304
273
output = headertemplate
307
276
processInfoDataList = self.getOutputData()
309
278
if len(processInfoDataList) == 0:
310
279
output = "Failed to retrieve process information"
312
281
for processInfoData in processInfoDataList:
314
283
output = output + self.getOutputFromTemplate(template, processInfoData.name, str(processInfoData.id), self.formatCPU(processInfoData.cpu), self.formatMemory(processInfoData.memory, self.totalkilobytes))
316
285
if self.config.LIMIT != None and count >= self.config.LIMIT:
319
288
return output.encode("utf-8")
321
def getHTMLText(self,text):
324
for char in text: #html:
326
htmlentities.append(char)
328
htmlentities.append('&%s;' % codepoint2name[ord(char)])
329
html = "".join(htmlentities)
331
html = html.replace("\n","<br>\n") # switch out new line for html breaks
336
def getCleanText(self,html):
339
text = text.replace("\n","") # remove new lines from html
340
text = text.replace("'","'") # workaround for shitty xml codes not compliant with html
341
text = text.replace("<br>","\n") # switch out html breaks for new line
342
text = re.sub('<(.|\n)+?>','',text) # remove any html tags
343
text = re.sub('&(%s);' % '|'.join(name2codepoint), lambda m: chr(name2codepoint[m.group(1)]), text)
348
def isNumeric(self,value):
355
290
def getHTML(options):
356
291
output = Output(options)
357
292
html = output.getOutput()
361
296
# to enable testing in isolation
362
297
if __name__ == "__main__":
364
299
parser = OptionParser()
365
parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")
300
parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")
366
301
parser.add_option("--headertemplate", dest="headertemplate", type="string", metavar="FILE", help=u"Override the header template for the plugin, default or config based template ignored.")
367
302
parser.add_option("--template", dest="template", type="string", metavar="FILE", help=u"Override the template for the plugin, default or config based template ignored.")
368
303
parser.add_option("--verbose", dest="verbose", default=False, action="store_true", help=u"Outputs verbose info to the terminal")
369
304
parser.add_option("--version", dest="version", default=False, action="store_true", help=u"Displays the version of the script.")
370
parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")
305
parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")
372
307
(options, args) = parser.parse_args()
374
309
output = Output(options)
375
310
html = output.getOutput()