#ifndef BABELTRACE_LOGGING_INTERNAL_H
#define BABELTRACE_LOGGING_INTERNAL_H
+#include <stdlib.h>
+#include <stdio.h>
#include <babeltrace/logging.h>
+#include <babeltrace/babeltrace-internal.h>
/* To detect incompatible changes you can define BT_LOG_VERSION_REQUIRED to be
* the current value of BT_LOG_VERSION before including this file (or via
* compiler command line):
*
* #define BT_LOG_VERSION_REQUIRED 4
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* Compilation will fail when included file has different version.
*/
* before including bt_log.h:
*
* #define BT_LOG_LEVEL BT_LOG_VERBOSE
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* If both BT_LOG_DEF_LEVEL and BT_LOG_LEVEL are undefined, then BT_LOG_INFO
* will be used for release builds (NDEBUG is defined) and BT_LOG_DEBUG
* Example:
*
* #define BT_LOG_OUTPUT_LEVEL g_module_log_level
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
* static int g_module_log_level = BT_LOG_INFO;
* static void foo() {
* BT_LOGI("Will check g_module_log_level for output log level");
* must be the first field in this structure:
*
* #define BT_LOG_OUTPUT_LEVEL (g_config.log_level)
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
* struct config {
* int log_level;
* unsigned other_field;
#if defined(BT_LOG_OUTPUT_LEVEL)
#define _BT_LOG_OUTPUT_LEVEL BT_LOG_OUTPUT_LEVEL
#else
- #define _BT_LOG_OUTPUT_LEVEL _bt_log_global_output_lvl
+ /*
+ * We disallow this to make sure Babeltrace modules always
+ * have their own local log level.
+ */
+ #error No log level symbol specified: please define BT_LOG_OUTPUT_LEVEL before including this header.
#endif
/* "Tag" is a compound string that could be associated with a log message. It
* before including bt_log.h:
*
* #define BT_LOG_TAG "MAIN"
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* If both BT_LOG_DEF_TAG and BT_LOG_TAG are undefined no tag will be added to
* the log message (tag prefix still could be added though).
* before including bt_log.h:
*
* #define BT_LOG_SRCLOC BT_LOG_SRCLOC_NONE
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* If both BT_LOG_DEF_SRCLOC and BT_LOG_SRCLOC are undefined, then
* BT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and
* very careful not to push such temporary changes to source control):
*
* #define BT_LOG_CENSORING BT_LOG_UNCENSORED
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* If both BT_LOG_DEF_CENSORING and BT_LOG_CENSORING are undefined, then
* BT_LOG_CENSORED will be used for release builds (NDEBUG is defined) and
*
* For example, in log_config.c:
*
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
* BT_LOG_DEFINE_TAG_PREFIX = "MyApp";
* BT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
* BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback, 0};
* corresponding BT_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.
* Otherwise build will fail with link error (undefined symbol).
*/
-#define BT_LOG_DEFINE_TAG_PREFIX const char *_bt_log_tag_prefix
-#define BT_LOG_DEFINE_GLOBAL_FORMAT bt_log_format _bt_log_global_format
-#define BT_LOG_DEFINE_GLOBAL_OUTPUT bt_log_output _bt_log_global_output
-#define BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL int _bt_log_global_output_lvl
+#define BT_LOG_DEFINE_TAG_PREFIX BT_HIDDEN const char *_bt_log_tag_prefix
+#define BT_LOG_DEFINE_GLOBAL_FORMAT BT_HIDDEN bt_log_format _bt_log_global_format
+#define BT_LOG_DEFINE_GLOBAL_OUTPUT BT_HIDDEN bt_log_output _bt_log_global_output
+#define BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL BT_HIDDEN int _bt_log_global_output_lvl
/* Pointer to global format options. Direct modification is not allowed. Use
* bt_log_set_mem_width() instead. Could be used to initialize bt_log_spec
*
* // KittyHttpLogging.h
* #define BT_LOG_LIBRARY_PREFIX KittyHttp_
- * #include <babeltrace/log-internal.h>
+ * #include <babeltrace/logging-internal.h>
*
* Regardless of the method chosen, the end result is that bt_log symbols will
* be prefixed with "KittyHttp_", so if a user of KittyHttp (say DogeBrowser)
#endif
#if defined(__printflike)
- #define _BT_LOG_PRINTFLIKE(a, b) __printflike(a, b)
+ #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __printflike(str_index, first_to_check)
+#elif defined(__MINGW_PRINTF_FORMAT)
+ #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __attribute__((format(__MINGW_PRINTF_FORMAT, str_index, first_to_check)))
+#elif defined(__GNUC__)
+ #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+ __attribute__((format(__printf__, str_index, first_to_check)))
#else
- #define _BT_LOG_PRINTFLIKE(a, b)
+ #define _BT_LOG_PRINTFLIKE(str_index, first_to_check)
#endif
#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
* - BT_LOGE("format string", args, ...)
* - BT_LOGF("format string", args, ...)
*
+ * Message and error string (errno) logging macros:
+ * - BT_LOGV_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGD_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGI_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGW_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGE_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGF_ERRNO("initial message", "format string", args, ...)
+ *
* Memory logging macros:
* - BT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
* - BT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
} _BT_LOG_ONCE
#endif
+#define BT_LOG_WRITE_ERRNO(lvl, tag, _msg, _fmt, args...) \
+ do { \
+ const char *error_str; \
+ error_str = g_strerror(errno); \
+ BT_LOG_WRITE(lvl, tag, _msg ": %s" _fmt, error_str, ## args); \
+ } _BT_LOG_ONCE
+
static _BT_LOG_INLINE void _bt_log_unused(const int dummy, ...) {(void)dummy;}
#define _BT_LOG_UNUSED(...) \
#if BT_LOG_ENABLED_VERBOSE
#define BT_LOGV(...) \
BT_LOG_WRITE(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGV_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGV_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGV_MEM(d, d_sz, ...) \
#if BT_LOG_ENABLED_DEBUG
#define BT_LOGD(...) \
BT_LOG_WRITE(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGD_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGD_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGD_MEM(d, d_sz, ...) \
#if BT_LOG_ENABLED_INFO
#define BT_LOGI(...) \
BT_LOG_WRITE(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGI_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGI_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGI_MEM(d, d_sz, ...) \
#if BT_LOG_ENABLED_WARN
#define BT_LOGW(...) \
BT_LOG_WRITE(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGW_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGW_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGW_MEM(d, d_sz, ...) \
#if BT_LOG_ENABLED_ERROR
#define BT_LOGE(...) \
BT_LOG_WRITE(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGE_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGE_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGE_MEM(d, d_sz, ...) \
#if BT_LOG_ENABLED_FATAL
#define BT_LOGF(...) \
BT_LOG_WRITE(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
+ #define BT_LOGF_ERRNO(...) \
+ BT_LOG_WRITE_ERRNO(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGF_AUX(log, ...) \
BT_LOG_WRITE_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
#define BT_LOGF_MEM(d, d_sz, ...) \
* bt_log_set_output_v(BT_LOG_OUT_STDERR);
*/
enum { BT_LOG_OUT_STDERR_MASK = BT_LOG_PUT_STD };
+
+BT_HIDDEN
void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg);
#define BT_LOG_OUT_STDERR BT_LOG_OUT_STDERR_MASK, 0, bt_log_out_stderr_callback
*/
#define BT_LOG_STDERR (&_bt_log_stderr_spec)
+static inline
+int bt_log_get_level_from_env(const char *var)
+{
+ const char *varval = getenv(var);
+ int level = BT_LOG_NONE;
+
+ if (!varval) {
+ goto end;
+ }
+
+ if (strcmp(varval, "VERBOSE") == 0 ||
+ strcmp(varval, "V") == 0) {
+ level = BT_LOG_VERBOSE;
+ } else if (strcmp(varval, "DEBUG") == 0 ||
+ strcmp(varval, "D") == 0) {
+ level = BT_LOG_DEBUG;
+ } else if (strcmp(varval, "INFO") == 0 ||
+ strcmp(varval, "I") == 0) {
+ level = BT_LOG_INFO;
+ } else if (strcmp(varval, "WARN") == 0 ||
+ strcmp(varval, "WARNING") == 0 ||
+ strcmp(varval, "W") == 0) {
+ level = BT_LOG_WARN;
+ } else if (strcmp(varval, "ERROR") == 0 ||
+ strcmp(varval, "E") == 0) {
+ level = BT_LOG_ERROR;
+ } else if (strcmp(varval, "FATAL") == 0 ||
+ strcmp(varval, "F") == 0) {
+ level = BT_LOG_FATAL;
+ } else if (strcmp(varval, "NONE") == 0 ||
+ strcmp(varval, "N") == 0) {
+ level = BT_LOG_NONE;
+ } else {
+ /* Should we warn here? How? */
+ }
+
+end:
+ return level;
+}
+
+#define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym) \
+ extern int _level_sym
+
+#define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var) \
+ BT_HIDDEN int _level_sym = BT_LOG_NONE; \
+ static \
+ void __attribute__((constructor)) _bt_log_level_ctor(void) \
+ { \
+ _level_sym = bt_log_get_level_from_env(_env_var); \
+ }
+
#ifdef __cplusplus
}
#endif
-#endif
+#endif /* BABELTRACE_LOGGING_INTERNAL_H */