- Overview
- Architecture
- Installation & Build
- Quick Start
- Core APIs
- Configuration
- Runtime Control
- Log Levels
- Utilities
- Examples
- Error Handling
- Best Practices
RDK Logger is a comprehensive logging framework designed for RDK (Reference Design Kit) components. It provides:
- Centralized Configuration: Single
debug.inifile for all components - Runtime Control: Dynamic log level changes without restart
- Multi-level Logging: Support for FATAL, ERROR, WARN, NOTICE, INFO, DEBUG, TRACE
- Module-specific Control: Independent log levels per component/module
- Performance Optimized: Minimal overhead when logging is disabled
- Thread-safe: Safe for multi-threaded applications
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Application │───▶│ RDK Logger │───▶│ Log Output │
│ │ │ │ │ (stdout/file) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌──────────────────┐
│ debug.ini │
│ Configuration │
└──────────────────┘
The RDK Logger sits between your application and the actual log output, providing filtering, formatting, and runtime control capabilities.
liblog4c- Log4C logging librarylibglib-2.0- GLib libraryautotools- For building from source
# Configure and build
./configure
make
# Install
sudo make install# Compile flags
gcc -o myapp myapp.c -lrdkloggers -llog4c -lglib-2.0#include "rdk_logger.h"int main() {
// Initialize with default config file (/etc/debug.ini)
if (RDK_LOGGER_INIT() != RDK_SUCCESS) {
fprintf(stderr, "Failed to initialize RDK Logger\n");
return -1;
}
// Your application code here
// Clean up
rdk_logger_deinit();
return 0;
}// Basic logging
RDK_LOG(RDK_LOG_INFO, "LOG.RDK.MYAPP", "Application started successfully\n");
// Formatted logging
int port = 8080;
RDK_LOG(RDK_LOG_NOTICE, "LOG.RDK.MYAPP", "Server listening on port %d\n", port);
// Error logging
RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.MYAPP", "Failed to connect to database: %s\n", strerror(errno));rdk_Error rdk_logger_init(const char* debugConfigFile);Purpose: Initialize the RDK Logger with a specific configuration file.
Parameters:
debugConfigFile: Path to the debug.ini configuration file
Returns: RDK_SUCCESS on success, error code otherwise
Example:
rdk_Error ret = rdk_logger_init("/etc/debug.ini");
if (ret != RDK_SUCCESS) {
printf("Logger initialization failed\n");
}rdk_Error rdk_logger_ext_init(const rdk_logger_ext_config_t* config);Purpose: Extended initialization with custom log file configuration.
Parameters:
config: Pointer to extended configuration structure
Configuration Structure:
typedef struct rdk_logger_ext_config_t {
char fileName[RDK_LOGGER_EXT_FILENAME_SIZE]; // Log file name
char logdir[RDK_LOGGER_EXT_LOGDIR_SIZE]; // Log directory path
long maxSize; // Max file size in bytes
long maxCount; // Max number of log files
} rdk_logger_ext_config_t;Example:
rdk_logger_ext_config_t config = {
.fileName = "myapp.log",
.logdir = "/var/log/",
.maxSize = 1024 * 1024, // 1MB
.maxCount = 5 // Keep 5 log files
};
rdk_logger_ext_init(&config);rdk_Error rdk_logger_deinit(void);Purpose: Clean up and deinitialize the logger.
Returns: RDK_SUCCESS on success
#define RDK_LOG rdk_logger_msg_printfPurpose: Primary logging macro for formatted messages.
Syntax:
RDK_LOG(level, module, format, ...);Parameters:
level: Log level (see Log Levels)module: Module name string (should match debug.ini entries)format: Printf-style format string...: Variable arguments for format string
void rdk_logger_msg_printf(rdk_LogLevel level, const char *module, const char *format, ...);Purpose: Core logging function with printf-style formatting.
Example:
rdk_logger_msg_printf(RDK_LOG_DEBUG, "LOG.RDK.NETWORK",
"Connection established to %s:%d\n", hostname, port);void rdk_logger_msg_vsprintf(rdk_LogLevel level, const char *module, const char *format, va_list args);Purpose: Logging function that accepts a va_list for wrapper functions.
Example:
void my_log_wrapper(rdk_LogLevel level, const char *module, const char *format, ...) {
va_list args;
va_start(args, format);
rdk_logger_msg_vsprintf(level, module, format, args);
va_end(args);
}rdk_logger_Bool rdk_logger_is_logLevel_enabled(const char *module, rdk_LogLevel level);Purpose: Check if a specific log level is enabled for a module.
Returns: TRUE if enabled, FALSE otherwise
Example:
if (rdk_logger_is_logLevel_enabled("LOG.RDK.MYAPP", RDK_LOG_DEBUG)) {
// Expensive debug computation only if debug logging is enabled
char *debug_info = generate_debug_info();
RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.MYAPP", "Debug info: %s\n", debug_info);
free(debug_info);
}rdk_logger_Bool rdk_logger_enable_logLevel(const char *module, rdk_LogLevel logLevel, rdk_logger_Bool enableLogLvl);Purpose: Dynamically enable or disable a log level for a module at runtime.
Parameters:
module: Module namelogLevel: Log level to modifyenableLogLvl:TRUEto enable,FALSEto disable
Returns: TRUE if successful
Example:
// Enable debug logging temporarily
rdk_logger_enable_logLevel("LOG.RDK.MYAPP", RDK_LOG_DEBUG, TRUE);
// ... debug operations ...
// Disable debug logging
rdk_logger_enable_logLevel("LOG.RDK.MYAPP", RDK_LOG_DEBUG, FALSE);rdk_LogLevel rdk_logger_level_from_string(const char* level);Purpose: Convert string representation to log level enum.
Parameters:
level: String like "INFO", "DEBUG", "ERROR"
Returns: Corresponding rdk_LogLevel value, or RDK_LOG_NONE if invalid
Example:
rdk_LogLevel level = rdk_logger_level_from_string("DEBUG");
if (level != RDK_LOG_NONE) {
rdk_logger_enable_logLevel("LOG.RDK.MYAPP", level, TRUE);
}void rdk_logger_log_onboard(const char *module, const char *msg, ...);Purpose: Special logging function for onboard/milestone logging.
Example:
rdk_logger_log_onboard("LOG.RDK.SYSTEM", "System initialization completed");The debug.ini file controls logging behavior for all modules:
##########################################################################
# RDK Logger Configuration
# Format: LOG.RDK.<MODULE>=<LEVEL>
##########################################################################
# Default log level for all modules
LOG.RDK.DEFAULT=WARNING
# Module-specific log levels
LOG.RDK.NETWORK=DEBUG # Network module: debug and above
LOG.RDK.DATABASE=INFO # Database module: info and above
LOG.RDK.SECURITY=ERROR # Security module: error and above
LOG.RDK.TESTMODULE=NONE # Test module: no logging- Primary:
/etc/debug.ini - Override:
/nvram/debug.ini(takes precedence if exists) - Custom: Specified in
rdk_logger_init()call
- RDK Components: Must start with
LOG.RDK. - Example:
LOG.RDK.NETWORK,LOG.RDK.AUDIO,LOG.RDK.VIDEO - Default Module:
LOG.RDK.DEFAULTsets the fallback level
The rdklogctrl command-line utility allows runtime modification of log levels:
# Set log level for a module
rdklogctrl <app_name> <module_name> <log_level>
# Examples
rdklogctrl myapp LOG.RDK.NETWORK DEBUG
rdklogctrl receiver LOG.RDK.AUDIO INFO
rdklogctrl player LOG.RDK.VIDEO ERROR
# Disable specific log level (using ~ prefix)
rdklogctrl myapp LOG.RDK.NETWORK ~DEBUGParameters:
app_name: Process name as shown bypscommandmodule_name: Module name (must match debug.ini format)log_level: FATAL, ERROR, WARN, NOTICE, INFO, DEBUG, TRACE, NONE
// Enable debug logging at runtime
rdk_logger_enable_logLevel("LOG.RDK.MYAPP", RDK_LOG_DEBUG, TRUE);
// Check if logging is enabled before expensive operations
if (rdk_dbg_enabled("LOG.RDK.MYAPP", RDK_LOG_TRACE)) {
generate_detailed_trace();
}| Level | Value | Description | Use Case |
|---|---|---|---|
RDK_LOG_FATAL |
0 | System unusable | Critical failures, system crash |
RDK_LOG_ERROR |
1 | Error conditions | Errors that affect functionality |
RDK_LOG_WARN |
2 | Warning conditions | Potential problems, degraded performance |
RDK_LOG_NOTICE |
3 | Normal significant condition | Important normal events |
RDK_LOG_INFO |
4 | Informational messages | General application flow |
RDK_LOG_DEBUG |
5 | Debug-level messages | Detailed debugging information |
RDK_LOG_TRACE |
6 | Trace-level messages | Very detailed execution tracing |
RDK_LOG_NONE |
7 | No logging | Disable all logging |
Setting a log level enables that level and all higher priority levels:
TRACE → DEBUG → INFO → NOTICE → WARN → ERROR → FATAL
Example: Setting DEBUG enables DEBUG, INFO, NOTICE, WARN, ERROR, and FATAL messages.
For backward compatibility with legacy RDK components:
#define RDK_LOG_TRACE1 RDK_LOG_TRACE
#define RDK_LOG_TRACE2 RDK_LOG_TRACE
// ... up to RDK_LOG_TRACE9Location: utils/rdklogctrl
Purpose: Command-line utility for modifying log levels of running processes.
Usage:
rdklogctrl <app_name> <module_name> <log_level>Examples:
# Enable debug logging for network module
rdklogctrl receiver LOG.RDK.NETWORK DEBUG
# Disable all logging for test module
rdklogctrl myapp LOG.RDK.TEST NONE
# Turn off only error logs (keep others)
rdklogctrl player LOG.RDK.AUDIO ~ERRORLocation: utils/rdklogmilestone.c
Purpose: C utility for milestone logging from applications.
Usage:
rdklogmilestone "APPLICATION_READY"#include <stdio.h>
#include <stdlib.h>
#include "rdk_logger.h"
#define MODULE_NAME "LOG.RDK.MYAPP"
int main() {
// Initialize logger
if (RDK_LOGGER_INIT() != RDK_SUCCESS) {
fprintf(stderr, "Failed to initialize RDK Logger\n");
return EXIT_FAILURE;
}
// Log application startup
RDK_LOG(RDK_LOG_NOTICE, MODULE_NAME, "Application starting up\n");
// Example operations with different log levels
RDK_LOG(RDK_LOG_INFO, MODULE_NAME, "Initializing components\n");
// Conditional debug logging for performance
if (rdk_dbg_enabled(MODULE_NAME, RDK_LOG_DEBUG)) {
RDK_LOG(RDK_LOG_DEBUG, MODULE_NAME, "Debug mode enabled\n");
}
// Simulated error condition
int error_code = 42;
if (error_code != 0) {
RDK_LOG(RDK_LOG_ERROR, MODULE_NAME,
"Operation failed with error code %d\n", error_code);
}
// Log application shutdown
RDK_LOG(RDK_LOG_NOTICE, MODULE_NAME, "Application shutting down\n");
rdk_logger_deinit();
return EXIT_SUCCESS;
}#include "rdk_logger.h"
#include <sys/socket.h>
#include <netinet/in.h>
#define NET_MODULE "LOG.RDK.NETWORK"
int start_server(int port) {
int server_fd;
struct sockaddr_in address;
RDK_LOG(RDK_LOG_INFO, NET_MODULE, "Starting server on port %d\n", port);
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
RDK_LOG(RDK_LOG_ERROR, NET_MODULE,
"Failed to create socket: %s\n", strerror(errno));
return -1;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
RDK_LOG(RDK_LOG_ERROR, NET_MODULE,
"Failed to bind to port %d: %s\n", port, strerror(errno));
close(server_fd);
return -1;
}
if (listen(server_fd, 10) < 0) {
RDK_LOG(RDK_LOG_ERROR, NET_MODULE,
"Failed to listen on socket: %s\n", strerror(errno));
close(server_fd);
return -1;
}
RDK_LOG(RDK_LOG_NOTICE, NET_MODULE,
"Server successfully started and listening on port %d\n", port);
return server_fd;
}
void handle_client(int client_fd, struct sockaddr_in *client_addr) {
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr->sin_addr, client_ip, INET_ADDRSTRLEN);
RDK_LOG(RDK_LOG_INFO, NET_MODULE,
"New client connected from %s:%d\n",
client_ip, ntohs(client_addr->sin_port));
// Handle client communication...
RDK_LOG(RDK_LOG_DEBUG, NET_MODULE,
"Processing request from %s\n", client_ip);
// When done
RDK_LOG(RDK_LOG_INFO, NET_MODULE,
"Client %s disconnected\n", client_ip);
close(client_fd);
}Create /etc/debug.ini:
##########################################################################
# Production Configuration
##########################################################################
# Default level - only warnings and errors
LOG.RDK.DEFAULT=WARN
# Network debugging enabled
LOG.RDK.NETWORK=DEBUG
# Application flow information
LOG.RDK.MYAPP=INFO
# Security - errors only
LOG.RDK.SECURITY=ERROR
# Disable test modules in production
LOG.RDK.TEST=NONE
LOG.RDK.UNITTEST=NONE
# Media components
LOG.RDK.AUDIO=NOTICE
LOG.RDK.VIDEO=NOTICE#include "rdk_logger.h"
#include <stdarg.h>
// Custom logging wrapper with timestamp
void my_log(rdk_LogLevel level, const char *module, const char *function,
int line, const char *format, ...) {
if (!rdk_dbg_enabled(module, level)) {
return; // Early return if logging disabled
}
va_list args;
va_start(args, format);
// Create enhanced format with function and line info
char enhanced_format[512];
snprintf(enhanced_format, sizeof(enhanced_format),
"[%s:%d] %s", function, line, format);
rdk_logger_msg_vsprintf(level, module, enhanced_format, args);
va_end(args);
}
// Convenience macro
#define MY_LOG(level, module, format, ...) \
my_log(level, module, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
// Usage
int main() {
RDK_LOGGER_INIT();
MY_LOG(RDK_LOG_INFO, "LOG.RDK.MYAPP", "Application started\n");
MY_LOG(RDK_LOG_DEBUG, "LOG.RDK.MYAPP", "Variable value: %d\n", 42);
rdk_logger_deinit();
return 0;
}All initialization functions return rdk_Error type:
typedef uint32_t rdk_Error;
#define RDK_SUCCESS 0Common Error Scenarios:
- Configuration file not found
- Invalid configuration format
- Memory allocation failures
- Log4C initialization errors
rdk_Error init_logging(const char *config_file) {
rdk_Error ret = rdk_logger_init(config_file);
if (ret != RDK_SUCCESS) {
fprintf(stderr, "Logger initialization failed: %u\n", ret);
fprintf(stderr, "Falling back to stdout logging\n");
// Implement fallback logging mechanism
return ret;
}
return RDK_SUCCESS;
}int main() {
// Try to initialize logger
if (RDK_LOGGER_INIT() != RDK_SUCCESS) {
fprintf(stderr, "Warning: RDK Logger initialization failed\n");
fprintf(stderr, "Continuing with fprintf logging\n");
// Application can continue with basic printf/fprintf
printf("Application started (no RDK logging)\n");
} else {
RDK_LOG(RDK_LOG_NOTICE, "LOG.RDK.MYAPP", "Application started\n");
}
// Rest of application...
return 0;
}// Good - descriptive and consistent
#define AUDIO_MODULE "LOG.RDK.AUDIO"
#define NETWORK_MODULE "LOG.RDK.NETWORK"
#define DATABASE_MODULE "LOG.RDK.DATABASE"
// Avoid - generic or unclear names
#define MODULE "LOG.RDK.APP"
#define MY_MODULE "LOG.RDK.THING"// Check if logging is enabled before expensive operations
if (rdk_dbg_enabled("LOG.RDK.MYAPP", RDK_LOG_DEBUG)) {
char *expensive_debug_info = generate_debug_dump();
RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.MYAPP", "Debug: %s\n", expensive_debug_info);
free(expensive_debug_info);
}
// Use appropriate log levels
RDK_LOG(RDK_LOG_FATAL, module, "System crash: %s\n", reason); // System unusable
RDK_LOG(RDK_LOG_ERROR, module, "Failed to connect: %s\n", err); // Error conditions
RDK_LOG(RDK_LOG_WARN, module, "Retrying connection\n"); // Warnings
RDK_LOG(RDK_LOG_NOTICE, module, "Service started\n"); // Important events
RDK_LOG(RDK_LOG_INFO, module, "Processing request\n"); // General info
RDK_LOG(RDK_LOG_DEBUG, module, "Variable x = %d\n", x); // Debug details
RDK_LOG(RDK_LOG_TRACE, module, "Entering function\n"); // Function tracing// RDK Logger is thread-safe, but avoid race conditions in your logic
void worker_thread(void *arg) {
int thread_id = *(int*)arg;
RDK_LOG(RDK_LOG_INFO, "LOG.RDK.WORKER",
"Worker thread %d started\n", thread_id);
// Worker logic...
RDK_LOG(RDK_LOG_INFO, "LOG.RDK.WORKER",
"Worker thread %d finished\n", thread_id);
}// Check for override config file
const char* get_config_file() {
if (access("/nvram/debug.ini", F_OK) == 0) {
return "/nvram/debug.ini"; // Development/debug config
}
return "/etc/debug.ini"; // Production config
}
// Initialize with appropriate config
rdk_Error ret = rdk_logger_init(get_config_file());// Include relevant context in log messages
RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.NETWORK",
"Connection failed: host=%s, port=%d, error=%s\n",
hostname, port, strerror(errno));
// Use consistent formats for similar events
RDK_LOG(RDK_LOG_INFO, "LOG.RDK.SERVICE",
"SERVICE_START: name=%s, pid=%d, version=%s\n",
service_name, getpid(), version);// Always clean up in signal handlers and exit paths
void signal_handler(int sig) {
RDK_LOG(RDK_LOG_NOTICE, "LOG.RDK.MYAPP",
"Received signal %d, shutting down\n", sig);
rdk_logger_deinit();
exit(0);
}
int main() {
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
RDK_LOGGER_INIT();
// Application logic...
rdk_logger_deinit();
return 0;
}Note: This documentation covers RDK Logger API version as implemented in the current codebase. For the most up-to-date information, refer to the source code and header files.