master
c 513 lines 19.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "cgroup-internals.h"
4
5 struct cgroup_netdev_link {
6 size_t read_slot;
7 NETDATA_DOUBLE received[2];
8 NETDATA_DOUBLE sent[2];
9 };
10
11 static DICTIONARY *cgroup_netdev_link_dict = NULL;
12
13 void netdev_renames_destroy(void);
14
15 void cgroup_netdev_link_init(void) {
16 cgroup_netdev_link_dict = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE|DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(struct cgroup_netdev_link));
17 }
18
19 void cgroup_netdev_link_destroy(void) {
20 dictionary_destroy(cgroup_netdev_link_dict);
21 cgroup_netdev_link_dict = NULL;
22
23 netdev_renames_destroy();
24 }
25
26 const DICTIONARY_ITEM *cgroup_netdev_get(struct cgroup *cg) {
27 if(!cg->cgroup_netdev_link) {
28 struct cgroup_netdev_link t = {
29 .read_slot = 0,
30 .received = {NAN, NAN},
31 .sent = {NAN, NAN},
32 };
33
34 cg->cgroup_netdev_link =
35 dictionary_set_and_acquire_item(cgroup_netdev_link_dict, cg->id, &t, sizeof(struct cgroup_netdev_link));
36 }
37
38 return dictionary_acquired_item_dup(cgroup_netdev_link_dict, cg->cgroup_netdev_link);
39 }
40
41 void cgroup_netdev_delete(struct cgroup *cg) {
42 if(cg->cgroup_netdev_link) {
43 dictionary_acquired_item_release(cgroup_netdev_link_dict, cg->cgroup_netdev_link);
44 dictionary_del(cgroup_netdev_link_dict, cg->id);
45 dictionary_garbage_collect(cgroup_netdev_link_dict);
46 cg->cgroup_netdev_link = NULL;
47 }
48 }
49
50 void cgroup_netdev_release(const DICTIONARY_ITEM *link) {
51 if(link)
52 dictionary_acquired_item_release(cgroup_netdev_link_dict, link);
53 }
54
55 const void *cgroup_netdev_dup(const DICTIONARY_ITEM *link) {
56 return dictionary_acquired_item_dup(cgroup_netdev_link_dict, link);
57 }
58
59 void cgroup_netdev_reset_all(void) {
60 struct cgroup_netdev_link *t;
61 dfe_start_read(cgroup_netdev_link_dict, t) {
62 if(t->read_slot >= 1) {
63 t->read_slot = 0;
64 t->received[1] = NAN;
65 t->sent[1] = NAN;
66 }
67 else {
68 t->read_slot = 1;
69 t->received[0] = NAN;
70 t->sent[0] = NAN;
71 }
72 }
73 dfe_done(t);
74 }
75
76 void cgroup_netdev_add_bandwidth(const DICTIONARY_ITEM *link, NETDATA_DOUBLE received, NETDATA_DOUBLE sent) {
77 if(!link)
78 return;
79
80 struct cgroup_netdev_link *t = dictionary_acquired_item_value(link);
81
82 size_t slot = (t->read_slot) ? 0 : 1;
83
84 if(isnan(t->received[slot]))
85 t->received[slot] = received;
86 else
87 t->received[slot] += received;
88
89 if(isnan(t->sent[slot]))
90 t->sent[slot] = sent;
91 else
92 t->sent[slot] += sent;
93 }
94
95 void cgroup_netdev_get_bandwidth(struct cgroup *cg, NETDATA_DOUBLE *received, NETDATA_DOUBLE *sent) {
96 if(!cg->cgroup_netdev_link) {
97 *received = NAN;
98 *sent = NAN;
99 return;
100 }
101
102 struct cgroup_netdev_link *t = dictionary_acquired_item_value(cg->cgroup_netdev_link);
103
104 size_t slot = (t->read_slot) ? 1 : 0;
105
106 *received = t->received[slot];
107 *sent = t->sent[slot];
108 }
109
110 int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused, BUFFER *payload __maybe_unused, const char *source __maybe_unused) {
111 buffer_flush(wb);
112 wb->content_type = CT_APPLICATION_JSON;
113 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
114
115 buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
116 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
117 buffer_json_member_add_string(wb, "type", "table");
118 buffer_json_member_add_time_t(wb, "update_every", 1);
119 buffer_json_member_add_boolean(wb, "has_history", false);
120 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
121 buffer_json_member_add_array(wb, "data");
122
123 double max_pids = 0.0;
124 double max_cpu = 0.0;
125 double max_cpu_throttled = 0.0;
126 double max_ram = 0.0;
127 double max_disk_io_read = 0.0;
128 double max_disk_io_written = 0.0;
129 double max_net_received = 0.0;
130 double max_net_sent = 0.0;
131
132 RRDDIM *rd = NULL;
133
134 netdata_mutex_lock(&cgroup_root_mutex);
135
136 for(struct cgroup *cg = cgroup_root; cg ; cg = cg->next) {
137 if(unlikely(!cg->enabled || cg->pending_renames || !cg->function_ready || is_cgroup_systemd_service(cg)))
138 continue;
139
140 buffer_json_add_array_item_array(wb);
141
142 buffer_json_add_array_item_string(wb, cg->name); // Name
143
144 if(k8s_is_kubepod(cg))
145 buffer_json_add_array_item_string(wb, "k8s"); // Kind
146 else
147 buffer_json_add_array_item_string(wb, "cgroup"); // Kind
148
149 double pids_current = rrddim_get_last_stored_value(cg->st_pids_rd_pids_current, &max_pids, 1.0);
150
151 double cpu = NAN;
152 if (cg->st_cpu_rd_user && cg->st_cpu_rd_system) {
153 cpu = cg->st_cpu_rd_user->collector.last_stored_value + cg->st_cpu_rd_system->collector.last_stored_value;
154 max_cpu = MAX(max_cpu, cpu);
155 }
156
157 double cpu_throttled = (double)cg->cpuacct_cpu_throttling.nr_throttled_perc;
158 max_cpu_throttled = MAX(max_cpu_throttled, cpu_throttled);
159
160 double ram = rrddim_get_last_stored_value(cg->st_mem_rd_ram, &max_ram, 1.0);
161
162 rd = cg->st_throttle_io_rd_read ? cg->st_throttle_io_rd_read : cg->st_io_rd_read;
163 double disk_io_read = rrddim_get_last_stored_value(rd, &max_disk_io_read, 1024.0);
164 rd = cg->st_throttle_io_rd_written ? cg->st_throttle_io_rd_written : cg->st_io_rd_written;
165 double disk_io_written = rrddim_get_last_stored_value(rd, &max_disk_io_written, 1024.0);
166
167 NETDATA_DOUBLE received, sent;
168 cgroup_netdev_get_bandwidth(cg, &received, &sent);
169 if (!isnan(received) && !isnan(sent)) {
170 received /= 1000.0;
171 sent /= 1000.0;
172 max_net_received = MAX(max_net_received, received);
173 max_net_sent = MAX(max_net_sent, sent);
174 }
175
176 buffer_json_add_array_item_double(wb, pids_current);
177 buffer_json_add_array_item_double(wb, cpu);
178 buffer_json_add_array_item_double(wb, cpu_throttled);
179 buffer_json_add_array_item_double(wb, ram);
180 buffer_json_add_array_item_double(wb, disk_io_read);
181 buffer_json_add_array_item_double(wb, disk_io_written);
182 buffer_json_add_array_item_double(wb, received);
183 buffer_json_add_array_item_double(wb, sent);
184
185 buffer_json_array_close(wb);
186 }
187
188 netdata_mutex_unlock(&cgroup_root_mutex);
189
190 buffer_json_array_close(wb); // data
191 buffer_json_member_add_object(wb, "columns");
192 {
193 size_t field_id = 0;
194
195 // Node
196 buffer_rrdf_table_add_field(wb, field_id++, "Name", "CGROUP Name",
197 RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
198 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
199 RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
200 RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
201 NULL);
202
203 // Kind
204 buffer_rrdf_table_add_field(wb, field_id++, "Kind", "CGROUP Kind",
205 RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
206 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
207 RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
208 RRDF_FIELD_OPTS_VISIBLE,
209 NULL);
210
211 // PIDs
212 buffer_rrdf_table_add_field(wb, field_id++, "PIDs", "Number of Processes Currently in the CGROUP",
213 RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
214 0, "pids", max_pids, RRDF_FIELD_SORT_DESCENDING, NULL,
215 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
216 RRDF_FIELD_OPTS_VISIBLE,
217 NULL);
218
219 // CPU
220 buffer_rrdf_table_add_field(wb, field_id++, "CPU", "CPU Usage",
221 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
222 2, "%", max_cpu, RRDF_FIELD_SORT_DESCENDING, NULL,
223 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
224 RRDF_FIELD_OPTS_VISIBLE,
225 NULL);
226
227 buffer_rrdf_table_add_field(wb, field_id++, "CPU Throttling", "CPU Throttled Runnable Periods",
228 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
229 0, "%", max_cpu_throttled, RRDF_FIELD_SORT_DESCENDING, NULL,
230 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
231 is_inside_k8s ? RRDF_FIELD_OPTS_VISIBLE : RRDF_FIELD_OPTS_NONE,
232 NULL);
233
234 // RAM
235 buffer_rrdf_table_add_field(wb, field_id++, "RAM", "RAM Usage",
236 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
237 2, "MiB", max_ram, RRDF_FIELD_SORT_DESCENDING, NULL,
238 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
239 RRDF_FIELD_OPTS_VISIBLE,
240 NULL);
241
242 // Disk IO Reads
243 buffer_rrdf_table_add_field(wb, field_id++, "Reads", "Disk Read Data",
244 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
245 2, "MiB", max_disk_io_read, RRDF_FIELD_SORT_DESCENDING, NULL,
246 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
247 RRDF_FIELD_OPTS_VISIBLE,
248 NULL);
249
250 // Disk IO Writes
251 buffer_rrdf_table_add_field(wb, field_id++, "Writes", "Disk Written Data",
252 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
253 2, "MiB", max_disk_io_written, RRDF_FIELD_SORT_DESCENDING, NULL,
254 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
255 RRDF_FIELD_OPTS_VISIBLE,
256 NULL);
257
258 // Network Received
259 buffer_rrdf_table_add_field(wb, field_id++, "Received", "Network Traffic Received",
260 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
261 2, "Mbps", max_net_received, RRDF_FIELD_SORT_DESCENDING, NULL,
262 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
263 RRDF_FIELD_OPTS_VISIBLE,
264 NULL);
265
266 // Network Sent
267 buffer_rrdf_table_add_field(wb, field_id++, "Sent", "Network Traffic Sent ",
268 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
269 2, "Mbps", max_net_sent, RRDF_FIELD_SORT_DESCENDING, NULL,
270 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
271 RRDF_FIELD_OPTS_VISIBLE,
272 NULL);
273 }
274 buffer_json_object_close(wb); // columns
275 buffer_json_member_add_string(wb, "default_sort_column", "CPU");
276
277 buffer_json_member_add_object(wb, "charts");
278 {
279 buffer_json_member_add_object(wb, "CPU");
280 {
281 buffer_json_member_add_string(wb, "name", "CPU");
282 buffer_json_member_add_string(wb, "type", "stacked-bar");
283 buffer_json_member_add_array(wb, "columns");
284 {
285 buffer_json_add_array_item_string(wb, "CPU");
286 }
287 buffer_json_array_close(wb);
288 }
289 buffer_json_object_close(wb);
290
291 buffer_json_member_add_object(wb, "Memory");
292 {
293 buffer_json_member_add_string(wb, "name", "Memory");
294 buffer_json_member_add_string(wb, "type", "stacked-bar");
295 buffer_json_member_add_array(wb, "columns");
296 {
297 buffer_json_add_array_item_string(wb, "RAM");
298 }
299 buffer_json_array_close(wb);
300 }
301 buffer_json_object_close(wb);
302
303 buffer_json_member_add_object(wb, "Traffic");
304 {
305 buffer_json_member_add_string(wb, "name", "Traffic");
306 buffer_json_member_add_string(wb, "type", "stacked-bar");
307 buffer_json_member_add_array(wb, "columns");
308 {
309 buffer_json_add_array_item_string(wb, "Received");
310 buffer_json_add_array_item_string(wb, "Sent");
311 }
312 buffer_json_array_close(wb);
313 }
314 buffer_json_object_close(wb);
315 }
316 buffer_json_object_close(wb); // charts
317
318 buffer_json_member_add_array(wb, "default_charts");
319 {
320 buffer_json_add_array_item_array(wb);
321 buffer_json_add_array_item_string(wb, "CPU");
322 buffer_json_add_array_item_string(wb, "Name");
323 buffer_json_array_close(wb);
324
325 buffer_json_add_array_item_array(wb);
326 buffer_json_add_array_item_string(wb, "Memory");
327 buffer_json_add_array_item_string(wb, "Name");
328 buffer_json_array_close(wb);
329 }
330 buffer_json_array_close(wb);
331
332 buffer_json_member_add_object(wb, "group_by");
333 {
334 buffer_json_member_add_object(wb, "Kind");
335 {
336 buffer_json_member_add_string(wb, "name", "Kind");
337 buffer_json_member_add_array(wb, "columns");
338 {
339 buffer_json_add_array_item_string(wb, "Kind");
340 }
341 buffer_json_array_close(wb);
342 }
343 buffer_json_object_close(wb);
344 }
345 buffer_json_object_close(wb); // group_by
346
347 buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
348 buffer_json_finalize(wb);
349
350 return HTTP_RESP_OK;
351 }
352
353 int cgroup_function_systemd_top(BUFFER *wb, const char *function __maybe_unused, BUFFER *payload __maybe_unused, const char *source __maybe_unused) {
354 buffer_flush(wb);
355 wb->content_type = CT_APPLICATION_JSON;
356 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
357
358 buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
359 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
360 buffer_json_member_add_string(wb, "type", "table");
361 buffer_json_member_add_time_t(wb, "update_every", 1);
362 buffer_json_member_add_boolean(wb, "has_history", false);
363 buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
364 buffer_json_member_add_array(wb, "data");
365
366 double max_pids = 0.0;
367 double max_cpu = 0.0;
368 double max_ram = 0.0;
369 double max_disk_io_read = 0.0;
370 double max_disk_io_written = 0.0;
371
372 RRDDIM *rd = NULL;
373
374 netdata_mutex_lock(&cgroup_root_mutex);
375
376 for(struct cgroup *cg = cgroup_root; cg ; cg = cg->next) {
377 if(unlikely(!cg->enabled || cg->pending_renames || !cg->function_ready || !is_cgroup_systemd_service(cg)))
378 continue;
379
380 buffer_json_add_array_item_array(wb);
381
382 buffer_json_add_array_item_string(wb, cg->name);
383
384 double pids_current = rrddim_get_last_stored_value(cg->st_pids_rd_pids_current, &max_pids, 1.0);
385
386 double cpu = NAN;
387 if (cg->st_cpu_rd_user && cg->st_cpu_rd_system) {
388 cpu = cg->st_cpu_rd_user->collector.last_stored_value + cg->st_cpu_rd_system->collector.last_stored_value;
389 max_cpu = MAX(max_cpu, cpu);
390 }
391
392 double ram = rrddim_get_last_stored_value(cg->st_mem_rd_ram, &max_ram, 1.0);
393
394 rd = cg->st_throttle_io_rd_read ? cg->st_throttle_io_rd_read : cg->st_io_rd_read;
395 double disk_io_read = rrddim_get_last_stored_value(rd, &max_disk_io_read, 1024.0);
396 rd = cg->st_throttle_io_rd_written ? cg->st_throttle_io_rd_written : cg->st_io_rd_written;
397 double disk_io_written = rrddim_get_last_stored_value(rd, &max_disk_io_written, 1024.0);
398
399 buffer_json_add_array_item_double(wb, pids_current);
400 buffer_json_add_array_item_double(wb, cpu);
401 buffer_json_add_array_item_double(wb, ram);
402 buffer_json_add_array_item_double(wb, disk_io_read);
403 buffer_json_add_array_item_double(wb, disk_io_written);
404
405 buffer_json_array_close(wb);
406 }
407
408 netdata_mutex_unlock(&cgroup_root_mutex);
409
410 buffer_json_array_close(wb); // data
411 buffer_json_member_add_object(wb, "columns");
412 {
413 size_t field_id = 0;
414
415 // Node
416 buffer_rrdf_table_add_field(wb, field_id++, "Name", "Systemd Service Name",
417 RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
418 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
419 RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
420 RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
421 NULL);
422
423 // PIDs
424 buffer_rrdf_table_add_field(wb, field_id++, "PIDs", "Number of Processes Currently in the CGROUP",
425 RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
426 0, "pids", max_pids, RRDF_FIELD_SORT_DESCENDING, NULL,
427 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
428 RRDF_FIELD_OPTS_VISIBLE,
429 NULL);
430
431 // CPU
432 buffer_rrdf_table_add_field(wb, field_id++, "CPU", "CPU Usage",
433 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
434 2, "%", max_cpu, RRDF_FIELD_SORT_DESCENDING, NULL,
435 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
436 RRDF_FIELD_OPTS_VISIBLE,
437 NULL);
438
439 // RAM
440 buffer_rrdf_table_add_field(wb, field_id++, "RAM", "RAM Usage",
441 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
442 2, "MiB", max_ram, RRDF_FIELD_SORT_DESCENDING, NULL,
443 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
444 RRDF_FIELD_OPTS_VISIBLE,
445 NULL);
446
447 // Disk IO Reads
448 buffer_rrdf_table_add_field(wb, field_id++, "Reads", "Disk Read Data",
449 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
450 2, "MiB", max_disk_io_read, RRDF_FIELD_SORT_DESCENDING, NULL,
451 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
452 RRDF_FIELD_OPTS_VISIBLE,
453 NULL);
454
455 // Disk IO Writes
456 buffer_rrdf_table_add_field(wb, field_id++, "Writes", "Disk Written Data",
457 RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
458 2, "MiB", max_disk_io_written, RRDF_FIELD_SORT_DESCENDING, NULL,
459 RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
460 RRDF_FIELD_OPTS_VISIBLE,
461 NULL);
462 }
463
464 buffer_json_object_close(wb); // columns
465 buffer_json_member_add_string(wb, "default_sort_column", "CPU");
466
467 buffer_json_member_add_object(wb, "charts");
468 {
469 buffer_json_member_add_object(wb, "CPU");
470 {
471 buffer_json_member_add_string(wb, "name", "CPU");
472 buffer_json_member_add_string(wb, "type", "stacked-bar");
473 buffer_json_member_add_array(wb, "columns");
474 {
475 buffer_json_add_array_item_string(wb, "CPU");
476 }
477 buffer_json_array_close(wb);
478 }
479 buffer_json_object_close(wb);
480
481 buffer_json_member_add_object(wb, "Memory");
482 {
483 buffer_json_member_add_string(wb, "name", "Memory");
484 buffer_json_member_add_string(wb, "type", "stacked-bar");
485 buffer_json_member_add_array(wb, "columns");
486 {
487 buffer_json_add_array_item_string(wb, "RAM");
488 }
489 buffer_json_array_close(wb);
490 }
491 buffer_json_object_close(wb);
492 }
493 buffer_json_object_close(wb); // charts
494
495 buffer_json_member_add_array(wb, "default_charts");
496 {
497 buffer_json_add_array_item_array(wb);
498 buffer_json_add_array_item_string(wb, "CPU");
499 buffer_json_add_array_item_string(wb, "Name");
500 buffer_json_array_close(wb);
501
502 buffer_json_add_array_item_array(wb);
503 buffer_json_add_array_item_string(wb, "Memory");
504 buffer_json_add_array_item_string(wb, "Name");
505 buffer_json_array_close(wb);
506 }
507 buffer_json_array_close(wb);
508
509 buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
510 buffer_json_finalize(wb);
511
512 return HTTP_RESP_OK;
513 }