From 9ff107a9504abe331c714a0301f0f4726f01cf41 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Thu, 13 May 2021 18:41:35 -0400 Subject: [PATCH] Add critical log level Rename the unused BUG() macro to CRIT() to signify an error that can't be recovered from. Add a new environment variable LTTNG_UST_ABORT_ON_CRITICAL that when set will abort() on a critical log statement. Change-Id: Ib3384a66b7efa4004677b3c153f86cb97b06a091 Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- README.md | 4 +++ src/common/getenv.c | 7 +++-- src/common/logging.c | 71 ++++++++++++++++++++++++++++++++++++++------ src/common/logging.h | 56 ++++++++++++++++++++++++++++------ 4 files changed, 117 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9553ef15..e4fb9f2d 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,10 @@ human-readable text log. variable `LTTNG_UST_DEBUG` when launching the user application. It can also be enabled at build time by compiling LTTng-UST with `-DLTTNG_UST_DEBUG`. + - `liblttng-ust` abort on critical can be activated by setting the + environment variable `LTTNG_UST_ABORT_ON_CRITICAL` when launching the user + application. It can also be enabled at build time by compiling LTTng-UST with + `-DLTTNG_UST_ABORT_ON_CRITICAL`. - The environment variable `LTTNG_UST_REGISTER_TIMEOUT` can be used to specify how long the applications should wait for the session daemon _registration done_ command before proceeding to execute the diff --git a/src/common/getenv.c b/src/common/getenv.c index bc7a4d4a..55e6ad7c 100644 --- a/src/common/getenv.c +++ b/src/common/getenv.c @@ -32,11 +32,12 @@ static int lttng_ust_getenv_is_init = 0; static struct lttng_env lttng_env[] = { /* - * LTTNG_UST_DEBUG is used directly by snprintf, because it - * needs to be already set for ERR() used in - * lttng_ust_getenv_init(). + * LTTNG_UST_DEBUG and LTTNG_UST_ABORT_ON_CRITICAL are used directly by + * the internal logging, because they need to be already set for ERR() + * used in lttng_ust_getenv_init(). */ { "LTTNG_UST_DEBUG", LTTNG_ENV_NOT_SECURE, NULL, }, + { "LTTNG_UST_ABORT_ON_CRITICAL", LTTNG_ENV_NOT_SECURE, NULL, }, /* Env. var. which can be used in setuid/setgid executables. */ { "LTTNG_UST_WITHOUT_BADDR_STATEDUMP", LTTNG_ENV_NOT_SECURE, NULL, }, diff --git a/src/common/logging.c b/src/common/logging.c index fb3f119f..39b515ff 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -10,19 +10,18 @@ #include "common/logging.h" int lttng_ust_log_level = LTTNG_UST_LOG_LEVEL_UNKNOWN; +int lttng_ust_log_critical_action = LTTNG_UST_LOG_CRITICAL_ACTION_UNKNOWN; /* * Initialize the global log level from the "LTTNG_UST_DEBUG" environment * variable. * - * This could end up being called concurently by multiple threads but doesn't + * This could end up being called concurrently by multiple threads but doesn't * require a mutex since the input is invariant across threads and the result * will be the same. - * - * Return the current log level to save the caller a second read of the global - * log level. */ -int lttng_ust_logging_init(void) +static +void lttng_ust_logging_log_level_init(void) { char *lttng_ust_debug; int current_log_level; @@ -31,10 +30,10 @@ int lttng_ust_logging_init(void) /* * Check early if we are initialized, this is unlikely as it's already tested - * in lttng_ust_debug_enabled before performing lazy initialization. + * in lttng_ust_logging_debug_enabled before performing lazy initialization. */ if (caa_unlikely(current_log_level != LTTNG_UST_LOG_LEVEL_UNKNOWN)) - goto end; + return; /* * This getenv is not part of lttng_ust_getenv() because logging is @@ -54,7 +53,61 @@ int lttng_ust_logging_init(void) /* Initialize the log level */ CMM_STORE_SHARED(lttng_ust_log_level, current_log_level); +} + +/* + * Initialize the global log critical action from the "LTTNG_UST_ABORT_ON_CRITICAL" + * environment variable. + * + * This could end up being called concurrently by multiple threads but doesn't + * require a mutex since the input is invariant across threads and the result + * will be the same. + */ +static +void lttng_ust_logging_log_critical_action_init(void) +{ + char *lttng_ust_abort_on_critical; + int current_log_critical_action; -end: - return current_log_level; + current_log_critical_action = CMM_LOAD_SHARED(lttng_ust_log_critical_action); + + /* + * Check early if we are initialized, this is unlikely as it's already tested + * in lttng_ust_logging_abort_on_critical_enabled before performing lazy initialization. + */ + if (caa_unlikely(current_log_critical_action != LTTNG_UST_LOG_CRITICAL_ACTION_UNKNOWN)) + return; + + /* + * This getenv is not part of lttng_ust_getenv() because logging is + * used in the getenv initialization and thus logging must be + * initialized prior to getenv. + */ + lttng_ust_abort_on_critical = getenv("LTTNG_UST_ABORT_ON_CRITICAL"); + + /* + * If the LTTNG_UST_ABORT_ON_CRITICAL environment variable is defined, + * call abort() on CRIT(), otherwise take no action. + */ + if (lttng_ust_abort_on_critical) + current_log_critical_action = LTTNG_UST_LOG_CRITICAL_ACTION_ABORT; + else + current_log_critical_action = LTTNG_UST_LOG_CRITICAL_ACTION_NONE; + + /* Initialize the log critical action */ + CMM_STORE_SHARED(lttng_ust_log_critical_action, current_log_critical_action); +} + +/* + * Initialize the global log level from the "LTTNG_UST_DEBUG" environment + * variable and the global log critical action from "LTTNG_UST_ABORT_ON_CRITICAL". + * + * This could end up being called concurrently by multiple threads but doesn't + * require a mutex since the input is invariant across threads and the result + * will be the same. + */ +void lttng_ust_logging_init(void) +{ + lttng_ust_logging_log_level_init(); + lttng_ust_logging_log_critical_action_init(); } diff --git a/src/common/logging.h b/src/common/logging.h index 5ebf17bf..c98644d8 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -29,21 +29,27 @@ enum lttng_ust_log_level { LTTNG_UST_LOG_LEVEL_DEBUG, }; +enum lttng_ust_log_critical_action { + LTTNG_UST_LOG_CRITICAL_ACTION_UNKNOWN = 0, + LTTNG_UST_LOG_CRITICAL_ACTION_NONE, + LTTNG_UST_LOG_CRITICAL_ACTION_ABORT, +}; + extern int lttng_ust_log_level /* enum lttng_ust_log_level */ __attribute__((visibility("hidden"))); +extern int lttng_ust_log_critical_action /* enum lttng_ust_log_critical_action */ + __attribute__((visibility("hidden"))); + /* * Initialize the global log level from the "LTTNG_UST_DEBUG" environment - * variable. + * variable and the global log critical action from "LTTNG_UST_ABORT_ON_CRITICAL". * * This could end up being called concurrently by multiple threads but doesn't * require a mutex since the input is invariant across threads and the result * will be the same. - * - * Return the current log level to save the caller a second read of the global - * log level. */ -int lttng_ust_logging_init(void) +void lttng_ust_logging_init(void) __attribute__((visibility("hidden"))); #ifdef LTTNG_UST_DEBUG @@ -61,15 +67,41 @@ bool lttng_ust_logging_debug_enabled(void) current_log_level = CMM_LOAD_SHARED(lttng_ust_log_level); /* If the global log level is unknown, lazy-initialize it. */ - if (caa_unlikely(current_log_level == LTTNG_UST_LOG_LEVEL_UNKNOWN)) - current_log_level = lttng_ust_logging_init(); + if (caa_unlikely(current_log_level == LTTNG_UST_LOG_LEVEL_UNKNOWN)) { + lttng_ust_logging_init(); + current_log_level = CMM_LOAD_SHARED(lttng_ust_log_level); + } return current_log_level == LTTNG_UST_LOG_LEVEL_DEBUG; } #endif /* #ifdef LTTNG_UST_DEBUG */ +#ifdef LTTNG_UST_ABORT_ON_CRITICAL +static inline +bool lttng_ust_logging_abort_on_critical_enabled(void) +{ + return true; +} +#else /* #ifdef LTTNG_UST_ABORT_ON_CRITICAL */ +static inline +bool lttng_ust_logging_abort_on_critical_enabled(void) +{ + int current_log_critical_action; + + current_log_critical_action = CMM_LOAD_SHARED(lttng_ust_log_critical_action); + + /* If the global log critical action is unknown, lazy-initialize it. */ + if (caa_unlikely(current_log_critical_action == LTTNG_UST_LOG_CRITICAL_ACTION_UNKNOWN)) { + lttng_ust_logging_init(); + current_log_critical_action = CMM_LOAD_SHARED(lttng_ust_log_critical_action); + } + + return current_log_critical_action == LTTNG_UST_LOG_CRITICAL_ACTION_ABORT; +} +#endif /* #ifdef LTTNG_UST_ABORT_ON_CRITICAL */ + /* - * The default component for error messages. + * The default component for log statements. */ #ifndef UST_COMPONENT #define UST_COMPONENT libust @@ -113,7 +145,13 @@ do { \ #define DBG_raw(fmt, args...) sigsafe_print_err(fmt, ## args) #define WARN(fmt, args...) ERRMSG("Warning: " fmt, ## args) #define ERR(fmt, args...) ERRMSG("Error: " fmt, ## args) -#define BUG(fmt, args...) ERRMSG("BUG: " fmt, ## args) +#define CRIT(fmt, args...) \ + do { \ + ERRMSG("Critical: " fmt, ## args); \ + if (lttng_ust_logging_abort_on_critical_enabled()) { \ + abort(); \ + } \ + } while(0) #if !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE)) /* -- 2.34.1