v2/inc/c_logging/logger.h (93 lines of code) (raw):

// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #ifndef LOGGER_H #define LOGGER_H #ifdef __cplusplus #include <cstdio> #else #include <stdio.h> #endif #include "c_logging/log_context.h" #include "c_logging/log_level.h" #include "c_logging/log_sink_if.h" #include "c_logging/logger_v1_v2.h" // for convenience let's include log_lasterror too on Windows #if WIN32 #include "c_logging/log_lasterror.h" // IWYU pragma: keep #include "c_logging/log_hresult.h" // IWYU pragma: keep #endif #include "c_logging/log_errno.h" #define LOG_MAX_MESSAGE_LENGTH 4096 /*in bytes - a message is not expected to exceed this size in bytes, if it does, only LOG_MAX_MESSAGE_LENGTH characters are retained*/ #ifdef __cplusplus extern "C" { #endif extern uint32_t log_sink_count; extern const LOG_SINK_IF** log_sinks; typedef struct LOGGER_CONFIG_TAG { uint32_t log_sink_count; const LOG_SINK_IF** log_sinks; } LOGGER_CONFIG; /*a format specifier that can be used in printf function family to print the values behind a LOGGER_CONFIG, like printf("logger config is %" PRI_LOGGER_CONFIG "\n", LOGGER_CONFIG_VALUES(logger_config));*/ #define PRI_LOGGER_CONFIG "s(LOGGER_CONFIG){.log_sinks=%p, .log_sink_count=%" PRIu32 "}" /*a macro expanding to the 2 fields in the LOGGER_CONFIG structure*/ #define LOGGER_CONFIG_VALUES(logger_config) \ "", \ (logger_config).log_sinks, \ (logger_config).log_sink_count \ int logger_init(void); void logger_deinit(void); LOGGER_CONFIG logger_get_config(void); void logger_set_config(LOGGER_CONFIG new_config); void logger_log(LOG_LEVEL log_level, LOG_CONTEXT_HANDLE log_context, const char* file, const char* func, int line_no, const char* format, ...); void logger_log_with_config(LOGGER_CONFIG logger_config, LOG_LEVEL log_level, LOG_CONTEXT_HANDLE log_context, const char* file, const char* func, int line_no, const char* format, ...); #define LOGGER_FORMATTING_SYNTAX_CHECK(format, ...) \ do \ { \ (void)(0 && printf(format MU_IFCOMMALOGIC(MU_COUNT_ARG(__VA_ARGS__)) __VA_ARGS__)); \ } while (0) \ #define LOGGER_LOG(log_level, log_context, format, ...) \ do \ { \ /* Codes_SRS_LOGGER_01_023: [ LOGGER_LOG shall generate code that verifies at compile time that format and ... are suitable to be passed as arguments to printf. ] */ \ LOGGER_FORMATTING_SYNTAX_CHECK(format, __VA_ARGS__); \ logger_log(log_level, log_context, __FILE__, __FUNCTION__, __LINE__, format MU_IFCOMMALOGIC(MU_COUNT_ARG(__VA_ARGS__)) __VA_ARGS__); \ } while (0) #define LOGGER_LOG_WITH_CONFIG(logger_config, log_level, log_context, format, ...) \ do \ { \ /* Codes_SRS_LOGGER_01_024: [ LOGGER_LOG_WITH_CONFIG shall generate code that verifies at compile time that format and ... are suitable to be passed as arguments to printf. ] */ \ LOGGER_FORMATTING_SYNTAX_CHECK(format, __VA_ARGS__); \ logger_log_with_config((logger_config), log_level, log_context, __FILE__, __FUNCTION__, __LINE__, format MU_IFCOMMALOGIC(MU_COUNT_ARG(__VA_ARGS__)) __VA_ARGS__); \ } while (0) /* Codes_SRS_LOGGER_01_012: [ If LOG_CONTEXT_MESSAGE is specified in ..., message_format shall be passed to the log call together with a argument list made out of the ... portion of the LOG_CONTEXT_MESSAGE macro. ] */ #define EXPAND_MESSAGE_LOG_MESSAGE(...) \ __VA_ARGS__ #define EXPAND_MESSAGE_LOG_CONTEXT_PROPERTY(...) \ #define EXPAND_MESSAGE_LOG_CONTEXT_PROPERTY_CUSTOM_FUNCTION(...) \ #define EXPAND_MESSAGE_LOG_CONTEXT_STRING_PROPERTY(...) \ #define EXPAND_MESSAGE(A) MU_C2(EXPAND_MESSAGE_, A) #define HAS_ANY_PROPERTIES_LOG_MESSAGE(...) \ #define HAS_ANY_PROPERTIES_LOG_CONTEXT_PROPERTY(...) \ + 1 #define HAS_ANY_PROPERTIES_LOG_CONTEXT_STRING_PROPERTY(...) \ + 1 #define HAS_ANY_PROPERTIES(A) MU_C2(HAS_ANY_PROPERTIES_, A) #define LOGGER_LOG_EX(log_level, ...) \ MU_IF(MU_COUNT_ARG(__VA_ARGS__), \ do { \ MU_IF(MU_COUNT_ARG(MU_FOR_EACH_1(HAS_ANY_PROPERTIES, __VA_ARGS__)), \ { \ /* Codes_SRS_LOGGER_01_010: [ Otherwise, LOGGER_LOG_EX shall construct a log context with all the properties specified in .... ] */ \ /* Codes_SRS_LOGGER_01_011: [ Each LOG_CONTEXT_STRING_PROPERTY and LOG_CONTEXT_PROPERTY entry in ... shall be added as a property in the context that is passed to log. ] */ \ LOG_CONTEXT_LOCAL_DEFINE(local_context_3DFCB6F0_39A4_4C45_881B_A3BDA8B18CC1, NULL, __VA_ARGS__); \ /* Codes_SRS_LOGGER_01_008: [ LOGGER_LOG_EX shall call the log function of every sink that is configured to be used. ]*/ \ logger_log(log_level, &local_context_3DFCB6F0_39A4_4C45_881B_A3BDA8B18CC1, __FILE__, __FUNCTION__, __LINE__, MU_IF(MU_COUNT_ARG(MU_FOR_EACH_1(EXPAND_MESSAGE, __VA_ARGS__)),, "") MU_FOR_EACH_1(EXPAND_MESSAGE, __VA_ARGS__)); \ } \ , \ /* Codes_SRS_LOGGER_01_009: [ If no properties are specified in ..., LOGGER_LOG_EX shall call log with log_context being NULL. ] */ \ logger_log(log_level, NULL, __FILE__, __FUNCTION__, __LINE__, MU_IF(MU_COUNT_ARG(MU_FOR_EACH_1(EXPAND_MESSAGE, __VA_ARGS__)), , "") MU_FOR_EACH_1(EXPAND_MESSAGE, __VA_ARGS__)); \ ) \ } while (0); \ , \ /* Codes_SRS_LOGGER_01_009: [ If no properties are specified in ..., LOGGER_LOG_EX shall call log with log_context being NULL. ] */ \ logger_log(log_level, NULL, __FILE__, __FUNCTION__, __LINE__, ""); \ ) #ifdef __cplusplus } #endif #endif /* LOGGER_H */