├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── doc └── index.md ├── example └── src │ ├── main.cpp │ └── test │ ├── test_log.cpp │ └── test_log.h └── include ├── logger.hpp └── wlog.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build* 3 | /.vscode 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "spdlog"] 2 | path = third/spdlog 3 | url = https://github.com/gabime/spdlog.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.6) 2 | 3 | project(wlog) 4 | 5 | option(LOGGER_LEVEL "Log level" 0) 6 | 7 | # SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/) 8 | 9 | aux_source_directory(${CMAKE_SOURCE_DIR}/example/src/ EXAMPLE_SRC_FILES) 10 | aux_source_directory(${CMAKE_SOURCE_DIR}/example/src/test EXAMPLE_SRC_FILES) 11 | 12 | if (WIN32) 13 | add_definitions(-DUNICODE -D_UNICODE -D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING -DPROJECT_NAME="${PROJECT_NAME}" /std:c++17 /utf-8) 14 | else() 15 | add_definitions(-g -O0 -Wall -DPROJECT_NAME="${PROJECT_NAME}" -std=c++17) 16 | endif() 17 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_LOG_CONSOLE") 18 | 19 | add_executable(${PROJECT_NAME} ${EXAMPLE_SRC_FILES} ) 20 | target_include_directories(${PROJECT_NAME} 21 | PRIVATE ${CMAKE_HOME_DIRECTORY}/third/spdlog/include 22 | PUBLIC ${CMAKE_SOURCE_DIR}/include) 23 | if (UNIX) 24 | target_link_libraries(${PROJECT_NAME} pthread) 25 | endif() 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 gqw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spdlog_wrapper 2 | 3 | #### 介绍 4 | `spdlog`简单封装 5 | 6 | #### 安装教程 7 | 8 | 1. mkdir build && cd build 9 | 3. cmake .. 10 | 4. make 11 | 12 | #### 使用说明 13 | 14 | 1. 直接使用`logger.hpp`头文件 15 | 2. 代码示例: 16 | ```CPP 17 | #include "logger.hpp" 18 | 19 | int main() { 20 | using namespace wlog; 21 | if (!logger::get().init("logs/test.log")) { 22 | return 1; 23 | } 24 | 25 | STM_DEBUG() << "STM_DEBUG" << 1; 26 | PRINT_WARN("PRINT_WARN, %d", 1); 27 | LOG_INFO("LOG_INFO {}", 1); 28 | 29 | logger::get().set_level(spdlog::level::info); 30 | STM_DEBUG() << "STM_DEBUG " << 2; 31 | PRINT_WARN("PRINT_WARN, %d", 2); 32 | LOG_INFO("LOG_INFO {}", 2); 33 | 34 | // call before spdlog static variables destroy 35 | logger::get().shutdown(); 36 | return 0; 37 | } 38 | ``` 39 | 40 | #### 文档介绍 41 | 42 | [说明](./doc/index.md) 43 | 44 | #### 参与贡献 45 | 46 | 1. Fork 本仓库 47 | 2. 新建 Feat_xxx 分支 48 | 3. 提交代码 49 | 4. 新建 Pull Request 50 | 51 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | # spdlog_wrapper 2 | 3 | | date| title|description|author| 4 | | ------------- |:-------------:| :-------------:|-----:| 5 | | 2020-10-28 | `spdlog`简单封装 | `spdlog`使用技巧 | ([@gqw](https://gqw.github.io))| 6 | 7 | ---- 8 | ## 工程介绍 9 | ---- 10 | 11 | `spdlog`是一个简单高效的modern c++日志库,它使用c++ 20中全新的format格式,如果全新的工程使用它简单方便。但是实际工作中我们经常会要整合老旧的代码,这些代码中可能会包含各种各样的日志系统,如果想统一这些日志输出全部改一遍费时费力。下面介绍个小技巧让spdlog兼容这些老旧的日志系统格式。 12 | 13 | 以前的日志通常是通过sprintf函数族和stream字节流两种方式格式化字符串。所以我们需要让`spdlog`能够模仿这两种方法。 14 | 15 | 一般日志系统都会提供宏来定义日志输出指令,因为这样会方便使用编译器提供`__FILE__`、`__LINE__`这样的内置宏输出文件路径、行号、函数名等信息。所以我们可以通过宏定义替换以前的宏。 16 | 17 | ```cpp 18 | // got short filename(exlude file directory) 19 | #define __FILENAME__ (__FILE__ + logger::get_filename_pos(__FILE__)) 20 | 21 | // use fmt lib, e.g. LOG_WARN("warn log, {1}, {1}, {2}", 1, 2); 22 | #define LOG_TRACE(msg,...) { if (logger::get().getLogLevel() == spdlog::level::trace) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, msg, ##__VA_ARGS__); }; 23 | #define LOG_DEBUG(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, msg, ##__VA_ARGS__); 24 | #define LOG_INFO(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, msg, ##__VA_ARGS__); 25 | #define LOG_WARN(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, msg, ##__VA_ARGS__); 26 | #define LOG_ERROR(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::err, msg, ##__VA_ARGS__); 27 | #define LOG_FATAL(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::critical, msg, ##__VA_ARGS__); 28 | 29 | // use like sprintf, e.g. PRINT_WARN("warn log, %d-%d", 1, 2); 30 | #define PRINT_TRACE(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, msg, ##__VA_ARGS__); 31 | #define PRINT_DEBUG(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, msg, ##__VA_ARGS__); 32 | #define PRINT_INFO(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, msg, ##__VA_ARGS__); 33 | #define PRINT_WARN(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, msg, ##__VA_ARGS__); 34 | #define PRINT_ERROR(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::err, msg, ##__VA_ARGS__); 35 | #define PRINT_FATAL(msg,...) logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::critical, msg, ##__VA_ARGS__); 36 | 37 | // use like stream , e.g. STM_WARN() << "warn log: " << 1; 38 | #define STM_TRACE() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, "") 39 | #define STM_DEBUG() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, "") 40 | #define STM_INFO() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, "") 41 | #define STM_WARN() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, "") 42 | #define STM_ERROR() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::err, "") 43 | #define STM_FATAL() logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::critical, "") 44 | ``` 45 | 46 | 上面的定义中LOG_XXXX宏直接使用spdlog输出, PRINT_XXXX宏使用printf格式, STM_XXXX是使用字节流的方式。 __FILENAME__ 是从完整路径中提取文件名的宏(因为很多时候完整路径会很冗余特别是使用cmake编译后的代码),下面看下logger类的封装: 47 | 48 | ```cpp 49 | namespace fs = std::filesystem; 50 | /// spdlog wrap class 51 | class logger final { 52 | public: 53 | /// let logger like stream 54 | struct log_stream : public std::ostringstream 55 | { 56 | public: 57 | log_stream(const spdlog::source_loc& _loc, spdlog::level::level_enum _lvl, std::string_view _prefix) 58 | : loc(_loc) 59 | , lvl(_lvl) 60 | , prefix(_prefix) 61 | { 62 | } 63 | 64 | ~log_stream() 65 | { 66 | flush(); 67 | } 68 | 69 | void flush() 70 | { 71 | logger::get().log(loc, lvl, (prefix + str()).c_str()); 72 | } 73 | 74 | private: 75 | spdlog::source_loc loc; 76 | spdlog::level::level_enum lvl = spdlog::level::info; 77 | std::string prefix; 78 | }; 79 | 80 | public: 81 | static logger& get() { 82 | static logger logger; 83 | return logger; 84 | } 85 | 86 | bool init(std::string_view log_file_path) { 87 | if (_is_inited) return true; 88 | try 89 | { 90 | // check log path and try to create log directory 91 | fs::path log_path(log_file_path); 92 | fs::path log_dir = log_path.parent_path(); 93 | if (!fs::exists(log_path)) { 94 | fs::create_directories(log_dir); 95 | } 96 | // initialize spdlog 97 | constexpr std::size_t log_buffer_size = 32 * 1024; // 32kb 98 | // constexpr std::size_t max_file_size = 50 * 1024 * 1024; // 50mb 99 | spdlog::init_thread_pool(log_buffer_size, std::thread::hardware_concurrency()); 100 | spdlog::set_level(_log_level); 101 | spdlog::flush_on(_log_level); 102 | spdlog::set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); 103 | spdlog::set_default_logger(spdlog::daily_logger_mt("daily_logger", log_path.string(), false, 2)); 104 | } 105 | catch (std::exception_ptr e) 106 | { 107 | assert(false); 108 | return false; 109 | } 110 | _is_inited = true; 111 | return true; 112 | } 113 | 114 | void shutdown() { spdlog::shutdown(); } 115 | 116 | template 117 | void log(const spdlog::source_loc& loc, spdlog::level::level_enum lvl, const char* fmt, const Args &... args) 118 | { 119 | spdlog::log(loc, lvl, fmt, args...); 120 | } 121 | 122 | template 123 | void printf(const spdlog::source_loc& loc, spdlog::level::level_enum lvl, const char* fmt, const Args &... args) 124 | { 125 | spdlog::log(loc, lvl, fmt::sprintf(fmt, args...).c_str()); 126 | } 127 | 128 | spdlog::level::level_enum level() { 129 | return _log_level; 130 | } 131 | 132 | void set_level(spdlog::level::level_enum lvl) { 133 | _log_level = lvl; 134 | spdlog::set_level(lvl); 135 | spdlog::flush_on(lvl); 136 | } 137 | 138 | static std::size_t get_filename_pos(std::string_view path) { 139 | if (path.empty()) 140 | return 0; 141 | 142 | size_t pos = path.find_last_of("/\\"); 143 | return (pos == path.npos) ? 0 : pos + 1; 144 | } 145 | 146 | private: 147 | logger() = default; 148 | ~logger() = default; 149 | 150 | logger(const logger&) = delete; 151 | void operator=(const logger&) = delete; 152 | 153 | private: 154 | std::atomic_bool _is_inited = false; 155 | spdlog::level::level_enum _log_level = spdlog::level::info; 156 | }; 157 | ``` 158 | 159 | 其中`printf`直接封装`fmt::sprintf`没什么好说的, STM_XXXX字节流方式使用封装类log_stream,它继承ostringstream,充分利用标准库中现有的东西,结合构造和析构函数实现日志的写入操作。 160 | 161 | 测试代码: 162 | 163 | ```CPP 164 | #include "logger.h" 165 | 166 | int main() { 167 | if (!logger::get().init("logs/test.log")) { 168 | return 1; 169 | } 170 | 171 | STM_DEBUG() << "STM_DEBUG" << 1; 172 | PRINT_WARN("PRINT_WARN, %d", 1); 173 | LOG_INFO("LOG_INFO {}", 1); 174 | 175 | logger::get().set_level(spdlog::level::info); 176 | STM_DEBUG() << "STM_DEBUG " << 2; 177 | PRINT_WARN("PRINT_WARN, %d", 2); 178 | LOG_INFO("LOG_INFO {}", 2); 179 | 180 | // call before spdlog static variables destroy 181 | logger::get().shutdown(); 182 | return 0; 183 | } 184 | ``` 185 | 186 | 项目地址:https://github.com/gqw/spdlog_wrapper -------------------------------------------------------------------------------- /example/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.hpp" 2 | 3 | #include "test/test_log.h" 4 | 5 | int main() { 6 | using namespace wlog; 7 | if (!logger::get().init("logs/test.log")) { 8 | return 1; 9 | } 10 | logger::get().set_level(spdlog::level::trace); 11 | STREAM_DEBUG() << "STM_DEBUG " << 1; 12 | PRINT_WARN("PRINT_WARN, %d", 1); 13 | LOG_INFO("LOG_INFO {}", 1); 14 | 15 | logger::get().set_level(spdlog::level::info); 16 | STREAM_DEBUG() << "STM_DEBUG " << 2; 17 | PRINT_WARN("PRINT_WARN, %d", 2); 18 | LOG_INFO("LOG_INFO {}", 2); 19 | 20 | test_log(); 21 | 22 | // call before spdlog static variables destroy 23 | logger::get().shutdown(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /example/src/test/test_log.cpp: -------------------------------------------------------------------------------- 1 | #include "test_log.h" 2 | 3 | #include 4 | 5 | void test_log() { 6 | wlog::logger::get().set_level(spdlog::level::info); 7 | STREAM_DEBUG() << "STM_DEBUG " << 3; 8 | PRINT_WARN("PRINT_WARN, %d", 3); 9 | LOG_INFO("LOG_INFO {}", 3); 10 | } -------------------------------------------------------------------------------- /example/src/test/test_log.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_TEST_LOG_H__ 2 | #define TEST_TEST_LOG_H__ 3 | 4 | void test_log(); 5 | 6 | #endif // TEST_TEST_LOG_H__ -------------------------------------------------------------------------------- /include/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WLOG_MACRO_DEFINE_ 2 | #define WLOG_MACRO_DEFINE_ 3 | 4 | #include 5 | 6 | #define LOG_LEVEL_TRACE 0 7 | #define LOG_LEVEL_DEBUG 1 8 | #define LOG_LEVEL_INFO 2 9 | #define LOG_LEVEL_WARN 3 10 | #define LOG_LEVEL_ERROR 4 11 | #define LOG_LEVEL_FATAL 5 12 | #define LOG_LEVEL_CLOSE 6 13 | 14 | 15 | // got short filename(exlude file directory) 16 | #define __FILENAME__ (wlog::logger::get_shortname(__FILE__)) 17 | 18 | #if (LOGGER_LEVEL <= LOG_LEVEL_TRACE) 19 | # define LOG_TRACE(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, fmt, ##__VA_ARGS__); 20 | # define PRINT_TRACE(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, fmt, ##__VA_ARGS__); 21 | # define STREAM_TRACE() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, "") 22 | #else 23 | # define LOG_TRACE(fmt, ...) 24 | # define PRINT_TRACE(fmt,...) 25 | # define STREAM_TRACE() wlog::logger_none::get() 26 | #endif 27 | 28 | #if (LOGGER_LEVEL <= LOG_LEVEL_DEBUG) 29 | # define LOG_DEBUG(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, fmt, ##__VA_ARGS__); 30 | # define PRINT_DEBUG(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, fmt, ##__VA_ARGS__); 31 | # define STREAM_DEBUG() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, "") 32 | #else 33 | # define LOG_DEBUG(fmt, ...) 34 | # define PRINT_DEBUG(fmt,...) 35 | # define STREAM_DEBUG() wlog::logger_none::get() 36 | #endif 37 | 38 | #if (LOGGER_LEVEL <= LOG_LEVEL_INFO) 39 | # define LOG_INFO(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, fmt, ##__VA_ARGS__); 40 | # define PRINT_INFO(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, fmt, ##__VA_ARGS__); 41 | # define STREAM_INFO() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, "") 42 | #else 43 | # define LOG_INFO(fmt, ...) 44 | # define PRINT_INFO(fmt,...) 45 | # define STREAM_INFO() wlog::logger_none::get() 46 | #endif 47 | 48 | #if (LOGGER_LEVEL <= LOG_LEVEL_WARN) 49 | # define LOG_WARN(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, fmt, ##__VA_ARGS__); 50 | # define PRINT_WARN(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, fmt, ##__VA_ARGS__); 51 | # define STREAM_WARN() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, "") 52 | #else 53 | # define LOG_WARN(fmt, ...) 54 | # define PRINT_WARN(fmt,...) 55 | # define STREAM_WARN() wlog::logger_none::get() 56 | #endif 57 | 58 | #if (LOGGER_LEVEL <= LOG_LEVEL_ERROR) 59 | # define LOG_ERROR(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::error, fmt, ##__VA_ARGS__); 60 | # define PRINT_ERROR(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::error, fmt, ##__VA_ARGS__); 61 | # define STREAM_ERROR() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::error, "") 62 | #else 63 | # define LOG_ERROR(fmt, ...) 64 | # define PRINT_ERROR(fmt,...) 65 | # define STREAM_ERROR() wlog::logger_none::get() 66 | #endif 67 | 68 | #if (LOGGER_LEVEL <= LOG_LEVEL_FATAL) 69 | # define LOG_FATAL(fmt, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::fatal, fmt, ##__VA_ARGS__); 70 | # define PRINT_FATAL(fmt,...) wlog::logger::get().printf({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::fatal, fmt, ##__VA_ARGS__); 71 | # define STREAM_FATAL() wlog::logger::log_stream({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::fatal, "") 72 | #else 73 | # define LOG_FATAL(fmt, ...) 74 | # define PRINT_FATAL(fmt,...) 75 | # define STREAM_FATAL() wlog::logger_none::get() 76 | #endif 77 | 78 | #endif // WLOG_MACRO_DEFINE_ 79 | 80 | -------------------------------------------------------------------------------- /include/wlog.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef WLOG_LOGGER_ 3 | #define WLOG_LOGGER_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #if WIN32 10 | #ifndef NOMINMAX 11 | # undef min 12 | # undef max 13 | #endif 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | /// spdlog wrap class 29 | 30 | namespace wlog { 31 | class logger final { 32 | public: 33 | /// let logger like stream 34 | struct log_stream : public std::ostringstream 35 | { 36 | public: 37 | log_stream(const spdlog::source_loc& _loc, spdlog::level::level_enum _lvl, std::string_view _prefix) 38 | : loc(_loc) 39 | , lvl(_lvl) 40 | , prefix(_prefix) 41 | { 42 | } 43 | 44 | ~log_stream() 45 | { 46 | flush(); 47 | } 48 | 49 | void flush() 50 | { 51 | logger::get().log(loc, lvl, (prefix + str()).c_str()); 52 | } 53 | 54 | private: 55 | spdlog::source_loc loc; 56 | spdlog::level::level_enum lvl = spdlog::level::info; 57 | std::string prefix; 58 | }; 59 | 60 | public: 61 | static logger& get() { 62 | static logger logger; 63 | return logger; 64 | } 65 | 66 | bool init(std::string_view log_file_path) { 67 | namespace fs = std::filesystem; 68 | if (_is_inited) return true; 69 | try 70 | { 71 | // check log path and try to create log directory 72 | fs::path log_path(log_file_path); 73 | fs::path log_dir = log_path.parent_path(); 74 | if (!fs::exists(log_path)) { 75 | fs::create_directories(log_dir); 76 | } 77 | // initialize spdlog 78 | constexpr std::size_t log_buffer_size = 32 * 1024; // 32kb 79 | // constexpr std::size_t max_file_size = 50 * 1024 * 1024; // 50mb 80 | spdlog::init_thread_pool(log_buffer_size, std::thread::hardware_concurrency()); 81 | std::vector sinks; 82 | auto daily_sink = std::make_shared(log_path.string(), 0, 2); 83 | sinks.push_back(daily_sink); 84 | 85 | // auto file_sink = std::make_shared(log_path.string(), true); 86 | // sinks.push_back(file_sink); 87 | 88 | #if defined(_DEBUG) && defined(WIN32) && !defined(NO_CONSOLE_LOG) 89 | auto ms_sink = std::make_shared(); 90 | sinks.push_back(ms_sink); 91 | #endif // _DEBUG 92 | 93 | #if !defined(WIN32) && !defined(NO_CONSOLE_LOG) 94 | auto console_sink = std::make_shared(); 95 | sinks.push_back(console_sink); 96 | #endif 97 | spdlog::set_default_logger(std::make_shared("", sinks.begin(), sinks.end())); 98 | 99 | spdlog::set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); 100 | spdlog::flush_on(spdlog::level::warn); 101 | spdlog::set_level(_log_level); 102 | } 103 | catch (std::exception_ptr e) 104 | { 105 | assert(false); 106 | return false; 107 | } 108 | _is_inited = true; 109 | return true; 110 | } 111 | 112 | void shutdown() { spdlog::shutdown(); } 113 | 114 | template 115 | void log(const spdlog::source_loc& loc, spdlog::level::level_enum lvl, const char* fmt, const Args &... args) 116 | { 117 | spdlog::log(loc, lvl, fmt, args...); 118 | } 119 | 120 | template 121 | void printf(const spdlog::source_loc& loc, spdlog::level::level_enum lvl, const char* fmt, const Args &... args) 122 | { 123 | spdlog::log(loc, lvl, fmt::sprintf(fmt, args...).c_str()); 124 | } 125 | 126 | spdlog::level::level_enum level() { 127 | return _log_level; 128 | } 129 | 130 | void set_level(spdlog::level::level_enum lvl) { 131 | _log_level = lvl; 132 | spdlog::set_level(lvl); 133 | 134 | } 135 | 136 | void set_flush_on(spdlog::level::level_enum lvl) { 137 | spdlog::flush_on(lvl); 138 | } 139 | 140 | static const char* get_shortname(std::string_view path) { 141 | if (path.empty()) 142 | return path.data(); 143 | 144 | size_t pos = path.find_last_of("/\\"); 145 | return path.data() + ((pos == path.npos) ? 0 : pos + 1); 146 | } 147 | 148 | private: 149 | logger() = default; 150 | ~logger() = default; 151 | 152 | logger(const logger&) = delete; 153 | void operator=(const logger&) = delete; 154 | 155 | private: 156 | std::atomic_bool _is_inited = false; 157 | spdlog::level::level_enum _log_level = spdlog::level::trace; 158 | }; 159 | 160 | class logger_none { 161 | public: 162 | logger_none() = default; 163 | 164 | static logger_none& get() { 165 | static logger_none logger; 166 | return logger; 167 | } 168 | 169 | logger_none& operator<<(const char* content) { 170 | return *this; 171 | } 172 | }; 173 | 174 | 175 | 176 | } // namespace wlog 177 | 178 | #endif // WLOG_LOGGER_ --------------------------------------------------------------------------------