summaryrefslogtreecommitdiffstats
path: root/collectors/apps.plugin
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/apps.plugin')
-rw-r--r--collectors/apps.plugin/README.md7
-rw-r--r--collectors/apps.plugin/apps_groups.conf1
-rw-r--r--collectors/apps.plugin/apps_plugin.c578
-rw-r--r--collectors/apps.plugin/metrics.csv81
4 files changed, 484 insertions, 183 deletions
diff --git a/collectors/apps.plugin/README.md b/collectors/apps.plugin/README.md
index ac0d349a..ad4e0882 100644
--- a/collectors/apps.plugin/README.md
+++ b/collectors/apps.plugin/README.md
@@ -4,12 +4,13 @@ sidebar_label: "Application monitoring "
custom_edit_url: "https://github.com/netdata/netdata/edit/master/collectors/apps.plugin/README.md"
learn_status: "Published"
learn_topic_type: "References"
-learn_rel_path: "References/Collectors references/System metrics"
+learn_rel_path: "Integrations/Monitor/System metrics"
-->
-# apps.plugin
+# Application monitoring (apps.plugin)
-`apps.plugin` breaks down system resource usage to **processes**, **users** and **user groups**.
+`apps.plugin` breaks down system resource usage to **processes**, **users** and **user groups**.
+It is enabled by default on every Netdata installation.
To achieve this task, it iterates through the whole process tree, collecting resource usage information
for every process found running.
diff --git a/collectors/apps.plugin/apps_groups.conf b/collectors/apps.plugin/apps_groups.conf
index fdb04860..f35454fd 100644
--- a/collectors/apps.plugin/apps_groups.conf
+++ b/collectors/apps.plugin/apps_groups.conf
@@ -171,6 +171,7 @@ nvidia-smi: nvidia-smi
htop: htop
watchdog: watchdog
telegraf: telegraf
+grafana: grafana*
# -----------------------------------------------------------------------------
# storage, file systems and file servers
diff --git a/collectors/apps.plugin/apps_plugin.c b/collectors/apps.plugin/apps_plugin.c
index 84506c8e..3132b224 100644
--- a/collectors/apps.plugin/apps_plugin.c
+++ b/collectors/apps.plugin/apps_plugin.c
@@ -251,6 +251,8 @@ struct target {
kernel_uint_t status_rssfile;
kernel_uint_t status_rssshmem;
kernel_uint_t status_vmswap;
+ kernel_uint_t status_voluntary_ctxt_switches;
+ kernel_uint_t status_nonvoluntary_ctxt_switches;
kernel_uint_t io_logical_bytes_read;
kernel_uint_t io_logical_bytes_written;
@@ -381,12 +383,17 @@ struct pid_stat {
uid_t uid;
gid_t gid;
+ kernel_uint_t status_voluntary_ctxt_switches_raw;
+ kernel_uint_t status_nonvoluntary_ctxt_switches_raw;
+
kernel_uint_t status_vmsize;
kernel_uint_t status_vmrss;
kernel_uint_t status_vmshared;
kernel_uint_t status_rssfile;
kernel_uint_t status_rssshmem;
kernel_uint_t status_vmswap;
+ kernel_uint_t status_voluntary_ctxt_switches;
+ kernel_uint_t status_nonvoluntary_ctxt_switches;
#ifndef __FreeBSD__
ARL_BASE *status_arl;
#endif
@@ -638,9 +645,9 @@ int read_user_or_group_ids(struct user_or_group_ids *ids, struct timespec *last_
struct user_or_group_id *user_or_group_id = callocz(1, sizeof(struct user_or_group_id));
if(ids->type == USER_ID)
- user_or_group_id->id.uid = (uid_t)str2ull(id_string);
+ user_or_group_id->id.uid = (uid_t) str2ull(id_string, NULL);
else
- user_or_group_id->id.gid = (uid_t)str2ull(id_string);
+ user_or_group_id->id.gid = (uid_t) str2ull(id_string, NULL);
user_or_group_id->name = strdupz(name);
user_or_group_id->updated = 1;
@@ -1263,6 +1270,26 @@ void arl_callback_status_rssshmem(const char *name, uint32_t hash, const char *v
aptr->p->status_rssshmem = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1));
}
+void arl_callback_status_voluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
+ (void)name; (void)hash; (void)value;
+ struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
+ if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
+
+ struct pid_stat *p = aptr->p;
+ pid_incremental_rate(
+ stat, p->status_voluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
+}
+
+void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) {
+ (void)name; (void)hash; (void)value;
+ struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst;
+ if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return;
+
+ struct pid_stat *p = aptr->p;
+ pid_incremental_rate(
+ stat, p->status_nonvoluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)));
+}
+
static void update_proc_state_count(char proc_state) {
switch (proc_state) {
case 'S':
@@ -1293,6 +1320,8 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
p->status_rssfile = 0;
p->status_rssshmem = 0;
p->status_vmswap = 0;
+ p->status_voluntary_ctxt_switches = 0;
+ p->status_nonvoluntary_ctxt_switches = 0;
#ifdef __FreeBSD__
struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr;
@@ -1318,6 +1347,8 @@ static inline int read_proc_pid_status(struct pid_stat *p, void *ptr) {
arl_expect_custom(p->status_arl, "RssFile", arl_callback_status_rssfile, &arl_ptr);
arl_expect_custom(p->status_arl, "RssShmem", arl_callback_status_rssshmem, &arl_ptr);
arl_expect_custom(p->status_arl, "VmSwap", arl_callback_status_vmswap, &arl_ptr);
+ arl_expect_custom(p->status_arl, "voluntary_ctxt_switches", arl_callback_status_voluntary_ctxt_switches, &arl_ptr);
+ arl_expect_custom(p->status_arl, "nonvoluntary_ctxt_switches", arl_callback_status_nonvoluntary_ctxt_switches, &arl_ptr);
}
@@ -1452,7 +1483,7 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
pid_incremental_rate(stat, p->cstime, str2kernel_uint_t(procfile_lineword(ff, 0, 16)));
// p->priority = str2kernel_uint_t(procfile_lineword(ff, 0, 17));
// p->nice = str2kernel_uint_t(procfile_lineword(ff, 0, 18));
- p->num_threads = (int32_t)str2uint32_t(procfile_lineword(ff, 0, 19));
+ p->num_threads = (int32_t) str2uint32_t(procfile_lineword(ff, 0, 19), NULL);
// p->itrealvalue = str2kernel_uint_t(procfile_lineword(ff, 0, 20));
p->collected_starttime = str2kernel_uint_t(procfile_lineword(ff, 0, 21)) / system_hz;
p->uptime = (global_uptime > p->collected_starttime)?(global_uptime - p->collected_starttime):0;
@@ -2905,6 +2936,8 @@ static size_t zero_all_targets(struct target *root) {
w->status_rssfile = 0;
w->status_rssshmem = 0;
w->status_vmswap = 0;
+ w->status_voluntary_ctxt_switches = 0;
+ w->status_nonvoluntary_ctxt_switches = 0;
w->io_logical_bytes_read = 0;
w->io_logical_bytes_written = 0;
@@ -3095,6 +3128,8 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
w->status_rssfile += p->status_rssfile;
w->status_rssshmem += p->status_rssshmem;
w->status_vmswap += p->status_vmswap;
+ w->status_voluntary_ctxt_switches += p->status_voluntary_ctxt_switches;
+ w->status_nonvoluntary_ctxt_switches += p->status_nonvoluntary_ctxt_switches;
w->io_logical_bytes_read += p->io_logical_bytes_read;
w->io_logical_bytes_written += p->io_logical_bytes_written;
@@ -3540,6 +3575,22 @@ static void send_collected_data_to_netdata(struct target *root, const char *type
send_END();
}
+#ifndef __FreeBSD__
+ send_BEGIN(type, "voluntary_ctxt_switches", dt);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed && w->processes))
+ send_SET(w->name, w->status_voluntary_ctxt_switches);
+ }
+ send_END();
+
+ send_BEGIN(type, "involuntary_ctxt_switches", dt);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed && w->processes))
+ send_SET(w->name, w->status_nonvoluntary_ctxt_switches);
+ }
+ send_END();
+#endif
+
send_BEGIN(type, "threads", dt);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
@@ -3823,6 +3874,22 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
}
#ifndef __FreeBSD__
+ fprintf(stdout, "CHART %s.voluntary_ctxt_switches '' '%s Voluntary Context Switches' 'switches/s' cpu %s.voluntary_ctxt_switches stacked 20023 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+ APPS_PLUGIN_FUNCTIONS();
+
+ fprintf(stdout, "CHART %s.involuntary_ctxt_switches '' '%s Involuntary Context Switches' 'switches/s' cpu %s.involuntary_ctxt_switches stacked 20024 %d\n", type, title, type, update_every);
+ for (w = root; w ; w = w->next) {
+ if(unlikely(w->exposed))
+ fprintf(stdout, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+ }
+ APPS_PLUGIN_FUNCTIONS();
+#endif
+
+#ifndef __FreeBSD__
fprintf(stdout, "CHART %s.swap '' '%s Swap Memory' 'MiB' swap %s.swap stacked 20011 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
@@ -3846,6 +3913,7 @@ static void send_charts_updates_to_netdata(struct target *root, const char *type
APPS_PLUGIN_FUNCTIONS();
#ifdef __FreeBSD__
+ // FIXME: same metric name as in Linux but different units.
fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'blocks/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
for (w = root; w ; w = w->next) {
if(unlikely(w->exposed))
@@ -4234,7 +4302,7 @@ static void get_MemTotal(void) {
for(line = 0; line < lines ;line++) {
size_t words = procfile_linewords(ff, line);
if(words == 3 && strcmp(procfile_lineword(ff, line, 0), "MemTotal") == 0 && strcmp(procfile_lineword(ff, line, 2), "kB") == 0) {
- kernel_uint_t n = str2ull(procfile_lineword(ff, line, 1));
+ kernel_uint_t n = str2ull(procfile_lineword(ff, line, 1), NULL);
if(n) MemTotal = n;
break;
}
@@ -4289,54 +4357,48 @@ static void apps_plugin_function_processes_help(const char *transaction) {
}
#define add_table_field(wb, key, name, visible, type, visualization, transform, decimal_points, units, max, sort, sortable, sticky, unique_key, pointer_to, summary, range) do { \
- if(fields_added) buffer_strcat(wb, ","); \
- buffer_sprintf(wb, "\n \"%s\": {", key); \
- buffer_sprintf(wb, "\n \"index\":%d,", fields_added); \
- buffer_sprintf(wb, "\n \"unique_key\":%s,", (unique_key)?"true":"false"); \
- buffer_sprintf(wb, "\n \"name\":\"%s\",", name); \
- buffer_sprintf(wb, "\n \"visible\":%s,", (visible)?"true":"false"); \
- buffer_sprintf(wb, "\n \"type\":\"%s\",", type); \
- if(units) \
- buffer_sprintf(wb, "\n \"units\":\"%s\",", (char*)(units)); \
- buffer_sprintf(wb, "\n \"visualization\":\"%s\",", visualization); \
- buffer_sprintf(wb, "\n \"value_options\":{"); \
- if(units) \
- buffer_sprintf(wb, "\n \"units\":\"%s\",", (char*)(units)); \
- buffer_sprintf(wb, "\n \"transform\":\"%s\",", transform); \
- buffer_sprintf(wb, "\n \"decimal_points\":%d", decimal_points); \
- buffer_sprintf(wb, "\n },"); \
+ buffer_json_member_add_object(wb, key); \
+ buffer_json_member_add_uint64(wb, "index", fields_added); \
+ buffer_json_member_add_boolean(wb, "unique_key", unique_key); \
+ buffer_json_member_add_string(wb, "name", name); \
+ buffer_json_member_add_boolean(wb, "visible", visible); \
+ buffer_json_member_add_string(wb, "type", type); \
+ buffer_json_member_add_string_or_omit(wb, "units", (char*)(units)); \
+ buffer_json_member_add_string(wb, "visualization", visualization); \
+ buffer_json_member_add_object(wb, "value_options"); \
+ buffer_json_member_add_string_or_omit(wb, "units", (char*)(units)); \
+ buffer_json_member_add_string(wb, "transform", transform); \
+ buffer_json_member_add_uint64(wb, "decimal_points", decimal_points); \
+ buffer_json_object_close(wb); \
if(!isnan((NETDATA_DOUBLE)(max))) \
- buffer_sprintf(wb, "\n \"max\":%f,", (NETDATA_DOUBLE)(max)); \
- if(pointer_to) \
- buffer_sprintf(wb, "\n \"pointer_to\":\"%s\",", (char *)(pointer_to)); \
- buffer_sprintf(wb, "\n \"sort\":\"%s\",", sort); \
- buffer_sprintf(wb, "\n \"sortable\":%s,", (sortable)?"true":"false"); \
- buffer_sprintf(wb, "\n \"sticky\":%s,", (sticky)?"true":"false"); \
- buffer_sprintf(wb, "\n \"summary\":\"%s\",", summary); \
- buffer_sprintf(wb, "\n \"filter\":\"%s\"", (range)?"range":"multiselect"); \
- buffer_sprintf(wb, "\n }"); \
+ buffer_json_member_add_double(wb, "max", (NETDATA_DOUBLE)(max)); \
+ buffer_json_member_add_string_or_omit(wb, "pointer_to", (char *)(pointer_to)); \
+ buffer_json_member_add_string(wb, "sort", sort); \
+ buffer_json_member_add_boolean(wb, "sortable", sortable); \
+ buffer_json_member_add_boolean(wb, "sticky", sticky); \
+ buffer_json_member_add_string(wb, "summary", summary); \
+ buffer_json_member_add_string(wb, "filter", (range)?"range":"multiselect"); \
+ buffer_json_object_close(wb); \
fields_added++; \
} while(0)
#define add_value_field_llu_with_max(wb, key, value) do { \
unsigned long long _tmp = (value); \
key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \
- buffer_fast_strcat(wb, ",", 1); \
- buffer_print_llu(wb, _tmp); \
+ buffer_json_add_array_item_uint64(wb, _tmp); \
} while(0)
#define add_value_field_ndd_with_max(wb, key, value) do { \
NETDATA_DOUBLE _tmp = (value); \
key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \
- buffer_fast_strcat(wb, ",", 1); \
- buffer_rrd_value(wb, _tmp); \
+ buffer_json_add_array_item_double(wb, _tmp); \
} while(0)
static void apps_plugin_function_processes(const char *transaction, char *function __maybe_unused, char *line_buffer __maybe_unused, int line_max __maybe_unused, int timeout __maybe_unused) {
struct pid_stat *p;
char *words[PLUGINSD_MAX_WORDS] = { NULL };
- size_t num_words = pluginsd_split_words(function, words, PLUGINSD_MAX_WORDS, NULL, NULL, 0);
+ size_t num_words = pluginsd_split_words(function, words, PLUGINSD_MAX_WORDS);
struct target *category = NULL, *user = NULL, *group = NULL;
const char *process_name = NULL;
@@ -4406,18 +4468,12 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
unsigned int io_divisor = 1024 * RATES_DETAIL;
BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
- buffer_sprintf(wb,
- "{"
- "\n \"status\":%d"
- ",\n \"type\":\"table\""
- ",\n \"update_every\":%d"
- ",\n \"help\":\"%s\""
- ",\n \"data\":["
- "\n"
- , HTTP_RESP_OK
- , update_every
- , APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION
- );
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
+ buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
+ buffer_json_member_add_string(wb, "type", "table");
+ buffer_json_member_add_time_t(wb, "update_every", update_every);
+ buffer_json_member_add_string(wb, "help", APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION);
+ buffer_json_member_add_array(wb, "data");
NETDATA_DOUBLE
UserCPU_max = 0.0
@@ -4437,6 +4493,8 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
unsigned long long
Processes_max = 0
, Threads_max = 0
+ , VoluntaryCtxtSwitches_max = 0
+ , NonVoluntaryCtxtSwitches_max = 0
, Uptime_max = 0
, MinFlt_max = 0
, CMinFlt_max = 0
@@ -4493,52 +4551,41 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
if(filter_gid && p->gid != gid)
continue;
- if(rows) buffer_fast_strcat(wb, ",\n", 2);
rows++;
- buffer_strcat(wb, " [");
+ buffer_json_add_array_item_array(wb);
// IMPORTANT!
// THE ORDER SHOULD BE THE SAME WITH THE FIELDS!
// pid
- buffer_print_llu(wb, p->pid);
+ buffer_json_add_array_item_uint64(wb, p->pid);
// cmd
- buffer_fast_strcat(wb, ",\"", 2);
- buffer_strcat_jsonescape(wb, p->comm);
- buffer_fast_strcat(wb, "\"", 1);
+ buffer_json_add_array_item_string(wb, p->comm);
#ifdef NETDATA_DEV_MODE
// cmdline
- buffer_fast_strcat(wb, ",\"", 2);
- buffer_strcat_jsonescape(wb, (p->cmdline && *p->cmdline) ? p->cmdline : p->comm);
- buffer_fast_strcat(wb, "\"", 1);
+ buffer_json_add_array_item_string(wb, (p->cmdline && *p->cmdline) ? p->cmdline : p->comm);
#endif
// ppid
- buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->ppid);
+ buffer_json_add_array_item_uint64(wb, p->ppid);
// category
- buffer_fast_strcat(wb, ",\"", 2);
- buffer_strcat_jsonescape(wb, p->target ? p->target->name : "-");
- buffer_fast_strcat(wb, "\"", 1);
+ buffer_json_add_array_item_string(wb, p->target ? p->target->name : "-");
// user
- buffer_fast_strcat(wb, ",\"", 2);
- buffer_strcat_jsonescape(wb, p->user_target ? p->user_target->name : "-");
- buffer_fast_strcat(wb, "\"", 1);
+ buffer_json_add_array_item_string(wb, p->user_target ? p->user_target->name : "-");
// uid
- buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->uid);
+ buffer_json_add_array_item_uint64(wb, p->uid);
// group
- buffer_fast_strcat(wb, ",\"", 2);
- buffer_strcat_jsonescape(wb, p->group_target ? p->group_target->name : "-");
- buffer_fast_strcat(wb, "\"", 1);
+ buffer_json_add_array_item_string(wb, p->group_target ? p->group_target->name : "-");
// gid
- buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->gid);
+ buffer_json_add_array_item_uint64(wb, p->gid);
// CPU utilization %
add_value_field_ndd_with_max(wb, CPU, (NETDATA_DOUBLE)(p->utime + p->stime + p->gtime + p->cutime + p->cstime + p->cgtime) / cpu_divisor);
@@ -4549,6 +4596,9 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
add_value_field_ndd_with_max(wb, CSysCPU, (NETDATA_DOUBLE)(p->cstime) / cpu_divisor);
add_value_field_ndd_with_max(wb, CGuestCPU, (NETDATA_DOUBLE)(p->cgtime) / cpu_divisor);
+ add_value_field_llu_with_max(wb, VoluntaryCtxtSwitches, p->status_voluntary_ctxt_switches / RATES_DETAIL);
+ add_value_field_llu_with_max(wb, NonVoluntaryCtxtSwitches, p->status_nonvoluntary_ctxt_switches / RATES_DETAIL);
+
// memory MiB
if(MemTotal)
add_value_field_ndd_with_max(wb, Memory, (NETDATA_DOUBLE)p->status_vmrss * 100.0 / (NETDATA_DOUBLE)MemTotal);
@@ -4599,18 +4649,15 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
add_value_field_llu_with_max(wb, Threads, p->num_threads);
add_value_field_llu_with_max(wb, Uptime, p->uptime);
- buffer_fast_strcat(wb, "]", 1);
-
- fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
- buffer_flush(wb);
+ buffer_json_array_close(wb);
}
+ buffer_json_array_close(wb);
+ buffer_json_member_add_object(wb, "columns");
+
{
int fields_added = 0;
- buffer_flush(wb);
- buffer_sprintf(wb, "\n ],\n \"columns\": {");
-
// IMPORTANT!
// THE ORDER SHOULD BE THE SAME WITH THE VALUES!
add_table_field(wb, "PID", "Process ID", true, "integer", "value", "number", 0, NULL, NAN, "ascending", true, true, true, NULL, "count_unique", false);
@@ -4635,6 +4682,10 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
add_table_field(wb, "CSysCPU", "Children System CPU Time (100% = 1 core)", false, "bar-with-integer", "bar", "number", 2, "%", CSysCPU_max, "descending", true, false, false, NULL, "sum", true);
add_table_field(wb, "CGuestCPU", "Children Guest CPU Time (100% = 1 core)", false, "bar-with-integer", "bar", "number", 2, "%", CGuestCPU_max, "descending", true, false, false, NULL, "sum", true);
+ // CPU context switches
+ add_table_field(wb, "vCtxSwitch", "Voluntary Context Switches", false, "bar-with-integer", "bar", "number", 2, "switches/s", VoluntaryCtxtSwitches_max, "descending", true, false, false, NULL, "sum", true);
+ add_table_field(wb, "iCtxSwitch", "Involuntary Context Switches", false, "bar-with-integer", "bar", "number", 2, "switches/s", NonVoluntaryCtxtSwitches_max, "descending", true, false, false, NULL, "sum", true);
+
// memory
if(MemTotal)
add_table_field(wb, "Memory", "Memory Percentage", true, "bar-with-integer", "bar", "number", 2, "%", 100.0, "descending", true, false, false, NULL, "sum", true);
@@ -4684,118 +4735,284 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
add_table_field(wb, "Processes", "Processes", true, "bar-with-integer", "bar", "number", 0, "processes", Processes_max, "descending", true, false, false, NULL, "sum", true);
add_table_field(wb, "Threads", "Threads", true, "bar-with-integer", "bar", "number", 0, "threads", Threads_max, "descending", true, false, false, NULL, "sum", true);
add_table_field(wb, "Uptime", "Uptime in seconds", true, "duration", "bar", "duration", 2, "seconds", Uptime_max, "descending", true, false, false, NULL, "max", true);
+ }
+ buffer_json_object_close(wb);
- buffer_strcat(
- wb,
- ""
- "\n },"
- "\n \"default_sort_column\": \"CPU\","
- "\n \"charts\": {"
- "\n \"CPU\": {"
- "\n \"name\":\"CPU Utilization\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"UserCPU\", \"SysCPU\", \"GuestCPU\", \"CUserCPU\", \"CSysCPU\", \"CGuestCPU\" ]"
- "\n },"
- "\n \"Memory\": {"
- "\n \"name\":\"Memory\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"Virtual\", \"Resident\", \"Shared\", \"Swap\" ]"
- "\n },"
- );
+ buffer_json_member_add_string(wb, "default_sort_column", "CPU");
- if(MemTotal)
- buffer_strcat(
- wb,
- ""
- "\n \"MemoryPercent\": {"
- "\n \"name\":\"Memory Percentage\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"Memory\" ]"
- "\n },"
- );
+ buffer_json_member_add_object(wb, "charts");
+ {
+ // CPU chart
+ buffer_json_member_add_object(wb, "CPU");
+ {
+ buffer_json_member_add_string(wb, "name", "CPU Utilization");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "UserCPU");
+ buffer_json_add_array_item_string(wb, "SysCPU");
+ buffer_json_add_array_item_string(wb, "GuestCPU");
+ buffer_json_add_array_item_string(wb, "CUserCPU");
+ buffer_json_add_array_item_string(wb, "CSysCPU");
+ buffer_json_add_array_item_string(wb, "CGuestCPU");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_member_add_object(wb, "CPUCtxSwitches");
+ {
+ buffer_json_member_add_string(wb, "name", "CPU Context Switches");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "vCtxSwitch");
+ buffer_json_add_array_item_string(wb, "iCtxSwitch");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Memory chart
+ buffer_json_member_add_object(wb, "Memory");
+ {
+ buffer_json_member_add_string(wb, "name", "Memory");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Virtual");
+ buffer_json_add_array_item_string(wb, "Resident");
+ buffer_json_add_array_item_string(wb, "Shared");
+ buffer_json_add_array_item_string(wb, "Swap");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ if(MemTotal) {
+ // Memory chart
+ buffer_json_member_add_object(wb, "MemoryPercent");
+ {
+ buffer_json_member_add_string(wb, "name", "Memory Percentage");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Memory");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+ }
- buffer_strcat(
- wb, ""
- #ifndef __FreeBSD__
- "\n \"Reads\": {"
- "\n \"name\":\"I/O Reads\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"LReads\", \"PReads\" ]"
- "\n },"
- "\n \"Writes\": {"
- "\n \"name\":\"I/O Writes\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"LWrites\", \"PWrites\" ]"
- "\n },"
- "\n \"LogicalIO\": {"
- "\n \"name\":\"Logical I/O\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"LReads\", \"LWrites\" ]"
- "\n },"
- #endif
- "\n \"PhysicalIO\": {"
- "\n \"name\":\"Physical I/O\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"PReads\", \"PWrites\" ]"
- "\n },"
- "\n \"IOCalls\": {"
- "\n \"name\":\"I/O Calls\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"RCalls\", \"WCalls\" ]"
- "\n },"
- "\n \"MinFlt\": {"
- "\n \"name\":\"Minor Page Faults\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"MinFlt\", \"CMinFlt\" ]"
- "\n },"
- "\n \"MajFlt\": {"
- "\n \"name\":\"Major Page Faults\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"MajFlt\", \"CMajFlt\" ]"
- "\n },"
- "\n \"Threads\": {"
- "\n \"name\":\"Threads\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"Threads\" ]"
- "\n },"
- "\n \"Processes\": {"
- "\n \"name\":\"Processes\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"Processes\" ]"
- "\n },"
- "\n \"FDs\": {"
- "\n \"name\":\"File Descriptors\","
- "\n \"type\":\"stacked-bar\","
- "\n \"columns\": [ \"Files\", \"Pipes\", \"Sockets\", \"iNotiFDs\", \"EventFDs\", \"TimerFDs\", \"SigFDs\", \"EvPollFDs\", \"OtherFDs\" ]"
- "\n }"
- "\n },"
- "\n \"group_by\": {"
- "\n \"pid\": {"
- "\n \"name\":\"Process Tree by PID\","
- "\n \"columns\":[ \"PPID\" ]"
- "\n },"
- "\n \"category\": {"
- "\n \"name\":\"Process Tree by Category\","
- "\n \"columns\":[ \"Category\", \"PPID\" ]"
- "\n },"
- "\n \"user\": {"
- "\n \"name\":\"Process Tree by User\","
- "\n \"columns\":[ \"User\", \"PPID\" ]"
- "\n },"
- "\n \"group\": {"
- "\n \"name\":\"Process Tree by Group\","
- "\n \"columns\":[ \"Group\", \"PPID\" ]"
- "\n }"
- "\n }"
- );
+#ifndef __FreeBSD__
+ // I/O Reads chart
+ buffer_json_member_add_object(wb, "Reads");
+ {
+ buffer_json_member_add_string(wb, "name", "I/O Reads");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "LReads");
+ buffer_json_add_array_item_string(wb, "PReads");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // I/O Writes chart
+ buffer_json_member_add_object(wb, "Writes");
+ {
+ buffer_json_member_add_string(wb, "name", "I/O Writes");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "LWrites");
+ buffer_json_add_array_item_string(wb, "PWrites");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Logical I/O chart
+ buffer_json_member_add_object(wb, "LogicalIO");
+ {
+ buffer_json_member_add_string(wb, "name", "Logical I/O");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "LReads");
+ buffer_json_add_array_item_string(wb, "LWrites");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+#endif
+
+ // Physical I/O chart
+ buffer_json_member_add_object(wb, "PhysicalIO");
+ {
+ buffer_json_member_add_string(wb, "name", "Physical I/O");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "PReads");
+ buffer_json_add_array_item_string(wb, "PWrites");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // I/O Calls chart
+ buffer_json_member_add_object(wb, "IOCalls");
+ {
+ buffer_json_member_add_string(wb, "name", "I/O Calls");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "RCalls");
+ buffer_json_add_array_item_string(wb, "WCalls");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Minor Page Faults chart
+ buffer_json_member_add_object(wb, "MinFlt");
+ {
+ buffer_json_member_add_string(wb, "name", "Minor Page Faults");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "MinFlt");
+ buffer_json_add_array_item_string(wb, "CMinFlt");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Major Page Faults chart
+ buffer_json_member_add_object(wb, "MajFlt");
+ {
+ buffer_json_member_add_string(wb, "name", "Major Page Faults");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "MajFlt");
+ buffer_json_add_array_item_string(wb, "CMajFlt");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Threads chart
+ buffer_json_member_add_object(wb, "Threads");
+ {
+ buffer_json_member_add_string(wb, "name", "Threads");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Threads");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // Processes chart
+ buffer_json_member_add_object(wb, "Processes");
+ {
+ buffer_json_member_add_string(wb, "name", "Processes");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Processes");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // FDs chart
+ buffer_json_member_add_object(wb, "FDs");
+ {
+ buffer_json_member_add_string(wb, "name", "File Descriptors");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Files");
+ buffer_json_add_array_item_string(wb, "Pipes");
+ buffer_json_add_array_item_string(wb, "Sockets");
+ buffer_json_add_array_item_string(wb, "iNotiFDs");
+ buffer_json_add_array_item_string(wb, "EventFDs");
+ buffer_json_add_array_item_string(wb, "TimerFDs");
+ buffer_json_add_array_item_string(wb, "SigFDs");
+ buffer_json_add_array_item_string(wb, "EvPollFDs");
+ buffer_json_add_array_item_string(wb, "OtherFDs");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+ }
+ buffer_json_object_close(wb); // charts
- fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
+ buffer_json_member_add_object(wb, "group_by");
+ {
+ // group by PID
+ buffer_json_member_add_object(wb, "PID");
+ {
+ buffer_json_member_add_string(wb, "name", "Process Tree by PID");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "PPID");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // group by Category
+ buffer_json_member_add_object(wb, "Category");
+ {
+ buffer_json_member_add_string(wb, "name", "Process Tree by Category");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Category");
+ buffer_json_add_array_item_string(wb, "PPID");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // group by User
+ buffer_json_member_add_object(wb, "User");
+ {
+ buffer_json_member_add_string(wb, "name", "Process Tree by User");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "User");
+ buffer_json_add_array_item_string(wb, "PPID");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ // group by Group
+ buffer_json_member_add_object(wb, "Group");
+ {
+ buffer_json_member_add_string(wb, "name", "Process Tree by Group");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Group");
+ buffer_json_add_array_item_string(wb, "PPID");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
}
+ buffer_json_object_close(wb); // group_by
- buffer_free(wb);
+ buffer_json_member_add_time_t(wb, "expires", expires);
+ buffer_json_finalize(wb);
- fprintf(stdout, ",\n \"expires\":%lld", (long long)expires);
- fprintf(stdout, "\n}");
+ fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
+ buffer_free(wb);
pluginsd_function_result_end_to_stdout();
}
@@ -4809,7 +5026,7 @@ void *reader_main(void *arg __maybe_unused) {
while(!apps_plugin_exit && (s = fgets(buffer, PLUGINSD_LINE_MAX, stdin))) {
char *words[PLUGINSD_MAX_WORDS] = { NULL };
- size_t num_words = pluginsd_split_words(buffer, words, PLUGINSD_MAX_WORDS, NULL, NULL, 0);
+ size_t num_words = pluginsd_split_words(buffer, words, PLUGINSD_MAX_WORDS);
const char *keyword = get_word(words, num_words, 0);
@@ -5038,4 +5255,5 @@ int main(int argc, char **argv) {
debug_log("done Loop No %zu", global_iterations_counter);
}
+ netdata_mutex_unlock(&mutex);
}
diff --git a/collectors/apps.plugin/metrics.csv b/collectors/apps.plugin/metrics.csv
new file mode 100644
index 00000000..e1ca3434
--- /dev/null
+++ b/collectors/apps.plugin/metrics.csv
@@ -0,0 +1,81 @@
+metric,scope,dimensions,unit,description,chart_type,labels,plugin,module
+system.processes_state,,"running, sleeping_interruptible, sleeping_uninterruptible, zombie, stopped",processes,"System Processes State",line,,apps.plugin,
+apps.cpu,,a dimension per app group,percentage,"Apps CPU Time (100% = 1 core)",stacked,,apps.plugin,
+apps.cpu_user,,a dimension per app group,percentage,"Apps CPU User Time (100% = 1 core)",stacked,,apps.plugin,
+apps.cpu_system,,a dimension per app group,percentage,"Apps CPU System Time (100% = 1 core)",stacked,,apps.plugin,
+apps.cpu_guest,,a dimension per app group,percentage,"Apps CPU Guest Time (100% = 1 core)",stacked,,apps.plugin,
+apps.mem,,a dimension per app group,MiB,"Apps Real Memory (w/o shared)",stacked,,apps.plugin,
+apps.rss,,a dimension per app group,MiB,"Apps Resident Set Size (w/shared)",stacked,,apps.plugin,
+apps.vmem,,a dimension per app group,MiB,"Apps Virtual Memory Size",stacked,,apps.plugin,
+apps.swap,,a dimension per app group,MiB,"Apps Swap Memory",stacked,,apps.plugin,
+apps.major_faults,,a dimension per app group,"page faults/s","Apps Major Page Faults (swap read)",stacked,,apps.plugin,
+apps.minor_faults,,a dimension per app group,"page faults/s","Apps Minor Page Faults (swap read)",stacked,,apps.plugin,
+apps.preads,,a dimension per app group,"KiB/s","Apps Disk Reads",stacked,,apps.plugin,
+apps.pwrites,,a dimension per app group,"KiB/s","Apps Disk Writes",stacked,,apps.plugin,
+apps.lreads,,a dimension per app group,"KiB/s","Apps Disk Logical Reads",stacked,,apps.plugin,
+apps.lwrites,,a dimension per app group,"KiB/s","Apps I/O Logical Writes",stacked,,apps.plugin,
+apps.threads,,a dimension per app group,threads,"Apps Threads",stacked,,apps.plugin,
+apps.processes,,a dimension per app group,processes,"Apps Processes",stacked,,apps.plugin,
+apps.voluntary_ctxt_switches,,a dimension per app group,processes,"Apps Voluntary Context Switches",stacked,,apps.plugin,
+apps.involuntary_ctxt_switches,,a dimension per app group,processes,"Apps Involuntary Context Switches",stacked,,apps.plugin,
+apps.uptime,,a dimension per app group,seconds,"Apps Carried Over Uptime",line,,apps.plugin,
+apps.uptime_min,,a dimension per app group,seconds,"Apps Minimum Uptime",line,,apps.plugin,
+apps.uptime_avg,,a dimension per app group,seconds,"Apps Average Uptime",line,,apps.plugin,
+apps.uptime_max,,a dimension per app group,seconds,"Apps Maximum Uptime",line,,apps.plugin,
+apps.files,,a dimension per app group,"open files","Apps Open Files",stacked,,apps.plugin,
+apps.sockets,,a dimension per app group,"open sockets","Apps Open Sockets",stacked,,apps.plugin,
+apps.pipes,,a dimension per app group,"open pipes","Apps Open Pipes",stacked,,apps.plugin,
+groups.cpu,,a dimension per user group,percentage,"User Groups CPU Time (100% = 1 core)",stacked,,apps.plugin,
+groups.cpu_user,,a dimension per user group,percentage,"User Groups CPU User Time (100% = 1 core)",stacked,,apps.plugin,
+groups.cpu_system,,a dimension per user group,percentage,"User Groups CPU System Time (100% = 1 core)",stacked,,apps.plugin,
+groups.cpu_guest,,a dimension per user group,percentage,"User Groups CPU Guest Time (100% = 1 core)",stacked,,apps.plugin,
+groups.mem,,a dimension per user group,MiB,"User Groups Real Memory (w/o shared)",stacked,,apps.plugin,
+groups.rss,,a dimension per user group,MiB,"User Groups Resident Set Size (w/shared)",stacked,,apps.plugin,
+groups.vmem,,a dimension per user group,MiB,"User Groups Virtual Memory Size",stacked,,apps.plugin,
+groups.swap,,a dimension per user group,MiB,"User Groups Swap Memory",stacked,,apps.plugin,
+groups.major_faults,,a dimension per user group,"page faults/s","User Groups Major Page Faults (swap read)",stacked,,apps.plugin,
+groups.minor_faults,,a dimension per user group,"page faults/s","User Groups Page Faults (swap read)",stacked,,apps.plugin,
+groups.preads,,a dimension per user group,"KiB/s","User Groups Disk Reads",stacked,,apps.plugin,
+groups.pwrites,,a dimension per user group,"KiB/s","User Groups Disk Writes",stacked,,apps.plugin,
+groups.lreads,,a dimension per user group,"KiB/s","User Groups Disk Logical Reads",stacked,,apps.plugin,
+groups.lwrites,,a dimension per user group,"KiB/s","User Groups I/O Logical Writes",stacked,,apps.plugin,
+groups.threads,,a dimension per user group,threads,"User Groups Threads",stacked,,apps.plugin,
+groups.processes,,a dimension per user group,processes,"User Groups Processes",stacked,,apps.plugin,
+groups.voluntary_ctxt_switches,,a dimension per app group,processes,"User Groups Voluntary Context Switches",stacked,,apps.plugin,
+groups.involuntary_ctxt_switches,,a dimension per app group,processes,"User Groups Involuntary Context Switches",stacked,,apps.plugin,
+groups.uptime,,a dimension per user group,seconds,"User Groups Carried Over Uptime",line,,apps.plugin,
+groups.uptime_min,,a dimension per user group,seconds,"User Groups Minimum Uptime",line,,apps.plugin,
+groups.uptime_avg,,a dimension per user group,seconds,"User Groups Average Uptime",line,,apps.plugin,
+groups.uptime_max,,a dimension per user group,seconds,"User Groups Maximum Uptime",line,,apps.plugin,
+groups.files,,a dimension per user group,"open files","User Groups Open Files",stacked,,apps.plugin,
+groups.sockets,,a dimension per user group,"open sockets","User Groups Open Sockets",stacked,,apps.plugin,
+groups.pipes,,a dimension per user group,"open pipes","User Groups Open Pipes",stacked,,apps.plugin,
+users.cpu,,a dimension per user,percentage,"Users CPU Time (100% = 1 core)",stacked,,apps.plugin,
+users.cpu_user,,a dimension per user,percentage,"Users CPU User Time (100% = 1 core)",stacked,,apps.plugin,
+users.cpu_system,,a dimension per user,percentage,"Users CPU System Time (100% = 1 core)",stacked,,apps.plugin,
+users.cpu_guest,,a dimension per user,percentage,"Users CPU Guest Time (100% = 1 core)",stacked,,apps.plugin,
+users.mem,,a dimension per user,MiB,"Users Real Memory (w/o shared)",stacked,,apps.plugin,
+users.rss,,a dimension per user,MiB,"Users Resident Set Size (w/shared)",stacked,,apps.plugin,
+users.vmem,,a dimension per user,MiB,"Users Virtual Memory Size",stacked,,apps.plugin,
+users.swap,,a dimension per user,MiB,"Users Swap Memory",stacked,,apps.plugin,
+users.major_faults,,a dimension per user,"page faults/s","Users Major Page Faults (swap read)",stacked,,apps.plugin,
+users.minor_faults,,a dimension per user,"page faults/s","Users Page Faults (swap read)",stacked,,apps.plugin,
+users.preads,,a dimension per user,"KiB/s","Users Disk Reads",stacked,,apps.plugin,
+users.pwrites,,a dimension per user,"KiB/s","Users Disk Writes",stacked,,apps.plugin,
+users.lreads,,a dimension per user,"KiB/s","Users Disk Logical Reads",stacked,,apps.plugin,
+users.lwrites,,a dimension per user,"KiB/s","Users I/O Logical Writes",stacked,,apps.plugin,
+users.threads,,a dimension per user,threads,"Users Threads",stacked,,apps.plugin,
+users.processes,,a dimension per user,processes,"Users Processes",stacked,,apps.plugin,
+users.voluntary_ctxt_switches,,a dimension per app group,processes,"Users Voluntary Context Switches",stacked,,apps.plugin,
+users.involuntary_ctxt_switches,,a dimension per app group,processes,"Users Involuntary Context Switches",stacked,,apps.plugin,
+users.uptime,,a dimension per user,seconds,"Users Carried Over Uptime",line,,apps.plugin,
+users.uptime_min,,a dimension per user,seconds,"Users Minimum Uptime",line,,apps.plugin,
+users.uptime_avg,,a dimension per user,seconds,"Users Average Uptime",line,,apps.plugin,
+users.uptime_max,,a dimension per user,seconds,"Users Maximum Uptime",line,,apps.plugin,
+users.files,,a dimension per user,"open files","Users Open Files",stacked,,apps.plugin,
+users.sockets,,a dimension per user,"open sockets","Users Open Sockets",stacked,,apps.plugin,
+users.pipes,,a dimension per user,"open pipes","Users Open Pipes",stacked,,apps.plugin,
+netdata.apps_cpu,,"user, system",milliseconds/s,"Apps Plugin CPU",stacked,,apps.plugin,
+netdata.apps_sizes,,"calls, files, filenames, inode_changes, link_changes, pids, fds, targets, new_pids",files/s,"Apps Plugin Files",line,,apps.plugin,
+netdata.apps_fix,,"utime, stime, gtime, minflt, majflt",percentage,"Apps Plugin Normalization Ratios",line,,apps.plugin,
+netdata.apps_children_fix,,"utime, stime, gtime, minflt, majflt",percentage,"Apps Plugin Exited Children Normalization Ratios",line,,apps.plugin, \ No newline at end of file