A cross-platform real-time logging library for embedded systems that provides structured, colorized, and timestamped logging with automatic platform detection. ChronoLog seamlessly adapts to different embedded environments including Arduino, ESP-IDF, nRF Connect SDK (Zephyr), and STM32 HAL with or without RTOS support.
- β¨ Features
- π― Supported Platforms
- π¦ Installation
- π Quick Start
- π Log Output Examples
- βοΈ Configuration
- π οΈ Platform-Specific Requirements
- π§ Troubleshooting
- π Repository Structure
- π£οΈ Roadmap & Upcoming Features
- π Support & Motivation
- π€ Contributing
- π License
- π¨βπ» Author
- β Show Your Support
- π― Automatic Platform Detection: Detects and adapts to Arduino, ESP-IDF, Zephyr (nRF Connect SDK), STM32 HAL, and desktop environments
- β° Smart Timestamps:
- Real-time timestamps when system time is synced (Arduino/ESP-IDF with NTP)
- Uptime-based timestamps for other platforms
- System time for desktop platforms (Linux, Windows, macOS)
- π¨ Colorized Output: Color-coded log levels for better readability
- π Structured Logging: Clean tabular format with timestamps, module names, log levels, and thread/task information
- π§΅ Thread-Safe Operation: Safe concurrent logging from multiple threads
- π Multiple Log Levels: DEBUG, INFO, WARN, ERROR, FATAL with runtime level control
- ποΈ Module-based Logging: Create separate loggers for different modules with individual log levels
- π Progress Bar Support: Built-in progress tracking with visual progress bars (requires
CHRONOLOG_PRO_FEATURES) - οΏ½ Remote Logging: Stream logs over TCP to remote clients for centralized monitoring (requires
CHRONOLOG_REMOTE_ENABLE) - οΏ½π₯οΈ Desktop Support: Full compatibility with Linux, Windows, and macOS
- πΎ Memory Efficient: Header-only library with minimal memory footprint
- π Zero Configuration: Works out-of-the-box on supported platforms
- βοΈ Conditional Compilation: Enable only the features you need to optimize for your platform
- π¦ Official Package Managers: Available on Arduino IDE Library Manager, PlatformIO, and ESP-IDF Component Manager
| Platform | Framework | RTOS/Thread Support | Real-time Clock |
|---|---|---|---|
| ESP32 | Arduino | β FreeRTOS | β NTP Sync |
| ESP32 | ESP-IDF | β FreeRTOS | β NTP Sync |
| STM32 | HAL | β FreeRTOS/CMSIS-OS | β±οΈ HAL_GetTick() |
| STM32 | HAL | β Bare Metal | β±οΈ HAL_GetTick() |
| nRF52 | nRF Connect SDK | β Zephyr | β±οΈ k_uptime_get() |
| Linux | Native | β pthread | β System Time |
| Windows | Native | β Windows Threads | β System Time |
| macOS | Native | β pthread | β System Time |
ChronoLog is officially available on multiple package managers! Choose your preferred installation method:
Option 1: Arduino IDE Library Manager β (Easiest for Arduino)
- Open Arduino IDE β Sketch β Include Library β Manage Libraries
- Search for "ChronoLog"
- Click Install
Option 2: PlatformIO Library Manager β (Recommended for ESP32/ESP-IDF)
- Open PlatformIO β Libraries β Search for "ChronoLog" β Install
- Or manually add to
lib_depsinplatformio.ini
Option 3: ESP-IDF Component Manager β (For ESP-IDF Projects)
- ESP-IDF 5.0+ automatically finds ChronoLog in the component registry
- Or manually add to your project's dependency manifest
Search for "ChronoLog" in the PlatformIO Library Manager and add it to your project.
Simply add ChronoLog to the lib_deps section in your platformio.ini file:
[env:your_board]
platform = your_platform
board = your_board
framework = arduino ; or espidf
lib_deps =
ChronoLogExample for ESP32-C6:
[env:esp32-c6-devkitm-1]
platform = https://github.com/tasmota/platform-espressif32.git
board = esp32-c6-devkitm-1
framework = arduino
lib_deps =
ChronoLog- Create a
componentsfolder in your project root (if it doesn't exist) - Navigate to the components folder and clone the repository:
cd components git clone https://github.com/Hamas888/ChronoLog.git - Add the requirement to your main
CMakeLists.txt:idf_component_register( SRCS "main.cpp" INCLUDE_DIRS "." REQUIRES ChronoLog # Add this line )
- Create a
modulesfolder in your project root - Navigate to the modules folder and clone the repository:
cd modules git clone https://github.com/Hamas888/ChronoLog.git - Add the subdirectory to your root
CMakeLists.txt:add_subdirectory(modules/ChronoLog) target_link_libraries(app PRIVATE ChronoLog)
- Clone the repository in your project root:
git clone https://github.com/Hamas888/ChronoLog.git
- Add to your root
CMakeLists.txtafteradd_executable():add_executable(${PROJECT_NAME} ${SOURCES} ${LINKER_SCRIPT}) # Add ChronoLog add_subdirectory(ChronoLog) target_link_libraries(${PROJECT_NAME} ChronoLog)
For native desktop applications, simply include the library in your CMake project:
-
Clone or download ChronoLog to your project:
git clone https://github.com/Hamas888/ChronoLog.git
-
Add to your
CMakeLists.txt:add_subdirectory(ChronoLog) target_link_libraries(your_target_name ChronoLog)
Note: Desktop builds automatically detect the platform and provide full thread safety and system time support.
#include "ChronoLog.h"
// Create a logger for your module
ChronoLogger logger("MyModule", CHRONOLOG_LEVEL_DEBUG);
void setup() { // or main() for non-Arduino platforms
// For STM32, set UART handler (REQUIRED for STM32 platforms)
#if defined(CHRONOLOG_PLATFORM_STM32_HAL)
logger.setUartHandler(&huart2); // Your UART handle (e.g., huart1, huart2)
#endif
logger.info("System initialized");
logger.debug("Debug information");
logger.warn("This is a warning");
logger.error("An error occurred");
logger.fatal("Critical system error");
}#include "ChronoLog.h"
ChronoLogger sensorLogger("Sensors", CHRONOLOG_LEVEL_INFO);
ChronoLogger networkLogger("Network", CHRONOLOG_LEVEL_DEBUG);
ChronoLogger systemLogger("System", CHRONOLOG_LEVEL_WARN);
void initLoggers() {
// Required for STM32 platforms
#if defined(CHRONOLOG_PLATFORM_STM32_HAL)
sensorLogger.setUartHandler(&huart2);
networkLogger.setUartHandler(&huart2);
systemLogger.setUartHandler(&huart2);
#endif
}
void sensorTask() {
sensorLogger.info("Reading temperature: %.2fΒ°C", 25.6f);
sensorLogger.debug("Sensor calibration complete");
}
void networkTask() {
networkLogger.info("WiFi connected to %s", "MyNetwork");
networkLogger.error("Failed to connect to server");
}ChronoLogger logger("MyModule", CHRONOLOG_LEVEL_INFO);
void updateLogLevel(int level) {
logger.setLevel(static_cast<ChronoLogLevel>(level));
logger.info("Log level updated to %d", level);
}#include "ChronoLog.h"
#if defined(CHRONOLOG_PLATFORM_DESKTOP)
#include <thread>
#include <chrono>
#endif
ChronoLogger appLogger("DesktopApp", CHRONOLOG_LEVEL_DEBUG);
void workerThread(int threadId) {
for (int i = 0; i < 5; i++) {
appLogger.info("Worker %d processing item %d", threadId, i);
#if defined(CHRONOLOG_PLATFORM_DESKTOP)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
#endif
}
}
int main() {
appLogger.info("Desktop application started");
#if defined(CHRONOLOG_PLATFORM_DESKTOP)
// Create multiple threads for testing thread safety
std::thread t1(workerThread, 1);
std::thread t2(workerThread, 2);
t1.join();
t2.join();
#else
// For embedded platforms, run sequentially
workerThread(1);
workerThread(2);
#endif
appLogger.info("All workers completed");
return 0;
}#include "ChronoLog.h"
// Enable pro features in your build configuration
// #define CHRONOLOG_PRO_FEATURES 1
ChronoLogger logger("Progress", CHRONOLOG_LEVEL_PRO_FEATURES);
void processWithProgress() {
uint32_t total = 100;
for (uint32_t i = 0; i <= total; i++) {
// Update progress bar (parameter order: current, total, title)
logger.progress(i, total, "Processing data");
// Simulate work
#if defined(CHRONOLOG_PLATFORM_DESKTOP)
std::this_thread::sleep_for(std::chrono::milliseconds(50));
#elif defined(CHRONOLOG_PLATFORM_ARDUINO)
delay(50);
#elif defined(CHRONOLOG_PLATFORM_ESP_IDF)
vTaskDelay(pdMS_TO_TICKS(50));
#endif
}
logger.info("Processing completed!");
}#include "ChronoLog.h"
// Enable remote logging in your build configuration
// #define CHRONOLOG_REMOTE_ENABLE 1
ChronoLogger logger("RemoteApp", CHRONOLOG_LEVEL_INFO);
void setupRemoteLogging() {
#if CHRONOLOG_REMOTE_ENABLE
// Start the remote logging server on port 9999
ChronoLogRemote* remoteLogger = ChronoLogRemote::getInstance();
bool started = remoteLogger->start(9999);
if (started) {
logger.info("Remote logging started on port 9999");
} else {
logger.error("Failed to start remote logging server");
}
#else
logger.warn("Remote logging is disabled. Enable with CHRONOLOG_REMOTE_ENABLE=1");
#endif
}
void applicationLoop() {
logger.info("Application started - logs are streamed to connected clients");
logger.debug("This message is sent to all connected remote clients");
logger.error("Error logs are also transmitted to remote monitors");
}14:32:15 | Sensors | INFO | WiFiTask | Temperature reading: 25.6Β°C
14:32:15 | Network | DEBUG | NetworkTask | Attempting connection to server
14:32:16 | Network | WARN | NetworkTask | Connection timeout, retrying...
14:32:17 | System | ERROR | MainTask | Memory allocation failed
14:32:17 | System | FATAL | ErrorHandler | System halt required
00:05:23 | Sensors | INFO | SensorTask | Accelerometer initialized
00:05:23 | Sensors | DEBUG | SensorTask | Calibration data: X=1.02, Y=0.98, Z=9.81
00:05:24 | BLE | INFO | BLETask | Advertisement started
00:05:25 | System | WARN | MainTask | Low battery warning: 15%
14:32:15 | DesktopApp | INFO | Thread-123 | Worker 1 processing item 0
14:32:15 | DesktopApp | INFO | Thread-456 | Worker 2 processing item 0
14:32:15 | FileHandler | DEBUG | Thread-789 | Opening configuration file
14:32:16 | Database | ERROR | Thread-234 | Connection timeout after 5s
14:32:16 | Progress | PROGRESS | Thread-567 | Processing data: 100% (100/100) [====================]
Note: Progress bars require CHRONOLOG_PRO_FEATURES to be enabled and logger level set to CHRONOLOG_LEVEL_PRO_FEATURES or higher.
Progress bars use conditional coloring based on completion status:
- π Orange: In-progress (0-99% complete)
- π΅ Cyan: Completed (100% complete)
The library automatically applies color coding to different log levels:
- π΅ DEBUG: Blue (Italic)
- π’ INFO: Green (Italic)
- π‘ WARN: Yellow (Italic)
- π΄ ERROR: Red (Italic)
- π£ FATAL: Magenta (Italic)
- π PROGRESS (In-progress): Orange (Italic)
- π΅ PROGRESS (Complete): Cyan (Italic)
ChronoLog allows you to enable or disable features at compile time to optimize for your specific use case:
// === Core Logging Configuration ===
#define CHRONOLOG_MODE 1 // Set to 0 to disable all logging
#define CHRONOLOG_BUFFER_LEN 100 // Buffer size for log messages (default: 100)
#define CHRONOLOG_DEFAULT_LEVEL CHRONOLOG_LEVEL_DEBUG // Default log level
// === Feature Control ===
#define CHRONOLOG_COLOR_ENABLE 1 // Enable colored output (1 = enabled, 0 = disabled)
#define CHRONOLOG_THREAD_SAFE 1 // Enable thread-safe operations (1 = enabled, 0 = disabled)
#define CHRONOLOG_PRO_FEATURES 1 // Enable Pro features like progress bars (1 = enabled, 0 = disabled)
#define CHRONOLOG_REMOTE_ENABLE 0 // Enable remote logging via TCP (1 = enabled, 0 = disabled)
// Note: The following features are automatically detected based on platform:
// - Timestamps are always enabled and use platform-appropriate time sources
// - Thread/task information is automatically detected on RTOS platforms
// - Desktop support is automatic when compiling for Linux/Windows/macOS
// - RTOS support is automatic when FreeRTOS/Zephyr/CMSIS-OS is detected// Minimal configuration for resource-limited embedded systems
#define CHRONOLOG_MODE 1
#define CHRONOLOG_BUFFER_LEN 64 // Smaller buffer to save memory
#define CHRONOLOG_COLOR_ENABLE 0 // Disable colors to save memory
#define CHRONOLOG_THREAD_SAFE 0 // Disable if not using RTOS
#define CHRONOLOG_PRO_FEATURES 0 // Disable progress bars
#define CHRONOLOG_REMOTE_ENABLE 0 // Disable remote logging
#define CHRONOLOG_DEFAULT_LEVEL CHRONOLOG_LEVEL_ERROR // Only show errors// Full-featured configuration for desktop applications
#define CHRONOLOG_MODE 1
#define CHRONOLOG_BUFFER_LEN 512 // Larger buffer for detailed messages
#define CHRONOLOG_COLOR_ENABLE 1 // Enable colors for better readability
#define CHRONOLOG_THREAD_SAFE 1 // Essential for multi-threaded desktop apps
#define CHRONOLOG_PRO_FEATURES 1 // Enable progress bars and advanced features
#define CHRONOLOG_DEFAULT_LEVEL CHRONOLOG_LEVEL_DEBUG // Show all messages during development// Production configuration with essential features only
#define CHRONOLOG_MODE 1
#define CHRONOLOG_BUFFER_LEN 200 // Moderate buffer size
#define CHRONOLOG_COLOR_ENABLE 0 // Disable colors for production
#define CHRONOLOG_THREAD_SAFE 1 // Keep thread safety for RTOS
#define CHRONOLOG_PRO_FEATURES 0 // Disable progress bars in production
#define CHRONOLOG_DEFAULT_LEVEL CHRONOLOG_LEVEL_INFO // Info level for productionenum ChronoLogLevel {
CHRONOLOG_LEVEL_NONE, // No logging
CHRONOLOG_LEVEL_FATAL, // Only fatal errors
CHRONOLOG_LEVEL_ERROR, // Errors and above
CHRONOLOG_LEVEL_WARN, // Warnings and above
CHRONOLOG_LEVEL_INFO, // Info and above (recommended)
CHRONOLOG_LEVEL_DEBUG, // All messages (development)
CHRONOLOG_LEVEL_PRO_FEATURES // Includes progress bars (only when CHRONOLOG_PRO_FEATURES is enabled)
};Note: CHRONOLOG_LEVEL_PRO_FEATURES is only available when CHRONOLOG_PRO_FEATURES is defined as 1. This conditional level enables advanced features like progress bars while maintaining backward compatibility.
ChronoLogger logger("MyModule", CHRONOLOG_LEVEL_INFO);
// Change log level at runtime
logger.setLevel(CHRONOLOG_LEVEL_DEBUG);
// For STM32 platforms, set UART handler
#if defined(CHRONOLOG_PLATFORM_STM32_HAL)
logger.setUartHandler(&huart2);
#endif
// Note: Color and timestamp settings are compile-time only
// Use the #define directives shown above to control these features- No additional setup required
- Serial output at configured baud rate
- For real timestamps, sync system time with NTP
- No additional setup required
- Output to stdout/console
- For real timestamps, configure SNTP
- Required: Set UART handler using
logger.setUartHandler(&huartX) - Works with or without FreeRTOS/CMSIS-OS
- Output via specified UART peripheral
STM32 Complete Setup Example:
#include "ChronoLog.h"
ChronoLogger logger("STM32App", CHRONOLOG_LEVEL_DEBUG);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init(); // Initialize your UART
// REQUIRED: Set UART handler for ChronoLog
logger.setUartHandler(&huart2);
logger.info("STM32 application started");
while (1) {
logger.debug("Main loop iteration");
HAL_Delay(1000);
}
}- No additional setup required
- Uses Zephyr's printk for output
- Automatic thread name detection
- Thread Safety: Automatic mutex-based synchronization for multi-threaded applications
- Progress Bars: Full support for visual progress tracking
- System Time: Uses system clock for real-time timestamps
- File Logging: Optional file output support (coming in future releases)
- Colors: Full ANSI color support in compatible terminals
STM32: No log output visible
- Ensure
logger.setUartHandler(&huartX)is called before logging - Verify UART is properly initialized and connected
- Check baud rate settings match your serial monitor
Progress bars not working
- Verify
#define CHRONOLOG_PRO_FEATURES 1is set - Ensure logger level is
CHRONOLOG_LEVEL_PRO_FEATURESor higher - Progress bars are only available when Pro features are enabled
Compilation errors on platform detection
- Platform detection is automatic; avoid manually defining platform macros
- For custom platforms, check the header file for supported detection patterns
Thread safety issues
- Thread safety is enabled by default (
CHRONOLOG_THREAD_SAFE 1) - On custom RTOS implementations, mutex initialization may need adjustment
ChronoLog/
βββ include/
β βββ ChronoLog.h # Main header file
βββ examples/
β βββ PlatformIO/
β β βββ Arduino/ # Arduino framework examples
β β βββ ESP-IDF/ # ESP-IDF framework examples
β βββ ESP-IDF/ # Native ESP-IDF examples
β βββ STM32Cube/ # STM32CubeIDE examples
β βββ NRF Connect SDK/ # nRF Connect SDK examples
β βββ Pro Features/ # Advanced features examples
β β βββ ESP32-S3 Progress Bar/ # Progress bar implementation
β β βββ Remote Logging/ # Remote logging implementation (TCP streaming)
β βββ ThreadSafe/ # Thread safety examples
β β βββ ESP32-S3 Thread Safety/ # Multi-threading examples
β βββ Desktop/ # Desktop application examples
βββ CMakeLists.txt # Multi-platform CMake configuration
βββ library.json # PlatformIO library manifest
βββ library.properties # Arduino library properties
βββ idf_component.yml # ESP-IDF component configuration
βββ README.md
ChronoLog is actively developed with exciting features planned for future releases:
- π‘ Remote Logging: TCP-based log streaming to remote clients (v1.1.0+)
- π Progress Bar Support: Visual progress tracking with color indicators (v1.0+)
- π§΅ Thread-Safe Operation: Safe concurrent logging from multiple threads (v1.0+)
- πΎ Flash File Logging: Log directly to flash memory with retrieval capabilities
- β‘ Memory & Speed Optimization: Enhanced performance for resource-constrained systems
- π§ Robust 8-bit AVR Support: Full compatibility with Arduino Uno, Nano, and other 8-bit platforms
- π Log Filtering: Built-in filtering and pattern matching for logs
- π Log Analytics: Built-in log filtering and analysis tools
- π Encrypted Logging: Secure log transmission and storage
- π± Mobile App Integration: Real-time log monitoring via smartphone apps
- π Zero-copy Logging: Minimize memory allocations for high-frequency logging
- βοΈ Compile-time Optimization: Further reduction in code size and RAM usage
- π Circular Buffer Support: Efficient log rotation for continuous operation
Want to influence the roadmap? Share your ideas through GitHub Issues or reach out via Patreon for direct feature discussions!
ChronoLog is developed in my spare time with passion for the embedded community. Your support helps motivate continued development of this and other upcoming sensor libraries and embedded tools.
- β Star this repository - It means a lot and helps others discover ChronoLog
- π Patreon - Monthly support for ongoing development
- π Issues: Create a GitHub Issue for bugs or feature requests
- π Direct Help: Reach out on Patreon for direct support and discussions
- π§ Email: Contact me at hamasaeed@gmail.com for collaboration or questions
Your support enables me to:
- π§ Maintain and improve ChronoLog
- π‘ Develop upcoming sensor libraries
- π Create more embedded development tools
- π Provide community support and documentation
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
This permissive license allows for both commercial and non-commercial use, making ChronoLog suitable for any embedded project.
Hamas Saeed
- GitHub: @Hamas888
- Email: hamasaeed@gmail.com
If this project helped you, please give it a βοΈ on GitHub!