Logging

Mynewt log package supports logging of information within a Mynewt application. It allows packages to define their own log streams with separate names. It also allows an application to control the output destination of logs.

Description

In the Mynewt OS, the log package comes in two versions:

  • The sys/log/full package implements the complete log functionality and API.

  • The sys/log/stub package implements stubs for the API.

Both packages export the log API, and any package that uses the log API must list log as a requirement in its pkg.yml file as follows:

pkg.req_apis:
    - log

The application’s pkg.yml file specifies the version of the log package to use. A project that requires the full logging capability must list the sys/log/full package as a dependency in its pkg.yml file:

pkg.deps:
    - "@apache-mynewt-core/sys/log/full"

You can use the sys/log/stub package if you want to build your application without logging to reduce code size.

Syscfg Settings

The LOG_LEVEL syscfg setting allows you to specify the level of logs to enable in your application. Only logs for levels higher or equal to the value of LOG_LEVEL are enabled. The amount of logs you include affects your application code size. LOG_LEVEL: 0 specifies LOG_LEVEL_DEBUG and includes all logs. You set LOG_LEVEL: 255 to disable all logging. The #defines for the log levels are specified in the sys/log/full/include/log/log.h file. For example the following setting corresponds to LOG_LEVEL_ERROR:

syscfg.vals:
    LOG_LEVEL: 3

The LOG_LEVEL setting applies to all modules registered with the log package.

Log

Each log stream requires a log structure to define its logging properties.

Log Handler

To use logs, a log handler that handles the I/O from the log is required. The log package comes with three pre-built log handlers:

  • console – streams log events directly to the console port. Does not support walking and reading.

  • cbmem – writes/reads log events to a circular buffer. Supports walking and reading for access by newtmgr and shell commands.

  • fcb – writes/reads log events to a flash circular buffer. Supports walking and reading for access by newtmgr and shell commands.

In addition, it is possible to create custom log handlers for other methods. Examples may include

  • Flash file system

  • Flat flash buffer

  • Streamed over some other interface

To use logging, you typically do not need to create your own log handler. You can use one of the pre-built ones.

A package or an application must define a variable of type struct log and register a log handler for it with the log package. It must call the log_register() function to specify the log handler to use:

log_register(char *name, struct log *log, const struct log_handler *lh, void *arg, uint8_t level)

The parameters are:

  • name- Name of the log stream.

  • log - Log instance to register,

  • lh - Pointer to the log handler. You can specify one of the pre-built ones:

    • &log_console_handler for console

    • &log_cbm_handler for circular buffer

    • &log_fcb_handler for flash circular buffer

  • arg - Opaque argument that the specified log handler uses. The value of this argument depends on the log handler you specify:

    • NULL for the log_console_handler.

    • Pointer to an initialized cbmem structure (see util/cbmem package) for the log_cbm_handler.

    • Pointer to an initialized fcb_log structure (see fs/fcb package) for the log_fcb_handler.

Typically, a package that uses logging defines a global variable, such as my_package_log, of type struct log. The package can call the log_register() function with default values, but usually an application will override the logging properties and where to log to. There are two ways a package can allow an application to override the values:

  • Define system configuration settings that an application can set and the package can then call the log_register() function with the configuration values.

  • Make the my_package_log variable external and let the application call the log_register() function to specify a log handler for its specific purpose.

Configuring Logging for Packages that an Application Uses

Here is an example of how an application can set the log handlers for the logs of the packages that the application includes.

In this example, the package1 package defines the variable package1_log of type struct log and externs the variable. Similarly, the package2 package defines the variable package2_log and externs the variable. The application sets logs for package1 to use console and sets logs for package2 to use a circular buffer.

#include <package1/package1.h>
#include <package2/package2.h>
#include <util/cbmem.h>

#include <log/log.h>

static uint32_t cbmem_buf[MAX_CBMEM_BUF];
static struct cbmem cbmem;


void app_log_init(void)
{



    log_register("package1_log", &package1_log, &log_console_handler, NULL, LOG_SYSLEVEL);

    cbmem_init(&cbmem, cbmem_buf, MAX_CBMEM_BUF);
    log_register("package2_log", &package2_log, &log_cbmem_handler, &cbmem, LOG_SYSLEVEL);

}

Implementing a Package that Uses Logging

This example shows how a package logs to console. The package registers default logging properties to use the console, but allows an application to override the values. It defines the my_package_log variable and makes it external so an application can override log handler.

Make the my_package_log variable external:

/* my_package.h*/

/* pick a unique name here */
extern struct log my_package_log;

Define the my_package_log variable and register the console log handler:

/* my_package.c */

struct log my_package_log;

{
    ...

    /* register my log with a name to the system */
    log_register("log", &my_package_log, &log_console_handler, NULL, LOG_LEVEL_DEBUG);

    LOG_DEBUG(&my_package_log, LOG_MODULE_DEFAULT, "bla");
    LOG_DEBUG(&my_package_log, LOG_MODULE_DEFAULT, "bab");
}

Log API and Log Levels

Defines

LOG_ENTRY_HDR_SIZE
LOG_MODULE_STR(module)
LOG_DEBUG(__l, __mod, ...)
LOG_INFO(__l, __mod, ...)
LOG_WARN(__l, __mod, ...)
LOG_ERROR(__l, __mod, ...)
LOG_CRITICAL(__l, __mod, ...)
LOG_STATS_INC(log, name)
LOG_STATS_INCN(log, name, cnt)

Typedefs

typedef int (*log_walk_func_t)(struct log*, struct log_offset *log_offset, void *dptr, uint16_t len)
typedef int (*log_walk_body_func_t)(struct log *log, struct log_offset *log_offset, const struct log_entry_hdr *hdr, void *dptr, uint16_t len)
typedef int (*lh_read_func_t)(struct log*, void *dptr, void *buf, uint16_t offset, uint16_t len)
typedef int (*lh_read_mbuf_func_t)(struct log*, void *dptr, struct os_mbuf *om, uint16_t offset, uint16_t len)
typedef int (*lh_append_func_t)(struct log*, void *buf, int len)
typedef int (*lh_append_body_func_t)(struct log *log, const struct log_entry_hdr *hdr, const void *body, int body_len)
typedef int (*lh_append_mbuf_func_t)(struct log*, const struct os_mbuf *om)
typedef int (*lh_append_mbuf_body_func_t)(struct log *log, const struct log_entry_hdr *hdr, const struct os_mbuf *om)
typedef int (*lh_walk_func_t)(struct log*, log_walk_func_t walk_func, struct log_offset *log_offset)
typedef int (*lh_flush_func_t)(struct log*)
typedef int (*lh_storage_info_func_t)(struct log*, struct log_storage_info*)
typedef int (*lh_set_watermark_func_t)(struct log*, uint32_t)
typedef int (*lh_registered_func_t)(struct log*)

Functions

void log_init(void)
struct log *log_list_get_next(struct log*)
uint8_t log_module_register(uint8_t id, const char *name)
const char *log_module_get_name(uint8_t id)
int log_register(char *name, struct log *log, const struct log_handler*, void *arg, uint8_t level)
void log_set_append_cb(struct log *log, log_append_cb *cb)

Configures the given log with the specified append callback.

A log’s append callback is executed each time an entry is appended to the log.

Parameters
  • log: The log to configure.

  • cb: The callback to associate with the log.

struct log *log_find(const char *name)

Searches the list of registered logs for one with the specified name.

Return

The sought after log if found, NULL otherwise.

Parameters
  • name: The name of the log to search for.

int log_append_typed(struct log *log, uint8_t module, uint8_t level, uint8_t etype, void *data, uint16_t len)

Writes the raw contents of a flat buffer to the specified log.

NOTE: The flat buffer must have an initial padding of length LOG_ENTRY_HDR_SIZE. This padding is not reflected in the specified length. So, to log the string “abc”, you should pass the following arguments to this function:

data: <padding>abc   (total of `LOG_ENTRY_HDR_SIZE`+3 bytes.)
len: 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The log module of the entry to write.

  • level: The severity of the log entry to write.

  • etype: The type of data being written; one of the LOG_ETYPE_[...] constants.

  • data: The flat buffer to write.

  • len: The number of bytes in the message body.

int log_append_mbuf_typed_no_free(struct log *log, uint8_t module, uint8_t level, uint8_t etype, struct os_mbuf **om_ptr)

Logs the contents of the provided mbuf, only freeing the mbuf on failure.

Logs the contents of the provided mbuf, only freeing the mbuf on failure. On success, the mbuf remains allocated, but its structure may have been modified by pullup operations. The updated mbuf address is passed back to the caller via a write to the supplied mbuf pointer-to-pointer.

NOTE: The mbuf must have an initial padding of length LOG_ENTRY_HDR_SIZE. So, to log the string “abc”, you should pass an mbuf with the following characteristics:

om_data: <padding>abc
om_len: `LOG_ENTRY_HDR_SIZE` + 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • etype: The type of data to write; one of the LOG_ETYPE_[...] constants.

  • om_ptr: Indirectly points to the mbuf to write. This function updates the mbuf address if it changes.

int log_append_mbuf_typed(struct log *log, uint8_t module, uint8_t level, uint8_t etype, struct os_mbuf *om)

Logs the contents of the provided mbuf.

Logs the contents of the provided mbuf. This function always frees the mbuf regardless of the outcome.

NOTE: The mbuf must have an initial padding of length LOG_ENTRY_HDR_SIZE. So, to log the string “abc”, you should pass an mbuf with the following characteristics:

om_data: <padding>abc
om_len: `LOG_ENTRY_HDR_SIZE` + 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • etype: The type of data to write; one of the LOG_ETYPE_[...] constants.

  • om: The mbuf to write.

int log_append_body(struct log *log, uint8_t module, uint8_t level, uint8_t etype, const void *body, uint16_t body_len)

Writes the contents of a flat buffer to the specified log.

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The log module of the entry to write.

  • level: The severity of the log entry to write.

  • etype: The type of data being written; one of the LOG_ETYPE_[...] constants.

  • data: The flat buffer to write.

  • len: The number of bytes in the message body.

int log_append_mbuf_body_no_free(struct log *log, uint8_t module, uint8_t level, uint8_t etype, struct os_mbuf *om)

Logs the contents of the provided mbuf, only freeing the mbuf on failure.

Logs the contents of the provided mbuf, only freeing the mbuf on failure. On success, the mbuf remains allocated, but its structure may have been modified by pullup operations. The updated mbuf address is passed back to the caller via a write to the supplied mbuf pointer-to-pointer.

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • etype: The type of data to write; one of the LOG_ETYPE_[...] constants.

  • om_ptr: Indirectly points to the mbuf to write. This function updates the mbuf address if it changes.

int log_append_mbuf_body(struct log *log, uint8_t module, uint8_t level, uint8_t etype, struct os_mbuf *om)

Logs the contents of the provided mbuf.

Logs the contents of the provided mbuf. This function always frees the mbuf regardless of the outcome.

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • etype: The type of data to write; one of the LOG_ETYPE_[...] constants.

  • om: The mbuf to write.

struct log *log_console_get(void)
void log_console_init(void)
static inline int log_append(struct log *log, uint8_t module, uint8_t level, void *data, uint16_t len)

Writes the raw contents of a flat buffer to the specified log.

NOTE: The flat buffer must have an initial padding of length LOG_ENTRY_HDR_SIZE. This padding is not reflected in the specified length. So, to log the string “abc”, you should pass the following arguments to this function:

data: <padding>abc   (total of `LOG_ENTRY_HDR_SIZE`+3 bytes.)
len: 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The log module of the entry to write.

  • level: The severity of the log entry to write.

  • data: The flat buffer to write.

  • len: The number of byte in the message body.

static inline int log_append_mbuf_no_free(struct log *log, uint8_t module, uint8_t level, struct os_mbuf **om)

Logs the contents of the provided mbuf, only freeing the mbuf on failure.

Logs the contents of the provided mbuf, only freeing the mbuf on failure. On success, the mbuf remains allocated, but its structure may have been modified by pullup operations. The updated mbuf address is passed back to the caller via a write to the supplied mbuf pointer-to-pointer.

NOTE: The mbuf must have an initial padding of length LOG_ENTRY_HDR_SIZE. So, to log the string “abc”, you should pass an mbuf with the following characteristics:

om_data: <padding>abc
om_len: `LOG_ENTRY_HDR_SIZE` + 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • om_ptr: Indirectly points to the mbuf to write. This function updates the mbuf address if it changes.

static inline int log_append_mbuf(struct log *log, uint8_t module, uint8_t level, struct os_mbuf *om)

Logs the contents of the provided mbuf.

Logs the contents of the provided mbuf. This function always frees the mbuf regardless of the outcome.

NOTE: The mbuf must have an initial padding of length LOG_ENTRY_HDR_SIZE. So, to log the string “abc”, you should pass an mbuf with the following characteristics:

om_data: <padding>abc
om_len: `LOG_ENTRY_HDR_SIZE` + 3

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to write to.

  • module: The module ID of the entry to write.

  • level: The severity of the entry to write; one of the LOG_LEVEL_[...] constants.

  • om: The mbuf to write.

void log_printf(struct log *log, uint8_t module, uint8_t level, const char *msg, ...)
int log_read(struct log *log, void *dptr, void *buf, uint16_t off, uint16_t len)
int log_read_hdr(struct log *log, void *dptr, struct log_entry_hdr *hdr)

Reads a single log entry header.

Return

0 on success; nonzero on failure.

Parameters
  • log: The log to read from.

  • dptr: Medium-specific data describing the area to read from; typically obtained by a call to log_walk.

  • hdr: The destination header to read into.

int log_read_body(struct log *log, void *dptr, void *buf, uint16_t off, uint16_t len)

Reads data from the body of a log entry into a flat buffer.

Return

The number of bytes actually read on success; -1 on failure.

Parameters
  • log: The log to read from.

  • dptr: Medium-specific data describing the area to read from; typically obtained by a call to log_walk.

  • buf: The destination buffer to read into.

  • off: The offset within the log entry at which to start the read.

  • len: The number of bytes to read.

int log_read_mbuf(struct log *log, void *dptr, struct os_mbuf *om, uint16_t off, uint16_t len)
int log_read_mbuf_body(struct log *log, void *dptr, struct os_mbuf *om, uint16_t off, uint16_t len)

Reads data from the body of a log entry into an mbuf.

Return

The number of bytes actually read on success; -1 on failure.

Parameters
  • log: The log to read from.

  • dptr: Medium-specific data describing the area to read from; typically obtained by a call to log_walk.

  • om: The destination mbuf to read into.

  • off: The offset within the log entry at which to start the read.

  • len: The number of bytes to read.

int log_walk(struct log *log, log_walk_func_t walk_func, struct log_offset *log_offset)
int log_walk_body(struct log *log, log_walk_body_func_t walk_body_func, struct log_offset *log_offset)

Applies a callback to each message in the specified log.

Similar to log_walk, except it passes the message header and body separately to the callback.

Return

0 if the walk completed successfully; nonzero on error or if the walk was aborted.

Parameters
  • log: The log to iterate.

  • walk_body_func: The function to apply to each log entry.

  • log_offset: Specifies the range of entries to process. Entries not matching these criteria are skipped during the walk.

int log_flush(struct log *log)
uint8_t log_level_get(uint8_t module)

Retrieves the globally configured minimum log level for the specified module ID.

Writes with a level less than the module’s minimum level are discarded.

Return

The configured minimum level, or 0 (LOG_LEVEL_DEBUG) if unconfigured.

Parameters
  • module: The module whose level should be retrieved.

int log_level_set(uint8_t module, uint8_t level)

Sets the globally configured minimum log level for the specified module ID.

Writes with a level less than the module’s minimum level are discarded.

Parameters
  • module: The module to configure.

  • level: The minimum level to assign to the module (0-15, inclusive).

int log_storage_info(struct log *log, struct log_storage_info *info)

Return information about log storage.

This return information about size and usage of storage on top of which log instance is created.

Return

0 on success, error code otherwise

Parameters
  • log: The log to query.

  • info: The destination to write information to.

int log_set_watermark(struct log *log, uint32_t index)

Set watermark on log.

This sets watermark on log item with given index. This information is used to calculate size of entries which were logged after watermark item, i.e. unread items. The watermark is stored persistently for each log.

Return

0 on success, error code otherwise.

Parameters
  • log: The log to set watermark on.

  • index: The index of a watermarked item.

int log_nmgr_register_group(void)

Variables

const struct log_handler log_console_handler
const struct log_handler log_cbmem_handler
const struct log_handler log_fcb_handler
const struct log_handler log_fcb_slot1_handler
struct log_offset
#include <log.h>

Used for walks and reads; indicates part of log to access.

Public Members

int64_t lo_ts
uint32_t lo_index
uint32_t lo_data_len
void *lo_arg
struct log_storage_info
#include <log.h>

Log storage information.

Public Members

uint32_t size
uint32_t used
uint32_t used_unread
struct log_handler
#include <log.h>

Public Members

int log_type
lh_read_func_t log_read
lh_read_mbuf_func_t log_read_mbuf
lh_append_func_t log_append
lh_append_body_func_t log_append_body
lh_append_mbuf_func_t log_append_mbuf
lh_append_mbuf_body_func_t log_append_mbuf_body
lh_walk_func_t log_walk
lh_flush_func_t log_flush
lh_storage_info_func_t log_storage_info
lh_set_watermark_func_t log_set_watermark
lh_registered_func_t log_registered
struct log
#include <log.h>

Public Functions

STAILQ_ENTRY (log) l_next
STATS_SECT_DECL (logs) l_stats

Public Members

char *l_name
const struct log_handler *l_log
void *l_arg
log_append_cb *l_append_cb
uint8_t l_level