Fawkes API Fawkes Development Version
procrrd_thread.cpp
1
2/***************************************************************************
3 * procrrd_thread.cpp - Fawkes Proc RRD Thread
4 *
5 * Created: Mon Dec 17 12:54:00 2012
6 * Copyright 2012 Bastian Klingen
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "procrrd_thread.h"
24
25#include <utils/time/wait.h>
26
27#include <dirent.h>
28#include <stdio.h>
29#include <string.h>
30
31using namespace fawkes;
32
33#define PROC_CONF_PREFIX "/plugins/procrrd/processes/"
34
35/** @class ProcRRDThread "procrrd_thread.h"
36 * Proc RRD Thread.
37 * This thread queries performance data from system every few seconds and
38 * writes it to RRD databases. The sampling rate can be set via the config.
39 *
40 * @author Bastian Klingen
41 */
42
43/** Constructor. */
45: Thread("ProcRRDThread", Thread::OPMODE_CONTINUOUS), ConfigurationChangeHandler(PROC_CONF_PREFIX)
46{
48}
49
50/** Destructor. */
52{
53}
54
55void
57{
58 samplerate_ = 10;
59 try {
60 samplerate_ = config->get_uint("/plugins/procrrd/samplerate");
61 } catch (Exception &e) {
62 }
63
64 timewait_ = new TimeWait(clock, samplerate_ * 1000000);
65 netinterface_ = "wlan0";
66 try {
67 netinterface_ = config->get_string("/plugins/procrrd/netinterface");
68 } catch (Exception &e) {
69 }
70
71 lastcpu_ = new unsigned long int[11];
72 get_cpu(lastcpu_);
73
74 net_recv_graph_ = NULL;
75 net_trans_graph_ = NULL;
76 std::vector<RRDDataSource> rrds;
77 // /proc/net/dev
78 // use data for net_interface
79 // Receive bytes
80 rrds.push_back(RRDDataSource("net_recv_bytes", RRDDataSource::COUNTER));
81 // Receive packets
82 rrds.push_back(RRDDataSource("net_recv_packets", RRDDataSource::COUNTER));
83 // Receive errs
84 rrds.push_back(RRDDataSource("net_recv_errors", RRDDataSource::COUNTER));
85 // Transmit bytes
86 rrds.push_back(RRDDataSource("net_trans_bytes", RRDDataSource::COUNTER));
87 // Transmit packets
88 rrds.push_back(RRDDataSource("net_trans_packets", RRDDataSource::COUNTER));
89 // Transmit errs
90 rrds.push_back(RRDDataSource("net_trans_errors", RRDDataSource::COUNTER));
91 net_rrd_ = new RRDDefinition("network", rrds);
92
93 try {
94 rrd_manager->add_rrd(net_rrd_);
95 } catch (Exception &e) {
96 finalize();
97 throw;
98 }
99
100 std::vector<RRDGraphDataDefinition> defs;
101 std::vector<RRDGraphElement *> els;
102
103 defs.push_back(RRDGraphDataDefinition("net_recv_bytes", RRDArchive::AVERAGE, net_rrd_));
104 defs.push_back(RRDGraphDataDefinition("net_recv_packets", RRDArchive::AVERAGE, net_rrd_));
105 defs.push_back(RRDGraphDataDefinition("net_recv_errors", RRDArchive::AVERAGE, net_rrd_));
106
107 els.push_back(new RRDGraphLine("net_recv_bytes", 1, "006400", "Bytes"));
108 els.push_back(new RRDGraphGPrint("net_recv_bytes", RRDArchive::LAST, " Current\\:%8.2lf %s"));
109 els.push_back(new RRDGraphGPrint("net_recv_bytes", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
110 els.push_back(new RRDGraphGPrint("net_recv_bytes", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
111
112 els.push_back(new RRDGraphLine("net_recv_packets", 1, "808000", "Packets"));
113 els.push_back(new RRDGraphGPrint("net_recv_packets", RRDArchive::LAST, "Current\\:%8.2lf %s"));
114 els.push_back(new RRDGraphGPrint("net_recv_packets", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
115 els.push_back(new RRDGraphGPrint("net_recv_packets", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
116
117 els.push_back(new RRDGraphLine("net_recv_errors", 1, "FF0000", "Errors"));
118 els.push_back(new RRDGraphGPrint("net_recv_errors", RRDArchive::LAST, " Current\\:%8.2lf %s"));
119 els.push_back(new RRDGraphGPrint("net_recv_errors", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
120 els.push_back(new RRDGraphGPrint("net_recv_errors", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
121
122 net_recv_graph_ =
123 new RRDGraphDefinition("network_recv", net_rrd_, "Network Receive", "", defs, els);
124
125 defs.clear();
126 els.clear();
127
128 defs.push_back(RRDGraphDataDefinition("net_trans_bytes", RRDArchive::AVERAGE, net_rrd_));
129 defs.push_back(RRDGraphDataDefinition("net_trans_packets", RRDArchive::AVERAGE, net_rrd_));
130 defs.push_back(RRDGraphDataDefinition("net_trans_errors", RRDArchive::AVERAGE, net_rrd_));
131
132 els.push_back(new RRDGraphLine("net_trans_bytes", 1, "006400", "Bytes"));
133 els.push_back(new RRDGraphGPrint("net_trans_bytes", RRDArchive::LAST, " Current\\:%8.2lf %s"));
134 els.push_back(new RRDGraphGPrint("net_trans_bytes", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
135 els.push_back(new RRDGraphGPrint("net_trans_bytes", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
136
137 els.push_back(new RRDGraphLine("net_trans_packets", 1, "808000", "Packets"));
138 els.push_back(new RRDGraphGPrint("net_trans_packets", RRDArchive::LAST, "Current\\:%8.2lf %s"));
139 els.push_back(
140 new RRDGraphGPrint("net_trans_packets", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
141 els.push_back(new RRDGraphGPrint("net_trans_packets", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
142
143 els.push_back(new RRDGraphLine("net_trans_errors", 1, "FF0000", "Errors"));
144 els.push_back(new RRDGraphGPrint("net_trans_errors", RRDArchive::LAST, " Current\\:%8.2lf %s"));
145 els.push_back(new RRDGraphGPrint("net_trans_errors", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
146 els.push_back(new RRDGraphGPrint("net_trans_errors", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
147
148 net_trans_graph_ =
149 new RRDGraphDefinition("network_trans", net_rrd_, "Network Transmit", "", defs, els);
150
151 try {
152 rrd_manager->add_graph(net_recv_graph_);
153 rrd_manager->add_graph(net_trans_graph_);
154 } catch (Exception &e) {
155 finalize();
156 throw;
157 }
158
159 std::string procprefix = PROC_CONF_PREFIX;
160
161 try {
162 std::string selfid = get_process_id("fawkes");
163 add_process((procprefix + "fawkes").c_str(), selfid, "fawkes");
164 } catch (Exception &e) {
165 logger->log_warn(name(), "Failed to add process: Fawkes, exception follows");
166 logger->log_warn(name(), e);
167 finalize();
168 throw;
169 }
170
171 Configuration::ValueIterator *i = config->search(procprefix.c_str());
172 while (i->next()) {
173 if (!i->is_string()) {
175 "Entry %s is not a string, but of type %s, "
176 "ignoring",
177 i->path(),
178 i->type());
179 continue;
180 }
181
182 std::string name = i->get_string();
183 try {
184 std::string pid = get_process_id(name.c_str());
185 add_process(i->path(), pid, name);
186 } catch (Exception &e) {
187 logger->log_warn(this->name(), "Failed to add process: %s, exception follows", name.c_str());
188 logger->log_warn(this->name(), e);
189 finalize();
190 throw;
191 }
192 }
193
194 std::string p;
195 ProcessMap::iterator pi = processes_.begin();
196 p = pi->second.name;
197 ++pi;
198 for (; pi != processes_.end(); ++pi) {
199 p += ", " + pi->second.name;
200 }
201
203 "ProcRRD logging network interface %s and "
204 "processes %s with a samplerate of %d second(s)",
205 netinterface_.c_str(),
206 p.c_str(),
207 samplerate_);
208
210}
211
212void
214{
216 delete timewait_;
217
218 rrd_manager->remove_rrd(net_rrd_);
219
220 for (ProcessMap::iterator i = processes_.begin(); i != processes_.end(); ++i) {
221 ProcessInfo &info = i->second;
222 rrd_manager->remove_rrd(info.rrd);
223 delete info.cpu_graph;
224 delete info.mem_graph;
225 delete info.io_read_graph;
226 delete info.io_write_graph;
227 delete info.rrd;
228 }
229 processes_.clear();
230
231 delete net_recv_graph_;
232 delete net_trans_graph_;
233 delete net_rrd_;
234}
235
236void
237ProcRRDThread::add_process(const char *path, const std::string &pid, const std::string &name)
238{
239 if (processes_.find(path) != processes_.end()) {
240 throw Exception("Process stats for config %s already monitored", path);
241 }
242 if (pid == "") {
243 throw Exception("No PID set.");
244 }
245
246 ProcessInfo info;
247 info.last_cpu = new unsigned long int[3];
248 FILE *file;
249 file = fopen(("/proc/" + pid + "/stat").c_str(), "r");
250 if (file) {
251 // /proc/PID/stat
252 // 14th (utime %lu) and 15th (stime %lu) value
253 // number of jiffies that the process has executed in user mode and kernel mode
254 fscanf(
255 file,
256 "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %*u %*u "
257 "%*d %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d %*u %*u %*u %*d",
258 info.last_cpu + 1,
259 info.last_cpu + 2);
260 // process cpu = utime + stime
261 info.last_cpu[0] = info.last_cpu[1] + info.last_cpu[2];
262 fclose(file);
263 }
264
265 std::vector<RRDDataSource> rrds;
266 // totalcpu = sum of /proc/stat line 1
267 // usage% = 100 * process cpu / totalcpu
268 rrds.push_back(RRDDataSource("cpu_usage", RRDDataSource::GAUGE));
269 // Threads: number of currently running threads
270 rrds.push_back(RRDDataSource("cpu_threads", RRDDataSource::GAUGE));
271 // /proc/PID/status
272 // VmPeak: maximum virtual memory space used by the process, in kB (1024 bytes)
273 rrds.push_back(RRDDataSource("mem_maxvirt", RRDDataSource::GAUGE));
274 // VmSize: current virtual memory space used by the process, in kB (1024 bytes)
275 rrds.push_back(RRDDataSource("mem_curvirt", RRDDataSource::GAUGE));
276 // VmRss: amount of memory that have been mapped into the process' address space, or its resident set size, in kB (1024 bytes)
277 rrds.push_back(RRDDataSource("mem_rss", RRDDataSource::GAUGE));
278
279 // /proc/PID/io
280 // rchar: number of bytes the process read, using any read-like system call (from files, pipes, tty...).
281 rrds.push_back(RRDDataSource("io_rchar", RRDDataSource::COUNTER));
282 // wchar: number of bytes the process wrote using any write-like system call.
283 rrds.push_back(RRDDataSource("io_wchar", RRDDataSource::COUNTER));
284 // syscr: number of read-like system call invocations that the process performed.
285 rrds.push_back(RRDDataSource("io_syscr", RRDDataSource::COUNTER));
286 // syscw: number of write-like system call invocations that the process performed.
287 rrds.push_back(RRDDataSource("io_syscw", RRDDataSource::COUNTER));
288 // read_bytes: number of bytes the process directly read from disk.
289 rrds.push_back(RRDDataSource("io_read_bytes", RRDDataSource::COUNTER));
290 // write_bytes: number of bytes the process originally dirtied in the page-cache (assuming they will go to disk later).
291 rrds.push_back(RRDDataSource("io_write_bytes", RRDDataSource::COUNTER));
292 // cancelled_write_bytes: number of bytes the process "un-dirtied" - e.g. using an "ftruncate" call that truncated pages from the page-cache.
293 rrds.push_back(RRDDataSource("io_cancelled_write", RRDDataSource::COUNTER));
294
295 info.pid = pid;
296 info.name = name;
297
298 info.rrd_name = info.name + "_" + info.pid;
299 size_t pos = 0;
300 size_t at;
301 while ((at = info.rrd_name.find_first_of(" .-", pos)) != std::string::npos) {
302 info.rrd_name.replace(at, 1, "_");
303 pos = pos + 1;
304 }
305
306 info.rrd = new RRDDefinition(info.rrd_name.c_str(), rrds);
307
308 std::vector<RRDGraphDataDefinition> defs;
309 std::vector<RRDGraphElement *> els;
310
311 defs.push_back(RRDGraphDataDefinition("cpu_usage", RRDArchive::AVERAGE, info.rrd));
312 defs.push_back(RRDGraphDataDefinition("cpu_threads", RRDArchive::AVERAGE, info.rrd));
313
314 els.push_back(new RRDGraphLine("cpu_usage", 1, "FF0000", "Usage %"));
315 els.push_back(new RRDGraphGPrint("cpu_usage", RRDArchive::LAST, "Current\\:%8.2lf %s"));
316 els.push_back(new RRDGraphGPrint("cpu_usage", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
317 els.push_back(new RRDGraphGPrint("cpu_usage", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
318
319 els.push_back(new RRDGraphLine("cpu_threads", 1, "008800", "Threads"));
320 els.push_back(new RRDGraphGPrint("cpu_threads", RRDArchive::LAST, "Current\\:%8.2lf %s"));
321 els.push_back(new RRDGraphGPrint("cpu_threads", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
322 els.push_back(new RRDGraphGPrint("cpu_threads", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
323
324 std::string g1name = info.rrd_name + "_cpu";
325 std::string g1title =
326 std::string("CPU Usage in % and Number Threads for ") + info.name + "(" + pid + ")";
327 info.cpu_graph = new RRDGraphDefinition(g1name.c_str(), info.rrd, g1title.c_str(), "", defs, els);
328
329 defs.clear();
330 els.clear();
331 defs.push_back(
332 RRDGraphDataDefinition("mem_maxvirt_kb", RRDArchive::AVERAGE, info.rrd, "mem_maxvirt"));
333 defs.push_back(
334 RRDGraphDataDefinition("mem_curvirt_kb", RRDArchive::AVERAGE, info.rrd, "mem_curvirt"));
335 defs.push_back(RRDGraphDataDefinition("mem_rss_kb", RRDArchive::AVERAGE, info.rrd, "mem_rss"));
336 defs.push_back(RRDGraphDataDefinition("mem_maxvirt", "mem_maxvirt_kb,1024,*"));
337 defs.push_back(RRDGraphDataDefinition("mem_curvirt", "mem_curvirt_kb,1024,*"));
338 defs.push_back(RRDGraphDataDefinition("mem_rss", "mem_rss_kb,1024,*"));
339
340 els.push_back(new RRDGraphArea("mem_maxvirt", "3B7AD9", "VmPeak"));
341 els.push_back(new RRDGraphGPrint("mem_maxvirt", RRDArchive::LAST, "Current\\:%8.2lf %s"));
342 els.push_back(new RRDGraphGPrint("mem_maxvirt", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
343 els.push_back(new RRDGraphGPrint("mem_maxvirt", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
344
345 els.push_back(new RRDGraphArea("mem_curvirt", "6FD1BF", "VmSize"));
346 els.push_back(new RRDGraphGPrint("mem_curvirt", RRDArchive::LAST, "Current\\:%8.2lf %s"));
347 els.push_back(new RRDGraphGPrint("mem_curvirt", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
348 els.push_back(new RRDGraphGPrint("mem_curvirt", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
349
350 els.push_back(new RRDGraphArea("mem_rss", "0E6E5C", "VmRSS"));
351 els.push_back(new RRDGraphGPrint("mem_rss", RRDArchive::LAST, " Current\\:%8.2lf %s"));
352 els.push_back(new RRDGraphGPrint("mem_rss", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
353 els.push_back(new RRDGraphGPrint("mem_rss", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
354
355 std::string g2name = info.rrd_name + "_memory";
356 std::string g2title = std::string("Memory Usage for ") + info.name + "(" + pid + ")";
357 info.mem_graph =
358 new RRDGraphDefinition(g2name.c_str(), info.rrd, g2title.c_str(), "Bytes", defs, els);
359
360 defs.clear();
361 els.clear();
362 defs.push_back(RRDGraphDataDefinition("io_rchar", RRDArchive::AVERAGE, info.rrd));
363 defs.push_back(RRDGraphDataDefinition("io_syscr", RRDArchive::AVERAGE, info.rrd));
364 defs.push_back(RRDGraphDataDefinition("io_read_bytes", RRDArchive::AVERAGE, info.rrd));
365
366 els.push_back(new RRDGraphLine("io_rchar", 1, "556B2F", "rchar"));
367 els.push_back(new RRDGraphGPrint("io_rchar", RRDArchive::LAST, "Current\\:%8.2lf %s"));
368 els.push_back(new RRDGraphGPrint("io_rchar", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
369 els.push_back(new RRDGraphGPrint("io_rchar", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
370
371 els.push_back(new RRDGraphLine("io_syscr", 1, "9ACD32", "syscr"));
372 els.push_back(new RRDGraphGPrint("io_syscr", RRDArchive::LAST, "Current\\:%8.2lf %s"));
373 els.push_back(new RRDGraphGPrint("io_syscr", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
374 els.push_back(new RRDGraphGPrint("io_syscr", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
375
376 els.push_back(new RRDGraphLine("io_read_bytes", 1, "98FB98", "bytes"));
377 els.push_back(new RRDGraphGPrint("io_read_bytes", RRDArchive::LAST, "Current\\:%8.2lf %s"));
378 els.push_back(new RRDGraphGPrint("io_read_bytes", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
379 els.push_back(new RRDGraphGPrint("io_read_bytes", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
380
381 std::string g3name = info.rrd_name + "_io_read";
382 std::string g3title = std::string("IO Read Operations for ") + info.name + "(" + pid + ")";
383 info.io_read_graph =
384 new RRDGraphDefinition(g3name.c_str(), info.rrd, g3title.c_str(), "Bytes", defs, els);
385
386 defs.clear();
387 els.clear();
388 defs.push_back(RRDGraphDataDefinition("io_wchar", RRDArchive::AVERAGE, info.rrd));
389 defs.push_back(RRDGraphDataDefinition("io_syscw", RRDArchive::AVERAGE, info.rrd));
390 defs.push_back(RRDGraphDataDefinition("io_write_bytes", RRDArchive::AVERAGE, info.rrd));
391 defs.push_back(RRDGraphDataDefinition("io_cancelled_write", RRDArchive::AVERAGE, info.rrd));
392
393 els.push_back(new RRDGraphLine("io_wchar", 1, "800000", "wchar"));
394 els.push_back(new RRDGraphGPrint("io_wchar", RRDArchive::LAST, " Current\\:%8.2lf %s"));
395 els.push_back(new RRDGraphGPrint("io_wchar", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
396 els.push_back(new RRDGraphGPrint("io_wchar", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
397
398 els.push_back(new RRDGraphLine("io_syscw", 1, "FF0000", "syscw"));
399 els.push_back(new RRDGraphGPrint("io_syscw", RRDArchive::LAST, " Current\\:%8.2lf %s"));
400 els.push_back(new RRDGraphGPrint("io_syscw", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
401 els.push_back(new RRDGraphGPrint("io_syscw", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
402
403 els.push_back(new RRDGraphLine("io_write_bytes", 1, "FF8C00", "bytes"));
404 els.push_back(new RRDGraphGPrint("io_write_bytes", RRDArchive::LAST, " Current\\:%8.2lf %s"));
405 els.push_back(new RRDGraphGPrint("io_write_bytes", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
406 els.push_back(new RRDGraphGPrint("io_write_bytes", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
407
408 els.push_back(new RRDGraphLine("io_cancelled_write", 1, "FFA07A", "cancelled"));
409 els.push_back(new RRDGraphGPrint("io_cancelled_write", RRDArchive::LAST, "Current\\:%8.2lf %s"));
410 els.push_back(
411 new RRDGraphGPrint("io_cancelled_write", RRDArchive::AVERAGE, "Average\\:%8.2lf %s"));
412 els.push_back(
413 new RRDGraphGPrint("io_cancelled_write", RRDArchive::MAX, "Maximum\\:%8.2lf %s\\n"));
414
415 std::string g4name = info.rrd_name + "_io_write";
416 std::string g4title = std::string("IO Write Operations for ") + info.name + "(" + pid + ")";
417 info.io_write_graph =
418 new RRDGraphDefinition(g4name.c_str(), info.rrd, g4title.c_str(), "Bytes", defs, els);
419 rrd_manager->add_rrd(info.rrd);
420 try {
421 rrd_manager->add_graph(info.cpu_graph);
422 rrd_manager->add_graph(info.mem_graph);
423 rrd_manager->add_graph(info.io_read_graph);
424 rrd_manager->add_graph(info.io_write_graph);
425
426 processes_[path] = info;
427 logger->log_info(this->name(),
428 "Started monitoring process: %s (PID: %s)",
429 info.name.c_str(),
430 info.pid.c_str());
431 } catch (Exception &e) {
432 rrd_manager->remove_rrd(info.rrd);
433 delete info.cpu_graph;
434 delete info.mem_graph;
435 delete info.io_read_graph;
436 delete info.io_write_graph;
437 delete info.rrd;
438 throw;
439 }
440}
441
442void
443ProcRRDThread::remove_process(const char *path)
444{
445 if (processes_.find(path) != processes_.end()) {
446 ProcessInfo &info = processes_[path];
447 rrd_manager->remove_rrd(info.rrd);
448 delete info.cpu_graph;
449 delete info.mem_graph;
450 delete info.io_read_graph;
451 delete info.io_write_graph;
452 delete info.rrd;
453
455 "Stopped monitoring process: %s (PID: %s)",
456 info.name.c_str(),
457 info.pid.c_str());
458 processes_.erase(path);
459 }
460}
461
462std::string
463ProcRRDThread::get_process_id(const char *process)
464{
465 DIR * dir_p;
466 FILE * file;
467 struct dirent *dir_entry_p;
468 std::string result;
469 result = "";
470
471 // Open /proc/ directory
472 dir_p = opendir("/proc/");
473 // Reading /proc/ entries
474 while (NULL != (dir_entry_p = readdir(dir_p))) {
475 // Checking for numbered directories
476 if (strspn(dir_entry_p->d_name, "0123456789") == strlen(dir_entry_p->d_name)) {
477 std::string f = "/proc/" + std::string(dir_entry_p->d_name) + "/status";
478 // open /proc/PID/status
479 file = fopen(f.c_str(), "r");
480 char name[256];
481 if (file) {
482 fscanf(file, "Name: %255s", name);
483 fclose(file);
484 }
485 name[0] = '\0';
486 if (strcmp(process, name) == 0) {
487 result = std::string(dir_entry_p->d_name);
488 closedir(dir_p);
489 return result;
490 }
491 }
492 }
493 closedir(dir_p);
494
495 return result;
496}
497
498void
499ProcRRDThread::get_cpu(unsigned long int *cpus)
500{
501 FILE *file;
502 file = fopen("/proc/stat", "r");
503 if (file) {
504 int i = 0;
505 i = fscanf(file,
506 "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
507 cpus + 1,
508 cpus + 2,
509 cpus + 3,
510 cpus + 4,
511 cpus + 5,
512 cpus + 6,
513 cpus + 7,
514 cpus + 8,
515 cpus + 9,
516 cpus + 10);
517 cpus[0] = 0;
518 for (int j = 1; j <= i; j++) {
519 cpus[0] += cpus[j];
520 }
521
522 fclose(file);
523 }
524}
525
526void
528{
529 timewait_->mark_start();
530 FILE *file;
531 file = fopen("/proc/net/dev", "r");
532 unsigned long long int recv_bytes, recv_packets, recv_errors, trans_bytes, trans_packets,
533 trans_errors;
534 recv_bytes = recv_packets = recv_errors = trans_bytes = trans_packets = trans_errors = 0;
535 char line[1024];
536 while (file && fgets(line, 1024, file) != NULL) {
537 // sscanf the device to get rid of leading whitespaces
538 char dev[100];
539 sscanf(line, "%99s", dev);
540
541 if (strncmp(dev, (netinterface_ + ":").c_str(), netinterface_.length() + 1) == 0) {
542 sscanf(line,
543 "%*s %llu %llu %llu %*u %*u %*u %*u %*u %llu %llu %llu %*u %*u %*u %*u %*u",
544 &recv_bytes,
545 &recv_packets,
546 &recv_errors,
547 &trans_bytes,
548 &trans_packets,
549 &trans_errors);
550 break;
551 }
552 }
553 if (file)
554 fclose(file);
555 try {
556 rrd_manager->add_data("network",
557 "N:%llu:%llu:%llu:%llu:%llu:%llu",
558 recv_bytes,
559 recv_packets,
560 recv_errors,
561 trans_bytes,
562 trans_packets,
563 trans_errors);
564 } catch (Exception &e) {
565 logger->log_warn(name(), "Failed to update network RRD, exception follows");
566 logger->log_warn(name(), e);
567 }
568
569 unsigned long int *curcpu = new unsigned long int[11];
570 get_cpu(curcpu);
571
572 for (ProcessMap::iterator i = processes_.begin(); i != processes_.end(); ++i) {
573 file = fopen(("/proc/" + i->second.pid + "/stat").c_str(), "r");
574 unsigned long int cpu[3];
575 if (file) {
576 fscanf(file, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu", cpu + 1, cpu + 2);
577 cpu[0] = cpu[1] + cpu[2];
578 fclose(file);
579 }
580 file = fopen(("/proc/" + i->second.pid + "/status").c_str(), "r");
581 unsigned long long int vmpeak, vmsize, vmrss;
582 long int threads = 0;
583 vmpeak = vmsize = vmrss = 0;
584 char line[128];
585 while (file && fgets(line, 128, file) != NULL) {
586 if (strncmp(line, "VmPeak:", 7) == 0) {
587 sscanf(line, "VmPeak: %llu", &vmpeak);
588 } else if (strncmp(line, "VmSize:", 7) == 0) {
589 sscanf(line, "VmSize: %llu", &vmsize);
590 } else if (strncmp(line, "VmRSS:", 6) == 0) {
591 sscanf(line, "VmRSS: %llu", &vmrss);
592 } else if (strncmp(line, "Threads:", 8) == 0) {
593 sscanf(line, "Threads: %ld", &threads);
594 break;
595 }
596 }
597 if (file)
598 fclose(file);
599 file = fopen(("/proc/" + i->second.pid + "/io").c_str(), "r");
600 unsigned long long int rchar, wchar, syscr, syscw, read_bytes, write_bytes,
601 cancelled_write_bytes;
602 rchar = wchar = syscr = syscw = read_bytes = write_bytes = cancelled_write_bytes = 0;
603 char line2[128];
604 while (file && fgets(line2, 128, file) != NULL) {
605 if (strncmp(line2, "rchar:", 6) == 0) {
606 sscanf(line2, "rchar: %llu", &rchar);
607 } else if (strncmp(line2, "wchar:", 6) == 0) {
608 sscanf(line2, "wchar: %llu", &wchar);
609 } else if (strncmp(line2, "syscr:", 6) == 0) {
610 sscanf(line2, "syscr: %llu", &syscr);
611 } else if (strncmp(line2, "syscw:", 6) == 0) {
612 sscanf(line2, "syscw: %llu", &syscw);
613 } else if (strncmp(line2, "read_bytes:", 11) == 0) {
614 sscanf(line2, "read_bytes: %llu", &read_bytes);
615 } else if (strncmp(line2, "write_bytes:", 12) == 0) {
616 sscanf(line2, "write_bytes: %llu", &write_bytes);
617 } else if (strncmp(line2, "cancelled_write_bytes:", 22) == 0) {
618 sscanf(line2, "cancelled_write_bytes: %llu", &cancelled_write_bytes);
619 break;
620 }
621 }
622 if (file)
623 fclose(file);
624
625 if (curcpu[0] < lastcpu_[0] || curcpu[1] < lastcpu_[1] || curcpu[2] < lastcpu_[2]
626 || curcpu[3] < lastcpu_[3] || curcpu[4] < lastcpu_[4] || curcpu[5] < lastcpu_[5]
627 || curcpu[6] < lastcpu_[6] || curcpu[7] < lastcpu_[7] || curcpu[8] < lastcpu_[8]
628 || curcpu[9] < lastcpu_[9] || curcpu[10] < lastcpu_[10] || cpu[0] < i->second.last_cpu[0]
629 || cpu[1] < i->second.last_cpu[1] || cpu[2] < i->second.last_cpu[2]) {
630 // value rollover for atleast one value, ignore cpu data
631 try {
632 rrd_manager->add_data(i->second.rrd_name.c_str(),
633 "N:U:%ld:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
634 threads,
635 vmpeak,
636 vmsize,
637 vmrss,
638 rchar,
639 wchar,
640 syscr,
641 syscw,
642 read_bytes,
643 write_bytes,
644 cancelled_write_bytes);
645 } catch (Exception &e) {
647 "Failed to update %s RRD, exception follows",
648 i->second.rrd_name.c_str());
649 logger->log_warn(name(), e);
650 }
651 } else {
652 double cpuuse =
653 100.0 * (double)(cpu[0] - i->second.last_cpu[0]) / (double)(curcpu[0] - lastcpu_[0]);
654 try {
655 rrd_manager->add_data(i->second.rrd_name.c_str(),
656 "N:%f:%ld:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
657 cpuuse,
658 threads,
659 vmpeak,
660 vmsize,
661 vmrss,
662 rchar,
663 wchar,
664 syscr,
665 syscw,
666 read_bytes,
667 write_bytes,
668 cancelled_write_bytes);
669 } catch (Exception &e) {
671 "Failed to update %s RRD, exception follows",
672 i->second.rrd_name.c_str());
673 logger->log_warn(name(), e);
674 }
675 }
676
677 i->second.last_cpu[0] = cpu[0];
678 }
679
680 lastcpu_ = curcpu;
681
682 timewait_->wait_systime();
683}
684
685void
686ProcRRDThread::config_tag_changed(const char *new_tag)
687{
688 // ignored
689}
690
691void
692ProcRRDThread::config_value_changed(const Configuration::ValueIterator *v)
693{
694 if (v->is_string()) {
695 remove_process(v->path());
696 std::string name = v->get_string();
697 std::string pid = get_process_id(name.c_str());
698 add_process(v->path(), pid, name);
699 } else {
700 logger->log_warn(name(), "Non-string value at %s, ignoring", v->path());
701 }
702}
703
704void
705ProcRRDThread::config_comment_changed(const Configuration::ValueIterator *v)
706{
707}
708
709void
710ProcRRDThread::config_value_erased(const char *path)
711{
712 remove_process(path);
713}
virtual ~ProcRRDThread()
Destructor.
ProcRRDThread()
Constructor.
virtual void init()
Initialize the thread.
virtual void loop()
Code to execute in the thread.
virtual void finalize()
Finalize the thread.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
Interface for configuration change handling.
Iterator interface to iterate over config values.
Definition: config.h:75
virtual const char * path() const =0
Path of value.
virtual bool next()=0
Check if there is another element and advance to this if possible.
virtual bool is_string() const =0
Check if current value is a string.
virtual const char * type() const =0
Type of value.
virtual std::string get_string() const =0
Get string value.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
virtual void rem_change_handler(ConfigurationChangeHandler *h)
Remove a configuration change handler.
Definition: config.cpp:619
virtual ValueIterator * search(const char *path)=0
Iterator with search results.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
virtual void add_change_handler(ConfigurationChangeHandler *h)
Add a configuration change handler.
Definition: config.cpp:603
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
RRDManager * rrd_manager
Manager class to access RRD features.
Definition: rrd.h:44
Class to represent a RRD data source.
Print graph area.
Represent data definition in graph arguments.
Class representing a graph definition.
Print string inside graph.
Print graph line.
virtual void add_rrd(RRDDefinition *rrd_def)=0
Add RRD.
virtual void add_graph(RRDGraphDefinition *rrd_graph_def)=0
Add graph.
virtual void add_data(const char *rrd_name, const char *format,...)=0
Add data.
virtual void remove_rrd(RRDDefinition *rrd_def)=0
Remove RRD.
Thread class encapsulation of pthreads.
Definition: thread.h:46
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:716
const char * name() const
Get name of thread.
Definition: thread.h:100
Time wait utility.
Definition: wait.h:33
void mark_start()
Mark start of loop.
Definition: wait.cpp:68
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:96
Fawkes library namespace.