logging: Remove log.h including in headers limitation

Added macro trick which evaluates macro when used and not
when header file is included. After this change order of
defining LOG_LEVEL and including log.h is no longer fixed.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2018-07-19 09:50:35 +02:00 committed by Anas Nashif
commit c12fa740a2
4 changed files with 135 additions and 103 deletions

View file

@ -21,6 +21,12 @@ extern "C" {
* @{
*/
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERR 1
#define LOG_LEVEL_WRN 2
#define LOG_LEVEL_INF 3
#define LOG_LEVEL_DBG 4
/**
* @brief Writes an ERROR level message to the log.
*
@ -32,7 +38,6 @@ extern "C" {
*/
#define LOG_ERR(...) _LOG(LOG_LEVEL_ERR, __VA_ARGS__)
/**
* @brief Writes a WARNING level message to the log.
*
@ -242,37 +247,45 @@ extern "C" {
*/
int log_printk(const char *fmt, va_list ap);
/* Register a module unless explicitly skipped (using LOG_SKIP_MODULE_REGISTER).
* Skipping may be used in 2 cases:
#define __DYNAMIC_MODULE_REGISTER(_name)\
struct log_source_dynamic_data LOG_ITEM_DYNAMIC_DATA(_name) \
__attribute__ ((section("." STRINGIFY( \
LOG_ITEM_DYNAMIC_DATA(_name)))) \
) \
__attribute__((used))
#define _LOG_RUNTIME_MODULE_REGISTER(_name) \
_LOG_EVAL( \
CONFIG_LOG_RUNTIME_FILTERING, \
(; __DYNAMIC_MODULE_REGISTER(_name)), \
()\
)
#define _LOG_MODULE_REGISTER(_name, level) \
const struct log_source_const_data LOG_ITEM_CONST_DATA(_name) \
__attribute__ ((section("." STRINGIFY(LOG_ITEM_CONST_DATA(_name))))) \
__attribute__((used)) = { \
.name = STRINGIFY(_name) \
} \
_LOG_RUNTIME_MODULE_REGISTER(_name)
/** @brief Macro for registering a module.
*
* Module registration can be skipped in two cases:
* - Module consists of more than one file and must be registered only by one
* file.
* - Instance logging is used and there is no need to create module entry.
*
* @note Module is registered only if LOG_LEVEL for given module is non-zero or
* it is not defined and CONFIG_LOG_DEFAULT_LOG_LEVEL is non-zero.
*/
#if LOG_MODULE_PRESENT
#if CONFIG_LOG_RUNTIME_FILTERING
#define LOG_MODULE_REGISTER() \
_LOG_CONST_ITEM_REGISTER(LOG_MODULE_NAME, \
STRINGIFY(LOG_MODULE_NAME), \
_LOG_RESOLVED_LEVEL(LOG_LEVEL, \
CONFIG_LOG_DEFAULT_LEVEL)); \
struct log_source_dynamic_data LOG_ITEM_DYNAMIC_DATA(LOG_MODULE_NAME) \
__attribute__ ((section("." STRINGIFY( \
LOG_ITEM_DYNAMIC_DATA(LOG_MODULE_NAME)))) \
) \
__attribute__((used))
#else /*CONFIG_LOG_RUNTIME_FILTERING*/
#define LOG_MODULE_REGISTER() \
_LOG_CONST_ITEM_REGISTER(LOG_MODULE_NAME, \
STRINGIFY(LOG_MODULE_NAME), \
_LOG_RESOLVED_LEVEL(LOG_LEVEL, \
CONFIG_LOG_DEFAULT_LEVEL))
#endif /*CONFIG_LOG_RUNTIME_FILTERING*/
#else /* LOG_MODULE_PRESENT */
#define LOG_MODULE_REGISTER() /* Empty */
#endif /* LOG_MODULE_PRESENT */
#define LOG_MODULE_REGISTER() \
_LOG_EVAL( \
_LOG_LEVEL(), \
(_LOG_MODULE_REGISTER(LOG_MODULE_NAME, _LOG_LEVEL())), \
()/*Empty*/ \
)
/**
* @}

View file

@ -14,28 +14,12 @@
extern "C" {
#endif
#ifndef CONFIG_LOG_DEFAULT_LEVEL
#define CONFIG_LOG_DEFAULT_LEVEL LOG_LEVEL_NONE
#endif
#ifndef CONFIG_LOG_MAX_LEVEL
#define CONFIG_LOG_MAX_LEVEL LOG_LEVEL_NONE
#endif
#if !CONFIG_LOG
#define CONFIG_LOG_DEFAULT_LEVEL 0
#define CONFIG_LOG_DOMAIN_ID 0
#define LOG_LEVEL_BITS 3
/* Conditions determining if logger is used in a module on any level. */
#if CONFIG_LOG && \
((defined(LOG_LEVEL) && LOG_LEVEL) || \
(!defined(LOG_LEVEL) && CONFIG_LOG_DEFAULT_LEVEL))
#define LOG_MODULE_PRESENT 1
#else
#define LOG_MODULE_PRESENT 0
#define CONFIG_LOG_MAX_LEVEL 0
#endif
/** @brief Macro for returning local level value if defined or default.
*
* Check @ref IS_ENABLED macro for detailed explanation of the trick.
@ -53,10 +37,46 @@ extern "C" {
#define _LOG_XXXX4 _LOG_YYYY,
#define __LOG_RESOLVED_LEVEL2(one_or_two_args, _level, _default) \
__LOG_RESOLVED_LEVEL3(one_or_two_args _level, _default)
__LOG_ARG_2(one_or_two_args _level, _default)
#define __LOG_RESOLVED_LEVEL3(ignore_this, val, ...) val
#define LOG_DEBRACKET(x) x
#define __LOG_ARG_2(ignore_this, val, ...) val
#define __LOG_ARG_2_DEBRACKET(ignore_this, val, ...) LOG_DEBRACKET val
/**
* @brief Macro for conditional code generation if provided log level allows.
*
* Macro behaves similarly to standard #if #else #endif clause. The difference is
* that it is evaluated when used and not when header file is included.
*
* @param _eval_level Evaluated level. If level evaluates to one of existing log
* log level (1-4) then macro evaluates to _iftrue.
* @param _iftrue Code that should be inserted when evaluated to true. Note,
* that parameter must be provided in brackets.
* @param _iffalse Code that should be inserted when evaluated to false.
* Note, that parameter must be provided in brackets.
*/
#define _LOG_EVAL(_eval_level, _iftrue, _iffalse) \
_LOG_EVAL1(_eval_level, _iftrue, _iffalse)
#define _LOG_EVAL1(_eval_level, _iftrue, _iffalse) \
_LOG_EVAL2(_LOG_ZZZZ##_eval_level, _iftrue, _iffalse)
#define _LOG_ZZZZ1 _LOG_YYYY,
#define _LOG_ZZZZ2 _LOG_YYYY,
#define _LOG_ZZZZ3 _LOG_YYYY,
#define _LOG_ZZZZ4 _LOG_YYYY,
#define _LOG_EVAL2(one_or_two_args, _iftrue, _iffalse) \
__LOG_ARG_2_DEBRACKET(one_or_two_args _iftrue, _iffalse)
/** @brief Macro for getting log level for given module.
*
* It is evaluated to LOG_LEVEL if defined. Otherwise CONFIG_LOG_DEFAULT_LEVEL
* is used.
*/
#define _LOG_LEVEL() _LOG_RESOLVED_LEVEL(LOG_LEVEL, CONFIG_LOG_DEFAULT_LEVEL)
/**
* @def LOG_CONST_ID_GET
@ -64,41 +84,45 @@ extern "C" {
*
* @param _addr Address of the element.
*/
#define LOG_CONST_ID_GET(_addr) \
_LOG_EVAL( \
_LOG_LEVEL(), \
(log_const_source_id((const struct log_source_const_data *)_addr)), \
(0) \
)
/**
* @def LOG_CURRENT_MODULE_ID
* @brief Macro for getting ID of current module.
*/
#define LOG_CURRENT_MODULE_ID() \
_LOG_EVAL( \
_LOG_LEVEL(), \
(log_const_source_id(&LOG_ITEM_CONST_DATA(LOG_MODULE_NAME))), \
(0) \
)
/**
* @def LOG_CURRENT_DYNAMIC_DATA_ADDR
* @brief Macro for getting address of dynamic structure of current module.
*/
#if LOG_MODULE_PRESENT
#define LOG_CONST_ID_GET(_addr) \
log_const_source_id((const struct log_source_const_data *)_addr)
#define LOG_CURRENT_MODULE_ID() \
log_const_source_id(&LOG_ITEM_CONST_DATA(LOG_MODULE_NAME))
#define LOG_CURRENT_DYNAMIC_DATA_ADDR() \
(&LOG_ITEM_DYNAMIC_DATA(LOG_MODULE_NAME))
#else /* LOG_MODULE_PRESENT */
#define LOG_CONST_ID_GET(_addr) 0
#define LOG_CURRENT_MODULE_ID() 0
#define LOG_CURRENT_DYNAMIC_DATA_ADDR() ((struct log_source_dynamic_data *)0)
#endif /* LOG_MODULE_PRESENT */
#define LOG_CURRENT_DYNAMIC_DATA_ADDR() \
_LOG_EVAL( \
_LOG_LEVEL(), \
(&LOG_ITEM_DYNAMIC_DATA(LOG_MODULE_NAME)), \
((struct log_source_dynamic_data *)0) \
)
/** @brief Macro for getting ID of the element of the section.
*
* @param _addr Address of the element.
*/
#if LOG_MODULE_PRESENT
#define LOG_DYNAMIC_ID_GET(_addr) \
log_dynamic_source_id((struct log_source_dynamic_data *)_addr)
#else
#define LOG_DYNAMIC_ID_GET(_addr) 0
#endif
#define LOG_DYNAMIC_ID_GET(_addr) \
_LOG_EVAL( \
_LOG_LEVEL(), \
(log_dynamic_source_id((struct log_source_dynamic_data *)_addr)), \
(0) \
)
/******************************************************************************/
/****************** Internal macros for log frontend **************************/
@ -166,23 +190,22 @@ extern "C" {
/******************************************************************************/
/****************** Macros for standard logging *******************************/
/******************************************************************************/
#define __LOG(_level, _id, _filter, ...) \
do { \
if (_LOG_CONST_LEVEL_CHECK(_level) && \
(_level <= LOG_RUNTIME_FILTER(_filter))) { \
struct log_msg_ids src_level = { \
.level = _level, \
.source_id = _id, \
.domain_id = CONFIG_LOG_DOMAIN_ID \
}; \
__LOG_INTERNAL(src_level, __VA_ARGS__); \
} else { \
/* arg checker evaluated when log is filtered out \
* to ensure that __VA_ARGS__ are evaluated only \
* once giving always same side effects. \
*/ \
log_printf_arg_checker(__VA_ARGS__); \
} \
#define __LOG(_level, _id, _filter, ...) \
do { \
if (_LOG_CONST_LEVEL_CHECK(_level) && \
(_level <= LOG_RUNTIME_FILTER(_filter))) { \
struct log_msg_ids src_level = { \
.level = _level, \
.source_id = _id, \
.domain_id = CONFIG_LOG_DOMAIN_ID \
}; \
__LOG_INTERNAL(src_level, __VA_ARGS__); \
} else { \
/* arg checker evaluated when log is filtered out */\
/* to ensure that __VA_ARGS__ are evaluated only */ \
/* once giving always same side effects.*/ \
log_printf_arg_checker(__VA_ARGS__); \
} \
} while (0)
#define _LOG(_level, ...) \
@ -235,6 +258,9 @@ extern "C" {
/****************** Filtering macros ******************************************/
/******************************************************************************/
/** @brief Number of bits used to encode log level. */
#define LOG_LEVEL_BITS 3
/** @brief Filter slot size. */
#define LOG_FILTER_SLOT_SIZE LOG_LEVEL_BITS

View file

@ -12,12 +12,6 @@
extern "C" {
#endif
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERR 1
#define LOG_LEVEL_WRN 2
#define LOG_LEVEL_INF 3
#define LOG_LEVEL_DBG 4
/** @brief Constant data associated with the source of log messages. */
struct log_source_const_data {
const char *name;