master
c 286 lines 11.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "health.h"
4
5 void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix) {
6 if(value && *value) {
7 buffer_sprintf(wb, "%s\"%s\":\"", prefix, label);
8 buffer_strcat_htmlescape(wb, value);
9 buffer_strcat(wb, "\"");
10 buffer_strcat(wb, suffix);
11 }
12 else
13 buffer_sprintf(wb, "%s\"%s\":null%s", prefix, label, suffix);
14 }
15
16 static inline void health_rrdcalc_values2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
17 (void)host;
18 buffer_sprintf(wb,
19 "\t\t\"%s.%s\": {\n"
20 "\t\t\t\"id\": %lu,\n"
21 , rrdcalc_chart_name(rc), rrdcalc_name(rc)
22 , (unsigned long)rc->id);
23
24 buffer_strcat(wb, "\t\t\t\"value\":");
25 buffer_print_netdata_double(wb, rc->value);
26 buffer_strcat(wb, ",\n");
27
28 buffer_strcat(wb, "\t\t\t\"last_updated\":");
29 buffer_sprintf(wb, "%lu", (unsigned long)rc->last_updated);
30 buffer_strcat(wb, ",\n");
31
32 buffer_sprintf(wb,
33 "\t\t\t\"status\": \"%s\"\n"
34 , rrdcalc_status2string(rc->status));
35
36 buffer_strcat(wb, "\t\t}");
37 }
38
39 static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
40 char value_string[100 + 1];
41 format_value_and_unit(value_string, 100, rc->value, rrdcalc_units(rc), -1);
42
43 char hash_id[GUID_LEN + 1];
44 uuid_unparse_lower(rc->config.hash_id, hash_id);
45
46 buffer_sprintf(wb,
47 "\t\t\"%s.%s\": {\n"
48 "\t\t\t\"id\": %lu,\n"
49 "\t\t\t\"config_hash_id\": \"%s\",\n"
50 "\t\t\t\"name\": \"%s\",\n"
51 "\t\t\t\"chart\": \"%s\",\n"
52 "\t\t\t\"class\": \"%s\",\n"
53 "\t\t\t\"component\": \"%s\",\n"
54 "\t\t\t\"type\": \"%s\",\n"
55 "\t\t\t\"active\": %s,\n"
56 "\t\t\t\"disabled\": %s,\n"
57 "\t\t\t\"silenced\": %s,\n"
58 "\t\t\t\"exec\": \"%s\",\n"
59 "\t\t\t\"recipient\": \"%s\",\n"
60 "\t\t\t\"source\": \"%s\",\n"
61 "\t\t\t\"units\": \"%s\",\n"
62 "\t\t\t\"summary\": \"%s\",\n"
63 "\t\t\t\"info\": \"%s\",\n"
64 "\t\t\t\"status\": \"%s\",\n"
65 "\t\t\t\"last_status_change\": %lu,\n"
66 "\t\t\t\"last_updated\": %lu,\n"
67 "\t\t\t\"next_update\": %lu,\n"
68 "\t\t\t\"update_every\": %d,\n"
69 "\t\t\t\"delay_up_duration\": %d,\n"
70 "\t\t\t\"delay_down_duration\": %d,\n"
71 "\t\t\t\"delay_max_duration\": %d,\n"
72 "\t\t\t\"delay_multiplier\": %f,\n"
73 "\t\t\t\"delay\": %d,\n"
74 "\t\t\t\"delay_up_to_timestamp\": %lu,\n"
75 "\t\t\t\"warn_repeat_every\": \"%u\",\n"
76 "\t\t\t\"crit_repeat_every\": \"%u\",\n"
77 "\t\t\t\"value_string\": \"%s\",\n"
78 "\t\t\t\"last_repeat\": \"%lu\",\n"
79 "\t\t\t\"times_repeat\": %lu,\n"
80 , rrdcalc_chart_name(rc), rrdcalc_name(rc)
81 , (unsigned long)rc->id
82 , hash_id
83 , rrdcalc_name(rc)
84 , rrdcalc_chart_name(rc)
85 , rc->config.classification?rrdcalc_classification(rc):"Unknown"
86 , rc->config.component?rrdcalc_component(rc):"Unknown"
87 , rc->config.type?rrdcalc_type(rc):"Unknown"
88 , (rc->rrdset)?"true":"false"
89 , (rc->run_flags & RRDCALC_FLAG_DISABLED)?"true":"false"
90 , (rc->run_flags & RRDCALC_FLAG_SILENCED)?"true":"false"
91 , rc->config.exec?rrdcalc_exec(rc):string2str(host->health.default_exec)
92 , rc->config.recipient?rrdcalc_recipient(rc):string2str(host->health.default_recipient)
93 , rrdcalc_source(rc)
94 , rrdcalc_units(rc)
95 , string2str(rc->summary)
96 , string2str(rc->info)
97 , rrdcalc_status2string(rc->status)
98 , (unsigned long)rc->last_status_change
99 , (unsigned long)rc->last_updated
100 , (unsigned long)rc->next_update
101 , rc->config.update_every
102 , rc->config.delay_up_duration
103 , rc->config.delay_down_duration
104 , rc->config.delay_max_duration
105 , rc->config.delay_multiplier
106 , rc->delay_last
107 , (unsigned long)rc->delay_up_to_timestamp
108 , rc->config.warn_repeat_every
109 , rc->config.crit_repeat_every
110 , value_string
111 , (unsigned long)rc->last_repeat
112 , (unsigned long)rc->times_repeat
113 );
114
115 if(unlikely(rc->config.alert_action_options & ALERT_ACTION_OPTION_NO_CLEAR_NOTIFICATION)) {
116 buffer_strcat(wb, "\t\t\t\"no_clear_notification\": true,\n");
117 }
118
119 if(RRDCALC_HAS_DB_LOOKUP(rc)) {
120 if(rc->config.dimensions)
121 health_string2json(wb, "\t\t\t", "lookup_dimensions", rrdcalc_dimensions(rc), ",\n");
122
123 buffer_sprintf(wb,
124 "\t\t\t\"db_after\": %lu,\n"
125 "\t\t\t\"db_before\": %lu,\n"
126 "\t\t\t\"lookup_method\": \"%s\",\n"
127 "\t\t\t\"lookup_after\": %d,\n"
128 "\t\t\t\"lookup_before\": %d,\n"
129 "\t\t\t\"lookup_options\": \"",
130 (unsigned long) rc->db_after,
131 (unsigned long) rc->db_before,
132 time_grouping_id2txt(rc->config.time_group),
133 rc->config.after,
134 rc->config.before
135 );
136 rrdr_options_to_buffer(wb, rc->config.options);
137 buffer_strcat(wb, "\",\n");
138 }
139
140 if(rc->config.calculation) {
141 health_string2json(wb, "\t\t\t", "calc", expression_source(rc->config.calculation), ",\n");
142 health_string2json(wb, "\t\t\t", "calc_parsed", expression_parsed_as(rc->config.calculation), ",\n");
143 }
144
145 if(rc->config.warning) {
146 health_string2json(wb, "\t\t\t", "warn", expression_source(rc->config.warning), ",\n");
147 health_string2json(wb, "\t\t\t", "warn_parsed", expression_parsed_as(rc->config.warning), ",\n");
148 }
149
150 if(rc->config.critical) {
151 health_string2json(wb, "\t\t\t", "crit", expression_source(rc->config.critical), ",\n");
152 health_string2json(wb, "\t\t\t", "crit_parsed", expression_parsed_as(rc->config.critical), ",\n");
153 }
154
155 buffer_strcat(wb, "\t\t\t\"green\":");
156 buffer_print_netdata_double(wb, NAN);
157 buffer_strcat(wb, ",\n");
158
159 buffer_strcat(wb, "\t\t\t\"red\":");
160 buffer_print_netdata_double(wb, NAN);
161 buffer_strcat(wb, ",\n");
162
163 buffer_strcat(wb, "\t\t\t\"value\":");
164 buffer_print_netdata_double(wb, rc->value);
165 buffer_strcat(wb, "\n");
166
167 buffer_strcat(wb, "\t\t}");
168 }
169
170 void health_aggregate_alarms(RRDHOST *host, BUFFER *wb, BUFFER* contexts, RRDCALC_STATUS status) {
171 RRDCALC *rc;
172 int numberOfAlarms = 0;
173 char *tok = NULL;
174 char *p = NULL;
175
176 if (contexts) {
177 p = (char*)buffer_tostring(contexts);
178 while(p && *p && (tok = strsep_skip_consecutive_separators(&p, ", |"))) {
179 if(!*tok) continue;
180
181 STRING *tok_string = string_strdupz(tok);
182
183 foreach_rrdcalc_in_rrdhost_read(host, rc) {
184 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
185 continue;
186 if (unlikely(!rrdset_is_available_for_exporting_and_alarms(rc->rrdset)))
187 continue;
188 if(unlikely(rc->rrdset
189 && rc->rrdset->context == tok_string
190 && ((status==RRDCALC_STATUS_RAISED)?(rc->status >= RRDCALC_STATUS_WARNING):rc->status == status)))
191 numberOfAlarms++;
192 }
193 foreach_rrdcalc_in_rrdhost_done(rc);
194
195 string_freez(tok_string);
196 }
197 }
198 else {
199 foreach_rrdcalc_in_rrdhost_read(host, rc) {
200 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
201 continue;
202 if (unlikely(!rrdset_is_available_for_exporting_and_alarms(rc->rrdset)))
203 continue;
204 if(unlikely((status==RRDCALC_STATUS_RAISED)?(rc->status >= RRDCALC_STATUS_WARNING):rc->status == status))
205 numberOfAlarms++;
206 }
207 foreach_rrdcalc_in_rrdhost_done(rc);
208 }
209
210 buffer_sprintf(wb, "%d", numberOfAlarms);
211 }
212
213 static void health_alarms2json_fill_alarms(RRDHOST *host, BUFFER *wb, int all, void (*fp)(RRDHOST *, BUFFER *, RRDCALC *)) {
214 RRDCALC *rc;
215 int i = 0;
216 foreach_rrdcalc_in_rrdhost_read(host, rc) {
217 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
218 continue;
219
220 if (unlikely(!rrdset_is_available_for_exporting_and_alarms(rc->rrdset)))
221 continue;
222
223 if(likely(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL)))
224 continue;
225
226 if(likely(i)) buffer_strcat(wb, ",\n");
227 fp(host, wb, rc);
228 i++;
229 }
230 foreach_rrdcalc_in_rrdhost_done(rc);
231 }
232
233 void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
234 buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
235 "\n\t\"latest_alarm_log_unique_id\": %u,"
236 "\n\t\"status\": %s,"
237 "\n\t\"now\": %lu,"
238 "\n\t\"alarms\": {\n",
239 rrdhost_hostname(host),
240 (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
241 host->health.enabled ?"true":"false",
242 (unsigned long)now_realtime_sec());
243
244 health_alarms2json_fill_alarms(host, wb, all, health_rrdcalc2json_nolock);
245
246 buffer_strcat(wb, "\n\t}\n}\n");
247 }
248
249 void health_alarms_values2json(RRDHOST *host, BUFFER *wb, int all) {
250 buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
251 "\n\t\"alarms\": {\n",
252 rrdhost_hostname(host));
253
254 health_alarms2json_fill_alarms(host, wb, all, health_rrdcalc_values2json_nolock);
255
256 buffer_strcat(wb, "\n\t}\n}\n");
257 }
258
259 void health_entry_flags_to_json_array(BUFFER *wb, const char *key, HEALTH_ENTRY_FLAGS flags) {
260 buffer_json_member_add_array(wb, key);
261
262 if(flags & HEALTH_ENTRY_FLAG_PROCESSED)
263 buffer_json_add_array_item_string(wb, "PROCESSED");
264 if(flags & HEALTH_ENTRY_FLAG_UPDATED)
265 buffer_json_add_array_item_string(wb, "UPDATED");
266 if(flags & HEALTH_ENTRY_FLAG_EXEC_RUN)
267 buffer_json_add_array_item_string(wb, "EXEC_RUN");
268 if(flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)
269 buffer_json_add_array_item_string(wb, "EXEC_FAILED");
270 if(flags & HEALTH_ENTRY_FLAG_SILENCED)
271 buffer_json_add_array_item_string(wb, "SILENCED");
272 if(flags & HEALTH_ENTRY_RUN_ONCE)
273 buffer_json_add_array_item_string(wb, "RUN_ONCE");
274 if(flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS)
275 buffer_json_add_array_item_string(wb, "EXEC_IN_PROGRESS");
276 if(flags & HEALTH_ENTRY_FLAG_IS_REPEATING)
277 buffer_json_add_array_item_string(wb, "RECURRING");
278 if(flags & HEALTH_ENTRY_FLAG_SAVED)
279 buffer_json_add_array_item_string(wb, "SAVED");
280 if(flags & HEALTH_ENTRY_FLAG_ACLK_QUEUED)
281 buffer_json_add_array_item_string(wb, "ACLK_QUEUED");
282 if(flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)
283 buffer_json_add_array_item_string(wb, "NO_CLEAR_NOTIFICATION");
284
285 buffer_json_array_close(wb);
286 }