blob: 9e7c36eaf5551db2403e9ca8f8a3a8050fec2563 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file
* @brief modlog - Module-mapped logging.
*
* The modlog facility allows log entries to be written to numeric modules
* identifiers. In typical usage, startup code maps 8-bit module IDs to one or
* more log objects, while other parts of the application log events by write
* entries to modules IDs. This usage differs from the underlying `sys/log`
* facility, which requires clients to provide a log object to write to
* rather than just a module identifier.
*
* Benefits provided by the modlog package are:
* o Improved modularity - configuration and usage are distinct.
* o Ability to write to several logs with a single function call. If one
* module ID is mapped to several logs, a write to that ID causes all
* mapped logs to be written.
* o Default mappings. Writes to unmapped module IDs get written to an
* optional set of default logs.
* o Minimum log level per mapping. Writes specifying a log level less
* than the module's minimum level are discarded.
*
* Costs of using modlog rather than the bare `sys/log` facility are:
* o Increased RAM usage (`MODLOG_MAX_MAPPINGS` * 12).
* o Increased CPU usage - each log write requires a lookup in the set
* of configured modlog mappings.
*/
#ifndef H_MODLOG_
#define H_MODLOG_
#include "os/mynewt.h"
#include "log/log.h"
#define MODLOG_MODULE_DFLT 255
/**
* @brief Modlog mapping descriptor.
*
* Describes an individual mapping of module ID to log.
*/
struct modlog_desc {
/** The log being mapped. */
struct log *log;
/** Unique identifier for this mapping. */
uint8_t handle;
/** The numeric module ID being mapped. */
uint8_t module;
/** Log writes with a level less than this are discarded. */
uint8_t min_level;
};
/** @typedef modlog_foreach_fn
* @brief Function applied to each modlog mapping during a `modlog_foreach`
* traversal.
*
* @param desc The modlog mapping to operate on.
* @param arg Optional user argument.
*
* @return 0 if the traversal should continue;
* nonzero to abort the traversal with the
* specified return code.
*/
typedef int modlog_foreach_fn(const struct modlog_desc *desc, void *arg);
/* Only enable modlog if logging is also enabled. */
#if MYNEWT_VAL(LOG_FULL) || defined(__DOXYGEN__)
/**
* @brief Retrieves the modlog mapping with the specified handle.
*
* @param handle The handle of the modlog mapping to retrieve.
* @param out_desc On success, the retrieved mapping is written
* here. Pass NULL if you do not reqire this
* information.
*
* @return 0 on success;
* SYS_ENOENT if no mapping with the specified
* handle exists;
* Other SYS_[...] error code on failure.
*/
int modlog_get(uint8_t handle, struct modlog_desc *out_desc);
/**
* @brief Registers a new modlog mapping.
*
* @param module The module to map to a log.
* @param log The log to map.
* @param min_level Subsequent writes to this mapping with a level
* less than this value are discarded.
* @param out_handle On success, the new mapping's handle gets
* written here. Pass NULL if you do not
* require this information.
*
* @return 0 on success;
* SYS_ENOMEM on memory exhaustion.
* Other SYS_[...] error on failure.
*/
int modlog_register(uint8_t module, struct log *log, uint8_t min_level,
uint8_t *out_handle);
/**
* @brief Deletes the configured modlog mapping with the specified handle.
*
* @param handle The handle of the mapping to delete.
*
* @return 0 on success;
* SYS_ENOENT if the specified handle is unmapped.
* Other SYS_[...] error on failure.
*/
int modlog_delete(uint8_t handle);
/**
* @brief Deletes all configured modlog mappings.
*/
void modlog_clear(void);
/**
* @brief Writes the contents of a flat buffer to the specified log module.
*
* @param module The log module to write to.
* @param level The severity of the log entry to write.
* @param etype The type of data being written; one of the
* `LOG_ETYPE_[...]` constants.
* @param data The flat buffer to write.
* @param len The number of bytes to write.
*
* @return 0 on success; nonzero on failure.
*/
int modlog_append(uint8_t module, uint8_t level, uint8_t etype,
void *data, uint16_t len);
/**
* @brief Writes the contents of an mbuf to the specified log module.
*
* @param module The log module to write to.
* @param level The severity of the log entry to write.
* @param etype The type of data being written; one of the
* `LOG_ETYPE_[...]` constants.
* @param om The mbuf to write.
*
* @return 0 on success; nonzero on failure.
*/
int modlog_append_mbuf(uint8_t module, uint8_t level, uint8_t etype,
struct os_mbuf *om);
/**
* @brief Applies a function to each configured modlog mapping.
*
* The callback is permitted to delete the mapping under operation. No other
* manipulations of the mapping list are allowed during the traversal.
*
* @param fn The function to apply to each modlog mapping.
* @param arg Optional argument to pass to the callback.
*
* @return 0 if the full iteration completed;
* nonzero if the callback aborted the iteration.
*/
int modlog_foreach(modlog_foreach_fn *fn, void *arg);
/**
* @brief Writes a formatted text entry to the specified log module.
*
* @param module The log module to write to.
* @param level The severity of the log entry to write.
* @param msg The "printf" formatted string to write.
*/
void modlog_printf(uint8_t module, uint8_t level, const char *msg, ...);
#else /* LOG_FULL */
static inline int
modlog_get(uint8_t handle, struct modlog_desc *out_desc)
{
return SYS_ENOTSUP;
}
static inline int
modlog_register(uint8_t module, struct log *log, uint8_t min_level,
uint8_t *out_handle)
{
return 0;
}
static inline int
modlog_delete(uint8_t handle)
{
return SYS_ENOTSUP;
}
static inline void
modlog_clear(void)
{ }
static inline int
modlog_append(uint8_t module, uint8_t level, uint8_t etype, void *data,
uint16_t len)
{
return 0;
}
static inline int
modlog_append_mbuf(uint8_t module, uint8_t level, uint8_t etype,
struct os_mbuf *om)
{
os_mbuf_free_chain(om);
return 0;
}
static inline int
modlog_foreach(modlog_foreach_fn *fn, void *arg)
{
return SYS_ENOTSUP;
}
static inline void
modlog_printf(uint8_t module, uint8_t level, const char *msg, ...)
{ }
#endif
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG || defined __DOXYGEN__
/**
* @brief Writes a formatted debug text entry to the specified log module.
*
* This expands to nothing if the global log level is greater than
* `LOG_LEVEL_DEBUG`.
*
* @param ml_mod_ The log module to write to.
* @param ml_msg_ The "printf" formatted string to write.
*/
#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \
modlog_printf((ml_mod_), LOG_LEVEL_DEBUG, (ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_DEBUG(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_INFO || defined __DOXYGEN__
/**
* @brief Writes a formatted info text entry to the specified log module.
*
* This expands to nothing if the global log level is greater than
* `LOG_LEVEL_INFO`.
*
* @param ml_mod_ The log module to write to.
* @param ml_msg_ The "printf" formatted string to write.
*/
#define MODLOG_INFO(ml_mod_, ml_msg_, ...) \
modlog_printf((ml_mod_), LOG_LEVEL_INFO, (ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_INFO(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_WARN || defined __DOXYGEN__
/**
* @brief Writes a formatted warn text entry to the specified log module.
*
* This expands to nothing if the global log level is greater than
* `LOG_LEVEL_WARN`.
*
* @param ml_mod_ The log module to write to.
* @param ml_msg_ The "printf" formatted string to write.
*/
#define MODLOG_WARN(ml_mod_, ml_msg_, ...) \
modlog_printf((ml_mod_), LOG_LEVEL_WARN, (ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_WARN(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_ERROR || defined __DOXYGEN__
/**
* @brief Writes a formatted error text entry to the specified log module.
*
* This expands to nothing if the global log level is greater than
* `LOG_LEVEL_ERROR`.
*
* @param ml_mod_ The log module to write to.
* @param ml_msg_ The "printf" formatted string to write.
*/
#define MODLOG_ERROR(ml_mod_, ml_msg_, ...) \
modlog_printf((ml_mod_), LOG_LEVEL_ERROR, (ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_ERROR(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_CRITICAL || defined __DOXYGEN__
/**
* @brief Writes a formatted critical text entry to the specified log module.
*
* This expands to nothing if the global log level is greater than
* `LOG_LEVEL_CRITICAL`.
*
* @param ml_mod_ The log module to write to.
* @param ml_msg_ The "printf" formatted string to write.
*/
#define MODLOG_CRITICAL(ml_mod_, ml_msg_, ...) \
modlog_printf((ml_mod_), LOG_LEVEL_CRITICAL, (ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_CRITICAL(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
/**
* @brief Writes a formatted text entry with the specified level to the
* specified log module.
*
* The provided log level must be one of the following tokens:
* o CRITICAL
* o ERROR
* o WARN
* o INFO
* o DEBUG
*
* This expands to nothing if the global log level is greater than
* the specified level.
*
* @param ml_lvl_ The log level of the entry to write.
* @param ml_mod_ The log module to write to.
*/
#define MODLOG(ml_lvl_, ml_mod_, ...) \
MODLOG_ ## ml_lvl_((ml_mod_), __VA_ARGS__)
/**
* @brief Writes a formatted text entry with the specified level to the
* default log module.
*
* The provided log level must be one of the following tokens:
* o CRITICAL
* o ERROR
* o WARN
* o INFO
* o DEBUG
*
* This expands to nothing if the global log level is greater than
* the specified level.
*
* @param ml_lvl_ The log level of the entry to write.
*/
#define MODLOG_DFLT(ml_lvl_, ...) \
MODLOG(ml_lvl_, LOG_MODULE_DEFAULT, __VA_ARGS__)
/* If `MODLOG_LOG_MACROS` in enabled, retire the old `LOG_[...]` macros and
* redefine them to use modlog.
*/
#if MYNEWT_VAL(MODLOG_LOG_MACROS)
#undef LOG_DEBUG
#define LOG_DEBUG MODLOG_DEBUG
#undef LOG_INFO
#define LOG_INFO MODLOG_INFO
#undef LOG_WARN
#define LOG_WARN MODLOG_WARN
#undef LOG_ERROR
#define LOG_ERROR MODLOG_ERROR
#undef LOG_CRITICAL
#define LOG_CRITICAL MODLOG_CRITICAL
#undef LOG_DFLT
#define LOG_DFLT MODLOG_DFLT
#endif
#endif