From 1189e1dad1b1d3baf36bd81a4840d9678136cc72 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sat, 2 May 2020 11:52:26 +0300 Subject: [PATCH] initial commit --- example/example.cpp | 256 +-------------------- include/spdlog/common.h | 8 + include/spdlog/details/file_helper-inl.h | 18 ++ include/spdlog/details/file_helper.h | 4 +- include/spdlog/sinks/basic_file_sink-inl.h | 9 +- include/spdlog/sinks/basic_file_sink.h | 5 +- 6 files changed, 48 insertions(+), 252 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index ef8f23ff..8d5342b8 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -23,260 +23,20 @@ void custom_flags_example(); #include "spdlog/spdlog.h" #include "spdlog/cfg/env.h" // for loading levels from the environment variable -int main(int, char *[]) -{ - // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" - load_levels_example(); - - 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(); - custom_flags_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/cfg/env.h" -void load_levels_example() -{ - // Set the log level to "info" and mylogger to to "trace": - // SPDLOG_LEVEL=info,mylogger=trace && ./example - spdlog::cfg::load_env_levels(); - // or from command line: - // ./example SPDLOG_LEVEL=info,mylogger=trace - // #include "spdlog/cfg/argv.h" // for loading levels from argv - // spdlog::cfg::load_argv_levels(args, argv); -} - -#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) + spdlog::file_event_handlers handlers; + handlers.after_open = [](spdlog::filename_t, std::FILE* fstream) { - async_file->info("Async message #{}", i); - } + fputs("OPEN!\r\n", fstream); + }; + auto fsink = std::make_shared("c:\\temp\\test.log", true, handlers); } -// 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() +int main(int, char *[]) { - 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)); - // logger->info("hexdump style: {:a}", spdlog::to_hex(buf)); - // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20)); -} - -// 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 - -// Log patterns can contain custom flags. -// this will add custom flag '%*' which will be bound to a instance -#include "spdlog/pattern_formatter.h" -class my_formatter_flag : public spdlog::custom_flag_formatter -{ -public: - void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override - { - std::string some_txt = "custom-flag"; - dest.append(some_txt.data(), some_txt.data() + some_txt.size()); - } - - std::unique_ptr clone() const override - { - return spdlog::details::make_unique(); - } -}; - -void custom_flags_example() -{ - - using spdlog::details::make_unique; // for pre c++14 - auto formatter = make_unique(); - formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); - spdlog::set_formatter(std::move(formatter)); -} + basic_example(); +} \ No newline at end of file diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 5b58c06a..ad746495 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef SPDLOG_COMPILED_LIB #undef SPDLOG_HEADER_ONLY @@ -225,6 +226,13 @@ struct source_loc const char *funcname{nullptr}; }; +struct file_event_handlers +{ + std::function after_open; + std::function before_close; + std::function after_close; +}; + namespace details { // make_unique support for pre c++14 diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index 7cb00f2f..ebf316c1 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -20,6 +20,10 @@ namespace spdlog { namespace details { +SPDLOG_INLINE file_helper::file_helper(file_event_handlers event_handlers) + : event_handlers_{std::move(event_handlers_)} +{} + SPDLOG_INLINE file_helper::~file_helper() { close(); @@ -37,6 +41,10 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) os::create_dir(os::dir_name(fname)); if (!os::fopen_s(&fd_, fname, mode)) { + if (event_handlers_.after_open) + { + event_handlers_.after_open(filename_, fd_); + } return; } @@ -64,8 +72,18 @@ SPDLOG_INLINE void file_helper::close() { if (fd_ != nullptr) { + if (event_handlers_.before_close) + { + event_handlers_.before_close(filename_, fd_); + } + std::fclose(fd_); fd_ = nullptr; + + if (event_handlers_.after_close) + { + event_handlers_.after_close(filename_); + } } } diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 5395d9cb..b04c8144 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -16,7 +16,8 @@ namespace details { class SPDLOG_API file_helper { public: - explicit file_helper() = default; + file_helper() = default; + explicit file_helper(file_event_handlers handlers); file_helper(const file_helper &) = delete; file_helper &operator=(const file_helper &) = delete; @@ -50,6 +51,7 @@ private: const int open_interval_ = 10; std::FILE *fd_{nullptr}; filename_t filename_; + file_event_handlers event_handlers_{}; }; } // namespace details } // namespace spdlog diff --git a/include/spdlog/sinks/basic_file_sink-inl.h b/include/spdlog/sinks/basic_file_sink-inl.h index 1260d15c..454e8ccf 100644 --- a/include/spdlog/sinks/basic_file_sink-inl.h +++ b/include/spdlog/sinks/basic_file_sink-inl.h @@ -14,11 +14,18 @@ namespace spdlog { namespace sinks { template -SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate) +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, file_event_handlers handlers) + : file_helper_{std::move(handlers)} { file_helper_.open(filename, truncate); } +template +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate) + : basic_file_sink::basic_file_sink(filename, truncate, file_event_handlers{}) + +{} + template SPDLOG_INLINE const filename_t &basic_file_sink::filename() const { diff --git a/include/spdlog/sinks/basic_file_sink.h b/include/spdlog/sinks/basic_file_sink.h index 0ab9a4a1..5589a061 100644 --- a/include/spdlog/sinks/basic_file_sink.h +++ b/include/spdlog/sinks/basic_file_sink.h @@ -21,14 +21,15 @@ class basic_file_sink final : public base_sink { public: explicit basic_file_sink(const filename_t &filename, bool truncate = false); - const filename_t &filename() const; + explicit basic_file_sink(const filename_t &filename, bool truncate , file_event_handlers); + const filename_t &filename() const; protected: void sink_it_(const details::log_msg &msg) override; void flush_() override; private: - details::file_helper file_helper_; + details::file_helper file_helper_; }; using basic_file_sink_mt = basic_file_sink;