| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "apps_plugin.h" |
| 4 | |
| 5 | bool enable_function_cmdline = false; |
| 6 | |
| 7 | #define PROCESS_FILTER_CATEGORY "category:" |
| 8 | #define PROCESS_FILTER_USER "user:" |
| 9 | #define PROCESS_FILTER_GROUP "group:" |
| 10 | #define PROCESS_FILTER_PROCESS "process:" |
| 11 | #define PROCESS_FILTER_PID "pid:" |
| 12 | #define PROCESS_FILTER_UID "uid:" |
| 13 | #define PROCESS_FILTER_GID "gid:" |
| 14 | |
| 15 | static void apps_plugin_function_processes_help(const char *transaction) { |
| 16 | BUFFER *wb = buffer_create(0, NULL); |
| 17 | buffer_sprintf(wb, "%s", |
| 18 | "apps.plugin / processes\n" |
| 19 | "\n" |
| 20 | "Function `processes` presents all the currently running processes of the system.\n" |
| 21 | "\n" |
| 22 | "The following filters are supported:\n" |
| 23 | "\n" |
| 24 | " category:NAME\n" |
| 25 | " Shows only processes that are assigned the category `NAME` in apps_groups.conf\n" |
| 26 | "\n" |
| 27 | " parent:NAME\n" |
| 28 | " Shows only processes that are aggregated under parent `NAME`\n" |
| 29 | "\n" |
| 30 | #if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) |
| 31 | " user:NAME\n" |
| 32 | " Shows only processes that are running as user name `NAME`.\n" |
| 33 | "\n" |
| 34 | #endif |
| 35 | #if (PROCESSES_HAVE_GID == 1) |
| 36 | " group:NAME\n" |
| 37 | " Shows only processes that are running as group name `NAME`.\n" |
| 38 | "\n" |
| 39 | #endif |
| 40 | " process:NAME\n" |
| 41 | " Shows only processes that their Command is `NAME` or their parent's Command is `NAME`.\n" |
| 42 | "\n" |
| 43 | " pid:NUMBER\n" |
| 44 | " Shows only processes that their PID is `NUMBER` or their parent's PID is `NUMBER`\n" |
| 45 | "\n" |
| 46 | #if (PROCESSES_HAVE_UID == 1) |
| 47 | " uid:NUMBER\n" |
| 48 | " Shows only processes that their UID is `NUMBER`\n" |
| 49 | "\n" |
| 50 | #endif |
| 51 | #if (PROCESSES_HAVE_GID == 1) |
| 52 | " gid:NUMBER\n" |
| 53 | " Shows only processes that their GID is `NUMBER`\n" |
| 54 | "\n" |
| 55 | #endif |
| 56 | "Filters can be combined. Each filter can be given only one time.\n" |
| 57 | ); |
| 58 | |
| 59 | wb->response_code = HTTP_RESP_OK; |
| 60 | wb->content_type = CT_TEXT_PLAIN; |
| 61 | wb->expires = now_realtime_sec() + 3600; |
| 62 | pluginsd_function_result_to_stdout(transaction, wb); |
| 63 | buffer_free(wb); |
| 64 | } |
| 65 | |
| 66 | #define add_value_field_llu_with_max(wb, key, value) do { \ |
| 67 | unsigned long long _tmp = (value); \ |
| 68 | key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \ |
| 69 | buffer_json_add_array_item_uint64(wb, _tmp); \ |
| 70 | } while(0) |
| 71 | |
| 72 | #define add_value_field_ndd_with_max(wb, key, value) do { \ |
| 73 | NETDATA_DOUBLE _tmp = (value); \ |
| 74 | key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \ |
| 75 | buffer_json_add_array_item_double(wb, _tmp); \ |
| 76 | } while(0) |
| 77 | |
| 78 | // Holds per-field maximums computed during the data collection loop. |
| 79 | // Passed to fp_emit_columns() so that section can live in its own function, |
| 80 | // keeping function_processes() below GCC's -fvar-tracking-assignments limit. |
| 81 | struct fp_maxvals { |
| 82 | NETDATA_DOUBLE UserCPU_max; |
| 83 | NETDATA_DOUBLE SysCPU_max; |
| 84 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 85 | NETDATA_DOUBLE GuestCPU_max; |
| 86 | #endif |
| 87 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) |
| 88 | NETDATA_DOUBLE CUserCPU_max; |
| 89 | NETDATA_DOUBLE CSysCPU_max; |
| 90 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 91 | NETDATA_DOUBLE CGuestCPU_max; |
| 92 | #endif |
| 93 | #endif |
| 94 | NETDATA_DOUBLE CPU_max; |
| 95 | NETDATA_DOUBLE VMSize_max; |
| 96 | NETDATA_DOUBLE RSS_max; |
| 97 | #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1) |
| 98 | NETDATA_DOUBLE Estimated_max; |
| 99 | NETDATA_DOUBLE Pss_max; |
| 100 | NETDATA_DOUBLE PssAge_max; |
| 101 | NETDATA_DOUBLE SharedRatio_max; |
| 102 | #endif |
| 103 | #if (PROCESSES_HAVE_VMSHARED == 1) |
| 104 | NETDATA_DOUBLE Shared_max; |
| 105 | #endif |
| 106 | NETDATA_DOUBLE Swap_max; |
| 107 | #if (PROCESSES_HAVE_FDS == 1) && (PROCESSES_HAVE_PID_LIMITS == 1) |
| 108 | NETDATA_DOUBLE FDsLimitPercent_max; |
| 109 | #endif |
| 110 | unsigned long long Processes_max; |
| 111 | unsigned long long Threads_max; |
| 112 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 113 | unsigned long long VoluntaryCtxtSwitches_max; |
| 114 | #endif |
| 115 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 116 | unsigned long long NonVoluntaryCtxtSwitches_max; |
| 117 | #endif |
| 118 | unsigned long long Uptime_max; |
| 119 | unsigned long long MinFlt_max; |
| 120 | #if (PROCESSES_HAVE_MAJFLT == 1) |
| 121 | unsigned long long MajFlt_max; |
| 122 | #endif |
| 123 | #if (PROCESSES_HAVE_CHILDREN_FLTS == 1) |
| 124 | unsigned long long CMinFlt_max; |
| 125 | unsigned long long CMajFlt_max; |
| 126 | unsigned long long TMinFlt_max; |
| 127 | unsigned long long TMajFlt_max; |
| 128 | #endif |
| 129 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 130 | unsigned long long LReads_max; |
| 131 | unsigned long long LWrites_max; |
| 132 | #endif |
| 133 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 134 | unsigned long long PReads_max; |
| 135 | unsigned long long PWrites_max; |
| 136 | #endif |
| 137 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 138 | unsigned long long ROps_max; |
| 139 | unsigned long long WOps_max; |
| 140 | #endif |
| 141 | #if (PROCESSES_HAVE_FDS == 1) |
| 142 | unsigned long long Files_max; |
| 143 | unsigned long long Pipes_max; |
| 144 | unsigned long long Sockets_max; |
| 145 | unsigned long long iNotiFDs_max; |
| 146 | unsigned long long EventFDs_max; |
| 147 | unsigned long long TimerFDs_max; |
| 148 | unsigned long long SigFDs_max; |
| 149 | unsigned long long EvPollFDs_max; |
| 150 | unsigned long long OtherFDs_max; |
| 151 | unsigned long long FDs_max; |
| 152 | #endif |
| 153 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 154 | unsigned long long Handles_max; |
| 155 | #endif |
| 156 | }; |
| 157 | |
| 158 | static void fp_emit_columns(BUFFER *wb, struct fp_maxvals *mv, bool show_cmdline, uint64_t total_memory_bytes) { |
| 159 | buffer_json_member_add_object(wb, "columns"); |
| 160 | { |
| 161 | int field_id = 0; |
| 162 | |
| 163 | // IMPORTANT! |
| 164 | // THE ORDER SHOULD BE THE SAME WITH THE VALUES! |
| 165 | // wb, key, name, visible, type, visualization, transform, decimal_points, units, max, sort, sortable, sticky, unique_key, pointer_to, summary, range |
| 166 | buffer_rrdf_table_add_field(wb, field_id++, "PID", "Process ID", RRDF_FIELD_TYPE_INTEGER, |
| 167 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN, |
| 168 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 169 | RRDF_FIELD_FILTER_MULTISELECT, |
| 170 | RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY | |
| 171 | RRDF_FIELD_OPTS_UNIQUE_KEY, NULL); |
| 172 | |
| 173 | buffer_rrdf_table_add_field(wb, field_id++, "Cmd", "Process Name", RRDF_FIELD_TYPE_STRING, |
| 174 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN, |
| 175 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 176 | RRDF_FIELD_FILTER_MULTISELECT, |
| 177 | RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL); |
| 178 | |
| 179 | #if (PROCESSES_HAVE_COMM_AND_NAME == 1) |
| 180 | buffer_rrdf_table_add_field(wb, field_id++, "Name", "Process Friendly Name", RRDF_FIELD_TYPE_STRING, |
| 181 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN, |
| 182 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 183 | RRDF_FIELD_FILTER_MULTISELECT, |
| 184 | RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL); |
| 185 | #endif |
| 186 | |
| 187 | if (show_cmdline) { |
| 188 | buffer_rrdf_table_add_field(wb, field_id++, "CmdLine", "Command Line", RRDF_FIELD_TYPE_STRING, |
| 189 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, |
| 190 | NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 191 | RRDF_FIELD_FILTER_MULTISELECT, |
| 192 | RRDF_FIELD_OPTS_NONE, NULL); |
| 193 | } |
| 194 | |
| 195 | buffer_rrdf_table_add_field(wb, field_id++, "PPID", "Parent Process ID", RRDF_FIELD_TYPE_INTEGER, |
| 196 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, |
| 197 | NAN, RRDF_FIELD_SORT_ASCENDING, "PID", RRDF_FIELD_SUMMARY_COUNT, |
| 198 | RRDF_FIELD_FILTER_MULTISELECT, |
| 199 | RRDF_FIELD_OPTS_NONE, NULL); |
| 200 | |
| 201 | buffer_rrdf_table_add_field(wb, field_id++, "Category", "Category (apps_groups.conf)", RRDF_FIELD_TYPE_STRING, |
| 202 | RRDF_FIELD_VISUAL_VALUE, |
| 203 | RRDF_FIELD_TRANSFORM_NONE, |
| 204 | 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 205 | RRDF_FIELD_FILTER_MULTISELECT, |
| 206 | RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL); |
| 207 | |
| 208 | #if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) |
| 209 | buffer_rrdf_table_add_field(wb, field_id++, "User", "User Owner", RRDF_FIELD_TYPE_STRING, |
| 210 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN, |
| 211 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 212 | RRDF_FIELD_FILTER_MULTISELECT, |
| 213 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 214 | #endif |
| 215 | #if (PROCESSES_HAVE_UID == 1) |
| 216 | buffer_rrdf_table_add_field(wb, field_id++, "Uid", "User ID", RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, |
| 217 | RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN, |
| 218 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 219 | RRDF_FIELD_FILTER_MULTISELECT, |
| 220 | RRDF_FIELD_OPTS_NONE, NULL); |
| 221 | #endif |
| 222 | |
| 223 | #if (PROCESSES_HAVE_GID == 1) |
| 224 | buffer_rrdf_table_add_field(wb, field_id++, "Group", "Group Owner", RRDF_FIELD_TYPE_STRING, |
| 225 | RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN, |
| 226 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 227 | RRDF_FIELD_FILTER_MULTISELECT, |
| 228 | RRDF_FIELD_OPTS_NONE, NULL); |
| 229 | buffer_rrdf_table_add_field(wb, field_id++, "Gid", "Group ID", RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, |
| 230 | RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN, |
| 231 | RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT, |
| 232 | RRDF_FIELD_FILTER_MULTISELECT, |
| 233 | RRDF_FIELD_OPTS_NONE, NULL); |
| 234 | #endif |
| 235 | |
| 236 | // CPU utilization |
| 237 | buffer_rrdf_table_add_field(wb, field_id++, "CPU", "Total CPU Time (100% = 1 core)", |
| 238 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 239 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->CPU_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 240 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 241 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 242 | |
| 243 | buffer_rrdf_table_add_field(wb, field_id++, "UserCPU", "User CPU time (100% = 1 core)", |
| 244 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 245 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->UserCPU_max, |
| 246 | RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 247 | RRDF_FIELD_OPTS_NONE, NULL); |
| 248 | buffer_rrdf_table_add_field(wb, field_id++, "SysCPU", "System CPU Time (100% = 1 core)", |
| 249 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 250 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->SysCPU_max, |
| 251 | RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 252 | RRDF_FIELD_OPTS_NONE, NULL); |
| 253 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 254 | buffer_rrdf_table_add_field(wb, field_id++, "GuestCPU", "Guest CPU Time (100% = 1 core)", |
| 255 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 256 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->GuestCPU_max, |
| 257 | RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 258 | RRDF_FIELD_OPTS_NONE, NULL); |
| 259 | #endif |
| 260 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) |
| 261 | buffer_rrdf_table_add_field(wb, field_id++, "CUserCPU", "Children User CPU Time (100% = 1 core)", |
| 262 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 263 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->CUserCPU_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 264 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 265 | RRDF_FIELD_OPTS_NONE, NULL); |
| 266 | buffer_rrdf_table_add_field(wb, field_id++, "CSysCPU", "Children System CPU Time (100% = 1 core)", |
| 267 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 268 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->CSysCPU_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 269 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 270 | RRDF_FIELD_OPTS_NONE, NULL); |
| 271 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 272 | buffer_rrdf_table_add_field(wb, field_id++, "CGuestCPU", "Children Guest CPU Time (100% = 1 core)", |
| 273 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 274 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->CGuestCPU_max, RRDF_FIELD_SORT_DESCENDING, |
| 275 | NULL, |
| 276 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, RRDF_FIELD_OPTS_NONE, NULL); |
| 277 | #endif |
| 278 | #endif |
| 279 | |
| 280 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 281 | // CPU context switches |
| 282 | buffer_rrdf_table_add_field(wb, field_id++, "vCtxSwitch", "Voluntary Context Switches", |
| 283 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 284 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, "switches/s", |
| 285 | mv->VoluntaryCtxtSwitches_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 286 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, RRDF_FIELD_OPTS_NONE, NULL); |
| 287 | #endif |
| 288 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 289 | buffer_rrdf_table_add_field(wb, field_id++, "iCtxSwitch", "Involuntary Context Switches", |
| 290 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 291 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, "switches/s", |
| 292 | mv->NonVoluntaryCtxtSwitches_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 293 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, RRDF_FIELD_OPTS_NONE, NULL); |
| 294 | #endif |
| 295 | |
| 296 | // memory |
| 297 | if (total_memory_bytes) |
| 298 | buffer_rrdf_table_add_field(wb, field_id++, "Memory", "Memory Percentage", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 299 | RRDF_FIELD_VISUAL_BAR, |
| 300 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", 100.0, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 301 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 302 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 303 | |
| 304 | buffer_rrdf_table_add_field(wb, field_id++, "Resident", "Resident Set Size", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 305 | RRDF_FIELD_VISUAL_BAR, |
| 306 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 307 | 2, "MiB", mv->RSS_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 308 | RRDF_FIELD_FILTER_RANGE, |
| 309 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 310 | #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1) |
| 311 | if(pss_refresh_period > 0) { |
| 312 | buffer_rrdf_table_add_field(wb, field_id++, "Estimated", "Estimated Memory Usage", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 313 | RRDF_FIELD_VISUAL_BAR, |
| 314 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 315 | 2, "MiB", mv->Estimated_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 316 | RRDF_FIELD_FILTER_RANGE, |
| 317 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 318 | buffer_rrdf_table_add_field(wb, field_id++, "Pss", "Proportional Set Size", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 319 | RRDF_FIELD_VISUAL_BAR, |
| 320 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 321 | 2, "MiB", mv->Pss_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 322 | RRDF_FIELD_FILTER_RANGE, |
| 323 | RRDF_FIELD_OPTS_NONE, NULL); |
| 324 | buffer_rrdf_table_add_field(wb, field_id++, "PssAge", "Time since last smaps sample", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 325 | RRDF_FIELD_VISUAL_BAR, |
| 326 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 327 | 2, "s", mv->PssAge_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_MAX, |
| 328 | RRDF_FIELD_FILTER_RANGE, |
| 329 | RRDF_FIELD_OPTS_NONE, NULL); |
| 330 | buffer_rrdf_table_add_field(wb, field_id++, "SharedRatio", "Shared Memory Ratio", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 331 | RRDF_FIELD_VISUAL_BAR, |
| 332 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 333 | 2, "%", mv->SharedRatio_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_MEAN, |
| 334 | RRDF_FIELD_FILTER_RANGE, |
| 335 | RRDF_FIELD_OPTS_NONE, NULL); |
| 336 | } |
| 337 | #endif |
| 338 | #if (PROCESSES_HAVE_VMSHARED == 1) |
| 339 | buffer_rrdf_table_add_field(wb, field_id++, "Shared", "Shared Pages", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 340 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, |
| 341 | "MiB", mv->Shared_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 342 | RRDF_FIELD_FILTER_RANGE, |
| 343 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 344 | #endif |
| 345 | |
| 346 | buffer_rrdf_table_add_field(wb, field_id++, "Virtual", "Virtual Memory Size", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 347 | RRDF_FIELD_VISUAL_BAR, |
| 348 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "MiB", mv->VMSize_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 349 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 350 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 351 | |
| 352 | #if (PROCESSES_HAVE_VMSWAP == 1) |
| 353 | buffer_rrdf_table_add_field(wb, field_id++, "Swap", "Swap Memory", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 354 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, |
| 355 | "MiB", |
| 356 | mv->Swap_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 357 | RRDF_FIELD_FILTER_RANGE, |
| 358 | RRDF_FIELD_OPTS_NONE, NULL); |
| 359 | #endif |
| 360 | |
| 361 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 362 | // Physical I/O |
| 363 | buffer_rrdf_table_add_field(wb, field_id++, "PReads", "Physical I/O Reads", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 364 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, |
| 365 | 2, "KiB/s", mv->PReads_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 366 | RRDF_FIELD_FILTER_RANGE, |
| 367 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 368 | buffer_rrdf_table_add_field(wb, field_id++, "PWrites", "Physical I/O Writes", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 369 | RRDF_FIELD_VISUAL_BAR, |
| 370 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "KiB/s", mv->PWrites_max, RRDF_FIELD_SORT_DESCENDING, |
| 371 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 372 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 373 | #endif |
| 374 | |
| 375 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 376 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 377 | RRDF_FIELD_OPTIONS logical_io_options = RRDF_FIELD_OPTS_NONE; |
| 378 | #else |
| 379 | RRDF_FIELD_OPTIONS logical_io_options = RRDF_FIELD_OPTS_VISIBLE; |
| 380 | #endif |
| 381 | // Logical I/O |
| 382 | buffer_rrdf_table_add_field(wb, field_id++, "LReads", "Logical I/O Reads", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 383 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, |
| 384 | 2, "KiB/s", mv->LReads_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 385 | RRDF_FIELD_FILTER_RANGE, |
| 386 | logical_io_options, NULL); |
| 387 | buffer_rrdf_table_add_field(wb, field_id++, "LWrites", "Logical I/O Writes", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 388 | RRDF_FIELD_VISUAL_BAR, |
| 389 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 390 | 2, "KiB/s", mv->LWrites_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 391 | RRDF_FIELD_FILTER_RANGE, |
| 392 | logical_io_options, NULL); |
| 393 | #endif |
| 394 | |
| 395 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 396 | // I/O calls |
| 397 | buffer_rrdf_table_add_field(wb, field_id++, "ROps", "I/O Read Operations", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 398 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, |
| 399 | "ops/s", mv->ROps_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 400 | RRDF_FIELD_FILTER_RANGE, |
| 401 | RRDF_FIELD_OPTS_NONE, NULL); |
| 402 | buffer_rrdf_table_add_field(wb, field_id++, "WOps", "I/O Write Operations", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 403 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 2, |
| 404 | "ops/s", mv->WOps_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 405 | RRDF_FIELD_FILTER_RANGE, |
| 406 | RRDF_FIELD_OPTS_NONE, NULL); |
| 407 | #endif |
| 408 | |
| 409 | // minor page faults |
| 410 | buffer_rrdf_table_add_field(wb, field_id++, "MinFlt", "Minor Page Faults/s", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 411 | RRDF_FIELD_VISUAL_BAR, |
| 412 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 413 | 2, "pgflts/s", mv->MinFlt_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 414 | RRDF_FIELD_FILTER_RANGE, |
| 415 | RRDF_FIELD_OPTS_NONE, NULL); |
| 416 | |
| 417 | #if (PROCESSES_HAVE_MAJFLT == 1) |
| 418 | // major page faults |
| 419 | buffer_rrdf_table_add_field(wb, field_id++, "MajFlt", "Major Page Faults/s", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 420 | RRDF_FIELD_VISUAL_BAR, |
| 421 | RRDF_FIELD_TRANSFORM_NUMBER, |
| 422 | 2, "pgflts/s", mv->MajFlt_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 423 | RRDF_FIELD_FILTER_RANGE, |
| 424 | RRDF_FIELD_OPTS_NONE, NULL); |
| 425 | #endif |
| 426 | |
| 427 | #if (PROCESSES_HAVE_CHILDREN_FLTS == 1) |
| 428 | buffer_rrdf_table_add_field(wb, field_id++, "CMinFlt", "Children Minor Page Faults/s", |
| 429 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 430 | RRDF_FIELD_VISUAL_BAR, |
| 431 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "pgflts/s", mv->CMinFlt_max, RRDF_FIELD_SORT_DESCENDING, |
| 432 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 433 | RRDF_FIELD_OPTS_NONE, NULL); |
| 434 | buffer_rrdf_table_add_field(wb, field_id++, "CMajFlt", "Children Major Page Faults/s", |
| 435 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 436 | RRDF_FIELD_VISUAL_BAR, |
| 437 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "pgflts/s", mv->CMajFlt_max, RRDF_FIELD_SORT_DESCENDING, |
| 438 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 439 | RRDF_FIELD_OPTS_NONE, NULL); |
| 440 | buffer_rrdf_table_add_field(wb, field_id++, "TMinFlt", "Total Minor Page Faults/s", |
| 441 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 442 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "pgflts/s", mv->TMinFlt_max, RRDF_FIELD_SORT_DESCENDING, |
| 443 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 444 | RRDF_FIELD_OPTS_NONE, NULL); |
| 445 | buffer_rrdf_table_add_field(wb, field_id++, "TMajFlt", "Total Major Page Faults/s", |
| 446 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 447 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "pgflts/s", mv->TMajFlt_max, RRDF_FIELD_SORT_DESCENDING, |
| 448 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 449 | RRDF_FIELD_OPTS_NONE, NULL); |
| 450 | #endif |
| 451 | |
| 452 | #if (PROCESSES_HAVE_FDS == 1) |
| 453 | // open file descriptors |
| 454 | #if (PROCESSES_HAVE_PID_LIMITS == 1) |
| 455 | buffer_rrdf_table_add_field(wb, field_id++, "FDsLimitPercent", "Percentage of Open Descriptors vs Limits", |
| 456 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 457 | RRDF_FIELD_TRANSFORM_NUMBER, 2, "%", mv->FDsLimitPercent_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 458 | RRDF_FIELD_SUMMARY_MAX, RRDF_FIELD_FILTER_RANGE, |
| 459 | RRDF_FIELD_OPTS_NONE, NULL); |
| 460 | #endif |
| 461 | buffer_rrdf_table_add_field(wb, field_id++, "FDs", "All Open File Descriptors", |
| 462 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 463 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->FDs_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 464 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 465 | RRDF_FIELD_OPTS_NONE, NULL); |
| 466 | |
| 467 | buffer_rrdf_table_add_field(wb, field_id++, "Files", "Open Files", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 468 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 469 | "fds", |
| 470 | mv->Files_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 471 | RRDF_FIELD_FILTER_RANGE, |
| 472 | RRDF_FIELD_OPTS_NONE, NULL); |
| 473 | buffer_rrdf_table_add_field(wb, field_id++, "Pipes", "Open Pipes", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 474 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 475 | "fds", |
| 476 | mv->Pipes_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 477 | RRDF_FIELD_FILTER_RANGE, |
| 478 | RRDF_FIELD_OPTS_NONE, NULL); |
| 479 | buffer_rrdf_table_add_field(wb, field_id++, "Sockets", "Open Sockets", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 480 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 481 | "fds", mv->Sockets_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 482 | RRDF_FIELD_FILTER_RANGE, |
| 483 | RRDF_FIELD_OPTS_NONE, NULL); |
| 484 | buffer_rrdf_table_add_field(wb, field_id++, "iNotiFDs", "Open iNotify Descriptors", |
| 485 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 486 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->iNotiFDs_max, RRDF_FIELD_SORT_DESCENDING, |
| 487 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 488 | RRDF_FIELD_OPTS_NONE, NULL); |
| 489 | buffer_rrdf_table_add_field(wb, field_id++, "EventFDs", "Open Event Descriptors", |
| 490 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 491 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->EventFDs_max, RRDF_FIELD_SORT_DESCENDING, |
| 492 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 493 | RRDF_FIELD_OPTS_NONE, NULL); |
| 494 | buffer_rrdf_table_add_field(wb, field_id++, "TimerFDs", "Open Timer Descriptors", |
| 495 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 496 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->TimerFDs_max, RRDF_FIELD_SORT_DESCENDING, |
| 497 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 498 | RRDF_FIELD_OPTS_NONE, NULL); |
| 499 | buffer_rrdf_table_add_field(wb, field_id++, "SigFDs", "Open Signal Descriptors", |
| 500 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 501 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->SigFDs_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 502 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 503 | RRDF_FIELD_OPTS_NONE, NULL); |
| 504 | buffer_rrdf_table_add_field(wb, field_id++, "EvPollFDs", "Open Event Poll Descriptors", |
| 505 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 506 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->EvPollFDs_max, |
| 507 | RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 508 | RRDF_FIELD_OPTS_NONE, NULL); |
| 509 | buffer_rrdf_table_add_field(wb, field_id++, "OtherFDs", "Other Open Descriptors", |
| 510 | RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, |
| 511 | RRDF_FIELD_TRANSFORM_NUMBER, 0, "fds", mv->OtherFDs_max, RRDF_FIELD_SORT_DESCENDING, |
| 512 | NULL, RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 513 | RRDF_FIELD_OPTS_NONE, NULL); |
| 514 | #endif |
| 515 | |
| 516 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 517 | buffer_rrdf_table_add_field(wb, field_id++, "Handles", "Open Handles", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 518 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 519 | "handles", |
| 520 | mv->Handles_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 521 | RRDF_FIELD_FILTER_RANGE, |
| 522 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 523 | #endif |
| 524 | |
| 525 | // processes, threads, uptime |
| 526 | buffer_rrdf_table_add_field(wb, field_id++, "Processes", "Processes", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 527 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 528 | "processes", mv->Processes_max, RRDF_FIELD_SORT_DESCENDING, NULL, |
| 529 | RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE, |
| 530 | RRDF_FIELD_OPTS_NONE, NULL); |
| 531 | buffer_rrdf_table_add_field(wb, field_id++, "Threads", "Threads", RRDF_FIELD_TYPE_BAR_WITH_INTEGER, |
| 532 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, 0, |
| 533 | "threads", mv->Threads_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_SUM, |
| 534 | RRDF_FIELD_FILTER_RANGE, |
| 535 | RRDF_FIELD_OPTS_NONE, NULL); |
| 536 | buffer_rrdf_table_add_field(wb, field_id++, "Uptime", "Uptime in seconds", RRDF_FIELD_TYPE_DURATION, |
| 537 | RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_DURATION_S, 2, |
| 538 | "seconds", mv->Uptime_max, RRDF_FIELD_SORT_DESCENDING, NULL, RRDF_FIELD_SUMMARY_MAX, |
| 539 | RRDF_FIELD_FILTER_RANGE, |
| 540 | RRDF_FIELD_OPTS_VISIBLE, NULL); |
| 541 | } |
| 542 | buffer_json_object_close(wb); // columns |
| 543 | } |
| 544 | |
| 545 | static void fp_emit_charts(BUFFER *wb, uint64_t total_memory_bytes) { |
| 546 | buffer_json_member_add_object(wb, "charts"); |
| 547 | { |
| 548 | // CPU chart |
| 549 | buffer_json_member_add_object(wb, "CPU"); |
| 550 | { |
| 551 | buffer_json_member_add_string(wb, "name", "CPU Utilization"); |
| 552 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 553 | buffer_json_member_add_array(wb, "columns"); |
| 554 | { |
| 555 | buffer_json_add_array_item_string(wb, "UserCPU"); |
| 556 | buffer_json_add_array_item_string(wb, "SysCPU"); |
| 557 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 558 | buffer_json_add_array_item_string(wb, "GuestCPU"); |
| 559 | #endif |
| 560 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) |
| 561 | buffer_json_add_array_item_string(wb, "CUserCPU"); |
| 562 | buffer_json_add_array_item_string(wb, "CSysCPU"); |
| 563 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 564 | buffer_json_add_array_item_string(wb, "CGuestCPU"); |
| 565 | #endif |
| 566 | #endif |
| 567 | } |
| 568 | buffer_json_array_close(wb); |
| 569 | } |
| 570 | buffer_json_object_close(wb); |
| 571 | |
| 572 | #if (PROCESSES_HAVE_VOLCTX == 1) || (PROCESSES_HAVE_NVOLCTX == 1) |
| 573 | buffer_json_member_add_object(wb, "CPUCtxSwitches"); |
| 574 | { |
| 575 | buffer_json_member_add_string(wb, "name", "CPU Context Switches"); |
| 576 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 577 | buffer_json_member_add_array(wb, "columns"); |
| 578 | { |
| 579 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 580 | buffer_json_add_array_item_string(wb, "vCtxSwitch"); |
| 581 | #endif |
| 582 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 583 | buffer_json_add_array_item_string(wb, "iCtxSwitch"); |
| 584 | #endif |
| 585 | } |
| 586 | buffer_json_array_close(wb); |
| 587 | } |
| 588 | buffer_json_object_close(wb); |
| 589 | #endif |
| 590 | |
| 591 | // Memory chart |
| 592 | buffer_json_member_add_object(wb, "Memory"); |
| 593 | { |
| 594 | buffer_json_member_add_string(wb, "name", "Memory"); |
| 595 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 596 | buffer_json_member_add_array(wb, "columns"); |
| 597 | { |
| 598 | buffer_json_add_array_item_string(wb, "Virtual"); |
| 599 | buffer_json_add_array_item_string(wb, "Resident"); |
| 600 | buffer_json_add_array_item_string(wb, "Shared"); |
| 601 | buffer_json_add_array_item_string(wb, "Swap"); |
| 602 | } |
| 603 | buffer_json_array_close(wb); |
| 604 | } |
| 605 | buffer_json_object_close(wb); |
| 606 | |
| 607 | if(total_memory_bytes) { |
| 608 | buffer_json_member_add_object(wb, "MemoryPercent"); |
| 609 | { |
| 610 | buffer_json_member_add_string(wb, "name", "Memory Percentage"); |
| 611 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 612 | buffer_json_member_add_array(wb, "columns"); |
| 613 | { |
| 614 | buffer_json_add_array_item_string(wb, "Memory"); |
| 615 | } |
| 616 | buffer_json_array_close(wb); |
| 617 | } |
| 618 | buffer_json_object_close(wb); |
| 619 | } |
| 620 | |
| 621 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) || (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 622 | // I/O Reads chart |
| 623 | buffer_json_member_add_object(wb, "Reads"); |
| 624 | { |
| 625 | buffer_json_member_add_string(wb, "name", "I/O Reads"); |
| 626 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 627 | buffer_json_member_add_array(wb, "columns"); |
| 628 | { |
| 629 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 630 | buffer_json_add_array_item_string(wb, "LReads"); |
| 631 | #endif |
| 632 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 633 | buffer_json_add_array_item_string(wb, "PReads"); |
| 634 | #endif |
| 635 | } |
| 636 | buffer_json_array_close(wb); |
| 637 | } |
| 638 | buffer_json_object_close(wb); |
| 639 | |
| 640 | // I/O Writes chart |
| 641 | buffer_json_member_add_object(wb, "Writes"); |
| 642 | { |
| 643 | buffer_json_member_add_string(wb, "name", "I/O Writes"); |
| 644 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 645 | buffer_json_member_add_array(wb, "columns"); |
| 646 | { |
| 647 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 648 | buffer_json_add_array_item_string(wb, "LWrites"); |
| 649 | #endif |
| 650 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 651 | buffer_json_add_array_item_string(wb, "PWrites"); |
| 652 | #endif |
| 653 | } |
| 654 | buffer_json_array_close(wb); |
| 655 | } |
| 656 | buffer_json_object_close(wb); |
| 657 | #endif |
| 658 | |
| 659 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 660 | // Logical I/O chart |
| 661 | buffer_json_member_add_object(wb, "LogicalIO"); |
| 662 | { |
| 663 | buffer_json_member_add_string(wb, "name", "Logical I/O"); |
| 664 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 665 | buffer_json_member_add_array(wb, "columns"); |
| 666 | { |
| 667 | buffer_json_add_array_item_string(wb, "LReads"); |
| 668 | buffer_json_add_array_item_string(wb, "LWrites"); |
| 669 | } |
| 670 | buffer_json_array_close(wb); |
| 671 | } |
| 672 | buffer_json_object_close(wb); |
| 673 | #endif |
| 674 | |
| 675 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 676 | // Physical I/O chart |
| 677 | buffer_json_member_add_object(wb, "PhysicalIO"); |
| 678 | { |
| 679 | buffer_json_member_add_string(wb, "name", "Physical I/O"); |
| 680 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 681 | buffer_json_member_add_array(wb, "columns"); |
| 682 | { |
| 683 | buffer_json_add_array_item_string(wb, "PReads"); |
| 684 | buffer_json_add_array_item_string(wb, "PWrites"); |
| 685 | } |
| 686 | buffer_json_array_close(wb); |
| 687 | } |
| 688 | buffer_json_object_close(wb); |
| 689 | #endif |
| 690 | |
| 691 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 692 | // I/O Calls chart |
| 693 | buffer_json_member_add_object(wb, "IOCalls"); |
| 694 | { |
| 695 | buffer_json_member_add_string(wb, "name", "I/O Calls"); |
| 696 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 697 | buffer_json_member_add_array(wb, "columns"); |
| 698 | { |
| 699 | buffer_json_add_array_item_string(wb, "ROps"); |
| 700 | buffer_json_add_array_item_string(wb, "WOps"); |
| 701 | } |
| 702 | buffer_json_array_close(wb); |
| 703 | } |
| 704 | buffer_json_object_close(wb); |
| 705 | #endif |
| 706 | |
| 707 | // Minor Page Faults chart |
| 708 | buffer_json_member_add_object(wb, "MinFlt"); |
| 709 | { |
| 710 | buffer_json_member_add_string(wb, "name", "Minor Page Faults"); |
| 711 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 712 | buffer_json_member_add_array(wb, "columns"); |
| 713 | { |
| 714 | buffer_json_add_array_item_string(wb, "MinFlt"); |
| 715 | buffer_json_add_array_item_string(wb, "CMinFlt"); |
| 716 | } |
| 717 | buffer_json_array_close(wb); |
| 718 | } |
| 719 | buffer_json_object_close(wb); |
| 720 | |
| 721 | // Major Page Faults chart |
| 722 | buffer_json_member_add_object(wb, "MajFlt"); |
| 723 | { |
| 724 | buffer_json_member_add_string(wb, "name", "Major Page Faults"); |
| 725 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 726 | buffer_json_member_add_array(wb, "columns"); |
| 727 | { |
| 728 | buffer_json_add_array_item_string(wb, "MajFlt"); |
| 729 | buffer_json_add_array_item_string(wb, "CMajFlt"); |
| 730 | } |
| 731 | buffer_json_array_close(wb); |
| 732 | } |
| 733 | buffer_json_object_close(wb); |
| 734 | |
| 735 | // Threads chart |
| 736 | buffer_json_member_add_object(wb, "Threads"); |
| 737 | { |
| 738 | buffer_json_member_add_string(wb, "name", "Threads"); |
| 739 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 740 | buffer_json_member_add_array(wb, "columns"); |
| 741 | { |
| 742 | buffer_json_add_array_item_string(wb, "Threads"); |
| 743 | } |
| 744 | buffer_json_array_close(wb); |
| 745 | } |
| 746 | buffer_json_object_close(wb); |
| 747 | |
| 748 | // Processes chart |
| 749 | buffer_json_member_add_object(wb, "Processes"); |
| 750 | { |
| 751 | buffer_json_member_add_string(wb, "name", "Processes"); |
| 752 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 753 | buffer_json_member_add_array(wb, "columns"); |
| 754 | { |
| 755 | buffer_json_add_array_item_string(wb, "Processes"); |
| 756 | } |
| 757 | buffer_json_array_close(wb); |
| 758 | } |
| 759 | buffer_json_object_close(wb); |
| 760 | |
| 761 | #if (PROCESSES_HAVE_FDS == 1) |
| 762 | // FDs chart |
| 763 | buffer_json_member_add_object(wb, "FDs"); |
| 764 | { |
| 765 | buffer_json_member_add_string(wb, "name", "File Descriptors"); |
| 766 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 767 | buffer_json_member_add_array(wb, "columns"); |
| 768 | { |
| 769 | buffer_json_add_array_item_string(wb, "Files"); |
| 770 | buffer_json_add_array_item_string(wb, "Pipes"); |
| 771 | buffer_json_add_array_item_string(wb, "Sockets"); |
| 772 | buffer_json_add_array_item_string(wb, "iNotiFDs"); |
| 773 | buffer_json_add_array_item_string(wb, "EventFDs"); |
| 774 | buffer_json_add_array_item_string(wb, "TimerFDs"); |
| 775 | buffer_json_add_array_item_string(wb, "SigFDs"); |
| 776 | buffer_json_add_array_item_string(wb, "EvPollFDs"); |
| 777 | buffer_json_add_array_item_string(wb, "OtherFDs"); |
| 778 | } |
| 779 | buffer_json_array_close(wb); |
| 780 | } |
| 781 | buffer_json_object_close(wb); |
| 782 | #endif |
| 783 | |
| 784 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 785 | // Handles chart |
| 786 | buffer_json_member_add_object(wb, "Handles"); |
| 787 | { |
| 788 | buffer_json_member_add_string(wb, "name", "Handles"); |
| 789 | buffer_json_member_add_string(wb, "type", "stacked-bar"); |
| 790 | buffer_json_member_add_array(wb, "columns"); |
| 791 | { |
| 792 | buffer_json_add_array_item_string(wb, "Handles"); |
| 793 | } |
| 794 | buffer_json_array_close(wb); |
| 795 | } |
| 796 | buffer_json_object_close(wb); |
| 797 | #endif |
| 798 | } |
| 799 | buffer_json_object_close(wb); // charts |
| 800 | } |
| 801 | |
| 802 | static void fp_emit_groupby(BUFFER *wb) { |
| 803 | buffer_json_member_add_array(wb, "default_charts"); |
| 804 | { |
| 805 | buffer_json_add_array_item_array(wb); |
| 806 | buffer_json_add_array_item_string(wb, "CPU"); |
| 807 | buffer_json_add_array_item_string(wb, "Category"); |
| 808 | buffer_json_array_close(wb); |
| 809 | |
| 810 | buffer_json_add_array_item_array(wb); |
| 811 | buffer_json_add_array_item_string(wb, "Memory"); |
| 812 | buffer_json_add_array_item_string(wb, "Category"); |
| 813 | buffer_json_array_close(wb); |
| 814 | } |
| 815 | buffer_json_array_close(wb); |
| 816 | |
| 817 | buffer_json_member_add_object(wb, "group_by"); |
| 818 | { |
| 819 | // group by PID |
| 820 | buffer_json_member_add_object(wb, "PID"); |
| 821 | { |
| 822 | buffer_json_member_add_string(wb, "name", "Process Tree by PID"); |
| 823 | buffer_json_member_add_array(wb, "columns"); |
| 824 | { |
| 825 | buffer_json_add_array_item_string(wb, "PPID"); |
| 826 | } |
| 827 | buffer_json_array_close(wb); |
| 828 | } |
| 829 | buffer_json_object_close(wb); |
| 830 | |
| 831 | // group by Category |
| 832 | buffer_json_member_add_object(wb, "Category"); |
| 833 | { |
| 834 | buffer_json_member_add_string(wb, "name", "Process Tree by Category"); |
| 835 | buffer_json_member_add_array(wb, "columns"); |
| 836 | { |
| 837 | buffer_json_add_array_item_string(wb, "Category"); |
| 838 | buffer_json_add_array_item_string(wb, "PPID"); |
| 839 | } |
| 840 | buffer_json_array_close(wb); |
| 841 | } |
| 842 | buffer_json_object_close(wb); |
| 843 | |
| 844 | // group by PPID |
| 845 | buffer_json_member_add_object(wb, "PPID"); |
| 846 | { |
| 847 | buffer_json_member_add_string(wb, "name", "Process Tree by Parent PID"); |
| 848 | buffer_json_member_add_array(wb, "columns"); |
| 849 | { |
| 850 | buffer_json_add_array_item_string(wb, "PPID"); |
| 851 | buffer_json_add_array_item_string(wb, "PID"); |
| 852 | } |
| 853 | buffer_json_array_close(wb); |
| 854 | } |
| 855 | buffer_json_object_close(wb); |
| 856 | |
| 857 | #if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) |
| 858 | // group by User |
| 859 | buffer_json_member_add_object(wb, "User"); |
| 860 | { |
| 861 | buffer_json_member_add_string(wb, "name", "Process Tree by User"); |
| 862 | buffer_json_member_add_array(wb, "columns"); |
| 863 | { |
| 864 | buffer_json_add_array_item_string(wb, "User"); |
| 865 | buffer_json_add_array_item_string(wb, "PPID"); |
| 866 | } |
| 867 | buffer_json_array_close(wb); |
| 868 | } |
| 869 | buffer_json_object_close(wb); |
| 870 | #endif |
| 871 | |
| 872 | #if (PROCESSES_HAVE_GID == 1) |
| 873 | // group by Group |
| 874 | buffer_json_member_add_object(wb, "Group"); |
| 875 | { |
| 876 | buffer_json_member_add_string(wb, "name", "Process Tree by Group"); |
| 877 | buffer_json_member_add_array(wb, "columns"); |
| 878 | { |
| 879 | buffer_json_add_array_item_string(wb, "Group"); |
| 880 | buffer_json_add_array_item_string(wb, "PPID"); |
| 881 | } |
| 882 | buffer_json_array_close(wb); |
| 883 | } |
| 884 | buffer_json_object_close(wb); |
| 885 | #endif |
| 886 | } |
| 887 | buffer_json_object_close(wb); // group_by |
| 888 | } |
| 889 | |
| 890 | void function_processes(const char *transaction, char *function, |
| 891 | usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused, |
| 892 | BUFFER *payload __maybe_unused, HTTP_ACCESS access, |
| 893 | const char *source __maybe_unused, void *data __maybe_unused) { |
| 894 | time_t now_s = now_realtime_sec(); |
| 895 | struct pid_stat *p; |
| 896 | |
| 897 | bool show_cmdline = http_access_user_has_enough_access_level_for_endpoint( |
| 898 | access, HTTP_ACCESS_SIGNED_ID | HTTP_ACCESS_SAME_SPACE | HTTP_ACCESS_SENSITIVE_DATA | HTTP_ACCESS_VIEW_AGENT_CONFIG) || enable_function_cmdline; |
| 899 | |
| 900 | char *words[PLUGINSD_MAX_WORDS] = { NULL }; |
| 901 | size_t num_words = quoted_strings_splitter_whitespace(function, words, PLUGINSD_MAX_WORDS); |
| 902 | |
| 903 | struct target *category = NULL, *user = NULL, *group = NULL; (void)category; (void)user; (void)group; |
| 904 | #if (PROCESSES_HAVE_UID == 1) |
| 905 | struct target *users_sid_root = users_root_target; |
| 906 | #endif |
| 907 | #if (PROCESSES_HAVE_SID == 1) |
| 908 | struct target *users_sid_root = sids_root_target; |
| 909 | #endif |
| 910 | const char *process_name = NULL; |
| 911 | pid_t pid = 0; |
| 912 | uid_t uid = 0; (void)uid; |
| 913 | gid_t gid = 0; (void)gid; |
| 914 | bool info = false; |
| 915 | |
| 916 | bool filter_pid = false, filter_uid = false, filter_gid = false; |
| 917 | (void)filter_uid; (void)filter_gid; |
| 918 | |
| 919 | for(int i = 1; i < PLUGINSD_MAX_WORDS ;i++) { |
| 920 | const char *keyword = get_word(words, num_words, i); |
| 921 | if(!keyword) break; |
| 922 | |
| 923 | if(!category && strncmp(keyword, PROCESS_FILTER_CATEGORY, strlen(PROCESS_FILTER_CATEGORY)) == 0) { |
| 924 | category = find_target_by_name(apps_groups_root_target, &keyword[strlen(PROCESS_FILTER_CATEGORY)]); |
| 925 | if(!category) { |
| 926 | pluginsd_function_json_error_to_stdout(transaction, HTTP_RESP_BAD_REQUEST, |
| 927 | "No category with that name found."); |
| 928 | return; |
| 929 | } |
| 930 | } |
| 931 | #if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) |
| 932 | else if(!user && strncmp(keyword, PROCESS_FILTER_USER, strlen(PROCESS_FILTER_USER)) == 0) { |
| 933 | user = find_target_by_name(users_sid_root, &keyword[strlen(PROCESS_FILTER_USER)]); |
| 934 | if(!user) { |
| 935 | pluginsd_function_json_error_to_stdout(transaction, HTTP_RESP_BAD_REQUEST, |
| 936 | "No user with that name found."); |
| 937 | return; |
| 938 | } |
| 939 | } |
| 940 | #endif |
| 941 | #if (PROCESSES_HAVE_GID == 1) |
| 942 | else if(strncmp(keyword, PROCESS_FILTER_GROUP, strlen(PROCESS_FILTER_GROUP)) == 0) { |
| 943 | group = find_target_by_name(groups_root_target, &keyword[strlen(PROCESS_FILTER_GROUP)]); |
| 944 | if(!group) { |
| 945 | pluginsd_function_json_error_to_stdout(transaction, HTTP_RESP_BAD_REQUEST, |
| 946 | "No group with that name found."); |
| 947 | return; |
| 948 | } |
| 949 | } |
| 950 | #endif |
| 951 | else if(!process_name && strncmp(keyword, PROCESS_FILTER_PROCESS, strlen(PROCESS_FILTER_PROCESS)) == 0) { |
| 952 | process_name = &keyword[strlen(PROCESS_FILTER_PROCESS)]; |
| 953 | } |
| 954 | else if(!pid && strncmp(keyword, PROCESS_FILTER_PID, strlen(PROCESS_FILTER_PID)) == 0) { |
| 955 | pid = str2i(&keyword[strlen(PROCESS_FILTER_PID)]); |
| 956 | filter_pid = true; |
| 957 | } |
| 958 | #if (PROCESSES_HAVE_UID == 1) |
| 959 | else if(!uid && strncmp(keyword, PROCESS_FILTER_UID, strlen(PROCESS_FILTER_UID)) == 0) { |
| 960 | uid = str2i(&keyword[strlen(PROCESS_FILTER_UID)]); |
| 961 | filter_uid = true; |
| 962 | } |
| 963 | #endif |
| 964 | #if (PROCESSES_HAVE_GID == 1) |
| 965 | else if(!gid && strncmp(keyword, PROCESS_FILTER_GID, strlen(PROCESS_FILTER_GID)) == 0) { |
| 966 | gid = str2i(&keyword[strlen(PROCESS_FILTER_GID)]); |
| 967 | filter_gid = true; |
| 968 | } |
| 969 | #endif |
| 970 | else if(strcmp(keyword, "help") == 0) { |
| 971 | apps_plugin_function_processes_help(transaction); |
| 972 | return; |
| 973 | } |
| 974 | else if(strcmp(keyword, "info") == 0) { |
| 975 | info = true; |
| 976 | } |
| 977 | } |
| 978 | |
| 979 | BUFFER *wb = buffer_create(4096, NULL); |
| 980 | buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY); |
| 981 | buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK); |
| 982 | buffer_json_member_add_string(wb, "type", "table"); |
| 983 | buffer_json_member_add_time_t(wb, "update_every", update_every); |
| 984 | buffer_json_member_add_boolean(wb, "has_history", false); |
| 985 | buffer_json_member_add_string(wb, "help", APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION); |
| 986 | |
| 987 | if(info) |
| 988 | goto close_and_send; |
| 989 | |
| 990 | buffer_json_member_add_array(wb, "data"); |
| 991 | |
| 992 | uint64_t cpu_divisor = NSEC_PER_SEC / 100; |
| 993 | unsigned int memory_divisor = 1024 * 1024; |
| 994 | unsigned int io_divisor = 1024 * RATES_DETAIL; |
| 995 | |
| 996 | uint64_t total_memory_bytes = OS_FUNCTION(apps_os_get_total_memory)(); |
| 997 | |
| 998 | NETDATA_DOUBLE |
| 999 | UserCPU_max = 0.0 |
| 1000 | , SysCPU_max = 0.0 |
| 1001 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 1002 | , GuestCPU_max = 0.0 |
| 1003 | #endif |
| 1004 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) |
| 1005 | , CUserCPU_max = 0.0 |
| 1006 | , CSysCPU_max = 0.0 |
| 1007 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 1008 | , CGuestCPU_max = 0.0 |
| 1009 | #endif |
| 1010 | #endif |
| 1011 | , CPU_max = 0.0 |
| 1012 | , VMSize_max = 0.0 |
| 1013 | , RSS_max = 0.0 |
| 1014 | #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1) |
| 1015 | , Estimated_max = 0.0 |
| 1016 | , Pss_max = 0.0 |
| 1017 | , PssAge_max = 0.0 |
| 1018 | , SharedRatio_max = 0.0 |
| 1019 | #endif |
| 1020 | #if (PROCESSES_HAVE_VMSHARED == 1) |
| 1021 | , Shared_max = 0.0 |
| 1022 | #endif |
| 1023 | , Swap_max = 0.0 |
| 1024 | , Memory_max = 0.0 |
| 1025 | #if (PROCESSES_HAVE_FDS == 1) && (PROCESSES_HAVE_PID_LIMITS == 1) |
| 1026 | , FDsLimitPercent_max = 0.0 |
| 1027 | #endif |
| 1028 | ; |
| 1029 | |
| 1030 | unsigned long long |
| 1031 | Processes_max = 0 |
| 1032 | , Threads_max = 0 |
| 1033 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 1034 | , VoluntaryCtxtSwitches_max = 0 |
| 1035 | #endif |
| 1036 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 1037 | , NonVoluntaryCtxtSwitches_max = 0 |
| 1038 | #endif |
| 1039 | , Uptime_max = 0 |
| 1040 | , MinFlt_max = 0 |
| 1041 | #if (PROCESSES_HAVE_MAJFLT == 1) |
| 1042 | , MajFlt_max = 0 |
| 1043 | #endif |
| 1044 | #if (PROCESSES_HAVE_CHILDREN_FLTS == 1) |
| 1045 | , CMinFlt_max = 0 |
| 1046 | , CMajFlt_max = 0 |
| 1047 | , TMinFlt_max = 0 |
| 1048 | , TMajFlt_max = 0 |
| 1049 | #endif |
| 1050 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 1051 | , LReads_max = 0 |
| 1052 | , LWrites_max = 0 |
| 1053 | #endif |
| 1054 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 1055 | , PReads_max = 0 |
| 1056 | , PWrites_max = 0 |
| 1057 | #endif |
| 1058 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 1059 | , ROps_max = 0 |
| 1060 | , WOps_max = 0 |
| 1061 | #endif |
| 1062 | #if (PROCESSES_HAVE_FDS == 1) |
| 1063 | , Files_max = 0 |
| 1064 | , Pipes_max = 0 |
| 1065 | , Sockets_max = 0 |
| 1066 | , iNotiFDs_max = 0 |
| 1067 | , EventFDs_max = 0 |
| 1068 | , TimerFDs_max = 0 |
| 1069 | , SigFDs_max = 0 |
| 1070 | , EvPollFDs_max = 0 |
| 1071 | , OtherFDs_max = 0 |
| 1072 | , FDs_max = 0 |
| 1073 | #endif |
| 1074 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 1075 | , Handles_max = 0 |
| 1076 | #endif |
| 1077 | ; |
| 1078 | |
| 1079 | netdata_mutex_lock(&apps_and_stdout_mutex); |
| 1080 | |
| 1081 | int rows= 0; |
| 1082 | for(p = root_of_pids(); p ; p = p->next) { |
| 1083 | if(!p->updated) |
| 1084 | continue; |
| 1085 | |
| 1086 | if(category && p->target != category) |
| 1087 | continue; |
| 1088 | |
| 1089 | #if (PROCESSES_HAVE_UID == 1) |
| 1090 | if(user && p->uid_target != user) |
| 1091 | continue; |
| 1092 | #endif |
| 1093 | |
| 1094 | #if (PROCESSES_HAVE_GID == 1) |
| 1095 | if(group && p->gid_target != group) |
| 1096 | continue; |
| 1097 | #endif |
| 1098 | |
| 1099 | #if (PROCESSES_HAVE_SID == 1) |
| 1100 | if(user && p->sid_target != user) |
| 1101 | continue; |
| 1102 | #endif |
| 1103 | |
| 1104 | if(process_name && ((strcmp(pid_stat_comm(p), process_name) != 0 && !p->parent) || (p->parent && strcmp(pid_stat_comm(p), process_name) != 0 && strcmp(pid_stat_comm(p->parent), process_name) != 0))) |
| 1105 | continue; |
| 1106 | |
| 1107 | if(filter_pid && p->pid != pid && p->ppid != pid) |
| 1108 | continue; |
| 1109 | |
| 1110 | #if (PROCESSES_HAVE_UID == 1) |
| 1111 | if(filter_uid && p->uid != uid) |
| 1112 | continue; |
| 1113 | #endif |
| 1114 | |
| 1115 | #if (PROCESSES_HAVE_GID == 1) |
| 1116 | if(filter_gid && p->gid != gid) |
| 1117 | continue; |
| 1118 | #endif |
| 1119 | |
| 1120 | rows++; |
| 1121 | |
| 1122 | buffer_json_add_array_item_array(wb); // for each pid |
| 1123 | |
| 1124 | // IMPORTANT! |
| 1125 | // THE ORDER SHOULD BE THE SAME WITH THE FIELDS! |
| 1126 | |
| 1127 | // pid |
| 1128 | buffer_json_add_array_item_uint64(wb, p->pid); |
| 1129 | |
| 1130 | // cmd |
| 1131 | buffer_json_add_array_item_string(wb, string2str(p->comm)); |
| 1132 | |
| 1133 | #if (PROCESSES_HAVE_COMM_AND_NAME == 1) |
| 1134 | // name |
| 1135 | buffer_json_add_array_item_string(wb, string2str(p->name ? p->name : p->comm)); |
| 1136 | #endif |
| 1137 | |
| 1138 | // cmdline |
| 1139 | if (show_cmdline) { |
| 1140 | buffer_json_add_array_item_string(wb, (string_strlen(p->cmdline)) ? pid_stat_cmdline(p) : pid_stat_comm(p)); |
| 1141 | } |
| 1142 | |
| 1143 | // ppid |
| 1144 | buffer_json_add_array_item_uint64(wb, p->ppid); |
| 1145 | |
| 1146 | // category |
| 1147 | buffer_json_add_array_item_string(wb, p->target ? string2str(p->target->name) : "-"); |
| 1148 | |
| 1149 | #if (PROCESSES_HAVE_UID == 1) |
| 1150 | // user |
| 1151 | buffer_json_add_array_item_string(wb, p->uid_target ? string2str(p->uid_target->name) : "-"); |
| 1152 | |
| 1153 | // uid |
| 1154 | buffer_json_add_array_item_uint64(wb, p->uid); |
| 1155 | #endif |
| 1156 | #if (PROCESSES_HAVE_SID == 1) |
| 1157 | // account |
| 1158 | buffer_json_add_array_item_string(wb, p->sid_target ? string2str(p->sid_target->name) : "-"); |
| 1159 | #endif |
| 1160 | |
| 1161 | #if (PROCESSES_HAVE_GID == 1) |
| 1162 | // group |
| 1163 | buffer_json_add_array_item_string(wb, p->gid_target ? string2str(p->gid_target->name) : "-"); |
| 1164 | |
| 1165 | // gid |
| 1166 | buffer_json_add_array_item_uint64(wb, p->gid); |
| 1167 | #endif |
| 1168 | |
| 1169 | // CPU utilization % |
| 1170 | kernel_uint_t total_cpu = p->values[PDF_UTIME] + p->values[PDF_STIME]; |
| 1171 | |
| 1172 | #if (PROCESSES_HAVE_CPU_GUEST_TIME) |
| 1173 | total_cpu += p->values[PDF_GTIME]; |
| 1174 | #endif |
| 1175 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME) |
| 1176 | total_cpu += p->values[PDF_CUTIME] + p->values[PDF_CSTIME]; |
| 1177 | #if (PROCESSES_HAVE_CPU_GUEST_TIME) |
| 1178 | total_cpu += p->values[PDF_CGTIME]; |
| 1179 | #endif |
| 1180 | #endif |
| 1181 | add_value_field_ndd_with_max(wb, CPU, (NETDATA_DOUBLE)(total_cpu) / cpu_divisor); |
| 1182 | |
| 1183 | add_value_field_ndd_with_max(wb, UserCPU, (NETDATA_DOUBLE)(p->values[PDF_UTIME]) / cpu_divisor); |
| 1184 | add_value_field_ndd_with_max(wb, SysCPU, (NETDATA_DOUBLE)(p->values[PDF_STIME]) / cpu_divisor); |
| 1185 | #if (PROCESSES_HAVE_CPU_GUEST_TIME) |
| 1186 | add_value_field_ndd_with_max(wb, GuestCPU, (NETDATA_DOUBLE)(p->values[PDF_GTIME]) / cpu_divisor); |
| 1187 | #endif |
| 1188 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME) |
| 1189 | add_value_field_ndd_with_max(wb, CUserCPU, (NETDATA_DOUBLE)(p->values[PDF_CUTIME]) / cpu_divisor); |
| 1190 | add_value_field_ndd_with_max(wb, CSysCPU, (NETDATA_DOUBLE)(p->values[PDF_CSTIME]) / cpu_divisor); |
| 1191 | #if (PROCESSES_HAVE_CPU_GUEST_TIME) |
| 1192 | add_value_field_ndd_with_max(wb, CGuestCPU, (NETDATA_DOUBLE)(p->values[PDF_CGTIME]) / cpu_divisor); |
| 1193 | #endif |
| 1194 | #endif |
| 1195 | |
| 1196 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 1197 | add_value_field_llu_with_max(wb, VoluntaryCtxtSwitches, p->values[PDF_VOLCTX] / RATES_DETAIL); |
| 1198 | #endif |
| 1199 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 1200 | add_value_field_llu_with_max(wb, NonVoluntaryCtxtSwitches, p->values[PDF_NVOLCTX] / RATES_DETAIL); |
| 1201 | #endif |
| 1202 | |
| 1203 | // memory MiB |
| 1204 | if(total_memory_bytes) |
| 1205 | add_value_field_ndd_with_max(wb, Memory, (NETDATA_DOUBLE)p->values[PDF_VMRSS] * 100.0 / (NETDATA_DOUBLE)total_memory_bytes); |
| 1206 | |
| 1207 | add_value_field_ndd_with_max(wb, RSS, (NETDATA_DOUBLE)p->values[PDF_VMRSS] / memory_divisor); |
| 1208 | #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1) |
| 1209 | if(pss_refresh_period > 0) { |
| 1210 | add_value_field_ndd_with_max(wb, Estimated, (NETDATA_DOUBLE)p->values[PDF_MEM_ESTIMATED] / memory_divisor); |
| 1211 | add_value_field_ndd_with_max(wb, Pss, (NETDATA_DOUBLE)p->values[PDF_PSS] / memory_divisor); |
| 1212 | NETDATA_DOUBLE pss_age; |
| 1213 | if(p->last_pss_iteration == 0) |
| 1214 | pss_age = NAN; |
| 1215 | else if(global_iterations_counter >= p->last_pss_iteration) |
| 1216 | pss_age = (NETDATA_DOUBLE)(global_iterations_counter - p->last_pss_iteration) * update_every; |
| 1217 | else |
| 1218 | pss_age = NAN; |
| 1219 | add_value_field_ndd_with_max(wb, PssAge, pss_age); |
| 1220 | NETDATA_DOUBLE shared_ratio = p->pss_total_ratio * 100.0; |
| 1221 | add_value_field_ndd_with_max(wb, SharedRatio, shared_ratio); |
| 1222 | } |
| 1223 | #endif |
| 1224 | #if (PROCESSES_HAVE_VMSHARED == 1) |
| 1225 | add_value_field_ndd_with_max(wb, Shared, (NETDATA_DOUBLE)p->values[PDF_VMSHARED] / memory_divisor); |
| 1226 | #endif |
| 1227 | |
| 1228 | add_value_field_ndd_with_max(wb, VMSize, (NETDATA_DOUBLE)p->values[PDF_VMSIZE] / memory_divisor); |
| 1229 | |
| 1230 | #if (PROCESSES_HAVE_VMSWAP == 1) |
| 1231 | add_value_field_ndd_with_max(wb, Swap, (NETDATA_DOUBLE)p->values[PDF_VMSWAP] / memory_divisor); |
| 1232 | #endif |
| 1233 | |
| 1234 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 1235 | // Physical I/O |
| 1236 | add_value_field_llu_with_max(wb, PReads, p->values[PDF_PREAD] / io_divisor); |
| 1237 | add_value_field_llu_with_max(wb, PWrites, p->values[PDF_PWRITE] / io_divisor); |
| 1238 | #endif |
| 1239 | |
| 1240 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 1241 | // Logical I/O |
| 1242 | add_value_field_llu_with_max(wb, LReads, p->values[PDF_LREAD] / io_divisor); |
| 1243 | add_value_field_llu_with_max(wb, LWrites, p->values[PDF_LWRITE] / io_divisor); |
| 1244 | #endif |
| 1245 | |
| 1246 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 1247 | // I/O calls |
| 1248 | add_value_field_llu_with_max(wb, ROps, p->values[PDF_OREAD] / RATES_DETAIL); |
| 1249 | add_value_field_llu_with_max(wb, WOps, p->values[PDF_OWRITE] / RATES_DETAIL); |
| 1250 | #endif |
| 1251 | |
| 1252 | // minor page faults |
| 1253 | add_value_field_llu_with_max(wb, MinFlt, p->values[PDF_MINFLT] / RATES_DETAIL); |
| 1254 | |
| 1255 | #if (PROCESSES_HAVE_MAJFLT == 1) |
| 1256 | // major page faults |
| 1257 | add_value_field_llu_with_max(wb, MajFlt, p->values[PDF_MAJFLT] / RATES_DETAIL); |
| 1258 | #endif |
| 1259 | |
| 1260 | #if (PROCESSES_HAVE_CHILDREN_FLTS == 1) |
| 1261 | add_value_field_llu_with_max(wb, CMinFlt, p->values[PDF_CMINFLT] / RATES_DETAIL); |
| 1262 | add_value_field_llu_with_max(wb, CMajFlt, p->values[PDF_CMAJFLT] / RATES_DETAIL); |
| 1263 | add_value_field_llu_with_max(wb, TMinFlt, (p->values[PDF_MINFLT] + p->values[PDF_CMINFLT]) / RATES_DETAIL); |
| 1264 | add_value_field_llu_with_max(wb, TMajFlt, (p->values[PDF_MAJFLT] + p->values[PDF_CMAJFLT]) / RATES_DETAIL); |
| 1265 | #endif |
| 1266 | |
| 1267 | #if (PROCESSES_HAVE_FDS == 1) |
| 1268 | // open file descriptors |
| 1269 | #if (PROCESSES_HAVE_PID_LIMITS == 1) |
| 1270 | add_value_field_ndd_with_max(wb, FDsLimitPercent, p->openfds_limits_percent); |
| 1271 | #endif |
| 1272 | add_value_field_llu_with_max(wb, FDs, pid_openfds_sum(p)); |
| 1273 | |
| 1274 | add_value_field_llu_with_max(wb, Files, p->openfds.files); |
| 1275 | add_value_field_llu_with_max(wb, Pipes, p->openfds.pipes); |
| 1276 | add_value_field_llu_with_max(wb, Sockets, p->openfds.sockets); |
| 1277 | add_value_field_llu_with_max(wb, iNotiFDs, p->openfds.inotifies); |
| 1278 | add_value_field_llu_with_max(wb, EventFDs, p->openfds.eventfds); |
| 1279 | add_value_field_llu_with_max(wb, TimerFDs, p->openfds.timerfds); |
| 1280 | add_value_field_llu_with_max(wb, SigFDs, p->openfds.signalfds); |
| 1281 | add_value_field_llu_with_max(wb, EvPollFDs, p->openfds.eventpolls); |
| 1282 | add_value_field_llu_with_max(wb, OtherFDs, p->openfds.other); |
| 1283 | #endif |
| 1284 | |
| 1285 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 1286 | add_value_field_llu_with_max(wb, Handles, p->values[PDF_HANDLES]); |
| 1287 | #endif |
| 1288 | |
| 1289 | // processes, threads, uptime |
| 1290 | add_value_field_llu_with_max(wb, Processes, p->values[PDF_PROCESSES]); |
| 1291 | add_value_field_llu_with_max(wb, Threads, p->values[PDF_THREADS]); |
| 1292 | add_value_field_llu_with_max(wb, Uptime, p->values[PDF_UPTIME]); |
| 1293 | |
| 1294 | buffer_json_array_close(wb); // for each pid |
| 1295 | } |
| 1296 | |
| 1297 | buffer_json_array_close(wb); // data |
| 1298 | |
| 1299 | struct fp_maxvals mv = { |
| 1300 | .UserCPU_max = UserCPU_max, |
| 1301 | .SysCPU_max = SysCPU_max, |
| 1302 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 1303 | .GuestCPU_max = GuestCPU_max, |
| 1304 | #endif |
| 1305 | #if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) |
| 1306 | .CUserCPU_max = CUserCPU_max, |
| 1307 | .CSysCPU_max = CSysCPU_max, |
| 1308 | #if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) |
| 1309 | .CGuestCPU_max = CGuestCPU_max, |
| 1310 | #endif |
| 1311 | #endif |
| 1312 | .CPU_max = CPU_max, |
| 1313 | .VMSize_max = VMSize_max, |
| 1314 | .RSS_max = RSS_max, |
| 1315 | #if (PROCESSES_HAVE_SMAPS_ROLLUP == 1) |
| 1316 | .Estimated_max = Estimated_max, |
| 1317 | .Pss_max = Pss_max, |
| 1318 | .PssAge_max = PssAge_max, |
| 1319 | .SharedRatio_max = SharedRatio_max, |
| 1320 | #endif |
| 1321 | #if (PROCESSES_HAVE_VMSHARED == 1) |
| 1322 | .Shared_max = Shared_max, |
| 1323 | #endif |
| 1324 | .Swap_max = Swap_max, |
| 1325 | #if (PROCESSES_HAVE_FDS == 1) && (PROCESSES_HAVE_PID_LIMITS == 1) |
| 1326 | .FDsLimitPercent_max = FDsLimitPercent_max, |
| 1327 | #endif |
| 1328 | .Processes_max = Processes_max, |
| 1329 | .Threads_max = Threads_max, |
| 1330 | #if (PROCESSES_HAVE_VOLCTX == 1) |
| 1331 | .VoluntaryCtxtSwitches_max = VoluntaryCtxtSwitches_max, |
| 1332 | #endif |
| 1333 | #if (PROCESSES_HAVE_NVOLCTX == 1) |
| 1334 | .NonVoluntaryCtxtSwitches_max = NonVoluntaryCtxtSwitches_max, |
| 1335 | #endif |
| 1336 | .Uptime_max = Uptime_max, |
| 1337 | .MinFlt_max = MinFlt_max, |
| 1338 | #if (PROCESSES_HAVE_MAJFLT == 1) |
| 1339 | .MajFlt_max = MajFlt_max, |
| 1340 | #endif |
| 1341 | #if (PROCESSES_HAVE_CHILDREN_FLTS == 1) |
| 1342 | .CMinFlt_max = CMinFlt_max, |
| 1343 | .CMajFlt_max = CMajFlt_max, |
| 1344 | .TMinFlt_max = TMinFlt_max, |
| 1345 | .TMajFlt_max = TMajFlt_max, |
| 1346 | #endif |
| 1347 | #if (PROCESSES_HAVE_LOGICAL_IO == 1) |
| 1348 | .LReads_max = LReads_max, |
| 1349 | .LWrites_max = LWrites_max, |
| 1350 | #endif |
| 1351 | #if (PROCESSES_HAVE_PHYSICAL_IO == 1) |
| 1352 | .PReads_max = PReads_max, |
| 1353 | .PWrites_max = PWrites_max, |
| 1354 | #endif |
| 1355 | #if (PROCESSES_HAVE_IO_CALLS == 1) |
| 1356 | .ROps_max = ROps_max, |
| 1357 | .WOps_max = WOps_max, |
| 1358 | #endif |
| 1359 | #if (PROCESSES_HAVE_FDS == 1) |
| 1360 | .Files_max = Files_max, |
| 1361 | .Pipes_max = Pipes_max, |
| 1362 | .Sockets_max = Sockets_max, |
| 1363 | .iNotiFDs_max = iNotiFDs_max, |
| 1364 | .EventFDs_max = EventFDs_max, |
| 1365 | .TimerFDs_max = TimerFDs_max, |
| 1366 | .SigFDs_max = SigFDs_max, |
| 1367 | .EvPollFDs_max = EvPollFDs_max, |
| 1368 | .OtherFDs_max = OtherFDs_max, |
| 1369 | .FDs_max = FDs_max, |
| 1370 | #endif |
| 1371 | #if (PROCESSES_HAVE_HANDLES == 1) |
| 1372 | .Handles_max = Handles_max, |
| 1373 | #endif |
| 1374 | }; |
| 1375 | |
| 1376 | fp_emit_columns(wb, &mv, show_cmdline, total_memory_bytes); |
| 1377 | |
| 1378 | buffer_json_member_add_string(wb, "default_sort_column", "CPU"); |
| 1379 | |
| 1380 | fp_emit_charts(wb, total_memory_bytes); |
| 1381 | |
| 1382 | fp_emit_groupby(wb); |
| 1383 | |
| 1384 | netdata_mutex_unlock(&apps_and_stdout_mutex); |
| 1385 | |
| 1386 | close_and_send: |
| 1387 | buffer_json_member_add_time_t(wb, "expires", now_s + update_every); |
| 1388 | buffer_json_finalize(wb); |
| 1389 | |
| 1390 | wb->response_code = HTTP_RESP_OK; |
| 1391 | wb->content_type = CT_APPLICATION_JSON; |
| 1392 | wb->expires = now_s + update_every; |
| 1393 | pluginsd_function_result_to_stdout(transaction, wb); |
| 1394 | |
| 1395 | buffer_free(wb); |
| 1396 | } |