{"id":18052549,"url":"https://github.com/mohamedelashri/loggerng","last_synced_at":"2025-04-05T07:23:48.167Z","repository":{"id":260351783,"uuid":"881053634","full_name":"MohamedElashri/LoggerNG","owner":"MohamedElashri","description":"logging utility for C++ programs","archived":false,"fork":false,"pushed_at":"2024-10-30T21:07:31.000Z","size":156,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-10T15:14:46.240Z","etag":null,"topics":["cpp","cpp-library","cpp17","logging"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MohamedElashri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-30T20:45:35.000Z","updated_at":"2024-10-30T21:07:34.000Z","dependencies_parsed_at":"2024-10-30T21:29:38.903Z","dependency_job_id":"e6899f3d-6b40-41a9-8ae5-6941ae33e3e0","html_url":"https://github.com/MohamedElashri/LoggerNG","commit_stats":null,"previous_names":["mohamedelashri/loggerng"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MohamedElashri%2FLoggerNG","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MohamedElashri%2FLoggerNG/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MohamedElashri%2FLoggerNG/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MohamedElashri%2FLoggerNG/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MohamedElashri","download_url":"https://codeload.github.com/MohamedElashri/LoggerNG/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247301694,"owners_count":20916559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp-library","cpp17","logging"],"created_at":"2024-10-30T23:12:12.203Z","updated_at":"2025-04-05T07:23:48.150Z","avatar_url":"https://github.com/MohamedElashri.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LoggerNG: Advanced Logger for C++ programs\n\nAn advanced, flexible, and memory-safe logging utility for C++ programs. This header-only library provides structured, categorized logging with multiple log levels, timestamping, ANSI color coding, asynchronous logging, and more.\n\n---\n\n## Table of Contents\n\n- [Motivation](#motivation)\n- [Basic Usage](#basic-usage)\n- [Features](#features)\n- [Feature Examples](#feature-examples)\n  - [Multiple Log Levels](#multiple-log-levels)\n  - [Timestamping](#timestamping)\n  - [ANSI Color Coding](#ansi-color-coding)\n  - [Structured Formatting](#structured-formatting)\n  - [Conditional Logging](#conditional-logging)\n  - [Output Control](#output-control)\n  - [Logging Categories and Tags](#logging-categories-and-tags)\n  - [Asynchronous Logging](#asynchronous-logging)\n  - [Custom Timestamp Format](#custom-timestamp-format)\n  - [Source Location Metadata](#source-location-metadata)\n  - [Profiling and Benchmarking](#profiling-and-benchmarking)\n  - [Configuration File Support](#configuration-file-support)\n- [Advanced Examples](#advanced-examples)\n- [Memory Safety Guidelines](#memory-safety-guidelines)\n- [Contributing](#contributing)\n- [Available Methods](#available-methods)\n- [Disclaimer](#disclaimer)\n- [License](#license)\n\n---\n\n## Motivation\n\nIn many C++ CLI projects, setting up a consistent and flexible logging system can be a repetitive and time-consuming task. This logging utility aims to provide a standardized, memory-safe way to handle logging across different projects, reducing the need to reinvent the wheel each time. It may not be the most feature-rich or performant logger available, but it strikes a balance between functionality, safety, and ease of integration.\n\n---\n\n## Basic Usage\n\n1. **Include the Header File**\n\n   ```cpp\n   #include \"Logger.hpp\"\n   ```\n\n2. **Configure the Logger**\n\n   ```cpp\n   using namespace LoggerNS;\n\n   // Get the singleton instance of the logger\n   Logger\u0026 logger = Logger::getInstance();\n\n   // Add console output\n   logger.addOutput(std::make_shared\u003cstd::ostream\u003e(std::cout.rdbuf()), LogLevel::DEBUG);\n\n   // Enable asynchronous logging\n   logger.enableAsynchronousLogging(true);\n   ```\n\n3. **Log Messages**\n\n   ```cpp\n   LOG_INFO(\"network\", {\"init\"}, []() { return \"Network initialized successfully.\"; });\n   LOG_DEBUG(\"database\", {\"connection\"}, []() { return \"Database connection established.\"; });\n   LOG_WARNING(\"network\", {\"latency\"}, []() { return \"Network latency is high.\"; });\n   LOG_ERROR(\"database\", {\"query\"}, []() { return \"Failed to execute query.\"; });\n   LOG_CRITICAL(\"system\", {\"memory\"}, []() { return \"Out of memory!\"; });\n   ```\n\n4. **Shutdown the Logger**\n\n   ```cpp\n   // Flush and shutdown the logger\n   logger.flush();\n   logger.enableAsynchronousLogging(false);\n   ```\n\n---\n\n## Features\n\n- **Multiple Log Levels**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, `OFF`\n- **Timestamping**: Includes timestamps with customizable formats\n- **ANSI Color Coding**: Color-coded messages based on severity level\n- **Structured Formatting**: Supports plain text and JSON formats\n- **Conditional Logging**: Logs messages based on the set log level\n- **Output Control**: Redirect logs to multiple `std::ostream` instances\n- **Logging Categories and Tags**: Organize logs by categories and tags\n- **Asynchronous Logging**: Non-blocking logging suitable for multi-threaded applications\n- **Custom Timestamp Format**: Use custom formats for timestamps\n- **Source Location Metadata**: Includes file name, line number, and function name\n- **Profiling and Benchmarking**: Measure execution time with timers\n- **Configuration File Support**: Configure logger via external JSON file\n- **Memory Safety**: Designed with smart pointers and RAII to prevent memory issues\n- **Thread Safety**: Safe to use in multi-threaded applications\n- **Header-only Design**: Easy integration without separate compilation\n\n---\n\n## Feature Examples\n\n### Multiple Log Levels\n\nControl the verbosity of your logs by setting the appropriate log level.\n\n```cpp\nlogger.setGlobalLogLevel(LogLevel::WARNING);\n```\n\nNow, only `WARNING`, `ERROR`, and `CRITICAL` messages will be logged.\n\n### Timestamping\n\nEach log message includes a timestamp for better traceability.\n\n**Output Example:**\n\n```\n2023-10-30 14:23:15 [INFO] [network] Network initialized successfully.\n```\n\n### ANSI Color Coding\n\nEnable or disable ANSI color codes for log messages.\n\n```cpp\nlogger.enableANSIColors(true);\n```\n\n**Color Codes:**\n\n- `DEBUG`: Cyan\n- `INFO`: Green\n- `WARNING`: Yellow\n- `ERROR`: Red\n- `CRITICAL`: Red background\n\n### Structured Formatting\n\nChoose between plain text and JSON output formats.\n\n```cpp\nlogger.setOutputFormat(\"json\");\n```\n\n**JSON Output Example:**\n\n```json\n{\n  \"timestamp\": \"2023-10-30 14:23:15\",\n  \"level\": \"INFO\",\n  \"category\": \"network\",\n  \"message\": \"Network initialized successfully.\",\n  \"file\": \"main.cpp\",\n  \"line\": 42,\n  \"function\": \"main\",\n  \"tags\": [\"init\"]\n}\n```\n\n### Conditional Logging\n\nMessages below the set log level are not logged, minimizing performance overhead.\n\n```cpp\n// This won't be logged if the global log level is set to WARNING\nLOG_DEBUG(\"database\", {\"debug\"}, []() { return \"This is a debug message.\"; });\n```\n\n### Output Control\n\nRedirect logs to multiple outputs, such as files and console.\n\n```cpp\n// Add file output\nauto fileStream = std::make_shared\u003cstd::ofstream\u003e(\"app.log\", std::ios::app);\nif (fileStream-\u003eis_open()) {\n    logger.addOutput(fileStream, LogLevel::DEBUG);\n}\n```\n\n### Logging Categories and Tags\n\nOrganize and filter logs by categories and tags.\n\n```cpp\nlogger.addCategory(\"authentication\");\nlogger.addTag(\"security\");\n\nLOG_INFO(\"authentication\", {\"security\"}, []() { return \"User login successful.\"; });\n```\n\n### Asynchronous Logging\n\nEnable asynchronous logging to improve performance in multi-threaded applications.\n\n```cpp\nlogger.enableAsynchronousLogging(true);\n```\n\n### Custom Timestamp Format\n\nSet a custom format for timestamps.\n\n```cpp\nlogger.setTimestampFormat(\"%d-%m-%Y %H:%M:%S\");\n```\n\n**Output Example:**\n\n```\n30-10-2023 14:23:15 [INFO] [network] Network initialized successfully.\n```\n\n### Source Location Metadata\n\nInclude file name, line number, and function name in log messages.\n\n```cpp\nLOG_ERROR(\"database\", {\"query\"}, []() { return \"Failed to execute query.\"; });\n```\n\n**Output Example:**\n\n```\n2023-10-30 14:23:15 [ERROR] [database] Failed to execute query. (main.cpp:45 in main)\n```\n\n### Profiling and Benchmarking\n\nMeasure the execution time of code blocks.\n\n```cpp\nSTART_TIMER(\"database_query\");\n// Execute database query\nEND_TIMER(\"database_query\", LogLevel::INFO, \"performance\", {\"benchmark\"});\n```\n\n**Output Example:**\n\n```\n2023-10-30 14:23:15 [INFO] [performance] Timer [database_query] elapsed time: 120 ms\n```\n\n### Configuration File Support\n\nConfigure the logger via an external JSON file.\n\n**config.json**\n\n```json\n{\n  \"globalLogLevel\": \"DEBUG\",\n  \"outputs\": [\n    {\n      \"type\": \"console\",\n      \"logLevel\": \"INFO\",\n      \"timestampFormat\": \"%Y-%m-%d %H:%M:%S\",\n      \"outputFormat\": \"plain\",\n      \"useANSIColors\": true\n    },\n    {\n      \"type\": \"file\",\n      \"filePath\": \"app.log\",\n      \"logLevel\": \"DEBUG\",\n      \"timestampFormat\": \"%Y-%m-%d %H:%M:%S\",\n      \"outputFormat\": \"json\",\n      \"useANSIColors\": false\n    }\n  ]\n}\n```\n\n**Load Configuration**\n\n```cpp\nlogger.loadConfiguration(\"config.json\");\n```\n\n---\n\n## Advanced Examples\n\n### Example 1: Multi-Output and Custom Formatting\n\n```cpp\n#include \"Logger.hpp\"\n#include \u003cfstream\u003e\n\nint main() {\n    using namespace LoggerNS;\n    Logger\u0026 logger = Logger::getInstance();\n\n    // Add console output with INFO level\n    logger.addOutput(std::make_shared\u003cstd::ostream\u003e(std::cout.rdbuf()), LogLevel::INFO);\n\n    // Add file output with DEBUG level\n    auto fileStream = std::make_shared\u003cstd::ofstream\u003e(\"app.log\", std::ios::app);\n    if (fileStream-\u003eis_open()) {\n        logger.addOutput(fileStream, LogLevel::DEBUG, \"%d-%m-%Y %H:%M:%S\", \"json\", false);\n    }\n\n    // Set global log level to DEBUG\n    logger.setGlobalLogLevel(LogLevel::DEBUG);\n\n    // Enable asynchronous logging\n    logger.enableAsynchronousLogging(true);\n\n    // Log messages\n    LOG_DEBUG(\"system\", {\"init\"}, []() { return \"System initialized.\"; });\n    LOG_INFO(\"network\", {\"connection\"}, []() { return \"Network connected.\"; });\n\n    // Shutdown the logger\n    logger.flush();\n    logger.enableAsynchronousLogging(false);\n\n    return 0;\n}\n```\n\n### Example 2: Tag-Based Filtering\n\n```cpp\n#include \"Logger.hpp\"\n\nint main() {\n    using namespace LoggerNS;\n    Logger\u0026 logger = Logger::getInstance();\n\n    // Add console output\n    logger.addOutput(std::make_shared\u003cstd::ostream\u003e(std::cout.rdbuf()), LogLevel::INFO);\n\n    // Add tags to filter\n    logger.addTag(\"critical\");\n\n    LOG_INFO(\"system\", {\"status\"}, []() { return \"System running smoothly.\"; }); // Not logged\n    LOG_CRITICAL(\"system\", {\"critical\"}, []() { return \"Critical system failure!\"; }); // Logged\n\n    return 0;\n}\n```\n\n### Example 3: Asynchronous Logging in Multi-threaded Environment\n\n```cpp\n#include \"Logger.hpp\"\n#include \u003cthread\u003e\n\nvoid threadFunction(const std::string\u0026 threadName) {\n    for (int i = 0; i \u003c 10; ++i) {\n        LOG_INFO(\"thread\", {threadName}, [i, threadName]() {\n            return \"Message \" + std::to_string(i) + \" from \" + threadName;\n        });\n    }\n}\n\nint main() {\n    using namespace LoggerNS;\n    Logger\u0026 logger = Logger::getInstance();\n\n    // Add console output\n    logger.addOutput(std::make_shared\u003cstd::ostream\u003e(std::cout.rdbuf()), LogLevel::INFO);\n\n    // Enable asynchronous logging\n    logger.enableAsynchronousLogging(true);\n\n    // Start threads\n    std::thread t1(threadFunction, \"Thread1\");\n    std::thread t2(threadFunction, \"Thread2\");\n\n    t1.join();\n    t2.join();\n\n    // Shutdown the logger\n    logger.flush();\n    logger.enableAsynchronousLogging(false);\n\n    return 0;\n}\n```\n\n---\n\n## Memory Safety Guidelines\n\nThe logger is designed with memory safety in mind, using smart pointers and RAII (Resource Acquisition Is Initialization) principles to manage resources automatically. However, it's important to follow certain guidelines to ensure memory safety while using the logger:\n\n1. **Use Smart Pointers for Streams**\n\n   - When adding outputs, use `std::shared_ptr` or `std::unique_ptr` to manage stream lifetimes.\n   - **Example:**\n\n     ```cpp\n     auto fileStream = std::make_shared\u003cstd::ofstream\u003e(\"app.log\", std::ios::app);\n     if (fileStream-\u003eis_open()) {\n         logger.addOutput(fileStream, LogLevel::DEBUG);\n     }\n     ```\n\n2. **Avoid Raw Pointers**\n\n   - Do not use raw pointers for dynamic memory allocation. Rely on smart pointers provided by the logger.\n\n3. **Thread Safety**\n\n   - The logger is thread-safe, but ensure that any data passed to the logger is also managed safely.\n   - When using tags or categories, ensure they are valid and not modified concurrently.\n\n4. **Exception Safety**\n\n   - The `messageGenerator` function in logging calls should handle exceptions internally if necessary.\n   - The logger catches exceptions thrown during message generation to prevent crashes.\n\n   **Example:**\n\n   ```cpp\n   LOG_INFO(\"system\", {\"init\"}, []() {\n       try {\n           // Generate message\n           return \"System initialized.\";\n       } catch (...) {\n           return \"Error generating message.\";\n       }\n   });\n   ```\n\n5. **Proper Shutdown**\n\n   - Always flush and properly shut down the logger before application exit to ensure all messages are processed.\n\n   ```cpp\n   logger.flush();\n   logger.enableAsynchronousLogging(false);\n   ```\n\n6. **Avoid Modifying Logger After Shutdown**\n\n   - Do not attempt to log messages or modify logger settings after shutting down asynchronous logging.\n\n7. **Use of RAII**\n\n   - Rely on RAII patterns for resource management in your application to complement the logger's design.\n\n8. **Avoid Long Blocking Operations in Message Generators**\n\n   - Since message generators are executed within the logger, avoid long-running operations that could block logging threads.\n\n---\n\n## Contributing\n\nThis project is open to contributions! If you have ideas for new features, optimizations, or improvements, feel free to:\n\n- Fork the repository\n- Create a new branch\n- Implement your feature\n- Submit a pull request\n\n**Example of Adding a New Feature:**\n\nSuppose you want to add support for logging to a remote server. You could:\n\n- Add a new method `logger.addRemoteOutput(const std::string\u0026 url);`\n- Implement a new `Output` subclass to handle network communication\n- Update the documentation accordingly\n\n---\n\n## Available Methods\n\n| Method                                           | Description                                       |\n|--------------------------------------------------|---------------------------------------------------|\n| `Logger::getInstance()`                          | Retrieves the singleton instance of the logger    |\n| `addOutput(std::shared_ptr\u003cstd::ostream\u003e, LogLevel, ...)` | Adds a new output destination           |\n| `setGlobalLogLevel(LogLevel level)`              | Sets the global log level                         |\n| `setCategoryLogLevel(const std::string\u0026, LogLevel)` | Sets log level for a specific category        |\n| `addCategory(const std::string\u0026 category)`       | Adds a category to filter logs                    |\n| `removeCategory(const std::string\u0026 category)`    | Removes a category from the filter                |\n| `addTag(const std::string\u0026 tag)`                 | Adds a tag to filter logs                         |\n| `removeTag(const std::string\u0026 tag)`              | Removes a tag from the filter                     |\n| `setTimestampFormat(const std::string\u0026 format)`  | Sets the format for timestamps                    |\n| `setOutputFormat(const std::string\u0026 format)`     | Sets the output format (\"plain\" or \"json\")        |\n| `enableAsynchronousLogging(bool enable)`         | Enables or disables asynchronous logging          |\n| `flush()`                                        | Flushes all pending log messages                  |\n| `loadConfiguration(const std::string\u0026 path)`     | Loads configuration from a JSON file              |\n| `startTimer(const std::string\u0026 timerName)`       | Starts a timer with the given name                |\n| `endTimer(const std::string\u0026, LogLevel, const std::string\u0026, const std::set\u003cstd::string\u003e\u0026)` | Ends a timer and logs the elapsed time |\n\n**Convenience Macros:**\n\n- `LOG_DEBUG(category, tags, message)`\n- `LOG_INFO(category, tags, message)`\n- `LOG_WARNING(category, tags, message)`\n- `LOG_ERROR(category, tags, message)`\n- `LOG_CRITICAL(category, tags, message)`\n- `START_TIMER(timerName)`\n- `END_TIMER(timerName, level, category, tags)`\n\n---\n\n## Disclaimer\n\nThis logging utility is designed to provide a standardized and memory-safe logging mechanism for personal projects. It may not be the most efficient or feature-rich solution available. The primary goal is to simplify logging across different projects without having to implement a new system each time.\n\n---\n\n## License\n\nThis project is licensed under the MIT License.\n\n---\n\nFeel free to customize and adapt this logger to suit your project's needs!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohamedelashri%2Floggerng","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmohamedelashri%2Floggerng","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmohamedelashri%2Floggerng/lists"}