diff --git a/example/example.cpp b/example/example.cpp index fd383f2f..46a641d2 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -18,17 +18,228 @@ void user_defined_example(); void err_handler_example(); void syslog_example(); -#include -#include -#include -#include +#include "spdlog/spdlog.h" +#include "spdlog/cfg/argv.h" +#include "spdlog/cfg/env.h" -int main(int args, char *argv[]) +int main(int args, char *argv []) { - spdlog::loaders::load_env(); - spdlog::loaders::load_argv(args, argv); - spdlog::info("HELLO INFO"); + // optionally init log levels from argv + spdlog::cfg::load_argv(args, argv); - auto l1 = spdlog::stderr_color_st("l1"); - l1->trace("L1 TRACE"); -} \ No newline at end of file + // optionally init load levels from an environment variable (SPDLOG_LEVEL) + spdlog::cfg::load_env(); + + spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); + spdlog::warn("Easy padding in numbers like {:08d}", 12); + spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + spdlog::info("Support for floats {:03.2f}", 1.23456); + spdlog::info("Positional args are {1} {0}..", "too", "supported"); + spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); + + + // Runtime log levels + spdlog::set_level(spdlog::level::info); // Set global log level to info + spdlog::debug("This message should not be displayed!"); + spdlog::set_level(spdlog::level::trace); // Set specific logger's log level + spdlog::debug("This message should be displayed.."); + + + + // Customize msg format for all loggers + spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); + spdlog::info("This an info message with custom format"); + spdlog::set_pattern("%+"); // back to default format + spdlog::set_level(spdlog::level::info); + + // Backtrace support + // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection. + // When needed, call dump_backtrace() to see what happened: + spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages + for (int i = 0; i < 100; i++) + { + spdlog::debug("Backtrace message {}", i); // not logged.. + } + // e.g. if some error happened: + spdlog::dump_backtrace(); // log them now! + + try + { + stdout_logger_example(); + basic_example(); + rotating_example(); + daily_example(); + async_example(); + binary_example(); + multi_sink_example(); + user_defined_example(); + err_handler_example(); + trace_example(); + + // Flush all *registered* loggers using a worker thread every 3 seconds. + // note: registered loggers *must* be thread safe for this to work correctly! + spdlog::flush_every(std::chrono::seconds(3)); + + // Apply some function on all registered loggers + spdlog::apply_all([&](std::shared_ptr l) { l->info("End of example."); }); + + // Release all spdlog resources, and drop all loggers in the registry. + // This is optional (only mandatory if using windows + async log). + spdlog::shutdown(); + } + + // Exceptions will only be thrown upon failed logger or sink construction (not during logging). + catch (const spdlog::spdlog_ex &ex) + { + std::printf("Log initialization failed: %s\n", ex.what()); + return 1; + } +} + +#include "spdlog/sinks/stdout_color_sinks.h" +// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed. +void stdout_logger_example() +{ + // Create color multi threaded logger. + auto console = spdlog::stdout_color_mt("console"); + // or for stderr: + // auto console = spdlog::stderr_color_mt("error-logger"); +} + +#include "spdlog/sinks/basic_file_sink.h" +void basic_example() +{ + // Create basic file logger (not rotated). + auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt"); +} + +#include "spdlog/sinks/rotating_file_sink.h" +void rotating_example() +{ + // Create a file rotating logger with 5mb size max and 3 rotated files. + auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); +} + +#include "spdlog/sinks/daily_file_sink.h" +void daily_example() +{ + // Create a daily logger - a new file is created every day on 2:30am. + auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); +} + +#include "spdlog/async.h" +void async_example() +{ + // Default thread pool settings can be modified *before* creating the async logger: + // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread. + auto async_file = spdlog::basic_logger_mt("async_file_logger", "logs/async_log.txt"); + // alternatively: + // auto async_file = spdlog::create_async("async_file_logger", "logs/async_log.txt"); + + for (int i = 1; i < 101; ++i) + { + async_file->info("Async message #{}", i); + } +} + +// Log binary data as hex. +// Many types of std::container types can be used. +// Iterator ranges are supported too. +// Format flags: +// {:X} - print in uppercase. +// {:s} - don't separate each byte with space. +// {:p} - don't print the position on each line start. +// {:n} - don't split the output to lines. + +#include "spdlog/fmt/bin_to_hex.h" +void binary_example() +{ + std::vector buf(80); + for (int i = 0; i < 80; i++) + { + buf.push_back(static_cast(i & 0xff)); + } + spdlog::info("Binary example: {}", spdlog::to_hex(buf)); + spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); + // more examples: + // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); + // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); + // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); +} + +// Compile time log levels. +// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE) +void trace_example() +{ + // trace from default logger + SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23); + // debug from default logger + SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23); + + // trace from logger object + auto logger = spdlog::get("file_logger"); + SPDLOG_LOGGER_TRACE(logger, "another trace message"); +} + +// A logger with multiple sinks (stdout and file) - each with a different format and log level. +void multi_sink_example() +{ + auto console_sink = std::make_shared(); + console_sink->set_level(spdlog::level::warn); + console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); + + auto file_sink = std::make_shared("logs/multisink.txt", true); + file_sink->set_level(spdlog::level::trace); + + spdlog::logger logger("multi_sink", {console_sink, file_sink}); + logger.set_level(spdlog::level::debug); + logger.warn("this should appear in both console and file"); + logger.info("this message should not appear in the console, only in the file"); +} + +// User defined types logging by implementing operator<< +#include "spdlog/fmt/ostr.h" // must be included +struct my_type +{ + int i; + template + friend OStream &operator<<(OStream &os, const my_type &c) + { + return os << "[my_type i=" << c.i << "]"; + } +}; + +void user_defined_example() +{ + spdlog::info("user defined type: {}", my_type{14}); +} + +// Custom error handler. Will be triggered on log failure. +void err_handler_example() +{ + // can be set globally or per logger(logger->set_error_handler(..)) + spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n", msg.c_str()); }); +} + +// syslog example (linux/osx/freebsd) +#ifndef _WIN32 +#include "spdlog/sinks/syslog_sink.h" +void syslog_example() +{ + std::string ident = "spdlog-example"; + auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); + syslog_logger->warn("This is warning that will end up in syslog."); +} +#endif + +// Android example. +#if defined(__ANDROID__) +#include "spdlog/sinks/android_sink.h" +void android_example() +{ + std::string tag = "spdlog-android"; + auto android_logger = spdlog::android_logger_mt("android", tag); + android_logger->critical("Use \"adb shell logcat\" to view this message."); +} + +#endif diff --git a/include/spdlog/loaders/argv.h b/include/spdlog/cfg/argv.h similarity index 93% rename from include/spdlog/loaders/argv.h rename to include/spdlog/cfg/argv.h index 736b8c49..71ddb9ea 100644 --- a/include/spdlog/loaders/argv.h +++ b/include/spdlog/cfg/argv.h @@ -2,7 +2,7 @@ // Distributed under the MIT License (http://opensource.org/licenses/MIT) #pragma once -#include +#include #include // @@ -18,7 +18,7 @@ // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" namespace spdlog { -namespace loaders { +namespace cfg { // search for SPDLOG_LEVEL= in the args and use it to init the levels void load_argv(int args, char **argv) @@ -36,5 +36,5 @@ void load_argv(int args, char **argv) } } -} // namespace loaders +} // namespace cfg } // namespace spdlog diff --git a/include/spdlog/loaders/env.h b/include/spdlog/cfg/env.h similarity index 92% rename from include/spdlog/loaders/env.h rename to include/spdlog/cfg/env.h index afd690b7..4b4a22c7 100644 --- a/include/spdlog/loaders/env.h +++ b/include/spdlog/cfg/env.h @@ -2,7 +2,7 @@ // Distributed under the MIT License (http://opensource.org/licenses/MIT) #pragma once -#include +#include #include #include @@ -24,7 +24,7 @@ // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" namespace spdlog { -namespace loaders { +namespace cfg { void load_env() { auto env_val = details::os::getenv("SPDLOG_LEVEL"); @@ -32,5 +32,5 @@ void load_env() details::registry::instance().update_levels(std::move(levels)); } -} // namespace loaders +} // namespace cfg } // namespace spdlog diff --git a/include/spdlog/loaders/helpers-inl.h b/include/spdlog/cfg/helpers-inl.h similarity index 97% rename from include/spdlog/loaders/helpers-inl.h rename to include/spdlog/cfg/helpers-inl.h index 0dea4616..b0915073 100644 --- a/include/spdlog/loaders/helpers-inl.h +++ b/include/spdlog/cfg/helpers-inl.h @@ -4,7 +4,7 @@ #pragma once #ifndef SPDLOG_HEADER_ONLY -#include +#include #endif #include @@ -16,7 +16,7 @@ #include namespace spdlog { -namespace loaders { +namespace cfg { namespace helpers { // inplace convert to lowercase @@ -99,5 +99,5 @@ SPDLOG_INLINE log_levels extract_levels(const std::string &input) } } // namespace helpers -} // namespace loaders +} // namespace cfg } // namespace spdlog diff --git a/include/spdlog/loaders/helpers.h b/include/spdlog/cfg/helpers.h similarity index 88% rename from include/spdlog/loaders/helpers.h rename to include/spdlog/cfg/helpers.h index 3239699d..cf5146c0 100644 --- a/include/spdlog/loaders/helpers.h +++ b/include/spdlog/cfg/helpers.h @@ -3,10 +3,10 @@ #pragma once -#include +#include namespace spdlog { -namespace loaders { +namespace cfg { namespace helpers { // // Init levels from given string @@ -20,7 +20,7 @@ namespace helpers { log_levels extract_levels(const std::string &txt); } // namespace helpers -} // namespace loaders +} // namespace cfg } // namespace spdlog #ifdef SPDLOG_HEADER_ONLY diff --git a/include/spdlog/loaders/log_levels.h b/include/spdlog/cfg/log_levels.h similarity index 95% rename from include/spdlog/loaders/log_levels.h rename to include/spdlog/cfg/log_levels.h index fab00d1c..867fe96b 100644 --- a/include/spdlog/loaders/log_levels.h +++ b/include/spdlog/cfg/log_levels.h @@ -8,7 +8,7 @@ #include namespace spdlog { -namespace loaders { +namespace cfg { class log_levels { std::unordered_map levels_; @@ -43,5 +43,5 @@ public: return default_level_; } }; -} // namespace loaders +} // namespace cfg } // namespace spdlog diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index 35ec1ace..a2a7e614 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -260,7 +260,7 @@ SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registrat automatic_registration_ = automatic_registration; } -SPDLOG_INLINE void registry::update_levels(loaders::log_levels levels) +SPDLOG_INLINE void registry::update_levels(cfg::log_levels levels) { std::lock_guard lock(logger_map_mutex_); levels_ = std::move(levels); diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index ce6ed0ef..e7adb541 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -9,7 +9,7 @@ // This class is thread safe #include -#include +#include #include #include @@ -80,7 +80,7 @@ public: void set_automatic_registration(bool automatic_registration); - void update_levels(loaders::log_levels levels); + void update_levels(cfg::log_levels levels); static registry &instance(); @@ -93,7 +93,7 @@ private: std::mutex logger_map_mutex_, flusher_mutex_; std::recursive_mutex tp_mutex_; std::unordered_map> loggers_; - loaders::log_levels levels_; + cfg::log_levels levels_; std::unique_ptr formatter_; level::level_enum flush_level_ = level::off; void (*err_handler_)(const std::string &msg); diff --git a/src/loaders.cpp b/src/loaders.cpp index 82a0be4f..e9e3ae09 100644 --- a/src/loaders.cpp +++ b/src/loaders.cpp @@ -5,4 +5,4 @@ #error Please define SPDLOG_COMPILED_LIB to compile this file. #endif -#include "spdlog/loaders/helpers-inl.h" +#include "spdlog/cfg/helpers-inl.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6bbf2263..f4f53107 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,7 +24,7 @@ set(SPDLOG_UTESTS_SOURCES test_stdout_api.cpp test_backtrace.cpp test_create_dir.cpp - test_loaders.cpp) + test_cfg.cpp) if(NOT SPDLOG_NO_EXCEPTIONS) list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) diff --git a/tests/meson.build b/tests/meson.build index 87b8c106..d59e702c 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -15,7 +15,7 @@ test_sources = files([ 'test_stdout_api.cpp', 'test_backtrace.cpp', 'test_create_dir.cpp', - 'test_loaders.cpp', + 'test_cfg.cpp', ]) if not get_option('no_exceptions') diff --git a/tests/test_loaders.cpp b/tests/test_cfg.cpp similarity index 85% rename from tests/test_loaders.cpp rename to tests/test_cfg.cpp index b4f516e5..3ee0e973 100644 --- a/tests/test_loaders.cpp +++ b/tests/test_cfg.cpp @@ -1,13 +1,13 @@ #include "includes.h" #include "test_sink.h" -#include -#include +#include +#include -using spdlog::loaders::load_argv; -using spdlog::loaders::load_env; +using spdlog::cfg::load_argv; +using spdlog::cfg::load_env; -TEST_CASE("env", "[loaders]") +TEST_CASE("env", "[cfg]") { spdlog::drop("l1"); auto l1 = spdlog::create("l1"); @@ -21,7 +21,7 @@ TEST_CASE("env", "[loaders]") REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); } -TEST_CASE("argv1", "[loaders]") +TEST_CASE("argv1", "[cfg]") { spdlog::drop("l1"); const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn"}; @@ -31,7 +31,7 @@ TEST_CASE("argv1", "[loaders]") REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); } -TEST_CASE("argv2", "[loaders]") +TEST_CASE("argv2", "[cfg]") { spdlog::drop("l1"); const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn,trace"}; @@ -41,7 +41,7 @@ TEST_CASE("argv2", "[loaders]") REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); } -TEST_CASE("argv3", "[loaders]") +TEST_CASE("argv3", "[cfg]") { spdlog::drop("l1"); const char *argv[] = {"ignore", "SPDLOG_LEVEL="}; @@ -51,7 +51,7 @@ TEST_CASE("argv3", "[loaders]") REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); } -TEST_CASE("argv4", "[loaders]") +TEST_CASE("argv4", "[cfg]") { spdlog::drop("l1"); const char *argv[] = {"ignore", "SPDLOG_LEVEL=junk"}; @@ -60,7 +60,7 @@ TEST_CASE("argv4", "[loaders]") REQUIRE(l1->level() == spdlog::level::info); } -TEST_CASE("argv5", "[loaders]") +TEST_CASE("argv5", "[cfg]") { spdlog::drop("l1"); const char *argv[] = {"ignore", "ignore", "SPDLOG_LEVEL=l1=warn,trace"}; @@ -70,7 +70,7 @@ TEST_CASE("argv5", "[loaders]") REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); } -TEST_CASE("argv6", "[loaders]") +TEST_CASE("argv6", "[cfg]") { spdlog::set_level(spdlog::level::err); const char *argv[] = {""}; @@ -79,7 +79,7 @@ TEST_CASE("argv6", "[loaders]") } -TEST_CASE("argv7", "[loaders]") +TEST_CASE("argv7", "[cfg]") { spdlog::set_level(spdlog::level::err); const char *argv[] = {""};