diff --git a/include/common/debug.h b/include/common/debug.h index f43258e923..df85522291 100644 --- a/include/common/debug.h +++ b/include/common/debug.h @@ -71,6 +71,7 @@ struct task; struct buffer; extern volatile unsigned long threads_to_dump; +extern unsigned int debug_commands_issued; void ha_task_dump(struct buffer *buf, const struct task *task, const char *pfx); void ha_thread_dump(struct buffer *buf, int thr, int calling_tid); void ha_thread_dump_all_to_trash(); diff --git a/include/types/stats.h b/include/types/stats.h index 8817746b36..52ea18db4a 100644 --- a/include/types/stats.h +++ b/include/types/stats.h @@ -327,6 +327,7 @@ enum info_field { INF_FAILED_RESOLUTIONS, INF_TOTAL_BYTES_OUT, INF_BYTES_OUT_RATE, + INF_DEBUG_COMMANDS_ISSUED, /* must always be the last one */ INF_TOTAL_FIELDS diff --git a/src/debug.c b/src/debug.c index ae788e12ff..8df2993492 100644 --- a/src/debug.c +++ b/src/debug.c @@ -36,6 +36,7 @@ * when USE_THREAD_DUMP is set. */ volatile unsigned long threads_to_dump = 0; +unsigned int debug_commands_issued = 0; /* Dumps to the buffer some known information for the desired thread, and * optionally extra info for the current thread. The dump will be appended to @@ -214,6 +215,7 @@ static int debug_parse_cli_exit(char **args, char *payload, struct appctx *appct if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); exit(code); return 1; } @@ -236,6 +238,7 @@ static int debug_parse_cli_close(char **args, char *payload, struct appctx *appc if (!fdtab[fd].owner) return cli_msg(appctx, LOG_INFO, "File descriptor was already closed.\n"); + _HA_ATOMIC_ADD(&debug_commands_issued, 1); fd_delete(fd); return 1; } @@ -248,6 +251,7 @@ static int debug_parse_cli_delay(char **args, char *payload, struct appctx *appc if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); usleep((long)delay * 1000); return 1; } @@ -260,6 +264,7 @@ static int debug_parse_cli_log(char **args, char *payload, struct appctx *appctx if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); chunk_reset(&trash); for (arg = 3; *args[arg]; arg++) { if (arg > 3) @@ -280,6 +285,7 @@ static int debug_parse_cli_loop(char **args, char *payload, struct appctx *appct if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); gettimeofday(&curr, NULL); tv_ms_add(&deadline, &curr, loop); @@ -295,6 +301,7 @@ static int debug_parse_cli_panic(char **args, char *payload, struct appctx *appc if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); ha_panic(); return 1; } @@ -309,6 +316,7 @@ static int debug_parse_cli_exec(char **args, char *payload, struct appctx *appct if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) return 1; + _HA_ATOMIC_ADD(&debug_commands_issued, 1); chunk_reset(&trash); for (arg = 3; *args[arg]; arg++) { if (arg > 3) @@ -353,6 +361,8 @@ static int debug_parse_cli_hex(char **args, char *payload, struct appctx *appctx if (!start) return cli_err(appctx, "Will not dump from NULL address.\n"); + _HA_ATOMIC_ADD(&debug_commands_issued, 1); + /* by default, dump ~128 till next block of 16 */ len = strtoul(args[4], NULL, 0); if (!len) @@ -382,6 +392,7 @@ static int debug_parse_cli_tkill(char **args, char *payload, struct appctx *appc if (*args[4]) sig = atoi(args[4]); + _HA_ATOMIC_ADD(&debug_commands_issued, 1); if (thr) ha_tkill(thr - 1, sig); else @@ -424,6 +435,7 @@ static int debug_parse_cli_stream(char **args, char *payload, struct appctx *app ); } + _HA_ATOMIC_ADD(&debug_commands_issued, 1); for (arg = 3; *args[arg]; arg++) { old = 0; end = word = args[arg]; diff --git a/src/stats.c b/src/stats.c index c152a7a337..7ebf2e567c 100644 --- a/src/stats.c +++ b/src/stats.c @@ -152,6 +152,7 @@ const struct name_desc info_fields[INF_TOTAL_FIELDS] = { [INF_FAILED_RESOLUTIONS] = { .name = "FailedResolutions", .desc = "Total number of failed DNS resolutions in current worker process since started" }, [INF_TOTAL_BYTES_OUT] = { .name = "TotalBytesOut", .desc = "Total number of bytes emitted by current worker process since started" }, [INF_BYTES_OUT_RATE] = { .name = "BytesOutRate", .desc = "Number of bytes emitted by current worker process over the last second" }, + [INF_DEBUG_COMMANDS_ISSUED] = { .name = "DebugCommandsIssued", .desc = "Number of debug commands issued on this process (anything > 0 is unsafe)" }, }; const struct name_desc stat_fields[ST_F_TOTAL_FIELDS] = { @@ -3463,6 +3464,7 @@ int stats_fill_info(struct field *info, int len) info[INF_FAILED_RESOLUTIONS] = mkf_u32(0, dns_failed_resolutions); info[INF_TOTAL_BYTES_OUT] = mkf_u64(0, global.out_bytes); info[INF_BYTES_OUT_RATE] = mkf_u64(FN_RATE, (unsigned long long)read_freq_ctr(&global.out_32bps) * 32); + info[INF_DEBUG_COMMANDS_ISSUED] = mkf_u32(0, debug_commands_issued); return 1; }