added systemd services charts, based on cgroups
Costa Tsaousis (ktsaou) committed
Jan 15, 2017 at 15:14 UTC
169f035436e59644469ceb7cca02111878135524
3 files changed
+161
-79
src/sys_fs_cgroup.c
+154
-78
@@ -8,10 +8,11 @@ static int cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_ONDEMAND;
8
static int cgroup_enable_memory = CONFIG_ONDEMAND_ONDEMAND;
9
static int cgroup_enable_devices = CONFIG_ONDEMAND_ONDEMAND;
10
static int cgroup_enable_blkio = CONFIG_ONDEMAND_ONDEMAND;
11
-static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_NO;
11
+static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_YES;
12
static int cgroup_enable_new_cgroups_detected_at_runtime = 1;
13
static int cgroup_check_for_new_every = 10;
14
static int cgroup_update_every = 1;
15
+
16
static char *cgroup_cpuacct_base = NULL;
17
static char *cgroup_blkio_base = NULL;
18
static char *cgroup_memory_base = NULL;
@@ -274,6 +275,7 @@ struct cgroup {
275
struct blkio io_merged; // operations
276
struct blkio io_queued; // operations
277
278
+ // per cgroup charts
279
RRDSET *st_cpu;
280
RRDSET *st_cpu_per_core;
281
RRDSET *st_mem;
@@ -289,6 +291,10 @@ struct cgroup {
291
RRDSET *st_queued_ops;
292
RRDSET *st_merged_ops;
293
294
+ // services
295
+ RRDDIM *rd_cpu;
296
+ RRDDIM *rd_mem_usage;
297
+
298
struct cgroup *next;
299
300
} *cgroup_root = NULL;
@@ -730,65 +736,24 @@ static char *cgroup_chart_id_strdupz(const char *s) {
736
void cgroup_get_chart_name(struct cgroup *cg) {
737
debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
738
733
- if(!netdata_simple_pattern_list_matches(disabled_cgroup_renames, cg->id) &&
734
- !netdata_simple_pattern_list_matches(disabled_cgroup_renames, cg->chart_id)) {
735
-
736
- pid_t cgroup_pid;
737
- char buffer[CGROUP_CHARTID_LINE_MAX + 1];
738
-
739
- snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'", cgroups_rename_script, cg->chart_id);
740
-
741
- debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
742
- FILE *fp = mypopen(buffer, &cgroup_pid);
743
- if(fp) {
744
- // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
745
- char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
746
- // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
747
- mypclose(fp, cgroup_pid);
748
- // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
749
-
750
- if(s && *s && *s != '\n') {
751
- debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
739
+ pid_t cgroup_pid;
740
+ char buffer[CGROUP_CHARTID_LINE_MAX + 1];
741
753
- trim(s);
742
+ snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'", cgroups_rename_script, cg->chart_id);
743
755
- freez(cg->chart_title);
756
- cg->chart_title = cgroup_title_strdupz(s);
744
+ debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
745
+ FILE *fp = mypopen(buffer, &cgroup_pid);
746
+ if(fp) {
747
+ // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
748
+ char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
749
+ // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
750
+ mypclose(fp, cgroup_pid);
751
+ // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
752
758
- freez(cg->chart_id);
759
- cg->chart_id = cgroup_chart_id_strdupz(s);
760
- cg->hash_chart = simple_hash(cg->chart_id);
761
- }
762
- }
763
- else
764
- error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
753
+ if(s && *s && *s != '\n') {
754
+ debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
755
766
- debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
767
- }
768
- else
769
- debug(D_CGROUP, "cgroup '%s' will not be renamed - it matches the list of disabled cgroup renames (will be shown as '%s')", cg->id, cg->chart_id);
770
-
771
-
772
- if(cgroup_enable_systemd_services) {
773
- if(netdata_simple_pattern_list_matches(systemd_services_cgroups, cg->id) ||
774
- netdata_simple_pattern_list_matches(systemd_services_cgroups, cg->chart_id)) {
775
- debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') matches systemd services cgroups", cg->id, cg->chart_id, cg->chart_title);
776
-
777
- char buffer[CGROUP_CHARTID_LINE_MAX + 1];
778
- cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
779
-
780
- strncpy(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
781
- char *s = buffer;
782
-
783
- // skip to the last slash
784
- size_t len = strlen(s);
785
- while(len--) if(unlikely(s[len] == '/')) break;
786
- if(len) s = &s[len + 1];
787
-
788
- // remove extension
789
- //len = strlen(s);
790
- //while(len--) if(unlikely(s[len] == '.')) break;
791
- //if(len) s[len] = '\0';
756
+ trim(s);
757
758
freez(cg->chart_title);
759
cg->chart_title = cgroup_title_strdupz(s);
@@ -796,13 +761,10 @@ void cgroup_get_chart_name(struct cgroup *cg) {
761
freez(cg->chart_id);
762
cg->chart_id = cgroup_chart_id_strdupz(s);
763
cg->hash_chart = simple_hash(cg->chart_id);
799
- cg->enabled = 1;
800
-
801
- debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
764
}
803
- else
804
- debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') does not match systemd services groups", cg->id, cg->chart_id, cg->chart_title);
765
}
766
+ else
767
+ error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
768
}
769
770
struct cgroup *cgroup_add(const char *id) {
@@ -836,13 +798,65 @@ struct cgroup *cgroup_add(const char *id) {
798
799
cgroup_root_count++;
800
839
- // fix the name by calling the external script
840
- cgroup_get_chart_name(cg);
801
+ // fix the chart_id and title by calling the external script
802
+ if(!netdata_simple_pattern_list_matches(disabled_cgroup_renames, cg->id) &&
803
+ !netdata_simple_pattern_list_matches(disabled_cgroup_renames, cg->chart_id)) {
804
+
805
+ cgroup_get_chart_name(cg);
806
+
807
+ debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
808
+ }
809
+ else
810
+ debug(D_CGROUP, "cgroup '%s' will not be renamed - it matches the list of disabled cgroup renames (will be shown as '%s')", cg->id, cg->chart_id);
811
+
812
+ int user_configurable = 1;
813
+
814
+ // check if this cgroup should be a systemd service
815
+ if(cgroup_enable_systemd_services) {
816
+ if(netdata_simple_pattern_list_matches(systemd_services_cgroups, cg->id) ||
817
+ netdata_simple_pattern_list_matches(systemd_services_cgroups, cg->chart_id)) {
818
+ debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') matches systemd services cgroups", cg->id, cg->chart_id, cg->chart_title);
819
+
820
+ char buffer[CGROUP_CHARTID_LINE_MAX + 1];
821
+ cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
822
+
823
+ strncpy(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
824
+ char *s = buffer;
825
+
826
+ //freez(cg->chart_id);
827
+ //cg->chart_id = cgroup_chart_id_strdupz(s);
828
+ //cg->hash_chart = simple_hash(cg->chart_id);
829
+
830
+ // skip to the last slash
831
+ size_t len = strlen(s);
832
+ while(len--) if(unlikely(s[len] == '/')) break;
833
+ if(len) s = &s[len + 1];
834
842
- char option[FILENAME_MAX + 1];
843
- snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
844
- cg->enabled = (char)config_get_boolean("plugin:cgroups", option, def);
835
+ // remove extension
836
+ len = strlen(s);
837
+ while(len--) if(unlikely(s[len] == '.')) break;
838
+ if(len) s[len] = '\0';
839
840
+ freez(cg->chart_title);
841
+ cg->chart_title = cgroup_title_strdupz(s);
842
+
843
+ cg->enabled = 1;
844
+ user_configurable = 0;
845
+
846
+ debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
847
+ }
848
+ else
849
+ debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') does not match systemd services groups", cg->id, cg->chart_id, cg->chart_title);
850
+ }
851
+
852
+ if(user_configurable) {
853
+ // allow the user to enable/disable this individualy
854
+ char option[FILENAME_MAX + 1];
855
+ snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
856
+ cg->enabled = (char) config_get_boolean("plugin:cgroups", option, def);
857
+ }
858
+
859
+ // detect duplicate cgroups
860
if(cg->enabled) {
861
struct cgroup *t;
862
for (t = cgroup_root; t; t = t->next) {
@@ -1230,6 +1244,59 @@ void find_all_cgroups() {
1244
1245
#define CHART_TITLE_MAX 300
1246
1247
+void update_services_charts(int update_every, int do_cpu, int do_mem_usage) {
1248
+ static RRDSET *st_cpu = NULL;
1249
+ static RRDSET *st_mem_usage = NULL;
1250
+
1251
+ // create the charts
1252
+
1253
+ if(do_cpu) {
1254
+ if(unlikely(!st_cpu)) {
1255
+ char title[CHART_TITLE_MAX + 1];
1256
+
1257
+ st_cpu = rrdset_find_bytype("services", "cpu");
1258
+ if(!st_cpu) {
1259
+ snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
1260
+ st_cpu = rrdset_create("services", "cpu", NULL, "cpu", "services.cpu", title, "%", 30000, update_every, RRDSET_TYPE_STACKED);
1261
+ }
1262
+ }
1263
+ else rrdset_next(st_cpu);
1264
+ }
1265
+
1266
+ if(do_mem_usage) {
1267
+ if(unlikely(!st_mem_usage)) {
1268
+ st_mem_usage = rrdset_find_bytype("services", "mem_usage");
1269
+ if(!st_mem_usage)
1270
+ st_mem_usage = rrdset_create("services", "mem_usage", NULL, "mem", "services.mem_usage", "Systemd Services RAM Usage", "MB", 30001, update_every, RRDSET_TYPE_STACKED);
1271
+ }
1272
+ else rrdset_next(st_mem_usage);
1273
+ }
1274
+
1275
+ // update the values
1276
+ struct cgroup *cg;
1277
+ for(cg = cgroup_root; cg ; cg = cg->next) {
1278
+ if(!cg->available || !cg->enabled || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) continue;
1279
+
1280
+ if(do_cpu && cg->cpuacct_stat.updated) {
1281
+ if(unlikely(!cg->rd_cpu))
1282
+ cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRDDIM_INCREMENTAL);
1283
+
1284
+ rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
1285
+ }
1286
+
1287
+ if(do_mem_usage) {
1288
+ if(unlikely(!cg->rd_mem_usage))
1289
+ cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1290
+
1291
+ rrddim_set_by_pointer(st_mem_usage, cg->rd_mem_usage, cg->memory.usage_in_bytes);
1292
+ }
1293
+ }
1294
+
1295
+ // complete the iteration
1296
+ if(do_cpu) rrdset_done(st_cpu);
1297
+ if(do_mem_usage) rrdset_done(st_mem_usage);
1298
+}
1299
+
1300
static inline char *cgroup_chart_type(char *buffer, const char *id, size_t len) {
1301
if(buffer[0]) return buffer;
1302
@@ -1248,11 +1315,18 @@ void update_cgroup_charts(int update_every) {
1315
char type[RRD_ID_LENGTH_MAX + 1];
1316
char title[CHART_TITLE_MAX + 1];
1317
1251
- struct cgroup *cg;
1318
+ int services_do_cpu = 0;
1319
+ int services_do_mem_usage = 0;
1320
1321
+ struct cgroup *cg;
1322
for(cg = cgroup_root; cg ; cg = cg->next) {
1254
- if(!cg->available || !cg->enabled || cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)
1323
+ if(!cg->available || !cg->enabled) continue;
1324
+
1325
+ if(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE) {
1326
+ if(cg->cpuacct_stat.updated && (cg->cpuacct_stat.user || cg->cpuacct_stat.system)) services_do_cpu++;
1327
+ if(cg->memory.usage_in_bytes_updated) services_do_mem_usage++;
1328
continue;
1329
+ }
1330
1331
type[0] = '\0';
1332
@@ -1300,7 +1374,7 @@ void update_cgroup_charts(int update_every) {
1374
}
1375
1376
if(cg->memory.updated) {
1303
- if(cg->memory.cache + cg->memory.rss + cg->memory.rss_huge + cg->memory.mapped_file > 0) {
1377
+ if(cg->memory.cache || cg->memory.rss || cg->memory.rss_huge || cg->memory.mapped_file) {
1378
if(unlikely(!cg->st_mem)) {
1379
cg->st_mem = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem");
1380
if(!cg->st_mem) {
@@ -1344,7 +1418,7 @@ void update_cgroup_charts(int update_every) {
1418
rrddim_set(cg->st_writeback, "writeback", cg->memory.writeback);
1419
rrdset_done(cg->st_writeback);
1420
1347
- if(cg->memory.pgpgin + cg->memory.pgpgout > 0) {
1421
+ if(cg->memory.pgpgin || cg->memory.pgpgout) {
1422
if(unlikely(!cg->st_mem_activity)) {
1423
cg->st_mem_activity = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_activity");
1424
if(!cg->st_mem_activity) {
@@ -1362,7 +1436,7 @@ void update_cgroup_charts(int update_every) {
1436
rrdset_done(cg->st_mem_activity);
1437
}
1438
1365
- if(cg->memory.pgfault + cg->memory.pgmajfault > 0) {
1439
+ if(cg->memory.pgfault || cg->memory.pgmajfault) {
1440
if(unlikely(!cg->st_pgfaults)) {
1441
cg->st_pgfaults = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "pgfaults");
1442
if(!cg->st_pgfaults) {
@@ -1399,7 +1473,7 @@ void update_cgroup_charts(int update_every) {
1473
rrdset_done(cg->st_mem_usage);
1474
}
1475
1402
- if(cg->memory.failcnt_updated && cg->memory.failcnt > 0) {
1476
+ if(cg->memory.failcnt_updated && cg->memory.failcnt) {
1477
if(unlikely(!cg->st_mem_failcnt)) {
1478
cg->st_mem_failcnt = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_failcnt");
1479
if(!cg->st_mem_failcnt) {
@@ -1415,7 +1489,7 @@ void update_cgroup_charts(int update_every) {
1489
rrdset_done(cg->st_mem_failcnt);
1490
}
1491
1418
- if(cg->io_service_bytes.updated && cg->io_service_bytes.Read + cg->io_service_bytes.Write > 0) {
1492
+ if(cg->io_service_bytes.updated && (cg->io_service_bytes.Read || cg->io_service_bytes.Write)) {
1493
if(unlikely(!cg->st_io)) {
1494
cg->st_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "io");
1495
if(!cg->st_io) {
@@ -1433,7 +1507,7 @@ void update_cgroup_charts(int update_every) {
1507
rrdset_done(cg->st_io);
1508
}
1509
1436
- if(cg->io_serviced.updated && cg->io_serviced.Read + cg->io_serviced.Write > 0) {
1510
+ if(cg->io_serviced.updated && (cg->io_serviced.Read || cg->io_serviced.Write)) {
1511
if(unlikely(!cg->st_serviced_ops)) {
1512
cg->st_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "serviced_ops");
1513
if(!cg->st_serviced_ops) {
@@ -1452,7 +1526,7 @@ void update_cgroup_charts(int update_every) {
1526
rrdset_done(cg->st_serviced_ops);
1527
}
1528
1455
- if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.Read + cg->throttle_io_service_bytes.Write > 0) {
1529
+ if(cg->throttle_io_service_bytes.updated && (cg->throttle_io_service_bytes.Read || cg->throttle_io_service_bytes.Write)) {
1530
if(unlikely(!cg->st_throttle_io)) {
1531
cg->st_throttle_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_io");
1532
if(!cg->st_throttle_io) {
@@ -1470,8 +1544,7 @@ void update_cgroup_charts(int update_every) {
1544
rrdset_done(cg->st_throttle_io);
1545
}
1546
1473
-
1474
- if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.Read + cg->throttle_io_serviced.Write > 0) {
1547
+ if(cg->throttle_io_serviced.updated && (cg->throttle_io_serviced.Read || cg->throttle_io_serviced.Write)) {
1548
if(unlikely(!cg->st_throttle_serviced_ops)) {
1549
cg->st_throttle_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_serviced_ops");
1550
if(!cg->st_throttle_serviced_ops) {
@@ -1507,7 +1580,7 @@ void update_cgroup_charts(int update_every) {
1580
rrdset_done(cg->st_queued_ops);
1581
}
1582
1510
- if(cg->io_merged.updated && cg->io_merged.Read + cg->io_merged.Write > 0) {
1583
+ if(cg->io_merged.updated && (cg->io_merged.Read || cg->io_merged.Write)) {
1584
if(unlikely(!cg->st_merged_ops)) {
1585
cg->st_merged_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "merged_ops");
1586
if(!cg->st_merged_ops) {
@@ -1527,6 +1600,9 @@ void update_cgroup_charts(int update_every) {
1600
}
1601
1602
debug(D_CGROUP, "done updating cgroups charts");
1603
+
1604
+ if(cgroup_enable_systemd_services && services_do_cpu)
1605
+ update_services_charts(update_every, services_do_cpu, services_do_mem_usage);
1606
}
1607
1608
// ----------------------------------------------------------------------------
web/dashboard_info.js
+6
@@ -11,6 +11,12 @@ netdataDashboard.menu = {
11
info: 'Overview of the key system metrics.'
12
},
13
14
+ 'services': {
15
+ title: 'Systemd Services',
16
+ icon: '<i class="fa fa-cogs" aria-hidden="true"></i>',
17
+ info: 'Resources utilization of systemd services.'
18
+ },
19
+
20
'ap': {
21
title: 'Access Points',
22
icon: '<i class="fa fa-wifi" aria-hidden="true"></i>',
web/index.html
+1
-1
@@ -2632,7 +2632,7 @@
2632
});
2633
2634
NETDATA.requiredJs.push({
2635
- url: NETDATA.serverDefault + 'dashboard_info.js?v20161226-1',
2635
+ url: NETDATA.serverDefault + 'dashboard_info.js?v20170115-1',
2636
async: false,
2637
isAlreadyLoaded: function() { return false; }
2638
});