@cryptotaxi247 / netdata-1 / commits / d4ec716a9

daemon-status-18 (#19876)

* daemon-status-18 * potential fix for uv thread names missing * add restarts, reliability, status and thread_id to sentry; added stack traces backend to agent-events post * add stack traces backend information; remove _ND_ from fields and ignore ECS compatibility for the moment * properly check for PJERR * make sure cleanup and exit does not return on linux

Costa Tsaousis committed Mar 17, 2025 at 11:26 UTC d4ec716a9c52ca5d03218d0ff55b179013e83521
11 files changed +375 -191
src/daemon/daemon-shutdown.c
+6 -5
@@ -378,11 +378,12 @@ void netdata_cleanup_and_exit(EXIT_REASON reason, const char *action, const char
378 #endif
379
380 #ifdef ENABLE_SENTRY
381 - if (!ret || !shutdown_on_fatal()) {
382 - nd_sentry_fini();
383 - curl_global_cleanup();
384 - exit(ret);
385 - }
381 + if(ret)
382 + shutdown_on_fatal();
383 +
384 + nd_sentry_fini();
385 + curl_global_cleanup();
386 + exit(ret);
387 #else
388 if(ret)
389 _exit(ret);
src/daemon/daemon-status-file.c
+194 -133
@@ -161,37 +161,42 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
161
162 dsf_acquire(*ds);
163
164 - buffer_json_member_add_datetime_rfc3339(wb, "@timestamp", ds->timestamp_ut, true); // ECS
165 - buffer_json_member_add_uint64(wb, "version", STATUS_FILE_VERSION); // custom
164 + buffer_json_member_add_datetime_rfc3339(wb, "@timestamp", ds->timestamp_ut, true);
165 + buffer_json_member_add_uint64(wb, "version", STATUS_FILE_VERSION);
166
167 - buffer_json_member_add_object(wb, "agent"); // ECS
167 + buffer_json_member_add_object(wb, "agent");
168 {
169 - buffer_json_member_add_uuid(wb, "id", ds->host_id.uuid); // ECS
170 - buffer_json_member_add_uuid_compact(wb, "ephemeral_id", ds->invocation.uuid); // ECS
171 - buffer_json_member_add_string(wb, "version", ds->version); // ECS
169 + buffer_json_member_add_uuid(wb, "id", ds->host_id.uuid);
170 + buffer_json_member_add_uuid_compact(wb, "ephemeral_id", ds->invocation.uuid);
171 + buffer_json_member_add_string(wb, "version", ds->version);
172
173 - buffer_json_member_add_time_t(wb, "uptime", ds->uptime); // custom
173 + buffer_json_member_add_time_t(wb, "uptime", ds->uptime);
174
175 - buffer_json_member_add_uuid(wb, "ND_node_id", ds->node_id.uuid); // custom
176 - buffer_json_member_add_uuid(wb, "ND_claim_id", ds->claim_id.uuid); // custom
177 - buffer_json_member_add_uint64(wb, "ND_restarts", ds->restarts); // custom
175 + buffer_json_member_add_uuid(wb, "node_id", ds->node_id.uuid);
176 + buffer_json_member_add_uuid(wb, "claim_id", ds->claim_id.uuid);
177 + buffer_json_member_add_uint64(wb, "restarts", ds->restarts);
178
179 - ND_PROFILE_2json(wb, "ND_profile", ds->profile); // custom
180 - buffer_json_member_add_string(wb, "ND_status", DAEMON_STATUS_2str(ds->status)); // custom
181 - EXIT_REASON_2json(wb, "ND_exit_reason", ds->exit_reason); // custom
179 + ND_PROFILE_2json(wb, "profile", ds->profile);
180 + buffer_json_member_add_string(wb, "status", DAEMON_STATUS_2str(ds->status));
181 + EXIT_REASON_2json(wb, "exit_reason", ds->exit_reason);
182
183 - buffer_json_member_add_string_or_empty(wb, "ND_install_type", ds->install_type); // custom
183 + buffer_json_member_add_string_or_empty(wb, "install_type", ds->install_type);
184
185 if(ds->v >= 14) {
186 - buffer_json_member_add_string(wb, "ND_db_mode", rrd_memory_mode_name(ds->db_mode)); // custom
187 - buffer_json_member_add_uint64(wb, "ND_db_tiers", ds->db_tiers); // custom
188 - buffer_json_member_add_boolean(wb, "ND_kubernetes", ds->kubernetes); // custom
186 + buffer_json_member_add_string(wb, "db_mode", rrd_memory_mode_name(ds->db_mode));
187 + buffer_json_member_add_uint64(wb, "db_tiers", ds->db_tiers);
188 + buffer_json_member_add_boolean(wb, "kubernetes", ds->kubernetes);
189 }
190
191 if(ds->v >= 16)
192 - buffer_json_member_add_boolean(wb, "ND_sentry_available", ds->sentry_available); // custom
192 + buffer_json_member_add_boolean(wb, "sentry_available", ds->sentry_available);
193
194 - buffer_json_member_add_object(wb, "ND_timings"); // custom
194 + if(ds->v >= 18) {
195 + buffer_json_member_add_int64(wb, "reliability", ds->reliability);
196 + buffer_json_member_add_string(wb, "stack_traces", ds->stack_traces);
197 + }
198 +
199 + buffer_json_member_add_object(wb, "timings");
200 {
201 buffer_json_member_add_time_t(wb, "init", ds->timings.init);
202 buffer_json_member_add_time_t(wb, "exit", ds->timings.exit);
@@ -200,28 +205,28 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
205 }
206 buffer_json_object_close(wb);
207
203 - buffer_json_member_add_object(wb, "host"); // ECS
208 + buffer_json_member_add_object(wb, "host");
209 {
210 buffer_json_member_add_uuid_compact(wb, "id", ds->machine_id.uuid);
206 - buffer_json_member_add_string_or_empty(wb, "architecture", ds->architecture); // ECS
207 - buffer_json_member_add_string_or_empty(wb, "virtualization", ds->virtualization); // custom
208 - buffer_json_member_add_string_or_empty(wb, "container", ds->container); // custom
209 - buffer_json_member_add_time_t(wb, "uptime", ds->boottime); // ECS
211 + buffer_json_member_add_string_or_empty(wb, "architecture", ds->architecture);
212 + buffer_json_member_add_string_or_empty(wb, "virtualization", ds->virtualization);
213 + buffer_json_member_add_string_or_empty(wb, "container", ds->container);
214 + buffer_json_member_add_time_t(wb, "uptime", ds->boottime);
215
211 - buffer_json_member_add_object(wb, "boot"); // ECS
216 + buffer_json_member_add_object(wb, "boot");
217 {
213 - buffer_json_member_add_uuid_compact(wb, "id", ds->boot_id.uuid); // ECS
218 + buffer_json_member_add_uuid_compact(wb, "id", ds->boot_id.uuid);
219 }
220 buffer_json_object_close(wb);
221
217 - buffer_json_member_add_object(wb, "memory"); // custom
222 + buffer_json_member_add_object(wb, "memory");
223 if(OS_SYSTEM_MEMORY_OK(ds->memory)) {
224 buffer_json_member_add_uint64(wb, "total", ds->memory.ram_total_bytes);
225 buffer_json_member_add_uint64(wb, "free", ds->memory.ram_available_bytes);
226 }
227 buffer_json_object_close(wb);
228
224 - buffer_json_member_add_object(wb, "disk"); // ECS
229 + buffer_json_member_add_object(wb, "disk");
230 {
231 buffer_json_member_add_object(wb, "db");
232 if (OS_SYSTEM_DISK_SPACE_OK(ds->var_cache)) {
@@ -237,18 +242,18 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
242 }
243 buffer_json_object_close(wb);
244
240 - buffer_json_member_add_object(wb, "os"); // ECS
245 + buffer_json_member_add_object(wb, "os");
246 {
242 - buffer_json_member_add_string(wb, "type", DAEMON_OS_TYPE_2str(ds->os_type)); // ECS
243 - buffer_json_member_add_string_or_empty(wb, "kernel", ds->kernel_version); // ECS
244 - buffer_json_member_add_string_or_empty(wb, "name", ds->os_name); // ECS
245 - buffer_json_member_add_string_or_empty(wb, "version", ds->os_version); // ECS
246 - buffer_json_member_add_string_or_empty(wb, "family", ds->os_id); // ECS
247 - buffer_json_member_add_string_or_empty(wb, "platform", ds->os_id_like); // ECS
247 + buffer_json_member_add_string(wb, "type", DAEMON_OS_TYPE_2str(ds->os_type));
248 + buffer_json_member_add_string_or_empty(wb, "kernel", ds->kernel_version);
249 + buffer_json_member_add_string_or_empty(wb, "name", ds->os_name);
250 + buffer_json_member_add_string_or_empty(wb, "version", ds->os_version);
251 + buffer_json_member_add_string_or_empty(wb, "family", ds->os_id);
252 + buffer_json_member_add_string_or_empty(wb, "platform", ds->os_id_like);
253 }
254 buffer_json_object_close(wb);
255
251 - buffer_json_member_add_object(wb, "fatal"); // custom
256 + buffer_json_member_add_object(wb, "fatal");
257 {
258 buffer_json_member_add_uint64(wb, "line", ds->fatal.line);
259 buffer_json_member_add_string_or_empty(wb, "filename", ds->fatal.filename);
@@ -256,6 +261,7 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
261 buffer_json_member_add_string_or_empty(wb, "message", ds->fatal.message);
262 buffer_json_member_add_string_or_empty(wb, "errno", ds->fatal.errno_str);
263 buffer_json_member_add_string_or_empty(wb, "thread", ds->fatal.thread);
264 + buffer_json_member_add_uint64(wb, "thread_id", ds->fatal.thread_id);
265 buffer_json_member_add_string_or_empty(wb, "stack_trace", ds->fatal.stack_trace);
266
267 if(ds->v >= 16) {
@@ -269,17 +275,17 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
275 }
276 buffer_json_object_close(wb);
277
272 - buffer_json_member_add_array(wb, "dedup"); // custom
278 + buffer_json_member_add_array(wb, "dedup");
279 {
280 for(size_t i = 0; i < _countof(ds->dedup.slot); i++) {
281 if (ds->dedup.slot[i].timestamp_ut == 0)
282 continue;
283
278 - buffer_json_add_array_item_object(wb); // custom
284 + buffer_json_add_array_item_object(wb);
285 {
280 - buffer_json_member_add_datetime_rfc3339(wb, "@timestamp", ds->dedup.slot[i].timestamp_ut, true); // custom
281 - buffer_json_member_add_uint64(wb, "hash", ds->dedup.slot[i].hash); // custom
282 - buffer_json_member_add_boolean(wb, "sentry", ds->dedup.slot[i].sentry); // custom
286 + buffer_json_member_add_datetime_rfc3339(wb, "@timestamp", ds->dedup.slot[i].timestamp_ut, true);
287 + buffer_json_member_add_uint64(wb, "hash", ds->dedup.slot[i].hash);
288 + buffer_json_member_add_boolean(wb, "sentry", ds->dedup.slot[i].sentry);
289 }
290 buffer_json_object_close(wb);
291 }
@@ -312,37 +318,52 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
318 bool required_v14 = version >= 14 ? strict : false;
319 bool required_v16 = version >= 16 ? strict : false;
320 bool required_v17 = version >= 17 ? strict : false;
321 + bool required_v18 = version >= 18 ? strict : false;
322
323 // Parse timestamp
324 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "@timestamp", datetime, error, required_v1);
325 if(datetime[0])
326 ds->timestamp_ut = rfc3339_parse_ut(datetime, NULL);
327
328 + const char *profile_key = version >= 18 ? "profile" : "ND_profile";
329 + const char *status_key = version >= 18 ? "status" : "ND_status";
330 + const char *exit_reason_key = version >= 18 ? "exit_reason" : "ND_exit_reason";
331 + const char *node_id_key = version >= 18 ? "node_id" : "ND_node_id";
332 + const char *claim_id_key = version >= 18 ? "claim_id" : "ND_claim_id";
333 + const char *install_type_key = version >= 18 ? "install_type" : "ND_install_type";
334 + const char *timings_key = version >= 18 ? "timings" : "ND_timings";
335 + const char *restarts_key = version >= 18 ? "restarts" : "ND_restarts";
336 + const char *db_mode_key = version >= 18 ? "db_mode" : "ND_db_mode";
337 + const char *db_tiers_key = version >= 18 ? "db_tiers" : "ND_db_tiers";
338 + const char *kubernetes_key = version >= 18 ? "kubernetes" : "ND_kubernetes";
339 + const char *sentry_available_key = version >= 18 ? "sentry_available" : "ND_sentry_available";
340 +
341 // Parse agent object
342 JSONC_PARSE_SUBOBJECT(jobj, path, "agent", error, required_v1, {
343 JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, "id", ds->host_id.uuid, error, required_v1);
344 JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, "ephemeral_id", ds->invocation.uuid, error, required_v1);
345 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "version", ds->version, error, required_v1);
346 JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "uptime", ds->uptime, error, required_v1);
327 - JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "ND_profile", ND_PROFILE_2id_one, ds->profile, error, required_v1);
328 - JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "ND_status", DAEMON_STATUS_2id, ds->status, error, required_v1);
329 - JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, "ND_exit_reason", EXIT_REASON_2id_one, ds->exit_reason, error, required_v1);
330 - JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, "ND_node_id", ds->node_id.uuid, error, required_v1);
331 - JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, "ND_claim_id", ds->claim_id.uuid, error, required_v1);
332 - JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "ND_install_type", ds->install_type, error, required_v3);
333 -
334 - JSONC_PARSE_SUBOBJECT(jobj, path, "ND_timings", error, required_v1, {
347 +
348 + JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, profile_key, ND_PROFILE_2id_one, ds->profile, error, required_v1);
349 + JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, status_key, DAEMON_STATUS_2id, ds->status, error, required_v1);
350 + JSONC_PARSE_ARRAY_OF_TXT2BITMAP_OR_ERROR_AND_RETURN(jobj, path, exit_reason_key, EXIT_REASON_2id_one, ds->exit_reason, error, required_v1);
351 + JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, node_id_key, ds->node_id.uuid, error, required_v1);
352 + JSONC_PARSE_TXT2UUID_OR_ERROR_AND_RETURN(jobj, path, claim_id_key, ds->claim_id.uuid, error, required_v1);
353 + JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, install_type_key, ds->install_type, error, required_v3);
354 +
355 + JSONC_PARSE_SUBOBJECT(jobj, path, timings_key, error, required_v1, {
356 JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "init", ds->timings.init, error, required_v1);
357 JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "exit", ds->timings.exit, error, required_v1);
358 });
359
360 if(version >= 4)
340 - JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "ND_restarts", ds->restarts, error, required_v4);
361 + JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, restarts_key, ds->restarts, error, required_v4);
362
363 if(version >= 14) {
343 - JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "ND_db_mode", rrd_memory_mode_id, ds->db_mode, error, required_v14);
344 - JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "ND_db_tiers", ds->db_tiers, error, required_v14);
345 - JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "ND_kubernetes", ds->kubernetes, error, required_v14);
364 + JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, db_mode_key, rrd_memory_mode_id, ds->db_mode, error, required_v14);
365 + JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, db_tiers_key, ds->db_tiers, error, required_v14);
366 + JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, kubernetes_key, ds->kubernetes, error, required_v14);
367 }
368 else {
369 ds->db_mode = default_rrd_memory_mode;
@@ -351,9 +372,13 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
372 }
373
374 if(version >= 17)
354 - JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "ND_sentry_available", ds->sentry_available, error, required_v17);
375 + JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, sentry_available_key, ds->sentry_available, error, required_v17);
376 else if(version == 16)
377 JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "ND_sentry", ds->sentry_available, error, required_v16);
378 + if(version >= 18) {
379 + JSONC_PARSE_INT64_OR_ERROR_AND_RETURN(jobj, path, "reliability", ds->reliability, error, required_v18);
380 + JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "stack_traces", ds->stack_traces, error, required_v18);
381 + }
382 });
383
384 // Parse host object
@@ -408,12 +433,14 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
433 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "errno", ds->fatal.errno_str, error, required_v3);
434 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "thread", ds->fatal.thread, error, required_v5);
435
411 - if(version >= 16) {
436 + if(version >= 16)
437 JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "signal_code", SIGNAL_CODE_2id_h, ds->fatal.signal_code, error, required_v16);
413 - }
414 - if(version >= 17) {
438 +
439 + if(version >= 17)
440 JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "sentry", SIGNAL_CODE_2id_h, ds->fatal.sentry, error, required_v17);
416 - }
441 +
442 + if(version >= 18)
443 + JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "thread_id", ds->fatal.thread_id, error, required_v18);
444 });
445
446 // Parse the last posted object
@@ -451,6 +478,85 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
478 // --------------------------------------------------------------------------------------------------------------------
479 // get the current status
480
481 +static void daemon_status_file_migrate_once(void) {
482 + FUNCTION_RUN_ONCE();
483 +
484 + dsf_acquire(last_session_status);
485 + dsf_acquire(session_status);
486 +
487 + strncpyz(session_status.version, NETDATA_VERSION, sizeof(session_status.version) - 1);
488 + session_status.machine_id = os_machine_id();
489 +
490 + {
491 + char *install_type = NULL, *prebuilt_arch = NULL, *prebuilt_dist = NULL;
492 + get_install_type_internal(&install_type, &prebuilt_arch, &prebuilt_dist);
493 +
494 + if(install_type)
495 + strncpyz(session_status.install_type, install_type, sizeof(session_status.install_type) - 1);
496 +
497 + freez(prebuilt_arch);
498 + freez(prebuilt_dist);
499 + freez(install_type);
500 + }
501 +
502 +#if defined(ENABLE_SENTRY)
503 + session_status.sentry_available = true;
504 +#else
505 + session_status.sentry_available = false;
506 +#endif
507 +
508 + session_status.boot_id = os_boot_id();
509 + if(!UUIDeq(session_status.boot_id, last_session_status.boot_id) && os_boot_ids_match(session_status.boot_id, last_session_status.boot_id)) {
510 + // there is a slight difference in boot_id, but it is still the same boot
511 + // copy the last boot_id
512 + session_status.boot_id = last_session_status.boot_id;
513 + }
514 +
515 + session_status.claim_id = last_session_status.claim_id;
516 + session_status.node_id = last_session_status.node_id;
517 + session_status.host_id = last_session_status.host_id;
518 + if(UUIDiszero(session_status.host_id)) {
519 + const char *machine_guid = registry_get_this_machine_guid(false);
520 + if(machine_guid && *machine_guid) {
521 + if (uuid_parse_flexi(machine_guid, session_status.host_id.uuid) != 0)
522 + session_status.host_id = UUID_ZERO;
523 + }
524 + }
525 +
526 + strncpyz(session_status.architecture, last_session_status.architecture, sizeof(session_status.architecture) - 1);
527 + strncpyz(session_status.virtualization, last_session_status.virtualization, sizeof(session_status.virtualization) - 1);
528 + strncpyz(session_status.container, last_session_status.container, sizeof(session_status.container) - 1);
529 + strncpyz(session_status.kernel_version, last_session_status.kernel_version, sizeof(session_status.kernel_version) - 1);
530 + strncpyz(session_status.os_name, last_session_status.os_name, sizeof(session_status.os_name) - 1);
531 + strncpyz(session_status.os_version, last_session_status.os_version, sizeof(session_status.os_version) - 1);
532 + strncpyz(session_status.os_id, last_session_status.os_id, sizeof(session_status.os_id) - 1);
533 + strncpyz(session_status.os_id_like, last_session_status.os_id_like, sizeof(session_status.os_id_like) - 1);
534 +
535 + session_status.restarts = last_session_status.restarts + 1;
536 + session_status.reliability = last_session_status.reliability;
537 +
538 + bool crashed = last_session_status.status != DAEMON_STATUS_NONE && last_session_status.status != DAEMON_STATUS_EXITED;
539 + bool exited_with_fatal = last_session_status.status == DAEMON_STATUS_EXITED && last_session_status.exit_reason != EXIT_REASON_NONE && !is_exit_reason_normal(last_session_status.exit_reason);
540 + if(crashed || exited_with_fatal) {
541 + if(session_status.reliability > 0) session_status.reliability = 0;
542 + session_status.reliability--;
543 + }
544 + else {
545 + if(session_status.reliability < 0) session_status.reliability = 0;
546 + session_status.reliability++;
547 + }
548 +
549 + if(last_session_status.v == STATUS_FILE_VERSION) {
550 + for (size_t i = 0; i < _countof(session_status.dedup.slot); i++)
551 + session_status.dedup.slot[i] = last_session_status.dedup.slot[i];
552 + }
553 +
554 + strncpyz(session_status.stack_traces, capture_stack_trace_backend(), sizeof(session_status.stack_traces) - 1);
555 +
556 + dsf_release(last_session_status);
557 + dsf_release(session_status);
558 +}
559 +
560 static void daemon_status_file_refresh(DAEMON_STATUS status) {
561 usec_t now_ut = now_realtime_usec();
562
@@ -479,15 +585,6 @@ static void daemon_status_file_refresh(DAEMON_STATUS status) {
585 if(session_status.status == DAEMON_STATUS_EXITING)
586 session_status.timings.exit = (time_t)((now_ut - session_status.timings.exit_started_ut + USEC_PER_SEC/2) / USEC_PER_SEC);
587
482 - strncpyz(session_status.version, NETDATA_VERSION, sizeof(session_status.version) - 1);
483 -
484 - session_status.boot_id = os_boot_id();
485 - if(!UUIDeq(session_status.boot_id, last_session_status.boot_id) && os_boot_ids_match(session_status.boot_id, last_session_status.boot_id)) {
486 - // there is a slight difference in boot_id, but it is still the same boot
487 - // copy the last boot_id
488 - session_status.boot_id = last_session_status.boot_id;
489 - }
490 -
588 session_status.boottime = now_boottime_sec();
589 session_status.uptime = now_realtime_sec() - netdata_start_time;
590 session_status.timestamp_ut = now_ut;
@@ -495,76 +592,14 @@ static void daemon_status_file_refresh(DAEMON_STATUS status) {
592 session_status.db_mode = default_rrd_memory_mode;
593 session_status.db_tiers = nd_profile.storage_tiers;
594
498 -#if defined(ENABLE_SENTRY)
499 - session_status.sentry_available = true;
500 -#else
501 - session_status.sentry_available = false;
502 -#endif
503 -
595 session_status.claim_id = claim_id_get_uuid();
596
597 if(localhost) {
507 - session_status.host_id = localhost->host_id;
508 - session_status.node_id = localhost->node_id;
509 - }
510 - else if(!UUIDiszero(last_session_status.host_id))
511 - session_status.host_id = last_session_status.host_id;
512 - else {
513 - const char *machine_guid = registry_get_this_machine_guid(false);
514 - if(machine_guid && *machine_guid) {
515 - if (uuid_parse_flexi(machine_guid, session_status.host_id.uuid) != 0)
516 - session_status.host_id = UUID_ZERO;
517 - }
518 - else
519 - session_status.host_id = UUID_ZERO;
520 - }
598 + if(!UUIDiszero(localhost->host_id))
599 + session_status.host_id = localhost->host_id;
600
522 - if(UUIDiszero(session_status.machine_id))
523 - session_status.machine_id = os_machine_id();
524 -
525 - // copy items from the old status if they are not set
526 - if(UUIDiszero(session_status.claim_id))
527 - session_status.claim_id = last_session_status.claim_id;
528 - if(UUIDiszero(session_status.node_id))
529 - session_status.node_id = last_session_status.node_id;
530 - if(UUIDiszero(session_status.host_id))
531 - session_status.host_id = last_session_status.host_id;
532 - if(!session_status.architecture[0] && last_session_status.architecture[0])
533 - strncpyz(session_status.architecture, last_session_status.architecture, sizeof(session_status.architecture) - 1);
534 - if(!session_status.virtualization[0] && last_session_status.virtualization[0])
535 - strncpyz(session_status.virtualization, last_session_status.virtualization, sizeof(session_status.virtualization) - 1);
536 - if(!session_status.container[0] && last_session_status.container[0])
537 - strncpyz(session_status.container, last_session_status.container, sizeof(session_status.container) - 1);
538 - if(!session_status.kernel_version[0] && last_session_status.kernel_version[0])
539 - strncpyz(session_status.kernel_version, last_session_status.kernel_version, sizeof(session_status.kernel_version) - 1);
540 - if(!session_status.os_name[0] && last_session_status.os_name[0])
541 - strncpyz(session_status.os_name, last_session_status.os_name, sizeof(session_status.os_name) - 1);
542 - if(!session_status.os_version[0] && last_session_status.os_version[0])
543 - strncpyz(session_status.os_version, last_session_status.os_version, sizeof(session_status.os_version) - 1);
544 - if(!session_status.os_id[0] && last_session_status.os_id[0])
545 - strncpyz(session_status.os_id, last_session_status.os_id, sizeof(session_status.os_id) - 1);
546 - if(!session_status.os_id_like[0] && last_session_status.os_id_like[0])
547 - strncpyz(session_status.os_id_like, last_session_status.os_id_like, sizeof(session_status.os_id_like) - 1);
548 - if(!session_status.restarts)
549 - session_status.restarts = last_session_status.restarts + 1;
550 -
551 - if(last_session_status.v == STATUS_FILE_VERSION) {
552 - if (!session_status.dedup.slot[0].timestamp_ut || !session_status.dedup.slot[0].hash) {
553 - for (size_t i = 0; i < _countof(session_status.dedup.slot); i++)
554 - session_status.dedup.slot[i] = last_session_status.dedup.slot[i];
555 - }
556 - }
557 -
558 - if(!session_status.install_type[0]) {
559 - char *install_type = NULL, *prebuilt_arch = NULL, *prebuilt_dist = NULL;
560 - get_install_type_internal(&install_type, &prebuilt_arch, &prebuilt_dist);
561 -
562 - if(install_type)
563 - strncpyz(session_status.install_type, install_type, sizeof(session_status.install_type) - 1);
564 -
565 - freez(prebuilt_arch);
566 - freez(prebuilt_dist);
567 - freez(install_type);
601 + if(!UUIDiszero(localhost->node_id))
602 + session_status.node_id = localhost->node_id;
603 }
604
605 get_daemon_status_fields_from_system_info(&session_status);
@@ -993,6 +1028,7 @@ void daemon_status_file_init(void) {
1028 static_save_buffer_init();
1029 mallocz_register_out_of_memory_cb(daemon_status_file_out_of_memory);
1030 daemon_status_file_load(&last_session_status);
1031 + daemon_status_file_migrate_once();
1032 }
1033
1034 void daemon_status_file_check_crash(void) {
@@ -1261,6 +1297,9 @@ void daemon_status_file_register_fatal(const char *filename, const char *functio
1297 exit_initiated_add(EXIT_REASON_FATAL);
1298 session_status.exit_reason |= EXIT_REASON_FATAL;
1299
1300 + if(!session_status.fatal.thread_id)
1301 + session_status.fatal.thread_id = gettid_cached();
1302 +
1303 copy_and_clean_thread_name_if_empty(&session_status, nd_thread_tag());
1304
1305 if(filename && *filename)
@@ -1337,6 +1376,9 @@ bool daemon_status_file_deadly_signal_received(EXIT_REASON reason, SIGNAL_CODE c
1376 if(code)
1377 session_status.fatal.signal_code = code;
1378
1379 + if(!session_status.fatal.thread_id)
1380 + session_status.fatal.thread_id = gettid_cached();
1381 +
1382 copy_and_clean_thread_name_if_empty(&session_status, nd_thread_tag_async_safe());
1383
1384 dsf_release(session_status);
@@ -1465,11 +1507,30 @@ const char *daemon_status_file_get_fatal_stack_trace(void) {
1507 return session_status.fatal.stack_trace;
1508 }
1509
1510 +const char *daemon_status_file_get_stack_trace_backend(void) {
1511 + return session_status.stack_traces;
1512 +}
1513 +
1514 const char *daemon_status_file_get_fatal_thread(void) {
1515 return session_status.fatal.thread;
1516 }
1517
1518 +pid_t daemon_status_file_get_fatal_thread_id(void) {
1519 + return session_status.fatal.thread_id;
1520 +}
1521 +
1522 long daemon_status_file_get_fatal_line(void) {
1523 return session_status.fatal.line;
1524 }
1525
1526 +DAEMON_STATUS daemon_status_file_get_status(void) {
1527 + return session_status.status;
1528 +}
1529 +
1530 +size_t daemon_status_file_get_restarts(void) {
1531 + return session_status.restarts;
1532 +}
1533 +
1534 +ssize_t daemon_status_file_get_reliability(void) {
1535 + return session_status.reliability;
1536 +}
src/daemon/daemon-status-file.h
+11 -2
@@ -7,7 +7,7 @@
7 #include "daemon/config/netdata-conf-profile.h"
8 #include "database/rrd-database-mode.h"
9
10 -#define STATUS_FILE_VERSION 17
10 +#define STATUS_FILE_VERSION 18
11
12 typedef enum {
13 DAEMON_STATUS_NONE,
@@ -44,7 +44,8 @@ typedef struct daemon_status_file {
44 time_t boottime; // system boottime
45 time_t uptime; // netdata uptime
46 usec_t timestamp_ut; // the timestamp of the status file
47 - size_t restarts; // the number of times this agent has restarted
47 + size_t restarts; // the number of times this agent has restarted (ever)
48 + ssize_t reliability; // consecutive restarts: > 0 reliable, < 0 crashing
49
50 ND_UUID boot_id; // the boot id of the system
51 ND_UUID invocation; // the netdata invocation id generated the file
@@ -74,6 +75,8 @@ typedef struct daemon_status_file {
75 char os_id_like[64]; // ECS: os.platform
76 bool read_system_info;
77
78 + char stack_traces[15]; // the backend for capturing stack traces
79 +
80 struct {
81 SPINLOCK spinlock;
82 long line;
@@ -83,6 +86,7 @@ typedef struct daemon_status_file {
86 char message[512];
87 char stack_trace[2048];
88 char thread[ND_THREAD_TAG_MAX + 1];
89 + pid_t thread_id;
90 SIGNAL_CODE signal_code;
91 bool sentry; // true when the error was also reported to sentry
92 } fatal;
@@ -129,6 +133,11 @@ const char *daemon_status_file_get_fatal_message(void);
133 const char *daemon_status_file_get_fatal_errno(void);
134 const char *daemon_status_file_get_fatal_stack_trace(void);
135 const char *daemon_status_file_get_fatal_thread(void);
136 +const char *daemon_status_file_get_stack_trace_backend(void);
137 +pid_t daemon_status_file_get_fatal_thread_id(void);
138 long daemon_status_file_get_fatal_line(void);
139 +DAEMON_STATUS daemon_status_file_get_status(void);
140 +size_t daemon_status_file_get_restarts(void);
141 +ssize_t daemon_status_file_get_reliability(void);
142
143 #endif //NETDATA_DAEMON_STATUS_FILE_H
src/daemon/libuv_workers.c
+3
@@ -86,6 +86,9 @@ static void register_libuv_worker_jobs_internal(void) {
86 // netdatacli
87 worker_register_job_name(UV_EVENT_SCHEDULE_CMD, "schedule command");
88
89 + // make sure we have the right thread id
90 + gettid_uncached();
91 +
92 static int workers = 0;
93 int worker_id = __atomic_add_fetch(&workers, 1, __ATOMIC_RELAXED);
94
src/daemon/sentry-native/sentry-native.c
+138 -43
@@ -17,34 +17,99 @@ void nd_sentry_crash_report(bool enable) {
17 nd_sentry_crash_report_enabled = enable;
18 }
19
20 -static sentry_value_t nd_sentry_on_crash(
21 - const sentry_ucontext_t *uctx __maybe_unused, // provides the user-space context of the crash
22 - sentry_value_t event, // used the same way as in `before_send`
23 - void *closure __maybe_unused // user-data that you can provide at configuration time
24 -) {
20 +// --------------------------------------------------------------------------------------------------------------------
21 +// helpers
22 +
23 +static void nd_sentry_set_tag(const char *key, const char *value) {
24 + if (!value || !*value)
25 + return;
26 +
27 + sentry_set_tag(key, value);
28 +}
29 +
30 +static void nd_sentry_set_tag_int64(const char *key, int64_t value) {
31 + if(!value)
32 + return;
33 +
34 + char buf[UINT64_MAX_LENGTH];
35 + print_int64(buf, value);
36 + nd_sentry_set_tag(key, buf);
37 +}
38 +
39 +static void nd_sentry_set_tag_uint64(const char *key, uint64_t value) {
40 + if(!value)
41 + return;
42 +
43 + char buf[UINT64_MAX_LENGTH];
44 + print_uint64(buf, value);
45 + nd_sentry_set_tag(key, buf);
46 +}
47 +
48 +static void nd_sentry_set_tag_uuid(const char *key, const ND_UUID uuid) {
49 + if(UUIDiszero(uuid))
50 + return;
51 +
52 + char uuid_str[UUID_STR_LEN];
53 + uuid_unparse_lower(uuid.uuid, uuid_str);
54 + nd_sentry_set_tag(key, uuid_str);
55 +}
56 +
57 +static void nd_sentry_set_tag_uuid_compact(const char *key, const ND_UUID uuid) {
58 + if(UUIDiszero(uuid))
59 + return;
60 +
61 + char uuid_str[UUID_COMPACT_STR_LEN];
62 + uuid_unparse_lower_compact(uuid.uuid, uuid_str);
63 + nd_sentry_set_tag(key, uuid_str);
64 +}
65 +
66 +static void nd_sentry_set_tag_uptime(void) {
67 + nd_sentry_set_tag_int64("uptime", now_realtime_sec() - netdata_start_time);
68 +}
69 +
70 +static void nd_sentry_set_tag_status(void) {
71 + nd_sentry_set_tag("status", DAEMON_STATUS_2str(daemon_status_file_get_status()));
72 +}
73 +
74 +// --------------------------------------------------------------------------------------------------------------------
75 +// sentry hooks
76 +
77 +static sentry_value_t nd_sentry_on_hook(sentry_value_t event) {
78 // IMPORTANT: this function is called from a signal handler
79
80 + // sentry enables a custom allocator for their use,
81 + // that is async signal safe, so the sentry API is available here.
82 +
83 if (!nd_sentry_crash_report_enabled) {
84 sentry_value_decref(event);
85 return sentry_value_new_null();
86 }
87
88 + nd_sentry_set_tag_status();
89 + nd_sentry_set_tag_uptime();
90 + nd_sentry_set_tag("thread", daemon_status_file_get_fatal_thread());
91 + nd_sentry_set_tag_uint64("thread_id", daemon_status_file_get_fatal_thread_id());
92 +
93 return event;
94 }
95
96 +static sentry_value_t nd_sentry_on_crash(
97 + const sentry_ucontext_t *uctx __maybe_unused, // provides the user-space context of the crash
98 + sentry_value_t event, // used the same way as in `before_send`
99 + void *closure __maybe_unused) { // user-data that you can provide at configuration time
100 + return nd_sentry_on_hook(event);
101 +}
102 +
103 static sentry_value_t nd_sentry_before_send(
104 sentry_value_t event,
105 void *hint __maybe_unused,
106 void *closure __maybe_unused) {
39 -
40 - if (!nd_sentry_crash_report_enabled) {
41 - sentry_value_decref(event);
42 - return sentry_value_new_null();
43 - }
44 -
45 - return event;
107 + return nd_sentry_on_hook(event);
108 }
109
110 +// --------------------------------------------------------------------------------------------------------------------
111 +// sentry initialization
112 +
113 void nd_sentry_init(void) {
114 if (!analytics_check_enabled())
115 return;
@@ -76,43 +141,42 @@ void nd_sentry_init(void) {
141 // ----------------------------------------------------------------------------------------------------------------
142 // initialization
143
79 - nd_cleanup_fatal_signals();
144 + nd_cleanup_deadly_signals(); // remove our signal handlers, so that sentry will not hook back to us
145 sentry_init(options);
81 - nd_initialize_signals(true);
146 + nd_initialize_signals(true); // add our signal handlers, we will hook back to sentry
147
148 // ----------------------------------------------------------------------------------------------------------------
149 // tags
150
86 - sentry_set_tag("install_type", daemon_status_file_get_install_type());
87 - sentry_set_tag("architecture", daemon_status_file_get_architecture());
88 - sentry_set_tag("virtualization", daemon_status_file_get_virtualization());
89 - sentry_set_tag("container", daemon_status_file_get_container());
90 - sentry_set_tag("os_name", daemon_status_file_get_os_name());
91 - sentry_set_tag("os_version", daemon_status_file_get_os_version());
92 - sentry_set_tag("os_id", daemon_status_file_get_os_id());
93 - sentry_set_tag("os_id_like", daemon_status_file_get_os_id_like());
151 + nd_sentry_set_tag("install_type", daemon_status_file_get_install_type());
152 + nd_sentry_set_tag("architecture", daemon_status_file_get_architecture());
153 + nd_sentry_set_tag("virtualization", daemon_status_file_get_virtualization());
154 + nd_sentry_set_tag("container", daemon_status_file_get_container());
155 + nd_sentry_set_tag("os_name", daemon_status_file_get_os_name());
156 + nd_sentry_set_tag("os_version", daemon_status_file_get_os_version());
157 + nd_sentry_set_tag("os_id", daemon_status_file_get_os_id());
158 + nd_sentry_set_tag("os_id_like", daemon_status_file_get_os_id_like());
159
160 // profile
161 CLEAN_BUFFER *profile = buffer_create(0, NULL);
162 ND_PROFILE_2buffer(profile, nd_profile_detect_and_configure(false), " ");
98 - sentry_set_tag("profile", buffer_tostring(profile));
163 + nd_sentry_set_tag("profile", buffer_tostring(profile));
164
165 // db_mode
101 - sentry_set_tag("db_mode", rrd_memory_mode_name(default_rrd_memory_mode));
166 + nd_sentry_set_tag("db_mode", rrd_memory_mode_name(default_rrd_memory_mode));
167
168 // db_tiers
104 - char tiers[UINT64_MAX_LENGTH];
105 - print_uint64(tiers, nd_profile.storage_tiers);
106 - sentry_set_tag("db_tiers", tiers);
169 + nd_sentry_set_tag_int64("db_tiers", (int64_t)nd_profile.storage_tiers);
170
108 - // invocation_id
109 - ND_UUID invocation_id = nd_log_get_invocation_id();
110 - char invocation_str[UUID_COMPACT_STR_LEN];
111 - uuid_unparse_lower_compact(invocation_id.uuid, invocation_str);
112 - sentry_set_tag("ephemeral_id", invocation_str);
171 + // ephemeral_id
172 + nd_sentry_set_tag_uuid_compact("ephemeral_id", nd_log_get_invocation_id());
173
174 // agent_events_version
115 - sentry_set_tag("agent_events_version", TOSTRING(STATUS_FILE_VERSION));
175 + nd_sentry_set_tag("agent_events_version", TOSTRING(STATUS_FILE_VERSION));
176 +
177 + nd_sentry_set_tag_uint64("restarts", daemon_status_file_get_restarts());
178 + nd_sentry_set_tag_int64("reliability", daemon_status_file_get_reliability());
179 + nd_sentry_set_tag("stack_traces", daemon_status_file_get_stack_trace_backend());
180 }
181
182 void nd_sentry_fini(void) {
@@ -128,6 +192,36 @@ void nd_sentry_set_user(const char *guid) {
192 sentry_set_user(user);
193 }
194
195 +// --------------------------------------------------------------------------------------------------------------------
196 +// sentry breadcrumbs
197 +
198 +static void nd_sentry_add_key_value_charp(sentry_value_t data, const char *key, const char *value) {
199 + if (!value || !*value)
200 + return;
201 +
202 + sentry_value_set_by_key(data, key, sentry_value_new_string(value));
203 +}
204 +
205 +static void nd_sentry_add_key_value_int64(sentry_value_t data, const char *key, int64_t value) {
206 + if (!value)
207 + return;
208 +
209 + char buf[UINT64_MAX_LENGTH];
210 + print_int64(buf, value);
211 +
212 + sentry_value_set_by_key(data, key, sentry_value_new_string(buf));
213 +}
214 +
215 +static void nd_sentry_add_key_value_uint64(sentry_value_t data, const char *key, uint64_t value) {
216 + if (!value)
217 + return;
218 +
219 + char buf[UINT64_MAX_LENGTH];
220 + print_uint64(buf, value);
221 +
222 + sentry_value_set_by_key(data, key, sentry_value_new_string(buf));
223 +}
224 +
225 void nd_sentry_add_fatal_message_as_breadcrumb(void) {
226 if (!analytics_check_enabled())
227 return;
@@ -136,6 +230,8 @@ void nd_sentry_add_fatal_message_as_breadcrumb(void) {
230 if(!function || !*function)
231 function = "unknown";
232
233 + nd_sentry_set_tag_uptime();
234 +
235 // Set the transaction name to the function where the error occurred
236 // this should be low cardinality
237 sentry_set_transaction(function);
@@ -146,16 +242,15 @@ void nd_sentry_add_fatal_message_as_breadcrumb(void) {
242 sentry_value_t crumb = sentry_value_new_breadcrumb("fatal", "fatal() event details");
243
244 sentry_value_t data = sentry_value_new_object();
149 - sentry_value_set_by_key(data, "message", sentry_value_new_string(daemon_status_file_get_fatal_message()));
150 - sentry_value_set_by_key(data, "function", sentry_value_new_string(daemon_status_file_get_fatal_function()));
151 - sentry_value_set_by_key(data, "filename", sentry_value_new_string(daemon_status_file_get_fatal_filename()));
152 - sentry_value_set_by_key(data, "thread", sentry_value_new_string(daemon_status_file_get_fatal_thread()));
153 -
154 - char line[UINT64_MAX_LENGTH];
155 - print_uint64(line, daemon_status_file_get_fatal_line());
156 - sentry_value_set_by_key(data, "line", sentry_value_new_string(line));
157 - sentry_value_set_by_key(data, "errno", sentry_value_new_string(daemon_status_file_get_fatal_errno()));
158 - sentry_value_set_by_key(data, "stack_trace", sentry_value_new_string(daemon_status_file_get_fatal_stack_trace()));
245 + nd_sentry_add_key_value_charp(data, "message", daemon_status_file_get_fatal_message());
246 + nd_sentry_add_key_value_charp(data, "function", daemon_status_file_get_fatal_function());
247 + nd_sentry_add_key_value_charp(data, "filename", daemon_status_file_get_fatal_filename());
248 + nd_sentry_add_key_value_charp(data, "thread", daemon_status_file_get_fatal_thread());
249 + nd_sentry_add_key_value_uint64(data, "thread_id", daemon_status_file_get_fatal_thread_id());
250 + nd_sentry_add_key_value_int64(data, "line", daemon_status_file_get_fatal_line());
251 + nd_sentry_add_key_value_charp(data, "errno", daemon_status_file_get_fatal_errno());
252 + nd_sentry_add_key_value_charp(data, "stack_trace", daemon_status_file_get_fatal_stack_trace());
253 + nd_sentry_add_key_value_charp(data, "status", DAEMON_STATUS_2str(daemon_status_file_get_status()));
254
255 sentry_value_set_by_key(crumb, "data", data);
256 sentry_add_breadcrumb(crumb);
src/daemon/signal-handler.c
+1 -1
@@ -138,7 +138,7 @@ static void posix_unmask_my_signals(void) {
138 netdata_log_error("SIGNAL: cannot unmask netdata signals");
139 }
140
141 -void nd_cleanup_fatal_signals(void) {
141 +void nd_cleanup_deadly_signals(void) {
142 struct sigaction act;
143 memset(&act, 0, sizeof(struct sigaction));
144
src/daemon/signal-handler.h
+1 -1
@@ -3,7 +3,7 @@
3 #ifndef NETDATA_SIGNAL_HANDLER_H
4 #define NETDATA_SIGNAL_HANDLER_H 1
5
6 -void nd_cleanup_fatal_signals(void);
6 +void nd_cleanup_deadly_signals(void);
7 void nd_initialize_signals(bool chain_existing);
8 void nd_process_signals(void) NORETURN;
9
src/database/engine/cache.c
+3 -3
@@ -2468,7 +2468,7 @@ void pgc_open_cache_to_journal_v2(PGC *cache, Word_t section, unsigned datafile_
2468
2469 size_t current_extent_index_id;
2470 Pvoid_t *PValue = JudyLIns(&JudyL_extents_pos, xio->pos, PJE0);
2471 - if(!PValue || *PValue == PJERR)
2471 + if(!PValue || PValue == PJERR)
2472 fatal("Corrupted JudyL extents pos");
2473
2474 struct jv2_extents_info *ei;
@@ -2492,7 +2492,7 @@ void pgc_open_cache_to_journal_v2(PGC *cache, Word_t section, unsigned datafile_
2492 // update the metrics JudyL
2493
2494 PValue = JudyLIns(&JudyL_metrics, page->metric_id, PJE0);
2495 - if(!PValue || *PValue == PJERR)
2495 + if(!PValue || PValue == PJERR)
2496 fatal("Corrupted JudyL metrics");
2497
2498 struct jv2_metrics_info *mi;
@@ -2518,7 +2518,7 @@ void pgc_open_cache_to_journal_v2(PGC *cache, Word_t section, unsigned datafile_
2518 }
2519
2520 PValue = JudyLIns(&mi->JudyL_pages_by_start_time, page->start_time_s, PJE0);
2521 - if(!PValue || *PValue == PJERR)
2521 + if(!PValue || PValue == PJERR)
2522 fatal("Corrupted JudyL metric pages");
2523
2524 if(!*PValue) {
src/libnetdata/log/nd_log-stacktrace.c
+12
@@ -12,6 +12,10 @@ bool nd_log_forked = false;
12 #endif
13 #include <libunwind.h>
14
15 +const char *capture_stack_trace_backend(void) {
16 + return "libunwind";
17 +}
18 +
19 void capture_stack_trace_init(void) {
20 unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_NONE);
21 }
@@ -80,6 +84,10 @@ void capture_stack_trace(BUFFER *wb) {
84
85 #elif defined(HAVE_BACKTRACE)
86
87 +const char *capture_stack_trace_backend(void) {
88 + return "backtrace";
89 +}
90 +
91 bool capture_stack_trace_available(void) {
92 return true;
93 }
@@ -151,6 +159,10 @@ void capture_stack_trace(BUFFER *wb) {
159
160 #else
161
162 +const char *capture_stack_trace_backend(void) {
163 + return "none";
164 +}
165 +
166 bool capture_stack_trace_available(void) {
167 return false;
168 }
src/libnetdata/log/nd_log.h
+1
@@ -38,6 +38,7 @@ void capture_stack_trace_init(void);
38 void capture_stack_trace_flush(void);
39 bool capture_stack_trace_available(void);
40 bool capture_stack_trace_is_async_signal_safe(void);
41 +const char *capture_stack_trace_backend(void);
42
43 typedef void (*log_event_t)(const char *filename, const char *function, const char *message, const char *errno_str, const char *stack_trace, long line);
44 void nd_log_register_fatal_data_cb(log_event_t cb);
src/libnetdata/threads/threads.c
+5 -3
@@ -150,9 +150,11 @@ void nd_thread_tag_set(const char *tag) {
150
151 // --------------------------------------------------------------------------------------------------------------------
152
153 -static __thread bool libuv_name_set = false;
154 -void uv_thread_set_name_np(const char* name) {
155 - if(libuv_name_set) return;
153 +void uv_thread_set_name_np(const char *name) {
154 + static __thread bool libuv_name_set = false;
155 +
156 + if(!name || !*name || (libuv_name_set && _nd_thread_os_name[0]))
157 + return;
158
159 strncpyz(_nd_thread_os_name, name, sizeof(_nd_thread_os_name) - 1);
160 os_set_thread_name(_nd_thread_os_name);