daemon status 24d (#20011)
* add the shutdown timings to status files stack trace * count the unique number of crashes ever
Costa Tsaousis committed
Mar 31, 2025 at 19:22 UTC
619dda24cba36345dc60fda5d6479bcfacef9e8f
4 files changed
+24
-5
src/daemon/daemon-shutdown-watcher.c
+10
-2
@@ -13,10 +13,12 @@ static struct completion shutdown_begin_completion;
13
static struct completion shutdown_end_completion;
14
static ND_THREAD *watcher_thread;
15
16
+static BUFFER *steps_timings = NULL;
17
+
18
NEVER_INLINE
19
static void shutdown_timed_out(void) {
20
// keep this as a separate function, to have it logged like this in sentry
19
- daemon_status_file_shutdown_timeout();
21
+ daemon_status_file_shutdown_timeout(steps_timings);
22
#ifdef ENABLE_SENTRY
23
nd_sentry_add_shutdown_timeout_as_breadcrumb();
24
#endif
@@ -37,6 +39,11 @@ void watcher_step_complete(watcher_step_id_t step_id) {
39
40
static void watcher_wait_for_step(const watcher_step_id_t step_id, usec_t shutdown_start_time)
41
{
42
+ if(!steps_timings) {
43
+ steps_timings = buffer_create(0, NULL);
44
+ buffer_strcat(steps_timings, "# shutdown steps timings");
45
+ }
46
+
47
usec_t step_start_time = now_monotonic_usec();
48
usec_t step_start_duration = step_start_time - shutdown_start_time;
49
@@ -71,6 +78,8 @@ static void watcher_wait_for_step(const watcher_step_id_t step_id, usec_t shutdo
78
duration_snprintf(
79
step_duration_txt, sizeof(step_duration_txt), (int64_t)(step_duration), "us", true);
80
81
+ buffer_sprintf(steps_timings, "\n#%u '%s': %s", step_id + 1, watcher_steps[step_id].msg, step_duration_txt);
82
+
83
if (ok) {
84
netdata_log_info("shutdown step: [%d/%d] - {at %s} finished '%s' in %s",
85
(int)step_id + 1, (int)WATCHER_STEP_ID_MAX, start_duration_txt,
@@ -94,7 +103,6 @@ static void watcher_wait_for_step(const watcher_step_id_t step_id, usec_t shutdo
103
watcher_steps[step_id].msg, step_duration_txt);
104
#endif
105
97
- daemon_status_file_shutdown_step("sentry timeout");
106
shutdown_timed_out();
107
}
108
}
src/daemon/status-file.c
+11
-1
@@ -112,6 +112,9 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
112
buffer_json_member_add_uuid(wb, "claim_id", ds->claim_id.uuid);
113
buffer_json_member_add_uint64(wb, "restarts", ds->restarts);
114
115
+ if(ds->v >= 24)
116
+ buffer_json_member_add_uint64(wb, "crashes", ds->crashes);
117
+
118
if(ds->v >= 22) {
119
buffer_json_member_add_uint64(wb, "posts", ds->posts);
120
buffer_json_member_add_string(wb, "aclk", CLOUD_STATUS_2str(ds->cloud_status));
@@ -316,6 +319,9 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
319
if(version >= 4)
320
JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, restarts_key, ds->restarts, error, required_v4);
321
322
+ if(version >= 24)
323
+ JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "crashes", ds->crashes, error, required_v24);
324
+
325
if(version >= 22) {
326
JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "posts", ds->posts, error, required_v22);
327
JSONC_PARSE_TXT2ENUM_OR_ERROR_AND_RETURN(jobj, path, "aclk", CLOUD_STATUS_2id, ds->cloud_status, error, required_v22);
@@ -492,9 +498,11 @@ static void daemon_status_file_migrate_once(void) {
498
499
session_status.posts = last_session_status.posts;
500
session_status.restarts = last_session_status.restarts + 1;
501
+ session_status.crashes = last_session_status.crashes;
502
session_status.reliability = last_session_status.reliability;
503
504
if(daemon_status_file_has_last_crashed(&last_session_status)) {
505
+ session_status.crashes++;
506
if(session_status.reliability > 0) session_status.reliability = 0;
507
session_status.reliability--;
508
}
@@ -1228,7 +1236,7 @@ bool daemon_status_file_deadly_signal_received(EXIT_REASON reason, SIGNAL_CODE c
1236
1237
static SPINLOCK shutdown_timeout_spinlock = SPINLOCK_INITIALIZER;
1238
1231
-void daemon_status_file_shutdown_timeout(void) {
1239
+void daemon_status_file_shutdown_timeout(BUFFER *trace) {
1240
FUNCTION_RUN_ONCE();
1241
1242
spinlock_lock(&shutdown_timeout_spinlock);
@@ -1236,6 +1244,8 @@ void daemon_status_file_shutdown_timeout(void) {
1244
dsf_acquire(session_status);
1245
exit_initiated_add(EXIT_REASON_SHUTDOWN_TIMEOUT);
1246
session_status.exit_reason |= EXIT_REASON_SHUTDOWN_TIMEOUT;
1247
+ if(trace && buffer_strlen(trace) && stack_trace_is_empty(&session_status))
1248
+ strncpyz(session_status.fatal.stack_trace, buffer_tostring(trace), sizeof(session_status.fatal.stack_trace) - 1);
1249
dsf_release(session_status);
1250
1251
strncpyz(session_status.fatal.function, "shutdown_timeout", sizeof(session_status.fatal.function) - 1);
src/daemon/status-file.h
+2
-1
@@ -48,6 +48,7 @@ typedef struct daemon_status_file {
48
time_t uptime; // netdata uptime
49
usec_t timestamp_ut; // the timestamp of the status file
50
size_t restarts; // the number of times this agent has restarted (ever)
51
+ size_t crashes; // the number of times this agent has crashed (ever)
52
size_t posts; // the number of posts to the backend
53
ssize_t reliability; // consecutive restarts: > 0 reliable, < 0 crashing
54
@@ -123,7 +124,7 @@ bool daemon_status_file_was_incomplete_shutdown(void);
124
125
void daemon_status_file_startup_step(const char *step);
126
void daemon_status_file_shutdown_step(const char *step);
126
-void daemon_status_file_shutdown_timeout(void);
127
+void daemon_status_file_shutdown_timeout(BUFFER *trace);
128
129
void daemon_status_file_init(void);
130
void daemon_status_file_register_fatal(const char *filename, const char *function, const char *message, const char *errno_str, const char *stack_trace, long line);
src/libnetdata/log/nd_log-stacktrace.c
+1
-1
@@ -4,7 +4,7 @@
4
5
bool nd_log_forked = false;
6
7
-#define NO_STACK_TRACE_PREFIX "stack trace not available: "
7
+#define NO_STACK_TRACE_PREFIX "info: stack trace is not available, "
8
9
#if defined(HAVE_LIBBACKTRACE)
10
#include "backtrace-supported.h"