{"id":31250606,"url":"https://github.com/moehoshio/nlog","last_synced_at":"2025-09-23T05:33:30.935Z","repository":{"id":315645950,"uuid":"1050339835","full_name":"moehoshio/nlog","owner":"moehoshio","description":"An easy-to-use, modern, lightweight, and efficient C++20 logging library.","archived":false,"fork":false,"pushed_at":"2025-09-19T19:58:11.000Z","size":20,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-19T21:52:01.057Z","etag":null,"topics":["cpp","cpp-library","cpp20"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moehoshio.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-04T09:42:41.000Z","updated_at":"2025-09-19T19:58:15.000Z","dependencies_parsed_at":"2025-09-20T00:18:21.090Z","dependency_job_id":null,"html_url":"https://github.com/moehoshio/nlog","commit_stats":null,"previous_names":["moehoshio/nlog"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/moehoshio/nlog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moehoshio%2Fnlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moehoshio%2Fnlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moehoshio%2Fnlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moehoshio%2Fnlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moehoshio","download_url":"https://codeload.github.com/moehoshio/nlog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moehoshio%2Fnlog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276519146,"owners_count":25656560,"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","status":"online","status_checked_at":"2025-09-23T02:00:09.130Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","cpp20"],"created_at":"2025-09-23T05:33:26.998Z","updated_at":"2025-09-23T05:33:30.870Z","avatar_url":"https://github.com/moehoshio.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Neko Logging\n\nNeko Logging (nlog) is an easy-to-use, modern, lightweight, and efficient C++20 logging library.\n\n[![License](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE)\n![Require](https://img.shields.io/badge/%20Require%20-%3E=%20C++%2020-orange.svg)\n\n## Features\n\n- No Macro\n- Header Only (No build/link required)\n- Auto SrcLoc (Automatically capture source code location)\n- Supports multiple appenders (Console, File, Custom)\n- Supports custom formatted log messages\n- Supports asynchronous logging\n- Thread-safe\n- RAII-style scope logging\n\n## Quick Start\n\nConfigure:\n[CMake](#cmake) | [Git Submodule](#git-submodule) | [Manual](#manual)\n\nExample:\n[Basic](#basic-example) | [Logging](#logging) | [Level](#level) | [Set Thread Name](#set-thread-name)\n\nAdvanced:\n[Appenders](#appenders) | [Formatting Logs](#formatting-logs) | [Asynchronous Logging](#asynchronous-logging) | [RAII Scope Logging](#raii-scope-logging)\n\n### CMake\n\n1. Using CMake's `FetchContent` to include NekoLog in your project:\n\n```cmake\ninclude(FetchContent)\n\n# Add NekoLog to your CMake project\nFetchContent_Declare(\n    NekoLog\n    GIT_REPOSITORY https://github.com/moehoshio/nlog.git\n    GIT_TAG        main\n)\nFetchContent_MakeAvailable(NekoLog)\n\ntarget_link_libraries(your_target PRIVATE NekoLog)\n```\n\n2. Include the header in your source code\n\n```cpp\n#include \u003cneko/log/nlog.hpp\u003e\n```\n\n### Git Submodule\n\n1. Add NekoLog as a submodule to your repository\n\n```shell\ngit submodule add https://github.com/moehoshio/nlog.git\n```\n\n2. Update submodules:\n\n```shell\ngit submodule update --init --recursive\n```\n\n3. Include the header in your source code\n\n```cpp\n#include \u003cneko/log/nlog.hpp\u003e\n```\n\n### Manual\n\n1. Clone or download the repository to your host\n\n```shell\ngit clone https://github.com/moehoshio/nlog.git\n```\n\nor\n\n```shell\ncurl -L -o nlog.zip https://github.com/moehoshio/nlog/archive/refs/heads/main.zip\n\nunzip nlog.zip\n```\n\n2. Copy the `include` folder to your include directory\n\n```shell\ncp -r nlog/include/ /path/to/your/include/\n```\n\n3. Include the header in your source code\n\n```cpp\n#include \u003cneko/log/nlog.hpp\u003e\n```\n\n### Basic Example\n\nNow you can start logging with minimal setup:\n\n```cpp\n#include \"neko/log/nlog.hpp\"\n\nint main() {\n    using namespace neko;\n    log::setCurrentThreadName(\"Main Thread\"); // Set the current thread name\n    log::setLevel(log::Level::Debug); // Set the log level\n\n    log::info(\"This is an info message.\");\n    log::debug(\"This is a debug message.\");\n    log::warn(\"This is a warning message.\");\n    log::error(\"This is an error message.\");\n}\n```\n\noutput:\n\n```log\n[2025-09-16 01:53:58.678] [Info] [Main Thread] [main.cpp:9] This is an info message.\n[2025-09-16 01:53:58.679] [Debug] [Main Thread] [main.cpp:10] This is a debug message.\n[2025-09-16 01:53:58.679] [Warn] [Main Thread] [main.cpp:11] This is a warning message.\n[2025-09-16 01:53:58.679] [Error] [Main Thread] [main.cpp:12] This is an error message.\n```\n\n## Usage\n\n### Logging\n\nLogging is simple, just like in the example above.\nUse the `neko::log::info`, `neko::log::debug`, `neko::log::warn`, and `neko::log::error` functions to log.\nEach of these functions has two versions.\n\nSingle string:\n```cpp\ninline void debug(const std::string \u0026message, const neko::SrcLocInfo \u0026location = {});\n\ndebug(\"msg\"); // (basic format)... msg\n```\n\nAnd with format arguments (via std::format):\n```cpp\n    template \u003ctypename... Args\u003e\n    void debug(const neko::SrcLocInfo \u0026location, std::format_string\u003cArgs...\u003e fmt, Args \u0026\u0026...args);\n\n    debug( {} , \"Hello , {} . 1 + 1 = {}\", \"World\" , 1 + 1); // (basic format)... Hello , World . 1 + 1 = 2\n```\nFunctions for other levels are the same.\n\nTip: `SrcLoc` can automatically get the source code location. You just need a default object, which you can generate via `{}` or a default parameter.\n\n### Level\n\nYou can set the log level for the logger, which controls which level of logs should be recorded.\n\nFor example, if you set `setLevel` to `Info`, only logs of `Info` level and above will be recorded (Debug messages will be discarded).\n\n```cpp\nlog::setLevel(log::Level::Info);\n\nlog::info(\"Info\"); // Outputs Info\nlog::warn(\"Warn\"); // Outputs Warn\nlog::debug(\"Debug\"); // More detailed messages will be discarded\n```\n\nIf needed, you can add more log levels and log with the `log` function.\nFor example:\n```cpp\n\n// nlog.hpp\nenum class Level : neko::uint8 {\n        Debug = 1, ///\u003c Debug\n        Info = 2,  ///\u003c General information\n        Warn = 3,  ///\u003c Potential issues\n        Error = 4, ///\u003c Error\n        lv5 = 5, /// Custom level\n        lv6 = 6,\n        lv10 = 10,\n        Off = 255  ///\u003c Logging off\n    };\n\n// main.cpp\nusing namespace neko;\n\nlog::logger.log(log::Level::lv10,\"Hello Lv10\");\n```\n\n### Set Thread Name\n\nYou can set the names of different threads in the logs using `neko::log::setCurrentThreadName` and `neko::log::setThreadName`.\n\nExample:\n```cpp\nusing namespace neko;\n\n// Set the current thread\nlog::setCurrentThreadName(\"Thread 1\");\nlog::info(\"\"); // ... [Thread 1] ...\n\n// Specify by id\nauto id = std::this_thread::get_id();\nlog::setThreadName(id, \"Thread-1\");\n\nlog::info(\"\"); // ... [Thread-1] ...\n```\n\n\n### Appenders\n\nYou can add multiple appenders simultaneously to output logs to different places. By default, appenders for console output and file writing are provided.\n\n#### Logging to a file:\n```cpp\n// Add a file appender and overwrite the file\nlog::addFileAppender(\"app.log\", true); \n```\n\n#### Output to console (enabled by default):\n```cpp\nlog::addConsoleAppender(); // Add a console appender\n```\n\n#### Custom Appender:\n\nYou can easily add your own appender to output to any destination.\n\nJust inherit from `neko::log::IAppender` and override the `append` and `flush` methods for your output.\n\nExample:\n\n```cpp\nusing namespace neko;\n\nclass MyAppender : public log::IAppender {\n    public:\n    void append(const log::LogRecord \u0026record) override {\n        std::unique_ptr\u003clog::IFormatter\u003e formatter = std::make_unique\u003clog::DefaultFormatter\u003e(); // Create a default log formatter\n        auto formatted = formatter-\u003eformat(record); // Format the log\n\n        // Output the string to your target\n        yourOutput \u003c\u003c formatted;\n    }\n    \n    void flush() override {\n        yourOutput.flush();\n    }\n};\n\n// Add a custom log appender\nlog::addAppender(std::make_unique\u003cMyAppender\u003e());\n```\n\n### Formatting Logs\n\nA formatter is a helper for an appender, used to format logs.\nIt is independent for each appender, and the appender calls the formatter's method to format the log.\nSo, it is recommended to have a built-in formatter object when creating a custom appender.\n\n#### Default Formatter\n\nThe default formatter's format is:\n[date time] [level] [thread] [file:line] [msg]\n\nWhen constructing it, you can specify a root path to truncate and whether to use the full path. The function is defined as follows:\n\n```cpp\nexplicit DefaultFormatter(const std::string \u0026rootPath = \"\", bool useFullPath = false)\n```\n\nWhen `rootPath` is an empty string (default), `file` = `main.cpp`.  \nWhen `rootPath` is a path, e.g., `/to/path/`, and the file is at `/to/path/src/main.cpp`, `file` = `/src/main.cpp`.  \nWhen `useFullPath` is `true`, `rootPath` is ignored, and the full path is always displayed. `file` = `/to/path/src/main.cpp`.  \n\n#### Custom Formatter\n\nInherit from `neko::log::IFormatter` and override the `format` function.\nYou need to implement the formatting of the incoming record in the `format` function.\n\nExample:\n```cpp\nusing namespace neko;\n\nclass MyFormatter : public log::IFormatter {\n    public:\n    std::string format(const log::LogRecord \u0026record) override {\n        // You can use any method to combine the record format, std::format, ostringstream, etc.\n        \n        std::ostringstream oss;\n        oss \u003c\u003c \"lv: \" \u003c\u003c log::levelToString(record.level) \u003c\u003c \" , msg: \"\u003c\u003c record.message ;\n        return oss.str();\n    }\n};\n\n// Create a console appender and specify MyFormatter as the formatter\nlog::ConsoleAppender consoleAppender(std::make_unique\u003cMyFormatter\u003e());\n\nlog::info(\"Hello\");\n```\n\noutput:\n```log\nlv: Info , msg: Hello\n```\n\n### Asynchronous Logging\n\nBy default, logging is written to IO by the logging thread.\n\nFor better performance, you can enable asynchronous mode. This lets logs be processed in a background thread.\n\n```cpp\n#include \"neko/log/nlog.hpp\"\n#include \u003cthread\u003e\nusing namespace neko;\n\nint main() {\n    // Set to asynchronous mode\n    log::setMode(neko::SyncMode::Async);\n\n    // Start the log processing loop (usually in a dedicated thread)\n    std::thread logThread([]{ log::runLogLoop(); });\n\n    // Main thread submits logs\n    log::info(\"This will be logged asynchronously.\");\n\n    // ... application execution ...\n\n    // Stop the log loop and flush remaining logs\n    log::stopLogLoop();\n    logThread.join();\n}\n```\n\nIn async mode, logs are not flushed in real-time. It's possible for a log to be submitted before a crash, but not be recorded in time.\nIt is recommended to disable this during debugging.\n\nTip: When using asynchronous mode, a thread must be running the `neko::log::runLogLoop()` function.\nOtherwise, no logs will be processed.\n\n### RAII Scope Logging\n\nUse `neko::log::autoLog` to automatically log the start and end of a scope.\n\n```cpp\nvoid someFunction() {\n    // Logs \"Start\" when someFunction is entered, and \"End\" when it is exited\n    log::autoLog log(\"Start\", \"End\"); \n    \n    // ... function body ...\n}\n```\n\n## License\n\n[License](./LICENSE) MIT OR Apache-2.0","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoehoshio%2Fnlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoehoshio%2Fnlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoehoshio%2Fnlog/lists"}