diff --git a/CMakeLists.txt b/CMakeLists.txt index e1d96563..12fe8bb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # cmake_minimum_required(VERSION 3.1) -project(spdlog VERSION 1.3.0 LANGUAGES CXX) +project(spdlog VERSION 1.3.1 LANGUAGES CXX) include(CMakeDependentOption) include(GNUInstallDirs) @@ -30,7 +30,6 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCH add_compile_options("-Wconversion") add_compile_options("-pedantic") add_compile_options("-Wfatal-errors") - endif() #--------------------------------------------------------------------------------------- @@ -47,17 +46,15 @@ add_library(spdlog::spdlog ALIAS spdlog) # Check if spdlog is being used directly or via add_subdirectory set(SPDLOG_MASTER_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(SPDLOG_MASTER_PROJECT ON) + set(SPDLOG_MASTER_PROJECT ON) endif() option(SPDLOG_BUILD_EXAMPLES "Build examples" ${SPDLOG_MASTER_PROJECT}) -option(SPDLOG_BUILD_BENCH "Build benchmarks" ${SPDLOG_MASTER_PROJECT}) +option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF) option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) - -if(SPDLOG_FMT_EXTERNAL) - find_package(fmt REQUIRED CONFIG) -endif() +option(SPDLOG_FMT_HEADER_ONLY "Use header-only variant of external fmt library" ON) +option(SPDLOG_INSTALL "Generate the install target." ${SPDLOG_MASTER_PROJECT}) target_include_directories( spdlog @@ -68,7 +65,16 @@ target_include_directories( if(SPDLOG_FMT_EXTERNAL) target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) - target_link_libraries(spdlog INTERFACE fmt::fmt) + + if(NOT TARGET fmt::fmt) + find_package(fmt REQUIRED CONFIG) + endif() + + if(SPDLOG_FMT_HEADER_ONLY) + target_link_libraries(spdlog INTERFACE fmt::fmt-header-only) + else() + target_link_libraries(spdlog INTERFACE fmt::fmt) + endif() endif() set(HEADER_BASE "${CMAKE_CURRENT_SOURCE_DIR}/include") @@ -89,59 +95,60 @@ endif() #--------------------------------------------------------------------------------------- # Install/export targets and files #--------------------------------------------------------------------------------------- -# set files and directories -set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") -set(include_install_dir "${CMAKE_INSTALL_INCLUDEDIR}") -set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") -set(version_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake") -set(project_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake") -set(targets_config "${PROJECT_NAME}Targets.cmake") -set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") -set(targets_export_name "${PROJECT_NAME}Targets") -set(namespace "${PROJECT_NAME}::") - -# generate package version file -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - "${version_config}" COMPATIBILITY SameMajorVersion -) - -# configure pkg config file -configure_file("cmake/spdlog.pc.in" "${pkg_config}" @ONLY) -# configure spdlogConfig.cmake file -configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY) - -# install targets -install( - TARGETS spdlog - EXPORT "${targets_export_name}" -) - -# install headers -install( - DIRECTORY "${HEADER_BASE}/${PROJECT_NAME}" - DESTINATION "${include_install_dir}" -) - -# install project config and version file -install( - FILES "${project_config}" "${version_config}" - DESTINATION "${config_install_dir}" -) - -# install pkg config file -install( - FILES "${pkg_config}" - DESTINATION "${pkgconfig_install_dir}" -) - -# install targets config file -install( - EXPORT "${targets_export_name}" - NAMESPACE "${namespace}" - DESTINATION "${config_install_dir}" - FILE ${targets_config} -) +if(SPDLOG_INSTALL) + # set files and directories + set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + set(include_install_dir "${CMAKE_INSTALL_INCLUDEDIR}") + set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + set(version_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake") + set(project_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake") + set(targets_config "${PROJECT_NAME}Targets.cmake") + set(pkg_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc") + set(targets_export_name "${PROJECT_NAME}Targets") + set(namespace "${PROJECT_NAME}::") + + # generate package version file + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + "${version_config}" COMPATIBILITY SameMajorVersion + ) + + # configure pkg config file + configure_file("cmake/spdlog.pc.in" "${pkg_config}" @ONLY) + # configure spdlogConfig.cmake file + configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY) + + # install targets + install( + TARGETS spdlog + EXPORT "${targets_export_name}" + ) + + # install headers + install( + DIRECTORY "${HEADER_BASE}/${PROJECT_NAME}" + DESTINATION "${include_install_dir}" + ) + + # install project config and version file + install( + FILES "${project_config}" "${version_config}" + DESTINATION "${config_install_dir}" + ) + + # install pkg config file + install( + FILES "${pkg_config}" + DESTINATION "${pkgconfig_install_dir}" + ) + + # install targets config file + install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}" + FILE ${targets_config} + ) # export build directory targets file export( @@ -153,5 +160,7 @@ export( # register project in CMake user registry export(PACKAGE ${PROJECT_NAME}) +endif() + file(GLOB_RECURSE spdlog_include_SRCS "${HEADER_BASE}/*.h") add_custom_target(spdlog_headers_for_ide SOURCES ${spdlog_include_SRCS}) diff --git a/README.md b/README.md index 48264324..7b3d39d7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Very fast, header only, C++ logging library. [![Build Status](https://travis-ci. #### Or use your favorite package manager: -* Ubuntu: `apt-get install libspdlog-dev` * Homebrew: `brew install spdlog` * FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean` * Fedora: `yum install spdlog` @@ -80,6 +79,8 @@ async... Elapsed: 0.349851 2,858,358/sec #### Basic usage ```c++ #include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" + int main() { spdlog::info("Welcome to spdlog!"); @@ -101,7 +102,10 @@ int main() // define SPDLOG_ACTIVE_LEVEL to desired level SPDLOG_TRACE("Some trace message with param {}", {}); SPDLOG_DEBUG("Some debug message"); - + + // Set the default logger to file logger + auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt"); + spdlog::set_default_logger(file_logger); } ``` #### create stdout/stderr logger object @@ -310,7 +314,7 @@ void syslog_example() void android_example() { std::string tag = "spdlog-android"; - auto android_logger = spdlog::android_logger("android", tag); + auto android_logger = spdlog::android_logger_mt("android", tag); android_logger->critical("Use \"adb shell logcat\" to view this message."); } ``` diff --git a/include/spdlog/common.h b/include/spdlog/common.h index d078a1ab..85e3cecd 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -125,9 +125,12 @@ enum level_enum "trace", "debug", "info", "warning", "error", "critical", "off" \ } #endif - static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; -static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"}; + +#if !defined(SPDLOG_SHORT_LEVEL_NAMES) +#define SPDLOG_SHORT_LEVEL_NAMES {"T", "D", "I", "W", "E", "C", "O"} +#endif +static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; inline string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT { @@ -156,6 +159,16 @@ inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCE using level_hasher = std::hash; } // namespace level +// +// Color mode used by sinks with color support. +// +enum class color_mode +{ + always, + automatic, + never +}; + // // Pattern time - specific time getting to use for pattern_formatter. // local time by default @@ -210,10 +223,10 @@ struct source_loc , funcname{""} { } - SPDLOG_CONSTEXPR source_loc(const char *filename, int line, const char *funcname) - : filename{filename} - , line{static_cast(line)} - , funcname{funcname} + SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) + : filename{filename_in} + , line{static_cast(line_in)} + , funcname{funcname_in} { } diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index 0212ede5..d44652b5 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -102,6 +102,12 @@ inline void spdlog::logger::log(level::level_enum lvl, const char *msg) log(source_loc{}, lvl, msg); } +template +inline void spdlog::logger::log(level::level_enum lvl, const T &msg) +{ + log(source_loc{}, lvl, msg); +} + template::value, T>::type *> inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) { @@ -117,12 +123,6 @@ inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const SPDLOG_CATCH_AND_HANDLE } -template::value, T>::type *> -inline void spdlog::logger::log(level::level_enum lvl, const T &msg) -{ - log(source_loc{}, lvl, msg); -} - template::value, T>::type *> inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) { @@ -141,12 +141,6 @@ inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const SPDLOG_CATCH_AND_HANDLE } -template::value, T>::type *> -inline void spdlog::logger::log(level::level_enum lvl, const T &msg) -{ - log(source_loc{}, lvl, msg); -} - template inline void spdlog::logger::trace(const char *fmt, const Args &... args) { diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 646805e6..8e8476f0 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -196,7 +196,7 @@ inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); #else // common linux/unix all have the stat system call struct stat buffer; - return (stat(filename.c_str(), &buffer) == 0); + return (::stat(filename.c_str(), &buffer) == 0); #endif } @@ -229,14 +229,14 @@ inline size_t filesize(FILE *f) // 64 bits(but not in osx or cygwin, where fstat64 is deprecated) #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__) struct stat64 st; - if (fstat64(fd, &st) == 0) + if (::fstat64(fd, &st) == 0) { return static_cast(st.st_size); } #else // unix 32 bits or cygwin struct stat st; - if (fstat(fd, &st) == 0) + if (::fstat(fd, &st) == 0) { return static_cast(st.st_size); } diff --git a/include/spdlog/details/pattern_formatter.h b/include/spdlog/details/pattern_formatter.h index c0ad86e8..60ed72ad 100644 --- a/include/spdlog/details/pattern_formatter.h +++ b/include/spdlog/details/pattern_formatter.h @@ -352,7 +352,7 @@ class Y_formatter final : public flag_formatter { public: explicit Y_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -418,7 +418,7 @@ class I_formatter final : public flag_formatter { public: explicit I_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -433,7 +433,7 @@ class M_formatter final : public flag_formatter { public: explicit M_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -448,7 +448,7 @@ class S_formatter final : public flag_formatter { public: explicit S_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -463,7 +463,7 @@ class e_formatter final : public flag_formatter { public: explicit e_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -486,7 +486,7 @@ class f_formatter final : public flag_formatter { public: explicit f_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -509,7 +509,7 @@ class F_formatter final : public flag_formatter { public: explicit F_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -532,7 +532,7 @@ class E_formatter final : public flag_formatter { public: explicit E_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -549,7 +549,7 @@ class p_formatter final : public flag_formatter { public: explicit p_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -564,7 +564,7 @@ class r_formatter final : public flag_formatter { public: explicit r_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -586,7 +586,7 @@ class R_formatter final : public flag_formatter { public: explicit R_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -604,7 +604,7 @@ class T_formatter final : public flag_formatter { public: explicit T_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override { @@ -624,7 +624,7 @@ class z_formatter final : public flag_formatter { public: explicit z_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} const std::chrono::seconds cache_refresh = std::chrono::seconds(5); @@ -683,7 +683,7 @@ class t_formatter final : public flag_formatter { public: explicit t_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -705,7 +705,7 @@ class pid_formatter final : public flag_formatter { public: explicit pid_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override { @@ -728,7 +728,7 @@ class i_formatter final : public flag_formatter { public: explicit i_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -742,7 +742,7 @@ class v_formatter final : public flag_formatter { public: explicit v_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -829,7 +829,7 @@ class source_location_formatter final : public flag_formatter { public: explicit source_location_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -858,7 +858,7 @@ class source_filename_formatter final : public flag_formatter { public: explicit source_filename_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -875,7 +875,7 @@ class source_linenum_formatter final : public flag_formatter { public: explicit source_linenum_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { @@ -900,7 +900,7 @@ class source_funcname_formatter final : public flag_formatter { public: explicit source_funcname_formatter(padding_info padinfo) - : flag_formatter(padinfo){}; + : flag_formatter(padinfo){} void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override { diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index 3dbaaa64..ec06828f 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -100,18 +100,13 @@ public: #endif // _WIN32 #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - // T can be statically converted to string_view - template::value, T>::type * = nullptr> + template void log(level::level_enum lvl, const T &); // T can be statically converted to string_view template::value, T>::type * = nullptr> void log(source_loc loc, level::level_enum lvl, const T &); - // T cannot be statically converted to string_view - template::value, T>::type * = nullptr> - void log(level::level_enum lvl, const T &); - // T cannot be statically converted to string_view template::value, T>::type * = nullptr> void log(source_loc loc, level::level_enum lvl, const T &); diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index 7c5e3539..3fbbf27b 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -33,12 +33,12 @@ class ansicolor_sink final : public sink { public: using mutex_t = typename ConsoleMutex::mutex_t; - ansicolor_sink() + ansicolor_sink(color_mode mode = color_mode::automatic) : target_file_(TargetStream::stream()) , mutex_(ConsoleMutex::mutex()) { - should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); + set_color_mode_(mode); colors_[level::trace] = white; colors_[level::debug] = cyan; colors_[level::info] = green; @@ -133,7 +133,35 @@ public: formatter_ = std::move(sink_formatter); } + bool should_color() + { + std::lock_guard lock(mutex_); + return should_do_colors_; + } + + void set_color_mode(color_mode mode) + { + std::lock_guard lock(mutex_); + set_color_mode_(mode); + } + private: + void set_color_mode_(color_mode mode) + { + switch (mode) + { + case color_mode::always: + should_do_colors_ = true; + break; + case color_mode::automatic: + should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); + break; + case color_mode::never: + should_do_colors_ = false; + break; + } + } + void print_ccode_(const std::string &color_code) { fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); diff --git a/include/spdlog/sinks/basic_file_sink.h b/include/spdlog/sinks/basic_file_sink.h index bc5fb5c3..facc7209 100644 --- a/include/spdlog/sinks/basic_file_sink.h +++ b/include/spdlog/sinks/basic_file_sink.h @@ -30,6 +30,11 @@ public: file_helper_.open(filename, truncate); } + const filename_t &filename() const + { + return file_helper_.filename(); + } + protected: void sink_it_(const details::log_msg &msg) override { diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index 7bf7c448..08392c16 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -63,6 +63,11 @@ public: rotation_tp_ = next_rotation_tp_(); } + const filename_t &filename() const + { + return file_helper_.filename(); + } + protected: void sink_it_(const details::log_msg &msg) override { diff --git a/include/spdlog/sinks/rotating_file_sink.h b/include/spdlog/sinks/rotating_file_sink.h index a579946f..ae0f70f6 100644 --- a/include/spdlog/sinks/rotating_file_sink.h +++ b/include/spdlog/sinks/rotating_file_sink.h @@ -31,13 +31,17 @@ template class rotating_file_sink final : public base_sink { public: - rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files) + rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open=false) : base_filename_(std::move(base_filename)) , max_size_(max_size) , max_files_(max_files) { file_helper_.open(calc_filename(base_filename_, 0)); current_size_ = file_helper_.size(); // expensive. called only once + if (rotate_on_open && current_size_ > 0) + { + rotate_(); + } } // calc filename according to index and file extension if exists. @@ -58,6 +62,11 @@ public: return fmt::to_string(w); } + const filename_t &filename() const + { + return file_helper_.filename(); + } + protected: void sink_it_(const details::log_msg &msg) override { @@ -141,15 +150,15 @@ using rotating_file_sink_st = rotating_file_sink; template inline std::shared_ptr rotating_logger_mt( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files) + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open=false) { - return Factory::template create(logger_name, filename, max_file_size, max_files); + return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); } template inline std::shared_ptr rotating_logger_st( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files) + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) { - return Factory::template create(logger_name, filename, max_file_size, max_files); + return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); } } // namespace spdlog diff --git a/include/spdlog/sinks/sink.h b/include/spdlog/sinks/sink.h index 2f1adc10..d8325233 100644 --- a/include/spdlog/sinks/sink.h +++ b/include/spdlog/sinks/sink.h @@ -14,15 +14,10 @@ namespace sinks { class sink { public: - sink() - : level_(level::trace) - , formatter_(new pattern_formatter()) - { - } + sink() = default; - explicit sink(std::unique_ptr formatter) - : level_(level::trace) - , formatter_(std::move(formatter)) + explicit sink(std::unique_ptr formatter) + : formatter_{std::move(formatter)} { } @@ -49,10 +44,10 @@ public: protected: // sink log level - default is all - level_t level_; + level_t level_{level::trace}; // sink formatter - default is full format - std::unique_ptr formatter_; + std::unique_ptr formatter_{details::make_unique()}; }; } // namespace sinks diff --git a/include/spdlog/sinks/stdout_color_sinks.h b/include/spdlog/sinks/stdout_color_sinks.h index 74bfceb4..89271666 100644 --- a/include/spdlog/sinks/stdout_color_sinks.h +++ b/include/spdlog/sinks/stdout_color_sinks.h @@ -31,26 +31,26 @@ using stderr_color_sink_st = ansicolor_stderr_sink_st; } // namespace sinks template -inline std::shared_ptr stdout_color_mt(const std::string &logger_name) +inline std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, mode); } template -inline std::shared_ptr stdout_color_st(const std::string &logger_name) +inline std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, mode); } template -inline std::shared_ptr stderr_color_mt(const std::string &logger_name) +inline std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, mode); } template -inline std::shared_ptr stderr_color_st(const std::string &logger_name) +inline std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, mode); } } // namespace spdlog diff --git a/include/spdlog/sinks/systemd_sink.h b/include/spdlog/sinks/systemd_sink.h new file mode 100644 index 00000000..fa9efd83 --- /dev/null +++ b/include/spdlog/sinks/systemd_sink.h @@ -0,0 +1,91 @@ +// +// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/sinks/base_sink.h" + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +inline int syslog_level(level::level_enum l) { + switch(l) { + case level::off: + case level::trace: + case level::debug: + return LOG_DEBUG; + case level::info: + return LOG_INFO; + case level::warn: + return LOG_WARNING; + case level::err: + return LOG_ERR; + case level::critical: + return LOG_CRIT; + default: + throw std::invalid_argument("systemd_sink.h syslog_level()"); + } +} + +/** + * Sink that write to systemd using the `sd_journal_print()` library call. + * + * Locking is not needed, as `sd_journal_print()` itself is thread-safe. + */ +template +class systemd_sink : public base_sink +{ +public: + // + explicit systemd_sink(void) {} + + ~systemd_sink() override {} + + systemd_sink(const systemd_sink &) = delete; + systemd_sink &operator=(const systemd_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override + { + if( sd_journal_print( + syslog_level(msg.level), + "%.*s", + static_cast(msg.payload.size()), + msg.payload.data() + ) + ) + throw spdlog_ex("Failed writing to systemd"); + } + + void flush_() override {} +}; + +using systemd_sink_mt = systemd_sink; +using systemd_sink_st = systemd_sink; +} // namespace sinks + +// Create and register a syslog logger +template +inline std::shared_ptr systemd_logger_mt( + const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr systemd_logger_st( + const std::string &logger_name) +{ + return Factory::template create(logger_name); +} +} // namespace spdlog diff --git a/include/spdlog/sinks/wincolor_sink.h b/include/spdlog/sinks/wincolor_sink.h index 1fdf8c56..7c51014b 100644 --- a/include/spdlog/sinks/wincolor_sink.h +++ b/include/spdlog/sinks/wincolor_sink.h @@ -37,10 +37,11 @@ public: const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; - wincolor_sink() + wincolor_sink(color_mode mode = color_mode::automatic) : out_handle_(OutHandle::handle()) , mutex_(ConsoleMutex::mutex()) { + set_color_mode_(mode); colors_[level::trace] = WHITE; colors_[level::debug] = CYAN; colors_[level::info] = GREEN; @@ -70,7 +71,7 @@ public: std::lock_guard lock(mutex_); fmt::memory_buffer formatted; formatter_->format(msg, formatted); - if (msg.color_range_end > msg.color_range_start) + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { // before color range print_range_(formatted, 0, msg.color_range_start); @@ -83,7 +84,7 @@ public: // after color range print_range_(formatted, msg.color_range_end, formatted.size()); } - else // print without colors if color range is invalid + else // print without colors if color range is invalid (or color is disabled) { print_range_(formatted, 0, formatted.size()); } @@ -106,8 +107,29 @@ public: formatter_ = std::move(sink_formatter); } + void set_color_mode(color_mode mode) + { + std::lock_guard lock(mutex_); + set_color_mode_(mode); + } + private: using mutex_t = typename ConsoleMutex::mutex_t; + + void set_color_mode_(color_mode mode) + { + switch (mode) + { + case color_mode::always: + case color_mode::automatic: + should_do_colors_ = true; + break; + case color_mode::never: + should_do_colors_ = false; + break; + } + } + // set color and return the orig console attributes (for resetting later) WORD set_console_attribs(WORD attribs) { @@ -130,6 +152,7 @@ private: HANDLE out_handle_; mutex_t &mutex_; + bool should_do_colors_; std::unordered_map colors_; }; diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 20ff24be..87a7c184 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -47,6 +47,21 @@ inline std::shared_ptr create(std::string logger_name, SinkArgs return default_factory::create(std::move(logger_name), std::forward(sink_args)...); } +// Initialize and register a logger, +// formatter and flush level will be set according the global settings. +// +// NOTE: +// Use this function when creating loggers manually. +// +// Example: +// auto console_sink = std::make_shared(); +// auto console_logger = std::make_shared("console_logger", console_sink); +// spdlog::initialize_logger(console_logger); +inline void initialize_logger(std::shared_ptr logger) +{ + details::registry::instance().initialize_logger(std::move(logger)); +} + // Return an existing logger or nullptr if a logger with such name doesn't // exist. // example: spdlog::get("my_logger")->info("hello {}", "world"); @@ -312,8 +327,10 @@ inline void critical(const wchar_t *fmt, const Args &... args) // #define SPDLOG_LOGGER_CALL(logger, level, ...) \ - if (logger->should_log(level)) \ - logger->log(spdlog::source_loc{SPDLOG_FILE_BASENAME(__FILE__), __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) + do { \ + if (logger->should_log(level)) \ + logger->log(spdlog::source_loc{SPDLOG_FILE_BASENAME(__FILE__), __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__); \ + } while (0) #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE #define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index b3b71e4f..dfcb09d2 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -121,6 +121,13 @@ // "MY ERROR", "MY CRITICAL", "OFF" } /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to customize short level names (e.g. "MT") +// These can be longer than one character. +// +// #define SPDLOG_SHORT_LEVEL_NAMES { "T", "D", "I", "W", "E", "C", "O" } +/////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// // Uncomment to disable default logger creation. // This might save some (very) small initialization time if no default logger is needed. @@ -142,4 +149,4 @@ // Defaults to __FUNCTION__ (should work on all compilers) if not defined. // // #define SPDLOG_FUNCTION __PRETTY_FUNCTION__ -/////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////// diff --git a/include/spdlog/version.h b/include/spdlog/version.h index 16b9194b..87a68bd1 100644 --- a/include/spdlog/version.h +++ b/include/spdlog/version.h @@ -7,6 +7,6 @@ #define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MINOR 3 -#define SPDLOG_VER_PATCH 0 +#define SPDLOG_VER_PATCH 1 #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) diff --git a/tests/Makefile b/tests/Makefile index bec3026d..c9ce3c01 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CXX ?= g++ CXXFLAGS = -Wall -pedantic -std=c++11 -pthread -Wconversion -O3 -I../include -fmax-errors=1 -LDPFALGS = -pthread +LDPFALGS = -pthread -lsystemd CPP_FILES := $(wildcard *.cpp) OBJ_FILES := $(addprefix ./,$(notdir $(CPP_FILES:.cpp=.o))) diff --git a/tests/test_file_logging.cpp b/tests/test_file_logging.cpp index c5886f5f..dd0c8999 100644 --- a/tests/test_file_logging.cpp +++ b/tests/test_file_logging.cpp @@ -60,7 +60,20 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") prepare_logdir(); size_t max_size = 1024 * 10; std::string basename = "logs/rotating_log"; - auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 1); + + { + // make an initial logger to create the first output file + auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true); + for (int i = 0; i < 10; ++i) + { + logger->info("Test message {}", i); + } + // drop causes the logger destructor to be called, which is required so the + // next logger can rename the first output file. + spdlog::drop(logger->name()); + } + + auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true); for (int i = 0; i < 10; ++i) { logger->info("Test message {}", i); diff --git a/tests/test_systemd.cpp b/tests/test_systemd.cpp new file mode 100644 index 00000000..0909082c --- /dev/null +++ b/tests/test_systemd.cpp @@ -0,0 +1,13 @@ +#include "includes.h" +#include + +TEST_CASE("systemd", "[all]") +{ + auto systemd_sink = std::make_shared(); + systemd_sink->set_level(spdlog::level::level_enum::err); + spdlog::logger logger("spdlog_systemd_test", systemd_sink); + + logger.debug("test debug"); + logger.error("test error"); + logger.info("test info"); +}