23 #include "procrrd_thread.h" 25 #include <utils/time/wait.h> 33 #define PROC_CONF_PREFIX "/plugins/procrrd/processes/" 65 netinterface_ =
"wlan0";
71 lastcpu_ =
new unsigned long int[11];
74 net_recv_graph_ = NULL;
75 net_trans_graph_ = NULL;
76 std::vector<RRDDataSource> rrds;
80 rrds.push_back(
RRDDataSource(
"net_recv_bytes", RRDDataSource::COUNTER));
82 rrds.push_back(
RRDDataSource(
"net_recv_packets", RRDDataSource::COUNTER));
84 rrds.push_back(
RRDDataSource(
"net_recv_errors", RRDDataSource::COUNTER));
86 rrds.push_back(
RRDDataSource(
"net_trans_bytes", RRDDataSource::COUNTER));
88 rrds.push_back(
RRDDataSource(
"net_trans_packets", RRDDataSource::COUNTER));
90 rrds.push_back(
RRDDataSource(
"net_trans_errors", RRDDataSource::COUNTER));
100 std::vector<RRDGraphDataDefinition> defs;
101 std::vector<RRDGraphElement *> els;
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"));
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"));
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"));
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"));
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"));
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"));
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"));
159 std::string procprefix = PROC_CONF_PREFIX;
162 std::string selfid = get_process_id(
"fawkes");
163 add_process((procprefix +
"fawkes").c_str(), selfid,
"fawkes");
175 "Entry %s is not a string, but of type %s, " 184 std::string pid = get_process_id(
name.c_str());
187 logger->
log_warn(this->
name(),
"Failed to add process: %s, exception follows", name.c_str());
195 ProcessMap::iterator pi = processes_.begin();
198 for (; pi != processes_.end(); ++pi) {
199 p +=
", " + pi->second.name;
203 "ProcRRD logging network interface %s and " 204 "processes %s with a samplerate of %d second(s)",
205 netinterface_.c_str(),
220 for (ProcessMap::iterator i = processes_.begin(); i != processes_.end(); ++i) {
221 ProcessInfo &info = i->second;
223 delete info.cpu_graph;
224 delete info.mem_graph;
225 delete info.io_read_graph;
226 delete info.io_write_graph;
231 delete net_recv_graph_;
232 delete net_trans_graph_;
237 ProcRRDThread::add_process(
const char *path,
const std::string &pid,
const std::string &name)
239 if (processes_.find(path) != processes_.end()) {
240 throw Exception(
"Process stats for config %s already monitored", path);
247 info.last_cpu =
new unsigned long int[3];
249 file = fopen((
"/proc/" + pid +
"/stat").c_str(),
"r");
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",
261 info.last_cpu[0] = info.last_cpu[1] + info.last_cpu[2];
265 std::vector<RRDDataSource> rrds;
268 rrds.push_back(
RRDDataSource(
"cpu_usage", RRDDataSource::GAUGE));
270 rrds.push_back(
RRDDataSource(
"cpu_threads", RRDDataSource::GAUGE));
273 rrds.push_back(
RRDDataSource(
"mem_maxvirt", RRDDataSource::GAUGE));
275 rrds.push_back(
RRDDataSource(
"mem_curvirt", RRDDataSource::GAUGE));
277 rrds.push_back(
RRDDataSource(
"mem_rss", RRDDataSource::GAUGE));
281 rrds.push_back(
RRDDataSource(
"io_rchar", RRDDataSource::COUNTER));
283 rrds.push_back(
RRDDataSource(
"io_wchar", RRDDataSource::COUNTER));
285 rrds.push_back(
RRDDataSource(
"io_syscr", RRDDataSource::COUNTER));
287 rrds.push_back(
RRDDataSource(
"io_syscw", RRDDataSource::COUNTER));
289 rrds.push_back(
RRDDataSource(
"io_read_bytes", RRDDataSource::COUNTER));
291 rrds.push_back(
RRDDataSource(
"io_write_bytes", RRDDataSource::COUNTER));
293 rrds.push_back(
RRDDataSource(
"io_cancelled_write", RRDDataSource::COUNTER));
298 info.rrd_name = info.name +
"_" + info.pid;
301 while ((at = info.rrd_name.find_first_of(
" .-", pos)) != std::string::npos) {
302 info.rrd_name.replace(at, 1,
"_");
308 std::vector<RRDGraphDataDefinition> defs;
309 std::vector<RRDGraphElement *> els;
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"));
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"));
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);
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"));
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"));
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"));
355 std::string g2name = info.rrd_name +
"_memory";
356 std::string g2title = std::string(
"Memory Usage for ") + info.name +
"(" + pid +
")";
358 new RRDGraphDefinition(g2name.c_str(), info.rrd, g2title.c_str(),
"Bytes", defs, els);
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"));
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"));
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"));
381 std::string g3name = info.rrd_name +
"_io_read";
382 std::string g3title = std::string(
"IO Read Operations for ") + info.name +
"(" + pid +
")";
384 new RRDGraphDefinition(g3name.c_str(), info.rrd, g3title.c_str(),
"Bytes", defs, els);
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"));
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"));
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"));
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"));
411 new RRDGraphGPrint(
"io_cancelled_write", RRDArchive::AVERAGE,
"Average\\:%8.2lf %s"));
413 new RRDGraphGPrint(
"io_cancelled_write", RRDArchive::MAX,
"Maximum\\:%8.2lf %s\\n"));
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);
426 processes_[path] = info;
428 "Started monitoring process: %s (PID: %s)",
433 delete info.cpu_graph;
434 delete info.mem_graph;
435 delete info.io_read_graph;
436 delete info.io_write_graph;
443 ProcRRDThread::remove_process(
const char *path)
445 if (processes_.find(path) != processes_.end()) {
446 ProcessInfo &info = processes_[path];
448 delete info.cpu_graph;
449 delete info.mem_graph;
450 delete info.io_read_graph;
451 delete info.io_write_graph;
455 "Stopped monitoring process: %s (PID: %s)",
458 processes_.erase(path);
463 ProcRRDThread::get_process_id(
const char *process)
467 struct dirent *dir_entry_p;
472 dir_p = opendir(
"/proc/");
474 while (NULL != (dir_entry_p = readdir(dir_p))) {
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";
479 file = fopen(f.c_str(),
"r");
482 fscanf(file,
"Name: %255s",
name);
486 if (strcmp(process,
name) == 0) {
487 result = std::string(dir_entry_p->d_name);
499 ProcRRDThread::get_cpu(
unsigned long int *cpus)
502 file = fopen(
"/proc/stat",
"r");
506 "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
518 for (
int j = 1; j <= i; j++) {
531 file = fopen(
"/proc/net/dev",
"r");
532 unsigned long long int recv_bytes, recv_packets, recv_errors, trans_bytes, trans_packets,
534 recv_bytes = recv_packets = recv_errors = trans_bytes = trans_packets = trans_errors = 0;
536 while (file && fgets(line, 1024, file) != NULL) {
539 sscanf(line,
"%99s", dev);
541 if (strncmp(dev, (netinterface_ +
":").c_str(), netinterface_.length() + 1) == 0) {
543 "%*s %llu %llu %llu %*u %*u %*u %*u %*u %llu %llu %llu %*u %*u %*u %*u %*u",
557 "N:%llu:%llu:%llu:%llu:%llu:%llu",
569 unsigned long int *curcpu =
new unsigned long int[11];
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];
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];
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;
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);
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;
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);
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]) {
633 "N:U:%ld:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
644 cancelled_write_bytes);
647 "Failed to update %s RRD, exception follows",
648 i->second.rrd_name.c_str());
653 100.0 * (double)(cpu[0] - i->second.last_cpu[0]) / (double)(curcpu[0] - lastcpu_[0]);
656 "N:%f:%ld:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
668 cancelled_write_bytes);
671 "Failed to update %s RRD, exception follows",
672 i->second.rrd_name.c_str());
677 i->second.last_cpu[0] = cpu[0];
686 ProcRRDThread::config_tag_changed(
const char *new_tag)
695 remove_process(v->
path());
697 std::string pid = get_process_id(
name.c_str());
710 ProcRRDThread::config_value_erased(
const char *path)
712 remove_process(path);
virtual void loop()
Code to execute in the thread.
RRDManager * rrd_manager
Manager class to access RRD features.
virtual void add_rrd(RRDDefinition *rrd_def)=0
Add RRD.
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
virtual const char * type() const =0
Type of value.
Fawkes library namespace.
Interface for configuration change handling.
virtual ValueIterator * search(const char *path)=0
Iterator with search results.
virtual bool next()=0
Check if there is another element and advance to this if possible.
virtual void add_graph(RRDGraphDefinition *rrd_graph_def)=0
Add graph.
Thread class encapsulation of pthreads.
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
virtual void add_data(const char *rrd_name, const char *format,...)=0
Add data.
Logger * logger
This is the Logger member used to access the logger.
void wait_systime()
Wait until minimum loop time has been reached in real time.
virtual void finalize()
Finalize the thread.
Clock * clock
By means of this member access to the clock is given.
virtual bool is_string() const =0
Check if current value is a string.
Represent data definition in graph arguments.
Base class for exceptions in Fawkes.
Class representing a graph definition.
virtual ~ProcRRDThread()
Destructor.
virtual void rem_change_handler(ConfigurationChangeHandler *h)
Remove a configuration change handler.
Class to represent a RRD data source.
virtual std::string get_string() const =0
Get string value.
const char * name() const
Get name of thread.
virtual void remove_rrd(RRDDefinition *rrd_def)=0
Remove RRD.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual const char * path() const =0
Path of value.
void mark_start()
Mark start of loop.
Iterator interface to iterate over config values.
ProcRRDThread()
Constructor.
virtual void add_change_handler(ConfigurationChangeHandler *h)
Add a configuration change handler.
Print string inside graph.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
virtual void init()
Initialize the thread.
Configuration * config
This is the Configuration member used to access the configuration.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.