Creating a Custom Logger with Zephyr and Kconfig
July 14, 2025
In Zephyr, the typical way to enable logging in your application is by setting LOG_LEVEL and registering the module. This works well for small projects where you have one or two modules. But if your repository has multiple source files or modules, setting the log level per file gets messy. This is especially true if all modules should have different log levels.
/* main.c */
#define LOG_LEVEL LOG_LEVEL_DBG
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(my_module);
Wouldn’t it be better to manage all log levels from one point? ..mabye prj.conf
?
That’s exactly what this post is about.
- Setting Up a Custom Kconfig for Logging
- Configuring Log Levels in prj.conf
- Final Thoughts
- References
Setting Up a Custom Kconfig for Logging
Zephyr’s CMake system automatically picks up a Kconfig file if it’s placed in the same directory as your application’s CMakeLists.txt.
$ tree --charset=utf-8 --dirsfirst -L 1
.
├── boards
├── src
├── CMakeLists.txt
├── Kconfig
└── prj.conf
Example Kconfig file for a custom logger
# Kconfig
# 1.
mainmenu "Custom Logger Configuration"
# 2.
source "Kconfig.zephyr"
# 3.
menu "Application Options"
config APP_LOG
bool "Enable logging in main"
default y if LOG
depends on LOG
help
Enable logging for the main application module.
endmenu
# 4.
if APP_LOG
module = APP
module-str = "app"
source "subsys/logging/Kconfig.template.log_config"
endif
Let’s break file down in four parts:
-
mainmenu
sets the title formenuconfig
. -
source
Kconfig.zephyr
includes the standard Zephyr config symbols. This is necessary since we’re modifyingzephyr/Kconfig
to add our symbols. -
APP_LOG
is a custom boolean symbol that enables logging for our custom module. Since we’re building our own logger, it makes sense that our logger depends on LOG, which is the global logging switch. Also, our logger is enabled by default. -
The definition of our custom logger. This is a defined structure in the logger documentation:
- module: defines the symbol of the new logger module
- module-str: defines the name or description of the module
- source: the is logging template from Zephyr (
Kconfig.template.log_config
) lets you define per-module log levels using Kconfig.
You can verify the new additions with west build -t menuconfig
. For example the menu “Application Options” we just defined
You also see that our logger is enabled by default and marked with an asterisk.
Configuring Log Levels in prj.conf
Once you’ve got your Kconfig set up, you can define the log level of your custom logger in prj.conf with just a few lines.
CONFIG_LOG=y
CONFIG_APP_LOG=y
CONFIG_APP_LOG_LEVEL_INF=y
Now in your code you can use CONFIG_APP_LOG_LEVEL
instead of LOG_LEVEL_DBG
when defining the LOG_LEVEL
/* main.c */
#define LOG_LEVEL CONFIG_APP_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);
You can repeat this pattern for other modules too:
# prj.conf
# Enable logging
CONFIG_LOG=y
# Enable custom logger
CONFIG_APP_LOG=y
CONFIG_APP_LOG_LEVEL_INF=y
# Enable other custom logger
CONFIG_OTHER_LOG=y
CONFIG_OTHER_LOG_LEVEL_DBG=y
# Enable MCUMGR logger, defined already in Zephyr
CONFIG_MCUMGR_LOG=y
CONFIG_MCUMGR_LOG_LEVEL_DBG=y
CONFIG_MCUMGR_TRANSPORT_LOG_LEVEL_DBG=y
This way, you manage all log levels from one central place 😎.
Final Thoughts
Zephyr offers an easy way to create custom and maintainable loggers using Kconfig and Kconfig.template.log_config
.
If your project has more than a couple of modules, this setup will save you time and keep your development consistent.
References