Compare commits

..

99 Commits

Author SHA1 Message Date
Gabi Melman
012fe99ab1 Update version.h 2021-03-25 20:34:53 +02:00
Gabi Melman
8ff5a3e096 Merge pull request #1890 from prince-chrismc/patch-4
Remove version requirement from fmt find_package
2021-03-25 19:22:51 +02:00
Chris Mc
65317eb019 Remove version requirement from fmt find_package
By introducing 'no module' support this inadvertently triggered the find_package to use the "full version" version selection.

From https://cmake.org/cmake/help/latest/command/find_package.html#version-selection:

> When the [version] argument is given, Config mode will only find a version of the package that claims compatibility with the requested version (see format specification).

FMT does not set this configuration https://github.com/fmtlib/fmt/blob/7.1.3/support/cmake/fmt-config.cmake.in... but regardless it would not be "any compatibility" based on version semantics.

Which causes this error. v1.8.2 builds perfectly fine.

```
CMake Error at CMakeLists.txt:181 (find_package):
  Could not find a configuration file for package "fmt" that is compatible
  with requested version "5.3.0".

  The following configuration files were considered but not accepted:

    /home/proj/build/e98598522b7c484d9220bffc7ec84474515facbc/fmt-config.cmake, version: 7.1.3
```
2021-03-24 21:54:36 -04:00
Gabi Melman
e86f450428 Merge pull request #1885 from ahmedyarub/fix_android_build
Add required libraries for Android CMake build
2021-03-25 00:14:41 +02:00
Gabi Melman
7b2776fdc7 Merge pull request #1888 from stevenlunt/set_string_view
added spdlog::level::set_string_view to enable alternate log level na…
2021-03-24 23:10:11 +02:00
steven lunt
2a16d1d230 added spdlog::level::set_string_view to enable alternate log level names without changing the build via SPDLOG_LEVEL_NAMES 2021-03-24 16:22:54 -04:00
Gabi Melman
53e1c9ab11 Update version number to 1.8.3 2021-03-24 21:49:10 +02:00
Gabi Melman
410abc4626 Added the Windows Event logger to readme features 2021-03-24 01:45:26 +02:00
Ahmed Yarub Hani Al Nuaimi
a2e28443f0 Add required libraries for Android CMake build 2021-03-22 00:08:17 -03:00
Gabi Melman
c1af0a3f21 Merge pull request #1882 from imsherlock/v1.x
add default cases
2021-03-20 21:02:57 +02:00
Ryan Sherlock
bb5e1ee2f9 Removing changes to bundled fmt
Removing changes to the bundled fmt library. The default case
statements will be changed in the upstream library.

Signed-off-by: Ryan Sherlock <sherlock@loftorbital.com>
2021-03-20 09:22:40 -07:00
Ryan Sherlock
3aee89c8fd add default cases
Adding default case for cases where the compilation flag
-Wswitch-default is present on the command line when spdlog is
included in external projects.

Signed-off-by: Ryan Sherlock <ryan.m.sherlock@gmail.com>
2021-03-19 10:06:09 -07:00
gabime
44e1f9f682 Added nonreturn sepcifier to fix #1748 2021-03-17 00:25:26 +02:00
gabime
37d76b961c Fix #1876 2021-03-16 23:39:55 +02:00
gabime
1305663d99 make sure __cplusplus is defined under msvc 2021-03-12 15:10:15 +02:00
gabime
8f4efe57a2 make sure __cplusplus is defined under msvc 2021-03-12 15:09:35 +02:00
gabime
0613dbc4a2 Revert pr #1860 2021-03-04 23:52:50 +02:00
Gabi Melman
0ed0d69368 Update CMakeLists.txt 2021-03-04 23:24:02 +02:00
Gabi Melman
2ffbbee1f6 Merge pull request #1860 from rofferom/msvc-allow-static-runtime
CMake: Add SPDLOG_STATIC_VCRT to choose static MSVC runtime
2021-03-04 23:17:32 +02:00
Romain Roffé
b9d2f2537b CMake: Add SPDLOG_STATIC_VCRT to choose static MSVC runtime 2021-03-04 20:14:18 +01:00
Gabi Melman
69dc173979 Update README.md 2021-03-03 00:17:33 +02:00
Gabi Melman
ded8b5ebd4 Added build2 to package managers section in readme 2021-03-03 00:16:59 +02:00
Gabi Melman
ed58ae9f98 Revert PR #1851 2021-03-02 22:49:11 +02:00
Gabi Melman
f7f790b4b3 Merge pull request #1851 from Klaim/patch-1
Add build2 package support
2021-03-02 22:37:43 +02:00
Klaim (Joël Lamotte)
fe74c80992 Add build2 package support
WARNING: Please do not merge yet! See below.

We are currently in the process of packaging `spdlog` for `build2`, we have it working (even on unsupported Windows, see for example: https://ci.stage.build2.org/@a993b64e-8ba2-422e-97d7-250cdb5828e0?builds=&pv=&tc=*&cf=&mn=&tg=&rs=*)

This change simply adds the necessary information to use this package when using `build2`. Some notes:
 - not sure how to give the info succintly because `build2` allows packages to come from different sources, including the git repository of the package - in doubt I just linked to the future community repository address providing all the info, but the other package manager didn't do it like that so not sure if it's ok for you?; 
 - `build2` distinguish the package (`depends: spdlog <some-version-scheme>`, added in the `manifest` file of a `build2` project) and the target (`spdlog%lib{spdlog}` imported in a `buildfile`) because packages can contain several targets. I was not sure how to formulate that here, so feel free to tell me if I should just provide the name of the package and not more info?

The package isn't available yet so this have to be merged only once it is made available (probably in a few days).
2021-02-27 14:45:55 +01:00
Gabi Melman
fa659bf7ad Update daily_file_sink.h 2021-02-27 11:18:12 +02:00
Gabi Melman
9b41649601 Merge pull request #1849 from concatime/cmake-library-type-option-flag
CMake: Replace custom SPDLOG_BUILD_SHARED by standard BUILD_SHARED_LIBS
2021-02-26 23:35:23 +02:00
Issam E. Maghni
1b3438f5a5 AppVeyor: Use standard BUILD_SHARED_LIBS 2021-02-26 16:26:53 -05:00
Issam E. Maghni
3eed64e5c4 CMake: Replace custom SPDLOG_BUILD_SHARED by standard BUILD_SHARED_LIBS 2021-02-26 16:26:50 -05:00
Gabi Melman
0fac33781d Update daily_file_sink.h 2021-02-26 12:38:49 +02:00
Gabi Melman
3135b6a33d Update comment 2021-02-26 12:33:43 +02:00
Gabi Melman
2686ae2322 Merge pull request #1847 from fawdlstty/v1.x
add daily sink filename format
2021-02-26 12:17:29 +02:00
fawdlstty
a709e29586 fix unique mode compile 2021-02-26 10:18:33 +08:00
fawdlstty
dd46579cb4 fix name 2021-02-26 10:17:43 +08:00
fawdlstty
f4b7210e7b remove externs 2021-02-26 09:28:12 +08:00
fawdlstty
05a0b0d7b0 use fmt::chrono and remove is_fmt flags 2021-02-26 09:21:13 +08:00
fawdlstty
c1f4d7506a replace tab 2021-02-25 23:57:37 +08:00
fawdlstty
b6ba0be550 add daily_logger_format_mt and daily_logger_format_st sink 2021-02-25 23:55:19 +08:00
Gabi Melman
23dfb4e2f9 Merge pull request #1846 from MathiasMagnus/fix-bench
Avoid relying on function name decay mechanics
2021-02-24 11:26:25 +02:00
Máté Ferenc Nagy-Egri
7a10e31982 Avoid relying on function name decay mechanics 2021-02-24 09:45:35 +01:00
Gabi Melman
de89c4fd01 Merge pull request #1835 from jneruda/v1.x
Set default value to registry::err_handler_
2021-02-18 19:49:39 +02:00
Jakub Neruda
5d4956d34b Set default value to registry::err_handler_ 2021-02-17 14:02:20 +01:00
Gabi Melman
42c5eb59c9 Update wincolor_sink-inl.h 2021-02-14 01:49:29 +02:00
Gabi Melman
09cc6e7754 Simplify wincolor_sink::set_foreground_color_ 2021-02-14 01:03:02 +02:00
Gabi Melman
4a5bc41e89 Validate range in wincolor_sink::print_range_ 2021-02-14 00:20:44 +02:00
Gabi Melman
0ade18828d Remove switch statement from wincolor_sink::set_color_mode_impl 2021-02-13 23:53:36 +02:00
Gabi Melman
91046e6ca4 Simplify wincolor sink color mode management 2021-02-13 20:59:10 +02:00
Gabi Melman
17e1ba8ae2 simplifiy and mutex protect set_color_mode in wincolor sink 2021-02-13 20:16:15 +02:00
Gabi Melman
c47c854f15 Merge branch 'v1.x' of https://github.com/gabime/spdlog into v1.x 2021-02-13 20:06:51 +02:00
Gabi Melman
e931866b35 Removed public color constants from wincolor sink and intensify red and yellow 2021-02-13 20:06:40 +02:00
Gabi Melman
7828a065bf Update stdout_sinks-inl.h 2021-02-13 17:45:00 +02:00
Gabi Melman
3e689e700e Handle return values of win32 color functions in wincolor sink 2021-02-13 17:26:55 +02:00
Gabi Melman
a9964afcf7 Don't throw wincolor redirection failed, to be consistent with the non-redirect behaviour 2021-02-13 16:58:04 +02:00
Gabi Melman
95c19876c6 Skip log in wincolor sink if out_handle_ is null 2021-02-13 16:55:40 +02:00
Gabi Melman
5efccfa5e2 Fix #1828 2021-02-13 16:11:07 +02:00
Gabi Melman
89e737a258 Handle invalid handle in wincolor sink 2021-02-13 15:00:35 +02:00
Gabi Melman
8fbc853b0d Merge pull request #1829 from prateek9623/fix-prevent-msvc-warning-in-cuda
Fix: prevents MSVC warning flags to propagate in CUDA
2021-02-12 10:57:33 +02:00
Prateek Chokse
2e008b319c Fix: prevents MSVC warning flags to propagate in CUDA 2021-02-12 14:13:51 +05:30
Gabi Melman
ff6e3c95f2 Merge pull request #1819 from NukeULater/v1.x
better numeric_limits<>::max/min fix when using SPDLOG_WCHAR_TO_UTF8_SUPPORT
2021-02-06 11:32:14 +02:00
Unknown
7e9385405f better numeric_limits<>::max/min fix when using SPDLOG_WCHAR_TO_UTF8_SUPPORT
NOMINMAX macro doesn't work everytime for some reason
2021-02-06 10:50:29 +02:00
Gabi Melman
592ea36a86 Fix #1811 2021-01-21 21:12:42 +02:00
Gabi Melman
e059ebf99d Merge pull request #1807 from ChristianPanov/patch-1
Initializer list style consistency
2021-01-21 03:02:26 +02:00
Gabi Melman
609480ed78 Merge pull request #1798 from gv-me/constexpr-log-levels
add constexpr to SPDLOG_LEVEL_NAMES declaration
2021-01-21 03:00:49 +02:00
Gabi Melman
4271185936 Merge pull request #1805 from sillykelvin/patch-1
fix compiling error and typo
2021-01-21 02:56:53 +02:00
Christian Panov
aacae62591 Initializer list style consistency 2021-01-20 20:11:34 +02:00
Kelvin Hu
47cbf3828d fix compiling error and typo 2021-01-19 22:03:47 +08:00
Gabi Melman
46d418164d Merge pull request #1787 from sylveon/windows-separator-filenames
Better support for / separators on Windows, improve wchar filename coverage
2021-01-12 00:29:08 +02:00
Gaurav Vaidya
ede8d84884 fix constexpr declaration for c++11 2021-01-11 11:25:27 +01:00
Gaurav Vaidya
53d223b45f add constexpr to SPDLOG_LEVEL_NAMES declaration
for #1791
2021-01-11 11:16:06 +01:00
Charles Milette
ac35dd5a6f Prevent integer overflows in wstr_to_utf8buf and utf8_to_wstrbuf 2021-01-10 18:26:24 -05:00
Charles Milette
9e19012cb0 Remove filename_memory_buf_t from headers 2021-01-10 18:19:28 -05:00
Charles Milette
1234cda3b3 Don't build the example with wide filenames 2021-01-10 18:19:00 -05:00
Gabi Melman
710a0e3a45 Merge pull request #1795 from graydon/truncate-but-still-append
Open files with "ab" mode even if truncating.
2021-01-09 12:20:26 +02:00
Graydon Hoare
b7f24b2456 Open files with "ab" mode even if truncating. 2021-01-09 00:35:32 -08:00
Charles Milette
fc594b551a Prevent win_eventlog_sink from silently discarding errors when wide support is enabled 2021-01-06 22:17:09 -05:00
Charles Milette
f39ccccc0c Fix linker error 2021-01-06 21:52:59 -05:00
Charles Milette
f0a4ddd78b Fix character issues in test_errors.cpp 2021-01-06 20:00:59 -05:00
Charles Milette
c691769e46 Fix other build errors and unit tests 2021-01-06 19:39:47 -05:00
Charles Milette
19dc30567e Fix build errors 2021-01-06 18:55:57 -05:00
Charles Milette
a453bccff0 Better support for / separators on Windows, improve wchar filename coverage 2021-01-06 04:15:14 -05:00
Gabi Melman
aa2053a575 Merge pull request #1774 from Ryan-rsm-McKenzie/v1.x
skip module mode when finding fmt
2020-12-27 14:19:08 +02:00
ryan-rsm-mckenzie
3d8f71c4d2 skip module mode when finding fmt 2020-12-27 01:37:12 -08:00
Gabi Melman
6aaaabbc4d Merge pull request #1773 from Ryan-rsm-McKenzie/v1.x
ensure SPDLOG_FMT_EXTERNAL is honored throughout whole codebase
2020-12-27 11:17:30 +02:00
ryan-rsm-mckenzie
42c36f48ed ensure SPDLOG_FMT_EXTERNAL is honored throughout whole codebase 2020-12-27 00:47:57 -08:00
Gabi Melman
a5f4139102 Merge pull request #1771 from Ryan-rsm-McKenzie/v1.x
ensure stdout color sinks do not leak windows headers with SPDLOG_COMPILED_LIB
2020-12-26 15:23:37 +02:00
ryan-rsm-mckenzie
030d85a9b3 ensure stdout color sinks do not leak windows headers with SPDLOG_COMPILED_LIB 2020-12-26 03:45:12 -08:00
Gabi Melman
adcfb7fb55 Merge pull request #1768 from dominicpoeschko/colorterminal_detection
Changed is_color_terminal to be more generic.
2020-12-20 03:01:42 +02:00
dominic
cec365888a Added check for COLORTERM environment variable to detect if terminal
supports color.
Added alacritty to supported color terminals.
2020-12-19 23:22:31 +01:00
Gabi Melman
55bfa8dd11 Merge pull request #1766 from shimaowo/v1.x
Fix #1765 - Add SPDLOG_DISABLE_DEFAULT_LOGGER as a cmake option
2020-12-19 07:40:39 +02:00
shimaowo
e99759fe45 Fix #1765 - Add SPDLOG_DISABLE_DEFAULT_LOGGER as a cmake option 2020-12-18 14:31:34 -08:00
Gabi Melman
17c6e6ee3f Merge pull request #1760 from iko1/v1.x
fix windows event sink log compilation error with UNICODE preprocessor
2020-12-16 11:41:44 +02:00
Amir Alperin
7fff900a1a Fix error message in exception 2020-12-16 06:57:24 +02:00
Amir Alperin
c67974e4c8 replace deprected wchar string conversion 2020-12-16 01:14:55 +02:00
Gabi Melman
a36696e02e Merge pull request #1763 from BVonk/v1.x
Add Hourly file sink
2020-12-16 01:11:51 +02:00
BVonk
9b80ca6c41 Add files via upload 2020-12-15 17:21:09 +01:00
Amir Alperin
22f514aabf restore ident format 2020-12-13 23:11:25 +02:00
Amir Alperin
211478e13e convert message back to wchar 2020-12-13 10:45:55 +02:00
Amir Alperin
5e33a7e58b fix compilation errors 2020-12-13 10:11:00 +02:00
gabime
b2e31721e8 Update example 2020-12-11 16:58:49 +02:00
37 changed files with 688 additions and 262 deletions

View File

@@ -30,6 +30,11 @@ if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif() endif()
# make sure __cplusplus is defined when using msvc
if(MSVC)
string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus")
endif()
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS") if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS")
@@ -100,6 +105,7 @@ option(
SPDLOG_NO_ATOMIC_LEVELS SPDLOG_NO_ATOMIC_LEVELS
"prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently"
OFF) OFF)
option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF)
# clang-tidy # clang-tidy
if(${CMAKE_VERSION} VERSION_GREATER "3.5") if(${CMAKE_VERSION} VERSION_GREATER "3.5")
@@ -123,7 +129,7 @@ if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
list(APPEND SPDLOG_SRCS src/fmt.cpp) list(APPEND SPDLOG_SRCS src/fmt.cpp)
endif() endif()
if(SPDLOG_BUILD_SHARED) if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS)
if(WIN32) if(WIN32)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc) list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
@@ -131,7 +137,8 @@ if(SPDLOG_BUILD_SHARED)
add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB)
if(MSVC) if(MSVC)
target_compile_options(spdlog PUBLIC /wd4251 /wd4275) target_compile_options(spdlog PUBLIC
$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251 /wd4275>)
endif() endif()
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED) target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED)
@@ -171,7 +178,7 @@ target_link_libraries(spdlog_header_only INTERFACE Threads::Threads)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
if(NOT TARGET fmt::fmt) if(NOT TARGET fmt::fmt)
find_package(fmt 5.3.0 REQUIRED) find_package(fmt CONFIG REQUIRED)
endif() endif()
target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL) target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL) target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)
@@ -188,6 +195,14 @@ if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
endif() endif()
# ---------------------------------------------------------------------------------------
# Add required libraries for Android CMake build
# ---------------------------------------------------------------------------------------
if (ANDROID)
target_link_libraries(spdlog PUBLIC log)
target_link_libraries(spdlog_header_only INTERFACE log)
endif ()
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Misc definitions according to tweak options # Misc definitions according to tweak options
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
@@ -201,7 +216,8 @@ foreach(
SPDLOG_PREVENT_CHILD_FD SPDLOG_PREVENT_CHILD_FD
SPDLOG_NO_THREAD_ID SPDLOG_NO_THREAD_ID
SPDLOG_NO_TLS SPDLOG_NO_TLS
SPDLOG_NO_ATOMIC_LEVELS) SPDLOG_NO_ATOMIC_LEVELS
SPDLOG_DISABLE_DEFAULT_LOGGER)
if(${SPDLOG_OPTION}) if(${SPDLOG_OPTION})
target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION}) target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION})
target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION}) target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION})
@@ -289,3 +305,4 @@ if(SPDLOG_INSTALL)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
include(cmake/spdlogCPack.cmake) include(cmake/spdlogCPack.cmake)
endif() endif()

View File

@@ -31,6 +31,8 @@ $ cmake .. && make -j
* vcpkg: `vcpkg install spdlog` * vcpkg: `vcpkg install spdlog`
* conan: `spdlog/[>=1.4.1]` * conan: `spdlog/[>=1.4.1]`
* conda: `conda install -c conda-forge spdlog` * conda: `conda install -c conda-forge spdlog`
* build2: ```depends: spdlog ^1.8.2```
## Features ## Features
@@ -45,7 +47,8 @@ $ cmake .. && make -j
* Daily log files. * Daily log files.
* Console logging (colors supported). * Console logging (colors supported).
* syslog. * syslog.
* Windows debugger (```OutputDebugString(..)```) * Windows event log.
* Windows debugger (```OutputDebugString(..)```).
* Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface).
* Log filtering - log levels can be modified in runtime as well as in compile time. * Log filtering - log levels can be modified in runtime as well as in compile time.
* Support for loading log levels from argv or from environment var. * Support for loading log levels from argv or from environment var.

View File

@@ -4,32 +4,52 @@ environment:
matrix: matrix:
- GENERATOR: '"Visual Studio 14 2015"' - GENERATOR: '"Visual Studio 14 2015"'
BUILD_TYPE: Debug BUILD_TYPE: Debug
WCHAR: 'OFF'
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 14 2015"' - GENERATOR: '"Visual Studio 14 2015"'
BUILD_TYPE: Release BUILD_TYPE: Release
WCHAR: 'ON'
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 14 2015 Win64"' - GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Debug BUILD_TYPE: Debug
WCHAR: 'ON'
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 14 2015 Win64"' - GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Release BUILD_TYPE: Release
WCHAR: 'ON'
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 15 2017 Win64"' - GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Debug BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
WCHAR: 'ON' WCHAR: 'ON'
BUILD_SHARED: 'OFF' WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 15 2017 Win64"' - GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release BUILD_TYPE: Release
WCHAR: 'OFF'
BUILD_SHARED: 'OFF' BUILD_SHARED: 'OFF'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 15 2017 Win64"' - GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release BUILD_TYPE: Release
WCHAR: 'OFF'
BUILD_SHARED: 'ON' BUILD_SHARED: 'ON'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
- GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'ON'
WCHAR: 'ON'
WCHAR_FILES: 'ON'
BUILD_EXAMPLE: 'OFF'
build_script: build_script:
- cmd: >- - cmd: >-
set set
@@ -40,7 +60,7 @@ build_script:
set PATH=%PATH%;C:\Program Files\Git\usr\bin set PATH=%PATH%;C:\Program Files\Git\usr\bin
cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=%WCHAR% -DSPDLOG_BUILD_SHARED=%BUILD_SHARED% -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF -DSPDLOG_BUILD_WARNINGS=ON cmake -G %GENERATOR% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -D BUILD_SHARED_LIBS=%BUILD_SHARED% -D SPDLOG_WCHAR_SUPPORT=%WCHAR% -D SPDLOG_WCHAR_FILENAMES=%WCHAR_FILES% -D SPDLOG_BUILD_EXAMPLE=%BUILD_EXAMPLE% -D SPDLOG_BUILD_EXAMPLE_HO=%BUILD_EXAMPLE% -D SPDLOG_BUILD_TESTS=ON -D SPDLOG_BUILD_TESTS_HO=OFF -D SPDLOG_BUILD_WARNINGS=ON ..
cmake --build . --config %BUILD_TYPE% cmake --build . --config %BUILD_TYPE%

View File

@@ -9,7 +9,12 @@
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/async.h" #include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#ifdef SPDLOG_FMT_EXTERNAL
#include <fmt/locale.h>
#else
#include "spdlog/fmt/bundled/locale.h" #include "spdlog/fmt/bundled/locale.h"
#endif
#include "utils.h" #include "utils.h"
#include <atomic> #include <atomic>

View File

@@ -11,7 +11,12 @@
#include "spdlog/sinks/daily_file_sink.h" #include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h" #include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/rotating_file_sink.h"
#ifdef SPDLOG_FMT_EXTERNAL
#include <fmt/locale.h>
#else
#include "spdlog/fmt/bundled/locale.h" #include "spdlog/fmt/bundled/locale.h"
#endif
#include "utils.h" #include "utils.h"
#include <atomic> #include <atomic>

View File

@@ -34,14 +34,14 @@ void bench_formatters()
for (auto &flag : all_flags) for (auto &flag : all_flags)
{ {
auto pattern = std::string("%") + flag; auto pattern = std::string("%") + flag;
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern); benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
// pattern = std::string("%16") + flag; // pattern = std::string("%16") + flag;
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern); // benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
// //
// // bench center padding // // bench center padding
// pattern = std::string("%=16") + flag; // pattern = std::string("%=16") + flag;
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern); // benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
} }
// complex patterns // complex patterns
@@ -52,7 +52,7 @@ void bench_formatters()
}; };
for (auto &pattern : patterns) for (auto &pattern : patterns)
{ {
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern)->Iterations(2500000); benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern)->Iterations(2500000);
} }
} }
@@ -73,7 +73,7 @@ int main(int argc, char *argv[])
} }
else else
{ {
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern); benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
} }
benchmark::Initialize(&argc, argv); benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks(); benchmark::RunSpecifiedBenchmarks();

View File

@@ -59,3 +59,4 @@ function(spdlog_enable_sanitizer target_name)
target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer) target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined -fuse-ld=gold) target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined -fuse-ld=gold)
endfunction() endfunction()

View File

@@ -22,7 +22,7 @@ void syslog_example();
void custom_flags_example(); void custom_flags_example();
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // for loading levels from the environment variable #include "spdlog/cfg/env.h" // support for loading levels from the environment variable
int main(int, char *[]) int main(int, char *[])
{ {

View File

@@ -9,15 +9,24 @@
namespace spdlog { namespace spdlog {
namespace level { namespace level {
#if __cplusplus >= 201703L
constexpr
#endif
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
SPDLOG_INLINE string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{ {
return level_string_views[l]; return level_string_views[l];
} }
SPDLOG_INLINE void set_string_view(spdlog::level::level_enum l, const string_view_t &s) SPDLOG_NOEXCEPT
{
level_string_views[l] = s;
}
SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{ {
return short_level_names[l]; return short_level_names[l];

View File

@@ -88,7 +88,9 @@ class sink;
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
using filename_t = std::wstring; using filename_t = std::wstring;
#define SPDLOG_FILENAME_T(s) L##s // allow macro expansion to occur in SPDLOG_FILENAME_T
#define SPDLOG_FILENAME_T_INNER(s) L##s
#define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
#else #else
using filename_t = std::string; using filename_t = std::string;
#define SPDLOG_FILENAME_T(s) s #define SPDLOG_FILENAME_T(s) s
@@ -101,6 +103,7 @@ using err_handler = std::function<void(const std::string &err_msg)>;
using string_view_t = fmt::basic_string_view<char>; using string_view_t = fmt::basic_string_view<char>;
using wstring_view_t = fmt::basic_string_view<wchar_t>; using wstring_view_t = fmt::basic_string_view<wchar_t>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>; using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifndef _WIN32 #ifndef _WIN32
@@ -163,7 +166,8 @@ enum level_enum
} }
#endif #endif
SPDLOG_API string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API void set_string_view(spdlog::level::level_enum l, const string_view_t &s) SPDLOG_NOEXCEPT;
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
@@ -203,8 +207,8 @@ private:
std::string msg_; std::string msg_;
}; };
SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); [[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
SPDLOG_API void throw_spdlog_ex(std::string msg); [[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);
struct source_loc struct source_loc
{ {

View File

@@ -29,12 +29,27 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
{ {
close(); close();
filename_ = fname; filename_ = fname;
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
auto *mode = SPDLOG_FILENAME_T("ab");
auto *trunc_mode = SPDLOG_FILENAME_T("wb");
for (int tries = 0; tries < open_tries_; ++tries) for (int tries = 0; tries < open_tries_; ++tries)
{ {
// create containing folder if not exists already. // create containing folder if not exists already.
os::create_dir(os::dir_name(fname)); os::create_dir(os::dir_name(fname));
if (truncate)
{
// Truncate by opening-and-closing a tmp file in "wb" mode, always
// opening the actual log-we-write-to in "ab" mode, since that
// interacts more politely with eternal processes that might
// rotate/truncate the file underneath us.
std::FILE *tmp;
if (os::fopen_s(&tmp, fname, trunc_mode))
{
continue;
}
std::fclose(tmp);
}
if (!os::fopen_s(&fd_, fname, mode)) if (!os::fopen_s(&fd_, fname, mode))
{ {
return; return;
@@ -118,7 +133,7 @@ SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension
} }
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
auto folder_index = fname.rfind(details::os::folder_sep); auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
if (folder_index != filename_t::npos && folder_index >= ext_index - 1) if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
{ {
return std::make_tuple(fname, filename_t()); return std::make_tuple(fname, filename_t());

View File

@@ -26,7 +26,9 @@ SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
update_string_views(); update_string_views();
} }
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT
: log_msg{other}
, buffer{std::move(other.buffer)}
{ {
update_string_views(); update_string_views();
} }

View File

@@ -397,17 +397,26 @@ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
#ifdef _WIN32 #ifdef _WIN32
return true; return true;
#else #else
static constexpr std::array<const char *, 14> terms = {
{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
const char *env_p = std::getenv("TERM"); static const bool result = []() {
if (env_p == nullptr) const char *env_colorterm_p = std::getenv("COLORTERM");
if (env_colorterm_p != nullptr)
{
return true;
}
static constexpr std::array<const char *, 15> terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux",
"msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty"}};
const char *env_term_p = std::getenv("TERM");
if (env_term_p == nullptr)
{ {
return false; return false;
} }
static const bool result = return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; });
std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); }();
return result; return result;
#endif #endif
} }
@@ -427,7 +436,7 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
{ {
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)())) if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1)
{ {
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
} }
@@ -459,6 +468,41 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
} }
SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
{
if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1)
{
throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
}
int str_size = static_cast<int>(str.size());
if (str_size == 0)
{
target.resize(0);
return;
}
int result_size = static_cast<int>(target.capacity());
if (str_size + 1 > result_size)
{
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
}
if (result_size > 0)
{
target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0)
{
target.resize(result_size);
return;
}
}
throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
// return true on success // return true on success
@@ -489,15 +533,10 @@ SPDLOG_INLINE bool create_dir(filename_t path)
return false; return false;
} }
#ifdef _WIN32
// support forward slash in windows
std::replace(path.begin(), path.end(), '/', folder_sep);
#endif
size_t search_offset = 0; size_t search_offset = 0;
do do
{ {
auto token_pos = path.find(folder_sep, search_offset); auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
// treat the entire path as a folder if no folder separator not found // treat the entire path as a folder if no folder separator not found
if (token_pos == filename_t::npos) if (token_pos == filename_t::npos)
{ {
@@ -523,11 +562,7 @@ SPDLOG_INLINE bool create_dir(filename_t path)
// "abc///" => "abc//" // "abc///" => "abc//"
SPDLOG_INLINE filename_t dir_name(filename_t path) SPDLOG_INLINE filename_t dir_name(filename_t path)
{ {
#ifdef _WIN32 auto pos = path.find_last_of(folder_seps_filename);
// support forward slash in windows
std::replace(path.begin(), path.end(), '/', folder_sep);
#endif
auto pos = path.find_last_of(folder_sep);
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
} }

View File

@@ -32,11 +32,16 @@ SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT;
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
// folder separator // folder separator
#if !defined(SPDLOG_FOLDER_SEPS)
#ifdef _WIN32 #ifdef _WIN32
static const char folder_sep = '\\'; #define SPDLOG_FOLDER_SEPS "\\/"
#else #else
SPDLOG_CONSTEXPR static const char folder_sep = '/'; #define SPDLOG_FOLDER_SEPS "/"
#endif #endif
#endif
SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS;
SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS);
// fopen_s on non windows for writing // fopen_s on non windows for writing
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
@@ -85,6 +90,8 @@ SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target);
#endif #endif
// Return directory name from given path or empty string // Return directory name from given path or empty string

View File

@@ -99,7 +99,7 @@ private:
std::unique_ptr<formatter> formatter_; std::unique_ptr<formatter> formatter_;
spdlog::level::level_enum global_log_level_ = level::info; spdlog::level::level_enum global_log_level_ = level::info;
level::level_enum flush_level_ = level::off; level::level_enum flush_level_ = level::off;
void (*err_handler_)(const std::string &msg); void (*err_handler_)(const std::string &msg) = nullptr;
std::shared_ptr<thread_pool> tp_; std::shared_ptr<thread_pool> tp_;
std::unique_ptr<periodic_worker> periodic_flusher_; std::unique_ptr<periodic_worker> periodic_flusher_;
std::shared_ptr<logger> default_logger_; std::shared_ptr<logger> default_logger_;

View File

@@ -13,11 +13,13 @@
#include <spdlog/fmt/fmt.h> #include <spdlog/fmt/fmt.h>
#include <spdlog/formatter.h> #include <spdlog/formatter.h>
#include <algorithm>
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <cctype> #include <cctype>
#include <cstring> #include <cstring>
#include <iterator>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
@@ -127,7 +129,7 @@ public:
void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
{ {
string_view_t &level_name = level::to_string_view(msg.level); const string_view_t &level_name = level::to_string_view(msg.level);
ScopedPadder p(level_name.size(), padinfo_, dest); ScopedPadder p(level_name.size(), padinfo_, dest);
fmt_helper::append_string_view(level_name, dest); fmt_helper::append_string_view(level_name, dest);
} }
@@ -814,11 +816,31 @@ public:
: flag_formatter(padinfo) : flag_formatter(padinfo)
{} {}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // consider using 'if constexpr' instead
#endif // _MSC_VER
static const char *basename(const char *filename) static const char *basename(const char *filename)
{ {
const char *rv = std::strrchr(filename, os::folder_sep); // if the size is 2 (1 character + null terminator) we can use the more efficient strrchr
// the branch will be elided by optimizations
if (sizeof(os::folder_seps) == 2)
{
const char *rv = std::strrchr(filename, os::folder_seps[0]);
return rv != nullptr ? rv + 1 : filename; return rv != nullptr ? rv + 1 : filename;
} }
else
{
const std::reverse_iterator<const char*> begin(filename + std::strlen(filename));
const std::reverse_iterator<const char*> end(filename);
const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps), std::end(os::folder_seps) - 1);
return it != end ? it.base() : filename;
}
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override
{ {

View File

@@ -106,6 +106,8 @@ SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
case color_mode::never: case color_mode::never:
should_do_colors_ = false; should_do_colors_ = false;
return; return;
default:
should_do_colors_ = false;
} }
} }

View File

@@ -7,6 +7,7 @@
#include <spdlog/details/file_helper.h> #include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/fmt/fmt.h> #include <spdlog/fmt/fmt.h>
#include <spdlog/fmt/chrono.h>
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/details/circular_q.h> #include <spdlog/details/circular_q.h>
@@ -36,6 +37,23 @@ struct daily_filename_calculator
} }
}; };
/*
* Generator of daily log file names with strftime format.
* Usages:
* auto sink = std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);"
* auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)"
*
*/
struct daily_filename_format_calculator
{
static filename_t calc_filename (const filename_t &filename, const tm &now_tm)
{
// generate fmt datetime format string, e.g. {:%Y-%m-%d}.
filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T ("{{:{}}}"), filename);
return fmt::format(fmt_filename, now_tm);
}
};
/* /*
* Rotating file sink based on date. * Rotating file sink based on date.
* If truncate != false , the created file will be truncated. * If truncate != false , the created file will be truncated.
@@ -182,6 +200,8 @@ private:
using daily_file_sink_mt = daily_file_sink<std::mutex>; using daily_file_sink_mt = daily_file_sink<std::mutex>;
using daily_file_sink_st = daily_file_sink<details::null_mutex>; using daily_file_sink_st = daily_file_sink<details::null_mutex>;
using daily_file_format_sink_mt = daily_file_sink<std::mutex, daily_filename_format_calculator>;
using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>;
} // namespace sinks } // namespace sinks
@@ -195,10 +215,24 @@ inline std::shared_ptr<logger> daily_logger_mt(
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files); return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
} }
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_mt(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_format_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
}
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_st( inline std::shared_ptr<logger> daily_logger_st(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0) const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{ {
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files); return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
} }
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_st(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_format_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
}
} // namespace spdlog } // namespace spdlog

View File

@@ -0,0 +1,194 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.h>
#include <spdlog/details/circular_q.h>
#include <spdlog/details/synchronous_factory.h>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext
*/
struct hourly_filename_calculator
{
// Create filename for the form basename.YYYY-MM-DD-H
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
return fmt::format(
SPDLOG_FILENAME_T("{}_{:04d}{:02d}{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, ext);
}
};
/*
* Rotating file sink based on time.
* If truncate != false , the created file will be truncated.
* If max_files > 0, retain only the last max_files and delete previous.
*/
template<typename Mutex, typename FileNameCalc = hourly_filename_calculator>
class hourly_file_sink final : public base_sink<Mutex>
{
public:
// create hourly file sink which rotates on given time
hourly_file_sink(filename_t base_filename, bool truncate = false, uint16_t max_files = 0)
: base_filename_(std::move(base_filename))
, truncate_(truncate)
, max_files_(max_files)
, filenames_q_()
{
auto now = log_clock::now();
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
file_helper_.open(filename, truncate_);
rotation_tp_ = next_rotation_tp_();
if (max_files_ > 0)
{
init_filenames_q_();
}
}
filename_t filename()
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
return file_helper_.filename();
}
protected:
void sink_it_(const details::log_msg &msg) override
{
auto time = msg.time;
bool should_rotate = time >= rotation_tp_;
if (should_rotate)
{
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time));
file_helper_.open(filename, truncate_);
rotation_tp_ = next_rotation_tp_();
}
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted);
file_helper_.write(formatted);
// Do the cleaning only at the end because it might throw on failure.
if (should_rotate && max_files_ > 0)
{
delete_old_();
}
}
void flush_() override
{
file_helper_.flush();
}
private:
void init_filenames_q_()
{
using details::os::path_exists;
filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_));
std::vector<filename_t> filenames;
auto now = log_clock::now();
while (filenames.size() < max_files_)
{
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
if (!path_exists(filename))
{
break;
}
filenames.emplace_back(filename);
now -= std::chrono::hours(1);
}
for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter)
{
filenames_q_.push_back(std::move(*iter));
}
}
tm now_tm(log_clock::time_point tp)
{
time_t tnow = log_clock::to_time_t(tp);
return spdlog::details::os::localtime(tnow);
}
log_clock::time_point next_rotation_tp_()
{
auto now = log_clock::now();
tm date = now_tm(now);
date.tm_min = 0;
date.tm_sec = 0;
auto rotation_time = log_clock::from_time_t(std::mktime(&date));
if (rotation_time > now)
{
return rotation_time;
}
return {rotation_time + std::chrono::hours(1)};
}
// Delete the file N rotations ago.
// Throw spdlog_ex on failure to delete the old file.
void delete_old_()
{
using details::os::filename_to_str;
using details::os::remove_if_exists;
filename_t current_file = file_helper_.filename();
if (filenames_q_.full())
{
auto old_filename = std::move(filenames_q_.front());
filenames_q_.pop_front();
bool ok = remove_if_exists(old_filename) == 0;
if (!ok)
{
filenames_q_.push_back(std::move(current_file));
SPDLOG_THROW(spdlog_ex("Failed removing hourly file " + filename_to_str(old_filename), errno));
}
}
filenames_q_.push_back(std::move(current_file));
}
filename_t base_filename_;
log_clock::time_point rotation_tp_;
details::file_helper file_helper_;
bool truncate_;
uint16_t max_files_;
details::circular_q<filename_t> filenames_q_;
};
using hourly_file_sink_mt = hourly_file_sink<std::mutex>;
using hourly_file_sink_st = hourly_file_sink<details::null_mutex>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> hourly_logger_mt(
const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::hourly_file_sink_mt>(logger_name, filename, truncate, max_files);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> hourly_logger_st(
const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::hourly_file_sink_st>(logger_name, filename, truncate, max_files);
}
} // namespace spdlog

View File

@@ -32,8 +32,13 @@ SPDLOG_INLINE stdout_sink_base<ConsoleMutex>::stdout_sink_base(FILE *file)
{ {
#ifdef _WIN32 #ifdef _WIN32
// get windows handle from the FILE* object // get windows handle from the FILE* object
handle_ = (HANDLE)::_get_osfhandle(::_fileno(file_)); handle_ = (HANDLE)::_get_osfhandle(::_fileno(file_));
if (handle_ == INVALID_HANDLE_VALUE)
// don't throw to support cases where no console is attached,
// and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE).
// throw only if non stdout/stderr target is requested (probably regular file and not console).
if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr)
{ {
throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno);
} }
@@ -43,10 +48,14 @@ SPDLOG_INLINE stdout_sink_base<ConsoleMutex>::stdout_sink_base(FILE *file)
template<typename ConsoleMutex> template<typename ConsoleMutex>
SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &msg) SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &msg)
{ {
#ifdef _WIN32
if (handle_ == INVALID_HANDLE_VALUE)
{
return;
}
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
#ifdef _WIN32
::fflush(file_); // flush in case there is somthing in this file_ already ::fflush(file_); // flush in case there is somthing in this file_ already
auto size = static_cast<DWORD>(formatted.size()); auto size = static_cast<DWORD>(formatted.size());
DWORD bytes_written = 0; DWORD bytes_written = 0;
@@ -56,6 +65,9 @@ SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &m
throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError())); throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError()));
} }
#else #else
std::lock_guard<mutex_t> lock(mutex_);
memory_buf_t formatted;
formatter_->format(msg, formatted);
::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
::fflush(file_); // flush every line to terminal ::fflush(file_); // flush every line to terminal
#endif // WIN32 #endif // WIN32

View File

@@ -57,7 +57,7 @@ struct win32_error : public spdlog_ex
LPSTR format_message_result{}; LPSTR format_message_result{};
auto format_message_succeeded = auto format_message_succeeded =
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr); error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr);
if (format_message_succeeded && format_message_result) if (format_message_succeeded && format_message_result)
@@ -203,7 +203,7 @@ private:
{ {
if (!hEventLog_) if (!hEventLog_)
{ {
hEventLog_ = ::RegisterEventSource(nullptr, source_.c_str()); hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str());
if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED)
{ {
SPDLOG_THROW(internal::win32_error("RegisterEventSource")); SPDLOG_THROW(internal::win32_error("RegisterEventSource"));
@@ -218,13 +218,23 @@ protected:
{ {
using namespace internal; using namespace internal;
bool succeeded;
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
formatted.push_back('\0'); formatted.push_back('\0');
LPCSTR lp_str = static_cast<LPCSTR>(formatted.data());
auto succeeded = ::ReportEvent(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
wmemory_buf_t buf;
details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf);
LPCWSTR lp_wstr = buf.data();
succeeded = ::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_,
current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr);
#else
LPCSTR lp_str = formatted.data();
succeeded = ::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_,
current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr); current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr);
#endif
if (!succeeded) if (!succeeded)
{ {

View File

@@ -7,30 +7,30 @@
#include <spdlog/sinks/wincolor_sink.h> #include <spdlog/sinks/wincolor_sink.h>
#endif #endif
#include <spdlog/details/windows_include.h>
#include <wincon.h>
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
template<typename ConsoleMutex> template<typename ConsoleMutex>
SPDLOG_INLINE wincolor_sink<ConsoleMutex>::wincolor_sink(HANDLE out_handle, color_mode mode) SPDLOG_INLINE wincolor_sink<ConsoleMutex>::wincolor_sink(void *out_handle, color_mode mode)
: out_handle_(out_handle) : out_handle_(out_handle)
, mutex_(ConsoleMutex::mutex()) , mutex_(ConsoleMutex::mutex())
, formatter_(details::make_unique<spdlog::pattern_formatter>()) , formatter_(details::make_unique<spdlog::pattern_formatter>())
{ {
// check if out_handle is points to the actual console.
// ::GetConsoleMode() should return 0 if it is redirected or not valid console handle.
DWORD console_mode;
in_console_ = ::GetConsoleMode(out_handle, &console_mode) != 0;
set_color_mode(mode); set_color_mode_impl(mode);
colors_[level::trace] = WHITE; // set level colors
colors_[level::debug] = CYAN; colors_[level::trace] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; // white
colors_[level::info] = GREEN; colors_[level::debug] = FOREGROUND_GREEN | FOREGROUND_BLUE; // cyan
colors_[level::warn] = YELLOW | BOLD; colors_[level::info] = FOREGROUND_GREEN; // green
colors_[level::err] = RED | BOLD; // red bold colors_[level::warn] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; // intense yellow
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background colors_[level::err] = FOREGROUND_RED | FOREGROUND_INTENSITY; // intense red
colors_[level::critical] =
BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; // intense white on red background
colors_[level::off] = 0; colors_[level::off] = 0;
} }
@@ -42,7 +42,7 @@ SPDLOG_INLINE wincolor_sink<ConsoleMutex>::~wincolor_sink()
// change the color for the given level // change the color for the given level
template<typename ConsoleMutex> template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color(level::level_enum level, WORD color) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color(level::level_enum level, std::uint16_t color)
{ {
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
colors_[level] = color; colors_[level] = color;
@@ -51,31 +51,30 @@ void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color(level::level_enum leve
template<typename ConsoleMutex> template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
{ {
if (out_handle_ == nullptr || out_handle_ == INVALID_HANDLE_VALUE)
{
return;
}
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
msg.color_range_start = 0; msg.color_range_start = 0;
msg.color_range_end = 0; msg.color_range_end = 0;
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
if (!in_console_)
{
write_to_file_(formatted);
return;
}
if (should_do_colors_ && msg.color_range_end > msg.color_range_start) if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
{ {
// before color range // before color range
print_range_(formatted, 0, msg.color_range_start); print_range_(formatted, 0, msg.color_range_start);
// in color range // in color range
auto orig_attribs = set_foreground_color_(colors_[msg.level]); auto orig_attribs = static_cast<WORD>(set_foreground_color_(colors_[msg.level]));
print_range_(formatted, msg.color_range_start, msg.color_range_end); print_range_(formatted, msg.color_range_start, msg.color_range_end);
// reset to orig colors // reset to orig colors
::SetConsoleTextAttribute(out_handle_, orig_attribs); ::SetConsoleTextAttribute(static_cast<HANDLE>(out_handle_), orig_attribs);
print_range_(formatted, msg.color_range_end, formatted.size()); print_range_(formatted, msg.color_range_end, formatted.size());
} }
else // print without colors if color range is invalid (or color is disabled) else // print without colors if color range is invalid (or color is disabled)
{ {
print_range_(formatted, 0, formatted.size()); write_to_file_(formatted);
} }
} }
@@ -102,56 +101,63 @@ void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<sp
template<typename ConsoleMutex> template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color_mode(color_mode mode) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
{ {
switch (mode) std::lock_guard<mutex_t> lock(mutex_);
set_color_mode_impl(mode);
}
template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_color_mode_impl(color_mode mode)
{ {
case color_mode::always: if (mode == color_mode::automatic)
case color_mode::automatic: {
should_do_colors_ = true; // should do colors only if out_handle_ points to actual console.
break; DWORD console_mode;
case color_mode::never: bool in_console = ::GetConsoleMode(static_cast<HANDLE>(out_handle_), &console_mode) != 0;
should_do_colors_ = false; should_do_colors_ = in_console;
break; }
default: else
should_do_colors_ = true; {
should_do_colors_ = mode == color_mode::always ? true : false;
} }
} }
// set foreground color and return the orig console attributes (for resetting later) // set foreground color and return the orig console attributes (for resetting later)
template<typename ConsoleMutex> template<typename ConsoleMutex>
WORD SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_foreground_color_(WORD attribs) std::uint16_t SPDLOG_INLINE wincolor_sink<ConsoleMutex>::set_foreground_color_(std::uint16_t attribs)
{ {
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); if (!::GetConsoleScreenBufferInfo(static_cast<HANDLE>(out_handle_), &orig_buffer_info))
WORD back_color = orig_buffer_info.wAttributes; {
// retrieve the current background color // just return white if failed getting console info
back_color &= static_cast<WORD>(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)); return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
// keep the background color unchanged }
::SetConsoleTextAttribute(out_handle_, attribs | back_color);
return orig_buffer_info.wAttributes; // return orig attribs // change only the foreground bits (lowest 4 bits)
auto new_attribs = static_cast<WORD>(attribs) | (orig_buffer_info.wAttributes & 0xfff0);
auto ignored = ::SetConsoleTextAttribute(static_cast<HANDLE>(out_handle_), static_cast<WORD>(new_attribs));
(void)(ignored);
return static_cast<std::uint16_t>(orig_buffer_info.wAttributes); // return orig attribs
} }
// print a range of formatted message to console // print a range of formatted message to console
template<typename ConsoleMutex> template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end)
{
if (end > start)
{ {
auto size = static_cast<DWORD>(end - start); auto size = static_cast<DWORD>(end - start);
::WriteConsoleA(out_handle_, formatted.data() + start, size, nullptr, nullptr); auto ignored = ::WriteConsoleA(static_cast<HANDLE>(out_handle_), formatted.data() + start, size, nullptr, nullptr);
(void)(ignored);
}
} }
template<typename ConsoleMutex> template<typename ConsoleMutex>
void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::write_to_file_(const memory_buf_t &formatted) void SPDLOG_INLINE wincolor_sink<ConsoleMutex>::write_to_file_(const memory_buf_t &formatted)
{ {
if (out_handle_ == nullptr) // no console and no file redirect
{
return;
}
auto size = static_cast<DWORD>(formatted.size()); auto size = static_cast<DWORD>(formatted.size());
DWORD bytes_written = 0; DWORD bytes_written = 0;
bool ok = ::WriteFile(out_handle_, formatted.data(), size, &bytes_written, nullptr) != 0; auto ignored = ::WriteFile(static_cast<HANDLE>(out_handle_), formatted.data(), size, &bytes_written, nullptr);
if (!ok) (void)(ignored);
{
throw_spdlog_ex("wincolor_sink: ::WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError()));
}
} }
// wincolor_stdout_sink // wincolor_stdout_sink
@@ -165,6 +171,5 @@ template<typename ConsoleMutex>
SPDLOG_INLINE wincolor_stderr_sink<ConsoleMutex>::wincolor_stderr_sink(color_mode mode) SPDLOG_INLINE wincolor_stderr_sink<ConsoleMutex>::wincolor_stderr_sink(color_mode mode)
: wincolor_sink<ConsoleMutex>(::GetStdHandle(STD_ERROR_HANDLE), mode) : wincolor_sink<ConsoleMutex>(::GetStdHandle(STD_ERROR_HANDLE), mode)
{} {}
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@@ -12,9 +12,7 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <array> #include <array>
#include <cstdint>
#include <spdlog/details/windows_include.h>
#include <wincon.h>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@@ -26,21 +24,14 @@ template<typename ConsoleMutex>
class wincolor_sink : public sink class wincolor_sink : public sink
{ {
public: public:
const WORD BOLD = FOREGROUND_INTENSITY; wincolor_sink(void *out_handle, color_mode mode);
const WORD RED = FOREGROUND_RED;
const WORD GREEN = FOREGROUND_GREEN;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink(HANDLE out_handle, color_mode mode);
~wincolor_sink() override; ~wincolor_sink() override;
wincolor_sink(const wincolor_sink &other) = delete; wincolor_sink(const wincolor_sink &other) = delete;
wincolor_sink &operator=(const wincolor_sink &other) = delete; wincolor_sink &operator=(const wincolor_sink &other) = delete;
// change the color for the given level // change the color for the given level
void set_color(level::level_enum level, WORD color); void set_color(level::level_enum level, std::uint16_t color);
void log(const details::log_msg &msg) final override; void log(const details::log_msg &msg) final override;
void flush() final override; void flush() final override;
void set_pattern(const std::string &pattern) override final; void set_pattern(const std::string &pattern) override final;
@@ -49,21 +40,22 @@ public:
protected: protected:
using mutex_t = typename ConsoleMutex::mutex_t; using mutex_t = typename ConsoleMutex::mutex_t;
HANDLE out_handle_; void *out_handle_;
mutex_t &mutex_; mutex_t &mutex_;
bool in_console_;
bool should_do_colors_; bool should_do_colors_;
std::unique_ptr<spdlog::formatter> formatter_; std::unique_ptr<spdlog::formatter> formatter_;
std::array<WORD, level::n_levels> colors_; std::array<std::uint16_t, level::n_levels> colors_;
// set foreground color and return the orig console attributes (for resetting later) // set foreground color and return the orig console attributes (for resetting later)
WORD set_foreground_color_(WORD attribs); std::uint16_t set_foreground_color_(std::uint16_t attribs);
// print a range of formatted message to console // print a range of formatted message to console
void print_range_(const memory_buf_t &formatted, size_t start, size_t end); void print_range_(const memory_buf_t &formatted, size_t start, size_t end);
// in case we are redirected to file (not in console mode) // in case we are redirected to file (not in console mode)
void write_to_file_(const memory_buf_t &formatted); void write_to_file_(const memory_buf_t &formatted);
void set_color_mode_impl(color_mode mode);
}; };
template<typename ConsoleMutex> template<typename ConsoleMutex>
@@ -85,7 +77,6 @@ using wincolor_stdout_sink_st = wincolor_stdout_sink<details::console_nullmutex>
using wincolor_stderr_sink_mt = wincolor_stderr_sink<details::console_mutex>; using wincolor_stderr_sink_mt = wincolor_stderr_sink<details::console_mutex>;
using wincolor_stderr_sink_st = wincolor_stderr_sink<details::console_nullmutex>; using wincolor_stderr_sink_st = wincolor_stderr_sink<details::console_nullmutex>;
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@@ -58,6 +58,14 @@
// #define SPDLOG_EOL ";-)\n" // #define SPDLOG_EOL ";-)\n"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to override default folder separators ("/" or "\\/" under
// Linux/Windows). Each character in the string is treated as a different
// separator.
//
// #define SPDLOG_FOLDER_SEPS "\\"
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Uncomment to use your own copy of the fmt library instead of spdlog's copy. // Uncomment to use your own copy of the fmt library instead of spdlog's copy.
// In this case spdlog will try to include <fmt/format.h> so set your -I flag // In this case spdlog will try to include <fmt/format.h> so set your -I flag

View File

@@ -5,6 +5,6 @@
#define SPDLOG_VER_MAJOR 1 #define SPDLOG_VER_MAJOR 1
#define SPDLOG_VER_MINOR 8 #define SPDLOG_VER_MINOR 8
#define SPDLOG_VER_PATCH 2 #define SPDLOG_VER_PATCH 4
#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)

View File

@@ -3,6 +3,8 @@
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#include "test_sink.h" #include "test_sink.h"
#define TEST_FILENAME "test_logs/async_test.log"
TEST_CASE("basic async test ", "[async]") TEST_CASE("basic async test ", "[async]")
{ {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
@@ -149,7 +151,7 @@ TEST_CASE("to_file", "[async]")
prepare_logdir(); prepare_logdir();
size_t messages = 1024; size_t messages = 1024;
size_t tp_threads = 1; size_t tp_threads = 1;
std::string filename = "test_logs/async_test.log"; spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
{ {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads); auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
@@ -161,8 +163,8 @@ TEST_CASE("to_file", "[async]")
} }
} }
require_message_count(filename, messages); require_message_count(TEST_FILENAME, messages);
auto contents = file_contents(filename); auto contents = file_contents(TEST_FILENAME);
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(ends_with(contents, fmt::format("Hello message #1023{}", default_eol))); REQUIRE(ends_with(contents, fmt::format("Hello message #1023{}", default_eol)));
} }
@@ -172,7 +174,7 @@ TEST_CASE("to_file multi-workers", "[async]")
prepare_logdir(); prepare_logdir();
size_t messages = 1024 * 10; size_t messages = 1024 * 10;
size_t tp_threads = 10; size_t tp_threads = 10;
std::string filename = "test_logs/async_test.log"; spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
{ {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads); auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
@@ -184,5 +186,5 @@ TEST_CASE("to_file multi-workers", "[async]")
} }
} }
require_message_count(filename, messages); require_message_count(TEST_FILENAME, messages);
} }

View File

@@ -6,7 +6,7 @@
using spdlog::details::os::create_dir; using spdlog::details::os::create_dir;
using spdlog::details::os::path_exists; using spdlog::details::os::path_exists;
bool try_create_dir(const char *path, const char *normalized_path) bool try_create_dir(const spdlog::filename_t &path, const spdlog::filename_t &normalized_path)
{ {
auto rv = create_dir(path); auto rv = create_dir(path);
REQUIRE(rv == true); REQUIRE(rv == true);
@@ -17,24 +17,24 @@ TEST_CASE("create_dir", "[create_dir]")
{ {
prepare_logdir(); prepare_logdir();
REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1/dir1"), SPDLOG_FILENAME_T("test_logs/dir1/dir1")));
REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1")); // test existing REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1/dir1"), SPDLOG_FILENAME_T("test_logs/dir1/dir1"))); // test existing
REQUIRE(try_create_dir("test_logs/dir1///dir2//", "test_logs/dir1/dir2")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1///dir2//"), SPDLOG_FILENAME_T("test_logs/dir1/dir2")));
REQUIRE(try_create_dir("./test_logs/dir1/dir3", "test_logs/dir1/dir3")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("./test_logs/dir1/dir3"), SPDLOG_FILENAME_T("test_logs/dir1/dir3")));
REQUIRE(try_create_dir("test_logs/../test_logs/dir1/dir4", "test_logs/dir1/dir4")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/../test_logs/dir1/dir4"), SPDLOG_FILENAME_T("test_logs/dir1/dir4")));
#ifdef WIN32 #ifdef WIN32
// test backslash folder separator // test backslash folder separator
REQUIRE(try_create_dir("test_logs\\dir1\\dir222", "test_logs\\dir1\\dir222")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\dir1\\dir222"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir222")));
REQUIRE(try_create_dir("test_logs\\dir1\\dir223\\", "test_logs\\dir1\\dir223\\")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\dir1\\dir223\\"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir223\\")));
REQUIRE(try_create_dir(".\\test_logs\\dir1\\dir2\\dir99\\..\\dir23", "test_logs\\dir1\\dir2\\dir23")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T(".\\test_logs\\dir1\\dir2\\dir99\\..\\dir23"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir2\\dir23")));
REQUIRE(try_create_dir("test_logs\\..\\test_logs\\dir1\\dir5", "test_logs\\dir1\\dir5")); REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\..\\test_logs\\dir1\\dir5"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir5")));
#endif #endif
} }
TEST_CASE("create_invalid_dir", "[create_dir]") TEST_CASE("create_invalid_dir", "[create_dir]")
{ {
REQUIRE(create_dir("") == false); REQUIRE(create_dir(SPDLOG_FILENAME_T("")) == false);
REQUIRE(create_dir(spdlog::filename_t{}) == false); REQUIRE(create_dir(spdlog::filename_t{}) == false);
#ifdef __linux__ #ifdef __linux__
REQUIRE(create_dir("/proc/spdlog-utest") == false); REQUIRE(create_dir("/proc/spdlog-utest") == false);
@@ -44,37 +44,31 @@ TEST_CASE("create_invalid_dir", "[create_dir]")
TEST_CASE("dir_name", "[create_dir]") TEST_CASE("dir_name", "[create_dir]")
{ {
using spdlog::details::os::dir_name; using spdlog::details::os::dir_name;
REQUIRE(dir_name("").empty()); REQUIRE(dir_name(SPDLOG_FILENAME_T("")).empty());
REQUIRE(dir_name("dir").empty()); REQUIRE(dir_name(SPDLOG_FILENAME_T("dir")).empty());
#ifdef WIN32 #ifdef WIN32
REQUIRE(dir_name(R"(dir\)") == "dir"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\)")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(R"(dir\\\)") == R"(dir\\)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\\\)")) == SPDLOG_FILENAME_T(R"(dir\\)"));
REQUIRE(dir_name(R"(dir\file)") == "dir"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file)")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(R"(dir/file)") == "dir"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(R"(dir\file.txt)") == "dir"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt)")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(R"(dir/file)") == "dir"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(R"(dir\file.txt\)") == R"(dir\file.txt)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt\)")) == SPDLOG_FILENAME_T(R"(dir\file.txt)"));
REQUIRE(dir_name(R"(dir/file.txt/)") == R"(dir\file.txt)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\dir)"));
REQUIRE(dir_name(R"(\dir\file.txt)") == R"(\dir)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\\dir)"));
REQUIRE(dir_name(R"(/dir/file.txt)") == R"(\dir)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(..\file.txt)")) == SPDLOG_FILENAME_T(".."));
REQUIRE(dir_name(R"(\\dir\file.txt)") == R"(\\dir)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(.\file.txt)")) == SPDLOG_FILENAME_T("."));
REQUIRE(dir_name(R"(//dir/file.txt)") == R"(\\dir)"); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c:\\a\b\c\d\file.txt)")) == SPDLOG_FILENAME_T(R"(c:\\a\b\c\d)"));
REQUIRE(dir_name(R"(..\file.txt)") == ".."); REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c://a/b/c/d/file.txt)")) == SPDLOG_FILENAME_T(R"(c://a/b/c/d)"));
REQUIRE(dir_name(R"(../file.txt)") == "..");
REQUIRE(dir_name(R"(.\file.txt)") == ".");
REQUIRE(dir_name(R"(./file.txt)") == ".");
REQUIRE(dir_name(R"(c:\\a\b\c\d\file.txt)") == R"(c:\\a\b\c\d)");
REQUIRE(dir_name(R"(c://a/b/c/d/file.txt)") == R"(c:\\a\b\c\d)");
#else
REQUIRE(dir_name("dir/") == "dir");
REQUIRE(dir_name("dir///") == "dir//");
REQUIRE(dir_name("dir/file") == "dir");
REQUIRE(dir_name("dir/file.txt") == "dir");
REQUIRE(dir_name("dir/file.txt/") == "dir/file.txt");
REQUIRE(dir_name("/dir/file.txt") == "/dir");
REQUIRE(dir_name("//dir/file.txt") == "//dir");
REQUIRE(dir_name("../file.txt") == "..");
REQUIRE(dir_name("./file.txt") == ".");
#endif #endif
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir///")) == SPDLOG_FILENAME_T("dir//"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt")) == SPDLOG_FILENAME_T("dir"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt/")) == SPDLOG_FILENAME_T("dir/file.txt"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("/dir/file.txt")) == SPDLOG_FILENAME_T("/dir"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("//dir/file.txt")) == SPDLOG_FILENAME_T("//dir"));
REQUIRE(dir_name(SPDLOG_FILENAME_T("../file.txt")) == SPDLOG_FILENAME_T(".."));
REQUIRE(dir_name(SPDLOG_FILENAME_T("./file.txt")) == SPDLOG_FILENAME_T("."));
} }

View File

@@ -3,6 +3,8 @@
*/ */
#include "includes.h" #include "includes.h"
using filename_memory_buf_t = fmt::basic_memory_buffer<spdlog::filename_t::value_type, 250>;
TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
{ {
using sink_type = spdlog::sinks::daily_file_sink<std::mutex, spdlog::sinks::daily_filename_calculator>; using sink_type = spdlog::sinks::daily_file_sink<std::mutex, spdlog::sinks::daily_filename_calculator>;
@@ -10,10 +12,10 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
prepare_logdir(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
std::string basename = "test_logs/daily_dateonly"; spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
spdlog::memory_buf_t w; filename_memory_buf_t w;
fmt::format_to(w, "{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); fmt::format_to(w, SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0); auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
@@ -23,7 +25,13 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
} }
logger->flush(); logger->flush();
#ifdef SPDLOG_WCHAR_FILENAMES
spdlog::memory_buf_t buf;
spdlog::details::os::wstr_to_utf8buf(fmt::to_string(w), buf);
auto filename = fmt::to_string(buf);
#else
auto filename = fmt::to_string(w); auto filename = fmt::to_string(w);
#endif
require_message_count(filename, 10); require_message_count(filename, 10);
} }
@@ -31,8 +39,8 @@ struct custom_daily_file_name_calculator
{ {
static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm) static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm)
{ {
spdlog::memory_buf_t w; filename_memory_buf_t w;
fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday); fmt::format_to(w, SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday);
return fmt::to_string(w); return fmt::to_string(w);
} }
}; };
@@ -44,10 +52,10 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
prepare_logdir(); prepare_logdir();
// calculate filename (time based) // calculate filename (time based)
std::string basename = "test_logs/daily_dateonly"; spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
spdlog::memory_buf_t w; filename_memory_buf_t w;
fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); fmt::format_to(w, SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0); auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
@@ -57,7 +65,13 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
logger->flush(); logger->flush();
#ifdef SPDLOG_WCHAR_FILENAMES
spdlog::memory_buf_t buf;
spdlog::details::os::wstr_to_utf8buf(fmt::to_string(w), buf);
auto filename = fmt::to_string(buf);
#else
auto filename = fmt::to_string(w); auto filename = fmt::to_string(w);
#endif
require_message_count(filename, 10); require_message_count(filename, 10);
} }
@@ -67,20 +81,20 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
TEST_CASE("rotating_file_sink::calc_filename1", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename1", "[rotating_file_sink]]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename("rotated.txt", 3); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 3);
REQUIRE(filename == "rotated.3.txt"); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3.txt"));
} }
TEST_CASE("rotating_file_sink::calc_filename2", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename2", "[rotating_file_sink]]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename("rotated", 3); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated"), 3);
REQUIRE(filename == "rotated.3"); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3"));
} }
TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]") TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]")
{ {
auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename("rotated.txt", 0); auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 0);
REQUIRE(filename == "rotated.txt"); REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt"));
} }
// regex supported only from gcc 4.9 and above // regex supported only from gcc 4.9 and above
@@ -91,10 +105,10 @@ TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]]")
TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]]") TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]]")
{ {
// daily_YYYY-MM-DD_hh-mm.txt // daily_YYYY-MM-DD_hh-mm.txt
auto filename = spdlog::sinks::daily_filename_calculator::calc_filename("daily.txt", spdlog::details::os::localtime()); auto filename = spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt"), spdlog::details::os::localtime());
// date regex based on https://www.regular-expressions.info/dates.html // date regex based on https://www.regular-expressions.info/dates.html
std::regex re(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)"); std::basic_regex<spdlog::filename_t::value_type> re(SPDLOG_FILENAME_T(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)"));
std::smatch match; std::match_results<spdlog::filename_t::const_iterator> match;
REQUIRE(std::regex_match(filename, match, re)); REQUIRE(std::regex_match(filename, match, re));
} }
#endif #endif
@@ -116,7 +130,7 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_
prepare_logdir(); prepare_logdir();
std::string basename = "test_logs/daily_rotate.txt"; spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_rotate.txt");
daily_file_sink_st sink{basename, 2, 30, true, max_days}; daily_file_sink_st sink{basename, 2, 30, true, max_days};
// simulate messages with 24 intervals // simulate messages with 24 intervals

View File

@@ -5,6 +5,9 @@
#include <iostream> #include <iostream>
#define SIMPLE_LOG "test_logs/simple_log.txt"
#define SIMPLE_ASYNC_LOG "test_logs/simple_async_log.txt"
class failing_sink : public spdlog::sinks::base_sink<std::mutex> class failing_sink : public spdlog::sinks::base_sink<std::mutex>
{ {
protected: protected:
@@ -22,7 +25,7 @@ protected:
TEST_CASE("default_error_handler", "[errors]]") TEST_CASE("default_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "test_logs/simple_log.txt"; spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
logger->set_pattern("%v"); logger->set_pattern("%v");
@@ -31,8 +34,8 @@ TEST_CASE("default_error_handler", "[errors]]")
logger->flush(); logger->flush();
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(filename) == fmt::format("Test message 2{}", default_eol)); REQUIRE(file_contents(SIMPLE_LOG) == fmt::format("Test message 2{}", default_eol));
REQUIRE(count_lines(filename) == 1); REQUIRE(count_lines(SIMPLE_LOG) == 1);
} }
struct custom_ex struct custom_ex
@@ -40,7 +43,7 @@ struct custom_ex
TEST_CASE("custom_error_handler", "[errors]]") TEST_CASE("custom_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "test_logs/simple_log.txt"; spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info); logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
@@ -48,7 +51,7 @@ TEST_CASE("custom_error_handler", "[errors]]")
REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex); REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex);
logger->info("Good message #2"); logger->info("Good message #2");
require_message_count(filename, 2); require_message_count(SIMPLE_LOG, 2);
} }
TEST_CASE("default_error_handler2", "[errors]]") TEST_CASE("default_error_handler2", "[errors]]")
@@ -72,7 +75,7 @@ TEST_CASE("async_error_handler", "[errors]]")
prepare_logdir(); prepare_logdir();
std::string err_msg("log failed with some msg"); std::string err_msg("log failed with some msg");
std::string filename = "test_logs/simple_async_log.txt"; spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG);
{ {
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
@@ -90,7 +93,7 @@ TEST_CASE("async_error_handler", "[errors]]")
spdlog::drop("logger"); // force logger to drain the queue and shutdown spdlog::drop("logger"); // force logger to drain the queue and shutdown
} }
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
require_message_count(filename, 2); require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
} }
@@ -100,7 +103,7 @@ TEST_CASE("async_error_handler2", "[errors]]")
prepare_logdir(); prepare_logdir();
std::string err_msg("This is async handler error message"); std::string err_msg("This is async handler error message");
{ {
spdlog::details::os::create_dir("test_logs"); spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs"));
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger"); auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { logger->set_error_handler([=](const std::string &) {

View File

@@ -24,20 +24,20 @@ static void test_single_print(std::function<void(std::string const &)> do_log, s
REQUIRE(CloseEventLog(handle_)); REQUIRE(CloseEventLog(handle_));
} }
} }
} event_log{::OpenEventLog(nullptr, TEST_SOURCE)}; } event_log{::OpenEventLogA(nullptr, TEST_SOURCE)};
REQUIRE(event_log.handle_); REQUIRE(event_log.handle_);
DWORD read_bytes{}, size_needed{}; DWORD read_bytes{}, size_needed{};
auto ok = auto ok =
::ReadEventLog(event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, &read_bytes, 0, &read_bytes, &size_needed); ::ReadEventLogA(event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, &read_bytes, 0, &read_bytes, &size_needed);
REQUIRE(!ok); REQUIRE(!ok);
REQUIRE(::GetLastError() == ERROR_INSUFFICIENT_BUFFER); REQUIRE(::GetLastError() == ERROR_INSUFFICIENT_BUFFER);
std::vector<char> record_buffer(size_needed); std::vector<char> record_buffer(size_needed);
PEVENTLOGRECORD record = (PEVENTLOGRECORD)record_buffer.data(); PEVENTLOGRECORD record = (PEVENTLOGRECORD)record_buffer.data();
ok = ::ReadEventLog( ok = ::ReadEventLogA(
event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, record, size_needed, &read_bytes, &size_needed); event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, record, size_needed, &read_bytes, &size_needed);
REQUIRE(ok); REQUIRE(ok);

View File

@@ -3,6 +3,8 @@
*/ */
#include "includes.h" #include "includes.h"
#define TEST_FILENAME "test_logs/file_helper_test.txt"
using spdlog::details::file_helper; using spdlog::details::file_helper;
static void write_with_helper(file_helper &helper, size_t howmany) static void write_with_helper(file_helper &helper, size_t howmany)
@@ -18,7 +20,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
prepare_logdir(); prepare_logdir();
file_helper helper; file_helper helper;
std::string target_filename = "test_logs/file_helper_test.txt"; spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
helper.open(target_filename); helper.open(target_filename);
REQUIRE(helper.filename() == target_filename); REQUIRE(helper.filename() == target_filename);
} }
@@ -26,7 +28,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
TEST_CASE("file_helper_size", "[file_helper::size()]]") TEST_CASE("file_helper_size", "[file_helper::size()]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt"; spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
size_t expected_size = 123; size_t expected_size = 123;
{ {
file_helper helper; file_helper helper;
@@ -34,13 +36,13 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]")
write_with_helper(helper, expected_size); write_with_helper(helper, expected_size);
REQUIRE(static_cast<size_t>(helper.size()) == expected_size); REQUIRE(static_cast<size_t>(helper.size()) == expected_size);
} }
REQUIRE(get_filesize(target_filename) == expected_size); REQUIRE(get_filesize(TEST_FILENAME) == expected_size);
} }
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt"; spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
file_helper helper; file_helper helper;
helper.open(target_filename); helper.open(target_filename);
write_with_helper(helper, 12); write_with_helper(helper, 12);
@@ -52,7 +54,7 @@ TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]") TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
{ {
prepare_logdir(); prepare_logdir();
std::string target_filename = "test_logs/file_helper_test.txt"; spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
size_t expected_size = 14; size_t expected_size = 14;
file_helper helper; file_helper helper;
helper.open(target_filename); helper.open(target_filename);
@@ -62,16 +64,12 @@ TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
REQUIRE(helper.size() == expected_size); REQUIRE(helper.size() == expected_size);
} }
static void test_split_ext(const char *fname, const char *expect_base, const char *expect_ext) static void test_split_ext(const spdlog::filename_t::value_type *fname, const spdlog::filename_t::value_type *expect_base, const spdlog::filename_t::value_type *expect_ext)
{ {
spdlog::filename_t filename(fname); spdlog::filename_t filename(fname);
spdlog::filename_t expected_base(expect_base); spdlog::filename_t expected_base(expect_base);
spdlog::filename_t expected_ext(expect_ext); spdlog::filename_t expected_ext(expect_ext);
#ifdef _WIN32 // replace folder sep
std::replace(filename.begin(), filename.end(), '/', '\\');
std::replace(expected_base.begin(), expected_base.end(), '/', '\\');
#endif
spdlog::filename_t basename; spdlog::filename_t basename;
spdlog::filename_t ext; spdlog::filename_t ext;
std::tie(basename, ext) = file_helper::split_by_extension(filename); std::tie(basename, ext) = file_helper::split_by_extension(filename);
@@ -81,22 +79,22 @@ static void test_split_ext(const char *fname, const char *expect_base, const cha
TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]]") TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]]")
{ {
test_split_ext("mylog.txt", "mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("mylog.txt"), SPDLOG_FILENAME_T("mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext(".mylog.txt", ".mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T(".mylog.txt"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext(".mylog", ".mylog", ""); test_split_ext(SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(""));
test_split_ext("/aaa/bb.d/mylog", "/aaa/bb.d/mylog", ""); test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(""));
test_split_ext("/aaa/bb.d/mylog.txt", "/aaa/bb.d/mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("aaa/bbb/ccc/mylog.txt", "aaa/bbb/ccc/mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("aaa/bbb/ccc/mylog.", "aaa/bbb/ccc/mylog.", ""); test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T(""));
test_split_ext("aaa/bbb/ccc/.mylog.txt", "aaa/bbb/ccc/.mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("/aaa/bbb/ccc/mylog.txt", "/aaa/bbb/ccc/mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("/aaa/bbb/ccc/.mylog", "/aaa/bbb/ccc/.mylog", ""); test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T(""));
test_split_ext("../mylog.txt", "../mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("../mylog.txt"), SPDLOG_FILENAME_T("../mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext(".././mylog.txt", ".././mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt"), SPDLOG_FILENAME_T(".././mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext(".././mylog.txt/xxx", ".././mylog.txt/xxx", ""); test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(""));
test_split_ext("/mylog.txt", "/mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("/mylog.txt"), SPDLOG_FILENAME_T("/mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("//mylog.txt", "//mylog", ".txt"); test_split_ext(SPDLOG_FILENAME_T("//mylog.txt"), SPDLOG_FILENAME_T("//mylog"), SPDLOG_FILENAME_T(".txt"));
test_split_ext("", "", ""); test_split_ext(SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""));
test_split_ext(".", ".", ""); test_split_ext(SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(""));
test_split_ext("..txt", ".", ".txt"); test_split_ext(SPDLOG_FILENAME_T("..txt"), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(".txt"));
} }

View File

@@ -3,10 +3,13 @@
*/ */
#include "includes.h" #include "includes.h"
#define SIMPLE_LOG "test_logs/simple_log"
#define ROTATING_LOG "test_logs/rotating_log"
TEST_CASE("simple_file_logger", "[simple_logger]]") TEST_CASE("simple_file_logger", "[simple_logger]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "test_logs/simple_log"; spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
@@ -15,29 +18,29 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
require_message_count(filename, 2); require_message_count(SIMPLE_LOG, 2);
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(filename) == fmt::format("Test message 1{}Test message 2{}", default_eol, default_eol)); REQUIRE(file_contents(SIMPLE_LOG) == fmt::format("Test message 1{}Test message 2{}", default_eol, default_eol));
} }
TEST_CASE("flush_on", "[flush_on]]") TEST_CASE("flush_on", "[flush_on]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "test_logs/simple_log"; spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
logger->set_level(spdlog::level::trace); logger->set_level(spdlog::level::trace);
logger->flush_on(spdlog::level::info); logger->flush_on(spdlog::level::info);
logger->trace("Should not be flushed"); logger->trace("Should not be flushed");
REQUIRE(count_lines(filename) == 0); REQUIRE(count_lines(SIMPLE_LOG) == 0);
logger->info("Test message {}", 1); logger->info("Test message {}", 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
require_message_count(filename, 3); require_message_count(SIMPLE_LOG, 3);
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(filename) == REQUIRE(file_contents(SIMPLE_LOG) ==
fmt::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol)); fmt::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol));
} }
@@ -45,7 +48,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
std::string basename = "test_logs/rotating_log"; spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0); auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
@@ -54,14 +57,14 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
} }
logger->flush(); logger->flush();
require_message_count(basename, 10); require_message_count(ROTATING_LOG, 10);
} }
TEST_CASE("rotating_file_logger2", "[rotating_logger]]") TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
{ {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
std::string basename = "test_logs/rotating_log"; spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
{ {
// make an initial logger to create the first output file // make an initial logger to create the first output file
@@ -83,7 +86,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
logger->flush(); logger->flush();
require_message_count(basename, 10); require_message_count(ROTATING_LOG, 10);
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
@@ -92,7 +95,6 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
} }
logger->flush(); logger->flush();
REQUIRE(get_filesize(basename) <= max_size); REQUIRE(get_filesize(ROTATING_LOG) <= max_size);
auto filename1 = basename + ".1"; REQUIRE(get_filesize(ROTATING_LOG ".1") <= max_size);
REQUIRE(get_filesize(filename1) <= max_size);
} }

View File

@@ -8,11 +8,13 @@
#error "Invalid SPDLOG_ACTIVE_LEVEL in test. Should be SPDLOG_LEVEL_DEBUG" #error "Invalid SPDLOG_ACTIVE_LEVEL in test. Should be SPDLOG_LEVEL_DEBUG"
#endif #endif
#define TEST_FILENAME "test_logs/simple_log"
TEST_CASE("debug and trace w/o format string", "[macros]]") TEST_CASE("debug and trace w/o format string", "[macros]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "test_logs/simple_log"; spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
@@ -23,8 +25,8 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
logger->flush(); logger->flush();
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(ends_with(file_contents(filename), fmt::format("Test message 2{}", default_eol))); REQUIRE(ends_with(file_contents(TEST_FILENAME), fmt::format("Test message 2{}", default_eol)));
REQUIRE(count_lines(filename) == 1); REQUIRE(count_lines(TEST_FILENAME) == 1);
spdlog::set_default_logger(logger); spdlog::set_default_logger(logger);
@@ -32,8 +34,8 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
SPDLOG_DEBUG("Test message {}", 4); SPDLOG_DEBUG("Test message {}", 4);
logger->flush(); logger->flush();
require_message_count(filename, 2); require_message_count(TEST_FILENAME, 2);
REQUIRE(ends_with(file_contents(filename), fmt::format("Test message 4{}", default_eol))); REQUIRE(ends_with(file_contents(TEST_FILENAME), fmt::format("Test message 4{}", default_eol)));
} }
TEST_CASE("disable param evaluation", "[macros]") TEST_CASE("disable param evaluation", "[macros]")

View File

@@ -55,6 +55,14 @@ TEST_CASE("level_to_string_view", "[convert_to_string_view")
REQUIRE(spdlog::level::to_string_view(spdlog::level::off) == "off"); REQUIRE(spdlog::level::to_string_view(spdlog::level::off) == "off");
} }
TEST_CASE("set_level_to_string_view", "[set_string_view")
{
spdlog::level::set_string_view(spdlog::level::info, "INF");
REQUIRE(spdlog::level::to_string_view(spdlog::level::info) == "INF");
spdlog::level::set_string_view(spdlog::level::info, "info"); // set it back
REQUIRE(spdlog::level::to_string_view(spdlog::level::info) == "info");
}
TEST_CASE("to_short_c_str", "[convert_to_short_c_str]") TEST_CASE("to_short_c_str", "[convert_to_short_c_str]")
{ {
REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::trace)) == "T"); REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::trace)) == "T");

View File

@@ -372,7 +372,7 @@ TEST_CASE("clone-custom_formatter", "[pattern_formatter]")
// //
#ifdef _WIN32 #ifdef _WIN32
static const char *const test_path = "\\a\\b\\myfile.cpp"; static const char *const test_path = "\\a\\b\\c/myfile.cpp";
#else #else
static const char *const test_path = "/a/b//myfile.cpp"; static const char *const test_path = "/a/b//myfile.cpp";
#endif #endif

View File

@@ -103,7 +103,7 @@ TEST_CASE("disable automatic registration", "[registry]")
spdlog::set_level(log_level); spdlog::set_level(log_level);
// but disable automatic registration // but disable automatic registration
spdlog::set_automatic_registration(false); spdlog::set_automatic_registration(false);
auto logger1 = spdlog::create<spdlog::sinks::daily_file_sink_st>(tested_logger_name, "filename", 11, 59); auto logger1 = spdlog::create<spdlog::sinks::daily_file_sink_st>(tested_logger_name, SPDLOG_FILENAME_T("filename"), 11, 59);
auto logger2 = spdlog::create_async<spdlog::sinks::stdout_color_sink_mt>(tested_logger_name2); auto logger2 = spdlog::create_async<spdlog::sinks::stdout_color_sink_mt>(tested_logger_name2);
// loggers should not be part of the registry // loggers should not be part of the registry
REQUIRE_FALSE(spdlog::get(tested_logger_name)); REQUIRE_FALSE(spdlog::get(tested_logger_name));

View File

@@ -1,6 +1,8 @@
#include "includes.h" #include "includes.h"
#ifndef _WIN32 #ifdef _WIN32
#include <Windows.h>
#else
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#endif #endif
@@ -82,7 +84,7 @@ bool ends_with(std::string const &value, std::string const &ending)
std::size_t count_files(const std::string &folder) std::size_t count_files(const std::string &folder)
{ {
size_t counter = 0; size_t counter = 0;
WIN32_FIND_DATA ffd; WIN32_FIND_DATAA ffd;
// Start iterating over the files in the folder directory. // Start iterating over the files in the folder directory.
HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd); HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd);
@@ -92,7 +94,7 @@ std::size_t count_files(const std::string &folder)
{ {
if (ffd.cFileName[0] != '.') if (ffd.cFileName[0] != '.')
counter++; counter++;
} while (::FindNextFile(hFind, &ffd) != 0); } while (::FindNextFileA(hFind, &ffd) != 0);
::FindClose(hFind); ::FindClose(hFind);
} }
else else