๐Ÿ“ BaseLogger API Reference

๐ŸŽฏ Unified logging abstraction for comprehensive system monitoring and debugging


๐Ÿ“š Table of Contents


๐ŸŽฏ Overview

The BaseLogger class provides a comprehensive logging abstraction that serves as the unified interface for all logging operations in the HardFOC system. It supports multiple log levels, configurable output destinations, thread-safe operations, performance monitoring, and works across different hardware implementations with minimal overhead.

โœจ Key Features

  • ๐Ÿ“ Multi-Level Logging - ERROR, WARN, INFO, DEBUG, VERBOSE levels
  • ๐Ÿ”’ Thread-Safe Operations - Concurrent logging from multiple tasks
  • ๐Ÿ“Š Multiple Output Destinations - UART, file, memory buffer, network
  • โšก High Performance - Minimal overhead with efficient buffering
  • ๐ŸŽฏ Configurable Filtering - Runtime level control and tag filtering
  • ๐Ÿ“ˆ Performance Monitoring - Built-in logging statistics and profiling
  • ๐Ÿ›ก๏ธ Robust Error Handling - Comprehensive validation and error reporting
  • ๐ŸŽ๏ธ Memory Efficient - Optimized memory usage with circular buffers
  • ๐Ÿ”Œ Platform Agnostic - Works across different MCU platforms

๐Ÿ“Š Supported Hardware

Implementation UART File Memory Network Performance

|โ€”โ€”โ€”โ€”โ€”-|โ€”โ€”|โ€”โ€”|โ€”โ€”โ€“|โ€”โ€”โ€”|โ€”โ€”โ€”โ€”-|

EspLogger โœ… โœ… โœ… โœ… High
Esp8266Logger โœ… โŒ โœ… โœ… Medium
ArmLogger โœ… โœ… โœ… โŒ High

๐Ÿ—๏ธ Class Hierarchy

classDiagram
    class BaseLogger {
        <<abstract>>
        +EnsureInitialized() hf_logger_err_t
        +SetLogLevel(hf_log_level_t) hf_logger_err_t
        +LogMessage(level, tag, format, ...) hf_logger_err_t
        +LogError(tag, format, ...) hf_logger_err_t
        +LogWarn(tag, format, ...) hf_logger_err_t
        +LogInfo(tag, format, ...) hf_logger_err_t
        +LogDebug(tag, format, ...) hf_logger_err_t
        +LogVerbose(tag, format, ...) hf_logger_err_t
        +AddOutput(hf_log_output_t*) hf_logger_err_t
        +RemoveOutput(hf_log_output_t*) hf_logger_err_t
        +FlushBuffers() hf_logger_err_t
        +GetStatistics(hf_logger_statistics_t&) hf_logger_err_t
        +IsInitialized() bool
        #DoInitialize() hf_logger_err_t*
        #DoLogMessage(level, tag, message) hf_logger_err_t*
    }

    class EspLogger {
        +EspLogger()
        +EnableUartOutput(uart_num) hf_logger_err_t
        +EnableFileOutput(path) hf_logger_err_t
        +EnableNetworkOutput(host, port) hf_logger_err_t
        +SetBufferSize(size) hf_logger_err_t
    }

    class ConsoleLogger {
        +ConsoleLogger()
        +SetColorOutput(enable) hf_logger_err_t
        +SetTimestampFormat(format) hf_logger_err_t
    }

    class FileLogger {
        +FileLogger(filepath)
        +SetRotationSize(size) hf_logger_err_t
        +SetMaxFiles(count) hf_logger_err_t
        +CompressOldLogs(enable) hf_logger_err_t
    }

    BaseLogger <|-- EspLogger
    BaseLogger <|-- ConsoleLogger  
    BaseLogger <|-- FileLogger

๐Ÿ“‹ Error Codes

๐Ÿšจ Logger Error Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
enum class hf_logger_err_t : hf_u32_t {
    // Success codes
    LOGGER_SUCCESS = 0,
    
    // General errors
    LOGGER_ERR_FAILURE = 1,
    LOGGER_ERR_NOT_INITIALIZED = 2,
    LOGGER_ERR_ALREADY_INITIALIZED = 3,
    LOGGER_ERR_INVALID_PARAMETER = 4,
    LOGGER_ERR_NULL_POINTER = 5,
    LOGGER_ERR_OUT_OF_MEMORY = 6,
    
    // Output errors
    LOGGER_ERR_OUTPUT_NOT_FOUND = 7,
    LOGGER_ERR_OUTPUT_ALREADY_ADDED = 8,
    LOGGER_ERR_OUTPUT_FAILURE = 9,
    LOGGER_ERR_OUTPUT_FULL = 10,
    
    // Buffer errors
    LOGGER_ERR_BUFFER_OVERFLOW = 11,
    LOGGER_ERR_BUFFER_UNDERFLOW = 12,
    LOGGER_ERR_BUFFER_FULL = 13,
    LOGGER_ERR_BUFFER_EMPTY = 14,
    
    // Format errors
    LOGGER_ERR_FORMAT_ERROR = 15,
    LOGGER_ERR_MESSAGE_TOO_LONG = 16,
    LOGGER_ERR_INVALID_TAG = 17,
    LOGGER_ERR_INVALID_LEVEL = 18,
    
    // File errors
    LOGGER_ERR_FILE_NOT_FOUND = 19,
    LOGGER_ERR_FILE_PERMISSION = 20,
    LOGGER_ERR_FILE_WRITE_ERROR = 21,
    LOGGER_ERR_DISK_FULL = 22,
    
    // Network errors
    LOGGER_ERR_NETWORK_UNAVAILABLE = 23,
    LOGGER_ERR_NETWORK_TIMEOUT = 24,
    LOGGER_ERR_NETWORK_ERROR = 25,
    
    // System errors
    LOGGER_ERR_SYSTEM_ERROR = 26,
    LOGGER_ERR_PERMISSION_DENIED = 27,
    LOGGER_ERR_OPERATION_ABORTED = 28
};

๐Ÿ“Š Error Code Categories

Category Range Description

|โ€”โ€”โ€”-|โ€”โ€”-|โ€”โ€”โ€”โ€”-|

Success 0 Successful operation
General 1-6 Basic initialization and parameter errors
Output 7-10 Output destination errors
Buffer 11-14 Buffer management errors
Format 15-18 Message formatting errors
File 19-22 File system errors
Network 23-25 Network logging errors
System 26-28 System-level errors

๐Ÿ”ง Core API

๐ŸŽฏ Essential Methods

Initialization & Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * @brief Ensure the logger is initialized
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t EnsureInitialized() = 0;

/**
 * @brief Set the global log level
 * @param level Minimum log level to output
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t SetLogLevel(hf_log_level_t level) = 0;

/**
 * @brief Check if logger is initialized
 * @return bool True if initialized
 */
virtual bool IsInitialized() const = 0;

Logging Methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
 * @brief Log a message with specified level
 * @param level Log level
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogMessage(hf_log_level_t level, 
                                 const char* tag,
                                 const char* format, ...) = 0;

/**
 * @brief Log error message
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogError(const char* tag, const char* format, ...) = 0;

/**
 * @brief Log warning message
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogWarn(const char* tag, const char* format, ...) = 0;

/**
 * @brief Log info message
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogInfo(const char* tag, const char* format, ...) = 0;

/**
 * @brief Log debug message
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogDebug(const char* tag, const char* format, ...) = 0;

/**
 * @brief Log verbose message
 * @param tag Message tag/category
 * @param format Printf-style format string
 * @param ... Format arguments
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t LogVerbose(const char* tag, const char* format, ...) = 0;

Output Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * @brief Add log output destination
 * @param output Pointer to output handler
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t AddOutput(hf_log_output_t* output) = 0;

/**
 * @brief Remove log output destination
 * @param output Pointer to output handler to remove
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t RemoveOutput(hf_log_output_t* output) = 0;

/**
 * @brief Flush all output buffers
 * @return hf_logger_err_t Error code
 */
virtual hf_logger_err_t FlushBuffers() = 0;

๐Ÿ“Š Data Structures

๐Ÿ“ Log Level Types

1
2
3
4
5
6
7
8
enum class hf_log_level_t : hf_u8_t {
    LOG_LEVEL_NONE = 0,     ///< No logging
    LOG_LEVEL_ERROR = 1,    ///< Error conditions only
    LOG_LEVEL_WARN = 2,     ///< Warning and error conditions
    LOG_LEVEL_INFO = 3,     ///< Informational messages
    LOG_LEVEL_DEBUG = 4,    ///< Debug information
    LOG_LEVEL_VERBOSE = 5   ///< Detailed trace information
};

๐Ÿ“ค Output Types

1
2
3
4
5
6
7
enum class hf_log_output_type_t : hf_u8_t {
    LOG_OUTPUT_UART = 0,        ///< UART/Serial output
    LOG_OUTPUT_FILE = 1,        ///< File system output
    LOG_OUTPUT_MEMORY = 2,      ///< Memory buffer output
    LOG_OUTPUT_NETWORK = 3,     ///< Network/UDP output
    LOG_OUTPUT_CUSTOM = 4       ///< Custom user-defined output
};

๐Ÿ“‹ Log Message Structure

1
2
3
4
5
6
7
8
9
struct hf_log_message_t {
    hf_u64_t timestamp_us;              ///< Timestamp in microseconds
    hf_log_level_t level;               ///< Log level
    char tag[16];                       ///< Message tag/category
    char message[256];                  ///< Formatted message
    hf_u32_t task_id;                   ///< Task/thread ID
    const char* file;                   ///< Source file name
    hf_u32_t line;                      ///< Source line number
};

๐Ÿ“ค Output Handler Interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct hf_log_output_t {
    hf_log_output_type_t type;          ///< Output type
    hf_log_level_t min_level;           ///< Minimum level for this output
    
    /**
     * @brief Write log message to output
     * @param message Log message to write
     * @return hf_logger_err_t Error code
     */
    hf_logger_err_t (*write)(const hf_log_message_t* message);
    
    /**
     * @brief Flush output buffer
     * @return hf_logger_err_t Error code
     */
    hf_logger_err_t (*flush)(void);
    
    void* user_data;                    ///< User-defined data
};

๐Ÿ“ˆ Logger Statistics

1
2
3
4
5
6
7
8
9
10
11
12
struct hf_logger_statistics_t {
    hf_u64_t total_messages;            ///< Total messages logged
    hf_u64_t messages_by_level[6];      ///< Messages per log level
    hf_u64_t dropped_messages;          ///< Messages dropped due to buffer full
    hf_u64_t format_errors;             ///< Format string errors
    hf_u64_t output_errors;             ///< Output write errors
    hf_u32_t buffer_high_water_mark;    ///< Maximum buffer usage
    hf_u32_t average_message_size;      ///< Average message size in bytes
    hf_u64_t total_bytes_logged;        ///< Total bytes written
    hf_u32_t active_outputs;            ///< Number of active outputs
    hf_u64_t uptime_ms;                 ///< Logger uptime in milliseconds
};

๐Ÿ“ Log Levels

๐Ÿšจ ERROR Level

Critical errors that require immediate attention:

1
2
logger.LogError("MOTOR", "Motor controller fault detected: %s", fault_description);
logger.LogError("COMM", "CAN bus communication timeout after %d ms", timeout_ms);

โš ๏ธ WARN Level

Warning conditions that should be monitored:

1
2
logger.LogWarn("TEMP", "Temperature high: %.1fยฐC (limit: %.1fยฐC)", temp, limit);
logger.LogWarn("MEMORY", "Low memory warning: %d bytes remaining", free_bytes);

โ„น๏ธ INFO Level

General informational messages:

1
2
logger.LogInfo("SYSTEM", "Motor controller initialized successfully");
logger.LogInfo("NETWORK", "Connected to WiFi: %s (IP: %s)", ssid, ip_address);

๐Ÿ”ง DEBUG Level

Debug information for troubleshooting:

1
2
logger.LogDebug("ADC", "Reading channel %d: raw=%u, voltage=%.3fV", channel, raw, voltage);
logger.LogDebug("GPIO", "Pin %d state changed: %s", pin, state ? "HIGH" : "LOW");

๐Ÿ“Š VERBOSE Level

Detailed trace information:

1
2
3
4
logger.LogVerbose("I2C", "Transaction: addr=0x%02X, write=%d bytes, read=%d bytes", 
                  address, write_len, read_len);
logger.LogVerbose("TIMER", "Callback executed: task=%s, duration=%lu us", 
                  task_name, duration);

๐Ÿ“Š Usage Examples

๐Ÿ”ง Basic System Logger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "inc/mcu/esp32/EspLogger.h"

class SystemLogger {
private:
    EspLogger logger*;
    bool is_initialized*;
    
public:
    SystemLogger() : is_initialized*(false) {}
    
    bool initialize() {
        if (logger*.EnsureInitialized() != hf_logger_err_t::LOGGER_SUCCESS) {
            return false;
        }
        
        // Set log level based on build configuration
        #ifdef DEBUG
            logger*.SetLogLevel(hf_log_level_t::LOG_LEVEL_VERBOSE);
        #else
            logger*.SetLogLevel(hf_log_level_t::LOG_LEVEL_INFO);
        #endif
        
        // Enable UART output for development
        if (logger*.EnableUartOutput(UART_NUM_0) != hf_logger_err_t::LOGGER_SUCCESS) {
            return false;
        }
        
        // Enable file output for production logging
        if (logger*.EnableFileOutput("/spiffs/system.log") != hf_logger_err_t::LOGGER_SUCCESS) {
            printf("Warning: File logging not available\n");
        }
        
        is_initialized* = true;
        logger*.LogInfo("SYSTEM", "System logger initialized");
        
        return true;
    }
    
    void log_system_startup() {
        if (!is_initialized*) return;
        
        logger*.LogInfo("BOOT", "=== HardFOC Motor Controller Starting ===");
        logger*.LogInfo("BOOT", "Firmware version: %s", get_firmware_version());
        logger*.LogInfo("BOOT", "Build date: %s %s", **DATE**, **TIME**);
        logger*.LogInfo("BOOT", "Free heap: %d bytes", esp_get_free_heap_size());
        logger*.LogInfo("BOOT", "CPU frequency: %d MHz", esp_clk_cpu_freq() / 1000000);
    }
    
    void log_motor_operation(float speed, float current, float temperature) {
        if (!is_initialized*) return;
        
        logger*.LogDebug("MOTOR", "Speed: %.2f RPM, Current: %.2f A, Temp: %.1fยฐC", 
                        speed, current, temperature);
        
        // Log warnings for abnormal conditions
        if (current > 10.0f) {
            logger*.LogWarn("MOTOR", "High current detected: %.2f A", current);
        }
        
        if (temperature > 80.0f) {
            logger*.LogWarn("MOTOR", "High temperature detected: %.1fยฐC", temperature);
        }
        
        // Log errors for fault conditions
        if (temperature > 100.0f) {
            logger*.LogError("MOTOR", "CRITICAL: Temperature overload: %.1fยฐC", temperature);
        }
    }
    
    void log_communication_event(const char* interface, bool success, 
                                const char* details) {
        if (!is_initialized*) return;
        
        if (success) {
            logger*.LogDebug("COMM", "%s: %s", interface, details);
        } else {
            logger*.LogError("COMM", "%s error: %s", interface, details);
        }
    }
    
    void show_logger_statistics() {
        if (!is_initialized*) return;
        
        hf_logger_statistics_t stats;
        if (logger*.GetStatistics(stats) == hf_logger_err_t::LOGGER_SUCCESS) {
            logger*.LogInfo("STATS", "=== Logger Statistics ===");
            logger*.LogInfo("STATS", "Total messages: %llu", stats.total_messages);
            logger*.LogInfo("STATS", "Errors: %llu, Warnings: %llu, Info: %llu",
                           stats.messages_by_level[1], 
                           stats.messages_by_level[2],
                           stats.messages_by_level[3]);
            logger*.LogInfo("STATS", "Debug: %llu, Verbose: %llu",
                           stats.messages_by_level[4],
                           stats.messages_by_level[5]);
            logger*.LogInfo("STATS", "Dropped messages: %llu", stats.dropped_messages);
            logger*.LogInfo("STATS", "Total bytes: %llu", stats.total_bytes_logged);
            
            if (stats.dropped_messages > 0) {
                logger*.LogWarn("STATS", "Performance issue: %llu messages dropped", 
                               stats.dropped_messages);
            }
        }
    }
    
private:
    const char* get_firmware_version() {
        return "1.2.3";  // This would come from build system
    }
};

๐Ÿ“Š Performance Monitoring Logger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "inc/mcu/esp32/EspLogger.h"

class PerformanceLogger {
private:
    EspLogger logger*;
    hf_u64_t last_memory_check*;
    hf_u64_t last_performance_log*;
    
public:
    bool initialize() {
        if (logger*.EnsureInitialized() != hf_logger_err_t::LOGGER_SUCCESS) {
            return false;
        }
        
        logger*.SetLogLevel(hf_log_level_t::LOG_LEVEL_DEBUG);
        logger*.EnableUartOutput(UART_NUM_0);
        
        last_memory_check* = esp_timer_get_time();
        last_performance_log* = esp_timer_get_time();
        
        return true;
    }
    
    void log_function_performance(const char* function_name, 
                                hf_u64_t start_time_us,
                                hf_u64_t end_time_us) {
        hf_u64_t duration_us = end_time_us - start_time_us;
        
        if (duration_us > 1000) {  // Log if > 1ms
            logger*.LogWarn("PERF", "%s took %llu us (> 1ms)", function_name, duration_us);
        } else if (duration_us > 100) {  // Log if > 100us
            logger*.LogDebug("PERF", "%s took %llu us", function_name, duration_us);
        } else {
            logger*.LogVerbose("PERF", "%s took %llu us", function_name, duration_us);
        }
    }
    
    void log_memory_usage() {
        hf_u64_t now = esp_timer_get_time();
        
        // Log memory usage every 5 seconds
        if (now - last_memory_check* >= 5000000) {
            size_t free_heap = esp_get_free_heap_size();
            size_t min_free_heap = esp_get_minimum_free_heap_size();
            
            logger*.LogInfo("MEMORY", "Free heap: %u bytes (minimum: %u bytes)", 
                           free_heap, min_free_heap);
            
            if (free_heap < 10000) {
                logger*.LogError("MEMORY", "CRITICAL: Low memory condition");
            } else if (free_heap < 50000) {
                logger*.LogWarn("MEMORY", "Low memory warning");
            }
            
            last_memory_check* = now;
        }
    }
    
    void log_task_performance() {
        hf_u64_t now = esp_timer_get_time();
        
        // Log task statistics every 10 seconds
        if (now - last_performance_log* >= 10000000) {
            TaskStatus_t* task_array;
            UBaseType_t task_count = uxTaskGetNumberOfTasks();
            
            task_array = (TaskStatus_t*)pvPortMalloc(task_count * sizeof(TaskStatus_t));
            if (task_array != nullptr) {
                task_count = uxTaskGetSystemState(task_array, task_count, nullptr);
                
                logger*.LogInfo("TASKS", "=== Task Performance ===");
                for (UBaseType_t i = 0; i < task_count; i++) {
                    logger*.LogInfo("TASKS", "%s: Priority=%u, Stack=%u", 
                                   task_array[i].pcTaskName,
                                   task_array[i].uxCurrentPriority,
                                   task_array[i].usStackHighWaterMark);
                    
                    if (task_array[i].usStackHighWaterMark < 512) {
                        logger*.LogWarn("TASKS", "Low stack warning for task: %s", 
                                       task_array[i].pcTaskName);
                    }
                }
                
                vPortFree(task_array);
            }
            
            last_performance_log* = now;
        }
    }
    
    // RAII class for automatic function timing
    class FunctionTimer {
    private:
        PerformanceLogger* logger*;
        const char* function_name*;
        hf_u64_t start_time*;
        
    public:
        FunctionTimer(PerformanceLogger* logger, const char* function_name)
            : logger*(logger), function_name*(function_name) {
            start_time* = esp_timer_get_time();
        }
        
        ~FunctionTimer() {
            hf_u64_t end_time = esp_timer_get_time();
            logger*->log_function_performance(function_name*, start_time*, end_time);
        }
    };
};

// Macro for easy function timing
#define PERF_TIME_FUNCTION(logger) \
    PerformanceLogger::FunctionTimer *timer(logger, **FUNCTION**)

๐Ÿ“ค Multi-Output Logger System

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include "inc/mcu/esp32/EspLogger.h"

class MultiOutputLogger {
private:
    EspLogger logger*;
    hf_log_output_t uart_output*;
    hf_log_output_t file_output*;
    hf_log_output_t network_output*;
    
public:
    bool initialize() {
        if (logger*.EnsureInitialized() != hf_logger_err_t::LOGGER_SUCCESS) {
            return false;
        }
        
        // Setup UART output for immediate feedback
        setup_uart_output();
        
        // Setup file output for persistent logging
        setup_file_output();
        
        // Setup network output for remote monitoring
        setup_network_output();
        
        logger*.LogInfo("LOGGER", "Multi-output logger system initialized");
        return true;
    }
    
private:
    void setup_uart_output() {
        uart_output*.type = hf_log_output_type_t::LOG_OUTPUT_UART;
        uart_output*.min_level = hf_log_level_t::LOG_LEVEL_DEBUG;
        uart_output*.write = uart_write_callback;
        uart_output*.flush = uart_flush_callback;
        uart_output*.user_data = this;
        
        logger*.AddOutput(&uart_output*);
    }
    
    void setup_file_output() {
        file_output*.type = hf_log_output_type_t::LOG_OUTPUT_FILE;
        file_output*.min_level = hf_log_level_t::LOG_LEVEL_INFO;
        file_output*.write = file_write_callback;
        file_output*.flush = file_flush_callback;
        file_output*.user_data = this;
        
        logger*.AddOutput(&file_output*);
    }
    
    void setup_network_output() {
        network_output*.type = hf_log_output_type_t::LOG_OUTPUT_NETWORK;
        network_output*.min_level = hf_log_level_t::LOG_LEVEL_ERROR;  // Only errors
        network_output*.write = network_write_callback;
        network_output*.flush = network_flush_callback;
        network_output*.user_data = this;
        
        logger*.AddOutput(&network_output*);
    }
    
    static hf_logger_err_t uart_write_callback(const hf_log_message_t* message) {
        // Format timestamp
        char timestamp[32];
        format_timestamp(message->timestamp_us, timestamp, sizeof(timestamp));
        
        // Add color coding based on level
        const char* color = get_color_code(message->level);
        const char* level_str = get_level_string(message->level);
        
        printf("%s[%s] %s (%s:%lu) %s: %s\033[0m\n",
               color,
               timestamp,
               level_str,
               message->file,
               message->line,
               message->tag,
               message->message);
        
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static hf_logger_err_t file_write_callback(const hf_log_message_t* message) {
        FILE* log_file = fopen("/spiffs/system.log", "a");
        if (log_file == nullptr) {
            return hf_logger_err_t::LOGGER_ERR_FILE_WRITE_ERROR;
        }
        
        char timestamp[32];
        format_timestamp(message->timestamp_us, timestamp, sizeof(timestamp));
        
        fprintf(log_file, "[%s] %s %s: %s\n",
                timestamp,
                get_level_string(message->level),
                message->tag,
                message->message);
        
        fclose(log_file);
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static hf_logger_err_t network_write_callback(const hf_log_message_t* message) {
        // Send critical errors to monitoring server
        if (message->level == hf_log_level_t::LOG_LEVEL_ERROR) {
            // Create JSON payload
            char json_payload[512];
            snprintf(json_payload, sizeof(json_payload),
                    "{"
                    "\"timestamp\":%llu,"
                    "\"level\":\"ERROR\","
                    "\"tag\":\"%s\","
                    "\"message\":\"%s\","
                    "\"file\":\"%s\","
                    "\"line\":%lu"
                    "}",
                    message->timestamp_us,
                    message->tag,
                    message->message,
                    message->file,
                    message->line);
            
            // Send via UDP (implementation depends on network stack)
            send_udp_message("log.server.com", 5140, json_payload);
        }
        
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static hf_logger_err_t uart_flush_callback(void) {
        fflush(stdout);
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static hf_logger_err_t file_flush_callback(void) {
        // File is closed after each write, so no flush needed
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static hf_logger_err_t network_flush_callback(void) {
        // UDP is connectionless, no flush needed
        return hf_logger_err_t::LOGGER_SUCCESS;
    }
    
    static void format_timestamp(hf_u64_t timestamp_us, char* buffer, size_t buffer_size) {
        hf_u64_t timestamp_ms = timestamp_us / 1000;
        hf_u32_t seconds = timestamp_ms / 1000;
        hf_u32_t milliseconds = timestamp_ms % 1000;
        
        snprintf(buffer, buffer_size, "%lu.%03lu", seconds, milliseconds);
    }
    
    static const char* get_level_string(hf_log_level_t level) {
        switch (level) {
            case hf_log_level_t::LOG_LEVEL_ERROR: return "ERROR";
            case hf_log_level_t::LOG_LEVEL_WARN: return "WARN ";
            case hf_log_level_t::LOG_LEVEL_INFO: return "INFO ";
            case hf_log_level_t::LOG_LEVEL_DEBUG: return "DEBUG";
            case hf_log_level_t::LOG_LEVEL_VERBOSE: return "VERB ";
            default: return "UNKN ";
        }
    }
    
    static const char* get_color_code(hf_log_level_t level) {
        switch (level) {
            case hf_log_level_t::LOG_LEVEL_ERROR: return "\033[31m";    // Red
            case hf_log_level_t::LOG_LEVEL_WARN: return "\033[33m";     // Yellow
            case hf_log_level_t::LOG_LEVEL_INFO: return "\033[32m";     // Green
            case hf_log_level_t::LOG_LEVEL_DEBUG: return "\033[36m";    // Cyan
            case hf_log_level_t::LOG_LEVEL_VERBOSE: return "\033[37m";  // White
            default: return "\033[0m";                                  // Reset
        }
    }
    
    static void send_udp_message(const char* host, int port, const char* message) {
        // UDP implementation would go here
        // This is a placeholder for actual network implementation
    }
};

๐Ÿงช Best Practices

  1. ๐ŸŽฏ Use Appropriate Log Levels
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    // Use ERROR for critical issues
    logger.LogError("MOTOR", "Controller fault: emergency stop engaged");
       
    // Use WARN for concerning but non-critical issues
    logger.LogWarn("TEMP", "Temperature approaching limit: %.1fยฐC", temp);
       
    // Use INFO for important operational messages
    logger.LogInfo("SYSTEM", "Motor controller initialized successfully");
       
    // Use DEBUG for troubleshooting information
    logger.LogDebug("ADC", "Channel %d reading: %u", channel, raw_value);
       
    // Use VERBOSE for detailed tracing
    logger.LogVerbose("I2C", "Write transaction complete: %d bytes", count);
    
  2. ๐Ÿท๏ธ Use Meaningful Tags
    1
    2
    3
    4
    5
    6
    7
    8
    
    // GOOD: Descriptive, hierarchical tags
    logger.LogInfo("MOTOR.CTRL", "Speed set to %.2f RPM", speed);
    logger.LogDebug("COMM.CAN", "Message received: ID=0x%03X", msg_id);
    logger.LogError("SENSOR.TEMP", "Temperature sensor not responding");
       
    // BAD: Vague or inconsistent tags
    logger.LogInfo("", "Something happened");
    logger.LogError("error", "Bad thing");
    
  3. ๐Ÿ“Š Monitor Performance
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    // Regular statistics monitoring
    hf_logger_statistics_t stats;
    logger.GetStatistics(stats);
       
    if (stats.dropped_messages > 0) {
        logger.LogWarn("LOGGER", "Performance issue: %llu messages dropped", 
                      stats.dropped_messages);
    }
       
    // Check buffer usage
    if (stats.buffer_high_water_mark > 80) {  // 80% usage
        logger.LogWarn("LOGGER", "High buffer usage: %u%%", 
                      stats.buffer_high_water_mark);
    }
    
  4. ๐Ÿ”„ Implement Log Rotation
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    // For file logging, implement rotation
    class LogRotator {
    public:
        void check_rotation() {
            struct stat st;
            if (stat("/spiffs/system.log", &st) == 0) {
                if (st.st_size > MAX_LOG_SIZE) {
                    rotate_logs();
                }
            }
        }
           
    private:
        void rotate_logs() {
            rename("/spiffs/system.log", "/spiffs/system.log.old");
            // Create new log file
        }
    };
    

โŒ Common Pitfalls

  1. ๐Ÿšซ Logging in ISRs or Critical Sections
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    // BAD: Logging from ISR
    void IRAM_ATTR gpio_isr_handler(void* arg) {
        logger.LogDebug("ISR", "GPIO interrupt");  // Don't do this!
    }
       
    // GOOD: Defer logging to task context
    void IRAM_ATTR gpio_isr_handler(void* arg) {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xSemaphoreGiveFromISR(gpio_semaphore, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
       
    void gpio_task(void* params) {
        while (true) {
            if (xSemaphoreTake(gpio_semaphore, portMAX_DELAY)) {
                logger.LogDebug("GPIO", "Interrupt processed");
            }
        }
    }
    
  2. ๐Ÿšซ Excessive Verbose Logging
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    // BAD: Too much verbose logging
    for (int i = 0; i < 1000; i++) {
        logger.LogVerbose("LOOP", "Iteration %d", i);  // Floods log
    }
       
    // GOOD: Sample verbose logging
    for (int i = 0; i < 1000; i++) {
        if (i % 100 == 0) {  // Log every 100 iterations
            logger.LogVerbose("LOOP", "Progress: %d/1000", i);
        }
    }
    
  3. ๐Ÿšซ Not Checking Logger Errors
    1
    2
    3
    4
    5
    6
    7
    8
    
    // BAD: Ignoring logger errors
    logger.LogError("CRITICAL", "System failure");
       
    // GOOD: Handle logger failures
    if (logger.LogError("CRITICAL", "System failure") != LOGGER_SUCCESS) {
        // Fallback logging method
        printf("CRITICAL ERROR: System failure\n");
    }
    

๐ŸŽฏ Performance Tips

  1. โšก Use Appropriate Buffer Sizes
    1
    2
    
    // Configure buffer size based on log volume
    logger.SetBufferSize(8192);  // 8KB buffer for high-volume logging
    
  2. ๐Ÿ“Š Batch Flush Operations
    1
    2
    3
    4
    5
    6
    7
    
    // Flush periodically rather than after each message
    void periodic_flush_task(void* params) {
        while (true) {
            vTaskDelay(pdMS_TO_TICKS(1000));  // Flush every second
            logger.FlushBuffers();
        }
    }
    
  3. ๐Ÿ” Use Conditional Compilation
    1
    2
    3
    4
    5
    6
    
    // Remove verbose logging in production builds
    #ifdef DEBUG_VERBOSE
    #define LOG_VERBOSE(tag, format, ...) logger.LogVerbose(tag, format, ##**VA_ARGS_*)
    #else
    #define LOG_VERBOSE(tag, format, ...) do {} while(0)
    #endif
    

๐Ÿ“‹ Navigation

โ† Previous: BaseNvs | Back to API Index | Next: BaseTemperature โ†’


๐Ÿ“ Professional Logging for Critical System Monitoring

Enabling comprehensive system observability with optimal performance and reliability