The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .clang-format
├── .clang-tidy
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
    └── workflows
    │   ├── coverity_scan.yml
    │   ├── linux.yml
    │   ├── macos.yml
    │   └── windows.yml
├── .gitignore
├── CMakeLists.txt
├── INSTALL
├── LICENSE
├── README.md
├── appveyor.yml
├── bench
    ├── CMakeLists.txt
    ├── async_bench.cpp
    ├── bench.cpp
    ├── formatter-bench.cpp
    ├── latency.cpp
    └── utils.h
├── cmake
    ├── ide.cmake
    ├── pch.h.in
    ├── spdlog.pc.in
    ├── spdlogCPack.cmake
    ├── spdlogConfig.cmake.in
    ├── utils.cmake
    └── version.rc.in
├── example
    ├── CMakeLists.txt
    └── example.cpp
├── include
    └── spdlog
    │   ├── async.h
    │   ├── async_logger-inl.h
    │   ├── async_logger.h
    │   ├── cfg
    │       ├── argv.h
    │       ├── env.h
    │       ├── helpers-inl.h
    │       └── helpers.h
    │   ├── common-inl.h
    │   ├── common.h
    │   ├── details
    │       ├── backtracer-inl.h
    │       ├── backtracer.h
    │       ├── circular_q.h
    │       ├── console_globals.h
    │       ├── file_helper-inl.h
    │       ├── file_helper.h
    │       ├── fmt_helper.h
    │       ├── log_msg-inl.h
    │       ├── log_msg.h
    │       ├── log_msg_buffer-inl.h
    │       ├── log_msg_buffer.h
    │       ├── mpmc_blocking_q.h
    │       ├── null_mutex.h
    │       ├── os-inl.h
    │       ├── os.h
    │       ├── periodic_worker-inl.h
    │       ├── periodic_worker.h
    │       ├── registry-inl.h
    │       ├── registry.h
    │       ├── synchronous_factory.h
    │       ├── tcp_client-windows.h
    │       ├── tcp_client.h
    │       ├── thread_pool-inl.h
    │       ├── thread_pool.h
    │       ├── udp_client-windows.h
    │       ├── udp_client.h
    │       └── windows_include.h
    │   ├── fmt
    │       ├── bin_to_hex.h
    │       ├── bundled
    │       │   ├── args.h
    │       │   ├── base.h
    │       │   ├── chrono.h
    │       │   ├── color.h
    │       │   ├── compile.h
    │       │   ├── core.h
    │       │   ├── fmt.license.rst
    │       │   ├── format-inl.h
    │       │   ├── format.h
    │       │   ├── os.h
    │       │   ├── ostream.h
    │       │   ├── printf.h
    │       │   ├── ranges.h
    │       │   ├── std.h
    │       │   └── xchar.h
    │       ├── chrono.h
    │       ├── compile.h
    │       ├── fmt.h
    │       ├── ostr.h
    │       ├── ranges.h
    │       ├── std.h
    │       └── xchar.h
    │   ├── formatter.h
    │   ├── fwd.h
    │   ├── logger-inl.h
    │   ├── logger.h
    │   ├── mdc.h
    │   ├── pattern_formatter-inl.h
    │   ├── pattern_formatter.h
    │   ├── sinks
    │       ├── android_sink.h
    │       ├── ansicolor_sink-inl.h
    │       ├── ansicolor_sink.h
    │       ├── base_sink-inl.h
    │       ├── base_sink.h
    │       ├── basic_file_sink-inl.h
    │       ├── basic_file_sink.h
    │       ├── callback_sink.h
    │       ├── daily_file_sink.h
    │       ├── dist_sink.h
    │       ├── dup_filter_sink.h
    │       ├── hourly_file_sink.h
    │       ├── kafka_sink.h
    │       ├── mongo_sink.h
    │       ├── msvc_sink.h
    │       ├── null_sink.h
    │       ├── ostream_sink.h
    │       ├── qt_sinks.h
    │       ├── ringbuffer_sink.h
    │       ├── rotating_file_sink-inl.h
    │       ├── rotating_file_sink.h
    │       ├── sink-inl.h
    │       ├── sink.h
    │       ├── stdout_color_sinks-inl.h
    │       ├── stdout_color_sinks.h
    │       ├── stdout_sinks-inl.h
    │       ├── stdout_sinks.h
    │       ├── syslog_sink.h
    │       ├── systemd_sink.h
    │       ├── tcp_sink.h
    │       ├── udp_sink.h
    │       ├── win_eventlog_sink.h
    │       ├── wincolor_sink-inl.h
    │       └── wincolor_sink.h
    │   ├── spdlog-inl.h
    │   ├── spdlog.h
    │   ├── stopwatch.h
    │   ├── tweakme.h
    │   └── version.h
├── logos
    ├── jetbrains-variant-4.svg
    └── spdlog.png
├── scripts
    ├── ci_setup_clang.sh
    ├── extract_version.py
    └── format.sh
├── src
    ├── async.cpp
    ├── bundled_fmtlib_format.cpp
    ├── cfg.cpp
    ├── color_sinks.cpp
    ├── file_sinks.cpp
    ├── spdlog.cpp
    └── stdout_sinks.cpp
└── tests
    ├── CMakeLists.txt
    ├── includes.h
    ├── main.cpp
    ├── test_async.cpp
    ├── test_backtrace.cpp
    ├── test_bin_to_hex.cpp
    ├── test_cfg.cpp
    ├── test_circular_q.cpp
    ├── test_create_dir.cpp
    ├── test_custom_callbacks.cpp
    ├── test_daily_logger.cpp
    ├── test_dup_filter.cpp
    ├── test_errors.cpp
    ├── test_eventlog.cpp
    ├── test_file_helper.cpp
    ├── test_file_logging.cpp
    ├── test_fmt_helper.cpp
    ├── test_macros.cpp
    ├── test_misc.cpp
    ├── test_mpmc_q.cpp
    ├── test_pattern_formatter.cpp
    ├── test_registry.cpp
    ├── test_ringbuffer.cpp
    ├── test_sink.h
    ├── test_stdout_api.cpp
    ├── test_stopwatch.cpp
    ├── test_systemd.cpp
    ├── test_time_point.cpp
    ├── utils.cpp
    └── utils.h


/.clang-format:
--------------------------------------------------------------------------------
 1 | ---
 2 | Language:        Cpp
 3 | BasedOnStyle:  Google
 4 | AccessModifierOffset: -4
 5 | Standard:        c++17
 6 | IndentWidth:     4
 7 | TabWidth:        4
 8 | UseTab:          Never
 9 | ColumnLimit:     100
10 | AlignAfterOpenBracket: Align
11 | BinPackParameters: false
12 | AlignEscapedNewlines: Left
13 | AlwaysBreakTemplateDeclarations: Yes
14 | PackConstructorInitializers: Never
15 | BreakConstructorInitializersBeforeComma: false
16 | IndentPPDirectives: BeforeHash
17 | SortIncludes:    Never
18 | ...
19 | 
20 | 


--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
 1 | Checks: 'cppcoreguidelines-*,
 2 | performance-*,
 3 | modernize-*,
 4 | google-*,
 5 | misc-*
 6 | cert-*,
 7 | readability-*,
 8 | clang-analyzer-*,
 9 | -performance-unnecessary-value-param,
10 | -modernize-use-trailing-return-type,
11 | -google-runtime-references,
12 | -misc-non-private-member-variables-in-classes,
13 | -readability-braces-around-statements,
14 | -google-readability-braces-around-statements,
15 | -cppcoreguidelines-avoid-magic-numbers,
16 | -readability-magic-numbers,
17 | -readability-magic-numbers,
18 | -cppcoreguidelines-pro-type-vararg,
19 | -cppcoreguidelines-pro-bounds-pointer-arithmetic,
20 | -cppcoreguidelines-avoid-c-arrays,
21 | -modernize-avoid-c-arrays,
22 | -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
23 | -readability-named-parameter,
24 | -cert-env33-c
25 | '
26 | 
27 | 
28 | WarningsAsErrors: ''
29 | HeaderFilterRegex: '*spdlog/[^f].*'
30 | FormatStyle:     none
31 | 
32 | CheckOptions:    
33 |   - key:             google-readability-braces-around-statements.ShortStatementLines
34 |     value:           '1'
35 |   - key:             google-readability-function-size.StatementThreshold
36 |     value:           '800'
37 |   - key:             google-readability-namespace-comments.ShortNamespaceLines
38 |     value:           '10'
39 |   - key:             google-readability-namespace-comments.SpacesBeforeComments
40 |     value:           '2'
41 |   - key:             modernize-loop-convert.MaxCopySize
42 |     value:           '16'
43 |   - key:             modernize-loop-convert.MinConfidence
44 |     value:           reasonable
45 |   - key:             modernize-loop-convert.NamingStyle
46 |     value:           CamelCase
47 |   - key:             modernize-pass-by-value.IncludeStyle
48 |     value:           llvm
49 |   - key:             modernize-replace-auto-ptr.IncludeStyle
50 |     value:           llvm
51 |   - key:             modernize-use-nullptr.NullMacros
52 |     value:           'NULL'
53 | 
54 | 


--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # clang-format
2 | 1a0bfc7a89f2d58e22605a4dc7e18a9a555b65aa
3 | 95c226e9c92928e20ccdac0d060e7241859e282b
4 | 9d52261185b5f2c454c381d626ec5c84d7b195f4
5 | 4b2a8219d5d1b40062d030441adde7d1fb0d4f84
6 | 0a53eafe18d983c7c8ba4cadd02d0cc7f7308f28
7 | 


--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=false
2 | 


--------------------------------------------------------------------------------
/.github/workflows/coverity_scan.yml:
--------------------------------------------------------------------------------
 1 | name: coverity-linux
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | permissions:
 6 |   contents: read
 7 | 
 8 | jobs:
 9 |   coverity_scan:
10 |     runs-on: ubuntu-latest
11 |     name: Coverity Scan
12 |     steps:
13 |       - uses: actions/checkout@v4
14 | 
15 |       - name: Install dependencies
16 |         run: |
17 |           sudo apt-get update
18 |           sudo apt-get install -y curl build-essential cmake pkg-config libsystemd-dev
19 | 
20 |       - name: Download Coverity Tool
21 |         run: |
22 |           curl -s -L --output coverity_tool.tgz "https://scan.coverity.com/download/linux64?token=${{ secrets.COVERITY_TOKEN }}&project=gabime%2Fspdlog"
23 |           mkdir coverity_tool
24 |           tar -C coverity_tool --strip-components=1 -xf coverity_tool.tgz
25 |           echo "$PWD/coverity_tool/bin" >> $GITHUB_PATH
26 | 
27 |       - name: Build with Coverity
28 |         run: |
29 |           mkdir build && cd build
30 |           cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=17
31 |           cd ..
32 |           cov-build --dir cov-int make -C build -j4
33 | 
34 |       - name: Submit results to Coverity
35 |         run: |
36 |           tar czf cov-int.tgz cov-int
37 |           response=$(curl --silent --show-error --fail \
38 |             --form email="${{ secrets.EMAIL }}" \
39 |             --form token="${{ secrets.COVERITY_TOKEN }}" \
40 |             --form file=@cov-int.tgz \
41 |             --form version="GitHub PR #${{ github.event.pull_request.number }}" \
42 |             --form description="CI run for PR" \
43 |             https://scan.coverity.com/builds?project=gabime%2Fspdlog)
44 | 
45 |           echo "$response"
46 | 
47 |           if echo "$response" | grep -qi "Build successfully submitted"; then
48 |             echo "Coverity upload succeeded"
49 |           else
50 |             echo "Coverity upload failed or was rejected"
51 |             exit 1
52 |           fi
53 | 


--------------------------------------------------------------------------------
/.github/workflows/linux.yml:
--------------------------------------------------------------------------------
 1 | name: linux
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | permissions:
 6 |   contents: read
 7 | 
 8 | jobs:
 9 |   # -----------------------------------------------------------------------
10 |   # Linux build matrix
11 |   # -----------------------------------------------------------------------
12 |   build:
13 |     runs-on: ubuntu-latest
14 |     defaults:
15 |       run:
16 |         shell: bash
17 |     strategy:
18 |       fail-fast: false
19 |       matrix:
20 |         config:
21 |           - { compiler: gcc, version: 9, build_type: Release, cppstd: 11 }
22 |           - { compiler: gcc, version: 11, build_type: Debug, cppstd: 17 }
23 |           - { compiler: gcc, version: 12, build_type: Release, cppstd: 20 }
24 |           - { compiler: gcc, version: 12, build_type: Debug, cppstd: 20, asan: ON }
25 |           - { compiler: clang, version: 12, build_type: Debug, cppstd: 17 }
26 |           - { compiler: clang, version: 15, build_type: Release, cppstd: 20, tsan: ON }
27 |     container:
28 |       image: ${{ matrix.config.compiler == 'clang' && 'teeks99/clang-ubuntu' || matrix.config.compiler }}:${{ matrix.config.version }}
29 |     name: "${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }} ${{ matrix.config.build_type }} ${{ matrix.config.asan == 'ON' && 'ASAN' || '' }}${{ matrix.config.tsan == 'ON' && 'TSAN' || '' }})"
30 |     steps:
31 |       - uses: actions/checkout@v4
32 |       - name: Setup
33 |         run: |
34 |           apt-get update
35 |           apt-get install -y curl git pkg-config libsystemd-dev
36 |           CMAKE_VERSION="3.24.2"
37 |           curl -sSL https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.sh -o install-cmake.sh
38 |           chmod +x install-cmake.sh
39 |           ./install-cmake.sh --prefix=/usr/local --skip-license
40 |       - name: Setup Compiler
41 |         if: matrix.config.compiler == 'clang'
42 |         run: |
43 |           scripts/ci_setup_clang.sh "${{ matrix.config.version }}"
44 |           echo "CXXFLAGS=-stdlib=libc++" >> $GITHUB_ENV          
45 |           echo "CC=clang-${{ matrix.config.version }}" >> $GITHUB_ENV
46 |           echo "CXX=clang++-${{ matrix.config.version }}" >> $GITHUB_ENV
47 |       - name: Build
48 |         run: |
49 |           mkdir -p build && cd build
50 |           cmake .. \
51 |             -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
52 |             -DCMAKE_CXX_STANDARD=${{ matrix.config.cppstd }} \
53 |             -DSPDLOG_BUILD_EXAMPLE=${{ matrix.config.examples || 'ON' }} \
54 |             -DSPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.examples || 'ON' }} \
55 |             -DSPDLOG_BUILD_WARNINGS=ON \
56 |             -DSPDLOG_BUILD_BENCH=OFF \
57 |             -DSPDLOG_BUILD_TESTS=ON \
58 |             -DSPDLOG_BUILD_TESTS_HO=OFF \
59 |             -DSPDLOG_SANITIZE_ADDRESS=${{ matrix.config.asan || 'OFF' }} \
60 |             -DSPDLOG_SANITIZE_THREAD=${{ matrix.config.tsan || 'OFF' }}
61 |           make -j 4
62 |           ctest -j 4 --output-on-failure
63 | 
64 |   # -----------------------------------------------------------------------
65 |   # OS X build matrix
66 |   # -----------------------------------------------------------------------
67 |   build_osx:
68 |     runs-on: macOS-latest
69 |     name: "OS X Clang (C++11, Release)"
70 |     steps:
71 |       - uses: actions/checkout@v4
72 |       - name: Build
73 |         run: |
74 |           mkdir -p build && cd build
75 |           cmake .. \
76 |             -DCMAKE_BUILD_TYPE=Release \
77 |             -DCMAKE_CXX_STANDARD=11 \
78 |             -DSPDLOG_BUILD_EXAMPLE=ON \
79 |             -DSPDLOG_BUILD_EXAMPLE_HO=ON \
80 |             -DSPDLOG_BUILD_WARNINGS=ON \
81 |             -DSPDLOG_BUILD_BENCH=OFF \
82 |             -DSPDLOG_BUILD_TESTS=ON \
83 |             -DSPDLOG_BUILD_TESTS_HO=OFF \
84 |             -DSPDLOG_SANITIZE_ADDRESS=OFF
85 |           make -j 4
86 |           ctest -j 4 --output-on-failure
87 | 


--------------------------------------------------------------------------------
/.github/workflows/macos.yml:
--------------------------------------------------------------------------------
 1 | name: macos
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | permissions:
 6 |   contents: read
 7 | 
 8 | jobs:
 9 |   build:
10 |     runs-on: macOS-latest
11 |     name: "macOS Clang (C++11, Release)"
12 |     strategy:
13 |       fail-fast: true
14 |       matrix:
15 |         config:
16 |             - USE_STD_FORMAT: 'ON'
17 |               BUILD_EXAMPLE: 'OFF'
18 |             - USE_STD_FORMAT: 'OFF'
19 |               BUILD_EXAMPLE: 'ON'
20 |               
21 |     steps:
22 |       - uses: actions/checkout@v4
23 |       - name: Build
24 |         run: |
25 |           mkdir -p build && cd build
26 |           cmake .. \
27 |             -DCMAKE_BUILD_TYPE=Release \
28 |             -DCMAKE_CXX_STANDARD=11 \
29 |             -DSPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} \
30 |             -DSPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} \
31 |             -DSPDLOG_BUILD_WARNINGS=ON \
32 |             -DSPDLOG_BUILD_BENCH=OFF \
33 |             -DSPDLOG_BUILD_TESTS=ON \
34 |             -DSPDLOG_BUILD_TESTS_HO=OFF \
35 |             -DSPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} \
36 |             -DSPDLOG_SANITIZE_ADDRESS=OFF
37 |           make -j 4
38 |           ctest -j 4 --output-on-failure
39 | 


--------------------------------------------------------------------------------
/.github/workflows/windows.yml:
--------------------------------------------------------------------------------
 1 | name: windows
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | permissions:
 6 |   contents: read
 7 | 
 8 | jobs:
 9 |   build:
10 |     runs-on: windows-latest
11 |     strategy:
12 |       fail-fast: true
13 |       matrix:
14 |         config:
15 |           - GENERATOR: "Visual Studio 17 2022"
16 |             BUILD_TYPE: Release
17 |             BUILD_SHARED: 'ON'
18 |             FATAL_ERRORS: 'ON'
19 |             WCHAR: 'OFF'
20 |             WCHAR_FILES: 'OFF'
21 |             BUILD_EXAMPLE: 'OFF'
22 |             USE_STD_FORMAT: 'ON'
23 |             CXX_STANDARD: 20
24 |           - GENERATOR: "Visual Studio 17 2022"
25 |             BUILD_TYPE: Release
26 |             BUILD_SHARED: 'ON'
27 |             FATAL_ERRORS: 'ON'
28 |             WCHAR: 'ON'
29 |             WCHAR_FILES: 'ON'
30 |             BUILD_EXAMPLE: 'OFF'
31 |             USE_STD_FORMAT: 'ON'
32 |             CXX_STANDARD: 20
33 |           - GENERATOR: "Visual Studio 17 2022"
34 |             BUILD_TYPE: Release
35 |             BUILD_SHARED: 'ON'
36 |             FATAL_ERRORS: 'ON'
37 |             WCHAR: 'OFF'
38 |             WCHAR_FILES: 'OFF'
39 |             BUILD_EXAMPLE: 'ON'
40 |             USE_STD_FORMAT: 'OFF'
41 |             CXX_STANDARD: 17
42 | 
43 |     steps:
44 |       - name: Checkout code
45 |         uses: actions/checkout@v4
46 | 
47 |       - name: CMake ${{ matrix.config.GENERATOR }} CXX=${{matrix.config.CXX_STANDARD}} WCHAR=${{matrix.config.WCHAR_FILES}} STD_FORMAT=${{matrix.config.USE_STD_FORMAT}}
48 |         shell: pwsh
49 |         run: |
50 |           mkdir build
51 |           cd build
52 |           cmake -G "${{ matrix.config.GENERATOR }}"  -A x64 `
53 |             -D CMAKE_BUILD_TYPE=${{ matrix.config.BUILD_TYPE }} `
54 |             -D BUILD_SHARED_LIBS=${{ matrix.config.BUILD_SHARED }} `
55 |             -D SPDLOG_WCHAR_SUPPORT=${{ matrix.config.WCHAR }} `
56 |             -D SPDLOG_WCHAR_FILENAMES=${{ matrix.config.WCHAR_FILES }} `
57 |             -D SPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} `
58 |             -D SPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} `
59 |             -D SPDLOG_BUILD_TESTS=ON `
60 |             -D SPDLOG_BUILD_TESTS_HO=OFF `
61 |             -D SPDLOG_BUILD_WARNINGS=${{ matrix.config.FATAL_ERRORS }} `
62 |             -D SPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} `
63 |             -D CMAKE_CXX_STANDARD=${{ matrix.config.CXX_STANDARD }} ..
64 | 
65 |       - name: Build
66 |         shell: pwsh
67 |         run: |
68 |           cd build
69 |           cmake --build  . --parallel --config ${{ matrix.config.BUILD_TYPE }}
70 | 
71 |       - name: Run Tests
72 |         shell: pwsh
73 |         env:
74 |           PATH: ${{ env.PATH }};${{ github.workspace }}\build\_deps\catch2-build\src\${{ matrix.config.BUILD_TYPE }};${{ github.workspace }}\build\${{ matrix.config.BUILD_TYPE }}
75 |         run: |
76 |           build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe
77 | 
78 | 
79 |   
80 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | # Auto generated files
 2 | [Dd]ebug/
 3 | [Rr]elease/
 4 | build/*
 5 | *.slo
 6 | *.lo
 7 | *.o
 8 | *.obj
 9 | *.suo
10 | *.tlog
11 | *.ilk
12 | *.log
13 | *.pdb
14 | *.idb
15 | *.iobj
16 | *.ipdb
17 | *.opensdf
18 | *.sdf
19 | 
20 | # Compiled Dynamic libraries
21 | *.so
22 | *.dylib
23 | *.dll
24 | 
25 | # Compiled Static libraries
26 | *.lai
27 | *.la
28 | *.a
29 | *.lib
30 | 
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | 
36 | # Codelite
37 | .codelite
38 | 
39 | # KDevelop
40 | *.kdev4
41 | 
42 | # .orig files
43 | *.orig
44 | 
45 | # example  files
46 | example/*
47 | !example/example.cpp
48 | !example/bench.cpp
49 | !example/utils.h
50 | !example/Makefile*
51 | !example/example.sln
52 | !example/example.vcxproj
53 | !example/CMakeLists.txt
54 | !example/meson.build
55 | !example/multisink.cpp
56 | !example/jni
57 | 
58 | # generated files
59 | generated
60 | version.rc
61 | 
62 | # Cmake
63 | CMakeCache.txt
64 | CMakeFiles
65 | CMakeScripts
66 | Makefile
67 | cmake_install.cmake
68 | install_manifest.txt
69 | /tests/tests.VC.VC.opendb
70 | /tests/tests.VC.db
71 | /tests/tests
72 | /tests/logs/*
73 | spdlogConfig.cmake
74 | spdlogConfigVersion.cmake
75 | compile_commands.json
76 | 
77 | # idea
78 | .idea/
79 | .cache/
80 | .vscode/
81 | cmake-build-*/
82 | *.db
83 | *.ipch
84 | *.filters
85 | *.db-wal
86 | *.opendb
87 | *.db-shm
88 | *.vcxproj
89 | *.tcl
90 | *.user
91 | *.sln
92 | 
93 | # macos
94 | *.DS_store
95 | *.xcodeproj/
96 | /.vs
97 | /out/build
98 | /CMakeSettings.json
99 | 


--------------------------------------------------------------------------------
/INSTALL:
--------------------------------------------------------------------------------
 1 | Header Only Version
 2 | ==================================================================
 3 | Just copy the files to your build tree and use a C++11 compiler.  
 4 | Or use CMake:
 5 | ``` 
 6 |   add_executable(example_header_only example.cpp)
 7 |   target_link_libraries(example_header_only spdlog::spdlog_header_only)
 8 | ```
 9 | 
10 | Compiled Library Version
11 | ==================================================================
12 | CMake:
13 | ```  
14 |   add_executable(example example.cpp)
15 |   target_link_libraries(example spdlog::spdlog)
16 | ```
17 | 
18 | Or copy files src/*.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler.
19 | 
20 | Important Information for Compilation:
21 | ==================================================================
22 | * If you encounter compilation errors with gcc 4.8.x, please note that gcc 4.8.x does not fully support C++11. In such cases, consider upgrading your compiler or using a different version that fully supports C++11 standards
23 | 
24 | Tested on:  
25 | gcc 4.8.1 and above
26 | clang 3.5
27 | Visual Studio 2013


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2016 Gabi Melman.                                       
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 | 
23 | -- NOTE: Third party dependency used by this software --
24 | This software depends on the fmt lib (MIT License),
25 | and users must comply to its license: https://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE
26 | 
27 | 


--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
 1 | version: 1.0.{build}
 2 | image: Visual Studio 2017
 3 | environment:
 4 |   matrix:
 5 |     - GENERATOR: '"Visual Studio 15 2017 Win64"'
 6 |       BUILD_TYPE: Debug
 7 |       BUILD_SHARED: 'OFF'
 8 |       FATAL_ERRORS: 'OFF'
 9 |       WCHAR: 'ON'
10 |       WCHAR_FILES: 'OFF'
11 |       BUILD_EXAMPLE: 'ON'
12 |       USE_STD_FORMAT: 'OFF'
13 |       CXX_STANDARD: 11
14 |     - GENERATOR: '"Visual Studio 15 2017 Win64"'
15 |       BUILD_TYPE: Release
16 |       BUILD_SHARED: 'OFF'
17 |       FATAL_ERRORS: 'OFF'
18 |       WCHAR: 'OFF'
19 |       WCHAR_FILES: 'OFF'
20 |       BUILD_EXAMPLE: 'ON'
21 |       USE_STD_FORMAT: 'OFF'
22 |       CXX_STANDARD: 11
23 |     - GENERATOR: '"Visual Studio 15 2017 Win64"'
24 |       BUILD_TYPE: Release
25 |       BUILD_SHARED: 'ON'
26 |       FATAL_ERRORS: 'OFF'
27 |       WCHAR: 'OFF'
28 |       WCHAR_FILES: 'OFF'
29 |       BUILD_EXAMPLE: 'ON'
30 |       USE_STD_FORMAT: 'OFF'
31 |       CXX_STANDARD: 11
32 |     - GENERATOR: '"Visual Studio 15 2017 Win64"'
33 |       BUILD_TYPE: Release
34 |       BUILD_SHARED: 'ON'
35 |       FATAL_ERRORS: 'OFF'
36 |       WCHAR: 'ON'
37 |       WCHAR_FILES: 'ON'
38 |       BUILD_EXAMPLE: 'OFF'
39 |       USE_STD_FORMAT: 'OFF'
40 |       CXX_STANDARD: 11
41 |     - GENERATOR: '"Visual Studio 16 2019" -A x64'
42 |       BUILD_TYPE: Release
43 |       BUILD_SHARED: 'ON'
44 |       FATAL_ERRORS: 'ON'
45 |       WCHAR: 'OFF'
46 |       WCHAR_FILES: 'OFF'
47 |       BUILD_EXAMPLE: 'OFF'
48 |       USE_STD_FORMAT: 'OFF'
49 |       CXX_STANDARD: 17
50 |       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
51 |     - GENERATOR: '"Visual Studio 17 2022" -A x64'
52 |       BUILD_TYPE: Release
53 |       BUILD_SHARED: 'ON'
54 |       FATAL_ERRORS: 'ON'
55 |       WCHAR: 'OFF'
56 |       WCHAR_FILES: 'OFF'
57 |       BUILD_EXAMPLE: 'OFF'
58 |       USE_STD_FORMAT: 'ON'
59 |       CXX_STANDARD: 20
60 |       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
61 |     - GENERATOR: '"Visual Studio 17 2022" -A x64'
62 |       BUILD_TYPE: Release
63 |       BUILD_SHARED: 'ON'
64 |       FATAL_ERRORS: 'ON'
65 |       WCHAR: 'ON'
66 |       WCHAR_FILES: 'ON'
67 |       BUILD_EXAMPLE: 'OFF'
68 |       USE_STD_FORMAT: 'ON'
69 |       CXX_STANDARD: 20
70 |       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
71 | build_script:
72 |   - cmd: >-
73 |       set
74 | 
75 |       mkdir build
76 | 
77 |       cd build
78 | 
79 |       set PATH=%PATH%;C:\Program Files\Git\usr\bin
80 | 
81 |       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=%FATAL_ERRORS% -D SPDLOG_USE_STD_FORMAT=%USE_STD_FORMAT% -D CMAKE_CXX_STANDARD=%CXX_STANDARD% ..
82 | 
83 |       cmake --build . --config %BUILD_TYPE%
84 | 
85 | before_test:
86 |   - set PATH=%PATH%;C:\projects\spdlog\build\_deps\catch2-build\src\%BUILD_TYPE%;C:\projects\spdlog\build\%BUILD_TYPE%
87 |   
88 | test_script:
89 |   - C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe
90 | 


--------------------------------------------------------------------------------
/bench/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | # Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)
 2 | 
 3 | cmake_minimum_required(VERSION 3.11)
 4 | project(spdlog_bench CXX)
 5 | 
 6 | if(NOT TARGET spdlog)
 7 |     # Stand-alone build
 8 |     find_package(spdlog CONFIG REQUIRED)
 9 | endif()
10 | 
11 | find_package(Threads REQUIRED)
12 | find_package(benchmark CONFIG)
13 | if(NOT benchmark_FOUND)
14 |     message(STATUS "Using CMake Version ${CMAKE_VERSION}")
15 |     # User can fetch googlebenchmark
16 |     message(STATUS "Downloading GoogleBenchmark")
17 |     include(FetchContent)
18 | 
19 |     # disable tests
20 |     set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "")
21 |     # Do not build and run googlebenchmark tests
22 |     FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0)
23 |     FetchContent_MakeAvailable(googlebenchmark)
24 | endif()
25 | 
26 | add_executable(bench bench.cpp)
27 | spdlog_enable_warnings(bench)
28 | target_link_libraries(bench PRIVATE spdlog::spdlog)
29 | 
30 | add_executable(async_bench async_bench.cpp)
31 | target_link_libraries(async_bench PRIVATE spdlog::spdlog)
32 | 
33 | add_executable(latency latency.cpp)
34 | target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog)
35 | 
36 | add_executable(formatter-bench formatter-bench.cpp)
37 | target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)
38 | 


--------------------------------------------------------------------------------
/bench/formatter-bench.cpp:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2018 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #include "benchmark/benchmark.h"
 7 | 
 8 | #include "spdlog/spdlog.h"
 9 | #include "spdlog/pattern_formatter.h"
10 | 
11 | void bench_formatter(benchmark::State &state, std::string pattern) {
12 |     auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern);
13 |     spdlog::memory_buf_t dest;
14 |     std::string logger_name = "logger-name";
15 |     const char *text =
16 |         "Hello. This is some message with length of 80                                   ";
17 | 
18 |     spdlog::source_loc source_loc{"a/b/c/d/myfile.cpp", 123, "some_func()"};
19 |     spdlog::details::log_msg msg(source_loc, logger_name, spdlog::level::info, text);
20 | 
21 |     for (auto _ : state) {
22 |         dest.clear();
23 |         formatter->format(msg, dest);
24 |         benchmark::DoNotOptimize(dest);
25 |     }
26 | }
27 | 
28 | void bench_formatters() {
29 |     // basic patterns(single flag)
30 |     std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%";
31 |     std::vector<std::string> basic_patterns;
32 |     for (auto &flag : all_flags) {
33 |         auto pattern = std::string("%") + flag;
34 |         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
35 | 
36 |         //        pattern = std::string("%16") + flag;
37 |         //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
38 |         //
39 |         //        // bench center padding
40 |         //        pattern = std::string("%=16") + flag;
41 |         //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
42 |     }
43 | 
44 |     // complex patterns
45 |     std::vector<std::string> patterns = {
46 |         "[%D %X] [%l] [%n] %v",
47 |         "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v",
48 |         "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v",
49 |     };
50 |     for (auto &pattern : patterns) {
51 |         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern)
52 |             ->Iterations(2500000);
53 |     }
54 | }
55 | 
56 | int main(int argc, char *argv[]) {
57 |     spdlog::set_pattern("[%^%l%$] %v");
58 |     if (argc != 2) {
59 |         spdlog::error("Usage: {} <pattern> (or \"all\" to bench all)", argv[0]);
60 |         exit(1);
61 |     }
62 | 
63 |     std::string pattern = argv[1];
64 |     if (pattern == "all") {
65 |         bench_formatters();
66 |     } else {
67 |         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
68 |     }
69 |     benchmark::Initialize(&argc, argv);
70 |     benchmark::RunSpecifiedBenchmarks();
71 | }
72 | 


--------------------------------------------------------------------------------
/bench/utils.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2015 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | 
 8 | #include <iomanip>
 9 | #include <locale>
10 | #include <sstream>
11 | 
12 | namespace utils {
13 | 
14 | template <typename T>
15 | inline std::string format(const T &value) {
16 |     static std::locale loc("");
17 |     std::stringstream ss;
18 |     ss.imbue(loc);
19 |     ss << value;
20 |     return ss.str();
21 | }
22 | 
23 | template <>
24 | inline std::string format(const double &value) {
25 |     static std::locale loc("");
26 |     std::stringstream ss;
27 |     ss.imbue(loc);
28 |     ss << std::fixed << std::setprecision(1) << value;
29 |     return ss.str();
30 | }
31 | 
32 | }  // namespace utils
33 | 


--------------------------------------------------------------------------------
/cmake/ide.cmake:
--------------------------------------------------------------------------------
 1 | # ---------------------------------------------------------------------------------------
 2 | # IDE support for headers
 3 | # ---------------------------------------------------------------------------------------
 4 | set(SPDLOG_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/../include")
 5 | 
 6 | file(GLOB SPDLOG_TOP_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/*.h")
 7 | file(GLOB SPDLOG_DETAILS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/details/*.h")
 8 | file(GLOB SPDLOG_SINKS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/sinks/*.h")
 9 | file(GLOB SPDLOG_FMT_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/*.h")
10 | file(GLOB SPDLOG_FMT_BUNDELED_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/bundled/*.h")
11 | set(SPDLOG_ALL_HEADERS ${SPDLOG_TOP_HEADERS} ${SPDLOG_DETAILS_HEADERS} ${SPDLOG_SINKS_HEADERS} ${SPDLOG_FMT_HEADERS}
12 |                        ${SPDLOG_FMT_BUNDELED_HEADERS})
13 | 
14 | source_group("Header Files\\spdlog" FILES ${SPDLOG_TOP_HEADERS})
15 | source_group("Header Files\\spdlog\\details" FILES ${SPDLOG_DETAILS_HEADERS})
16 | source_group("Header Files\\spdlog\\sinks" FILES ${SPDLOG_SINKS_HEADERS})
17 | source_group("Header Files\\spdlog\\fmt" FILES ${SPDLOG_FMT_HEADERS})
18 | source_group("Header Files\\spdlog\\fmt\\bundled\\" FILES ${SPDLOG_FMT_BUNDELED_HEADERS})
19 | 


--------------------------------------------------------------------------------
/cmake/spdlog.pc.in:
--------------------------------------------------------------------------------
 1 | prefix=@CMAKE_INSTALL_PREFIX@
 2 | exec_prefix=${prefix}
 3 | includedir=@PKG_CONFIG_INCLUDEDIR@
 4 | libdir=@PKG_CONFIG_LIBDIR@
 5 | 
 6 | Name: lib@PROJECT_NAME@
 7 | Description: Fast C++ logging library.
 8 | URL: https://github.com/gabime/@PROJECT_NAME@
 9 | Version: @SPDLOG_VERSION@
10 | CFlags: -I${includedir} @PKG_CONFIG_DEFINES@
11 | Libs: -L${libdir} -lspdlog -pthread
12 | Requires: @PKG_CONFIG_REQUIRES@
13 | 
14 | 


--------------------------------------------------------------------------------
/cmake/spdlogCPack.cmake:
--------------------------------------------------------------------------------
 1 | set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators")
 2 | 
 3 | set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
 4 | set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_BINARY_DIR}" "${PROJECT_NAME}" ALL .)
 5 | 
 6 | set(CPACK_PROJECT_URL "https://github.com/gabime/spdlog")
 7 | set(CPACK_PACKAGE_VENDOR "Gabi Melman")
 8 | set(CPACK_PACKAGE_CONTACT "Gabi Melman <gmelman1@gmail.com>")
 9 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Fast C++ logging library")
10 | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
11 | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
12 | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
13 | set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
14 | if(PROJECT_VERSION_TWEAK)
15 |     set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK})
16 | endif()
17 | set(CPACK_PACKAGE_RELOCATABLE ON CACHE BOOL "Build relocatable package")
18 | 
19 | set(CPACK_RPM_PACKAGE_LICENSE "MIT")
20 | set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries")
21 | set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
22 | set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL})
23 | set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PROJECT_URL})
24 | set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.")
25 | set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.")
26 | 
27 | if(CPACK_PACKAGE_NAME)
28 |     set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
29 |     set(CPACK_DEBIAN_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
30 | else()
31 |     set(CPACK_RPM_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
32 |     set(CPACK_DEBIAN_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
33 |     set(CPACK_RPM_PACKAGE_NAME "${PROJECT_NAME}")
34 |     set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
35 | endif()
36 | 
37 | if(CPACK_RPM_PACKAGE_RELEASE)
38 |     set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}")
39 | endif()
40 | if(CPACK_DEBIAN_PACKAGE_RELEASE)
41 |     set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}-${CPACK_DEBIAN_PACKAGE_RELEASE}")
42 | endif()
43 | 
44 | if(CPACK_RPM_PACKAGE_ARCHITECTURE)
45 |     set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
46 | endif()
47 | if(CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
48 |     set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
49 | endif()
50 | set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.rpm")
51 | set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb")
52 | 
53 | if(NOT CPACK_PACKAGE_RELOCATABLE)
54 |     # Depend on pkgconfig rpm to create the system pkgconfig folder
55 |     set(CPACK_RPM_PACKAGE_REQUIRES pkgconfig)
56 |     set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
57 |         "${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
58 | endif()
59 | 
60 | include(CPack)
61 | 


--------------------------------------------------------------------------------
/cmake/spdlogConfig.cmake.in:
--------------------------------------------------------------------------------
 1 | # Copyright(c) 2019 spdlog authors
 2 | # Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | @PACKAGE_INIT@
 5 | 
 6 | find_package(Threads REQUIRED)
 7 | 
 8 | set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@)
 9 | set(SPDLOG_FMT_EXTERNAL_HO @SPDLOG_FMT_EXTERNAL_HO@)
10 | set(config_targets_file @config_targets_file@)
11 | 
12 | if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
13 |     include(CMakeFindDependencyMacro)
14 |     find_dependency(fmt CONFIG)
15 | endif()
16 | 
17 | 
18 | include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}")
19 | 
20 | check_required_components(spdlog)
21 | 


--------------------------------------------------------------------------------
/cmake/utils.cmake:
--------------------------------------------------------------------------------
 1 | # Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION
 2 | function(spdlog_extract_version)
 3 |     file(READ "${CMAKE_CURRENT_LIST_DIR}/include/spdlog/version.h" file_contents)
 4 |     string(REGEX MATCH "SPDLOG_VER_MAJOR ([0-9]+)" _ "${file_contents}")
 5 |     if(NOT CMAKE_MATCH_COUNT EQUAL 1)
 6 |         message(FATAL_ERROR "Could not extract major version number from spdlog/version.h")
 7 |     endif()
 8 |     set(ver_major ${CMAKE_MATCH_1})
 9 | 
10 |     string(REGEX MATCH "SPDLOG_VER_MINOR ([0-9]+)" _ "${file_contents}")
11 |     if(NOT CMAKE_MATCH_COUNT EQUAL 1)
12 |         message(FATAL_ERROR "Could not extract minor version number from spdlog/version.h")
13 |     endif()
14 | 
15 |     set(ver_minor ${CMAKE_MATCH_1})
16 |     string(REGEX MATCH "SPDLOG_VER_PATCH ([0-9]+)" _ "${file_contents}")
17 |     if(NOT CMAKE_MATCH_COUNT EQUAL 1)
18 |         message(FATAL_ERROR "Could not extract patch version number from spdlog/version.h")
19 |     endif()
20 |     set(ver_patch ${CMAKE_MATCH_1})
21 | 
22 |     set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE)
23 |     set(SPDLOG_VERSION_MINOR ${ver_minor} PARENT_SCOPE)
24 |     set(SPDLOG_VERSION_PATCH ${ver_patch} PARENT_SCOPE)
25 |     set(SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE)
26 | endfunction()
27 | 
28 | # Turn on warnings on the given target
29 | function(spdlog_enable_warnings target_name)
30 |     if(SPDLOG_BUILD_WARNINGS)
31 |         if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
32 |             list(APPEND MSVC_OPTIONS "/W3")
33 |             if(MSVC_VERSION GREATER 1900) # Allow non fatal security warnings for msvc 2015
34 |                 list(APPEND MSVC_OPTIONS "/WX")
35 |             endif()
36 |         endif()
37 | 
38 |         target_compile_options(
39 |             ${target_name}
40 |             PRIVATE 
lt;
lt;OR:
lt;CXX_COMPILER_ID:Clang>,
lt;CXX_COMPILER_ID:AppleClang>,
lt;CXX_COMPILER_ID:GNU>>:
41 |                     -Wall
42 |                     -Wextra
43 |                     -Wconversion
44 |                     -pedantic
45 |                     -Werror
46 |                     -Wfatal-errors>
47 |                     
lt;
lt;CXX_COMPILER_ID:MSVC>:${MSVC_OPTIONS}>)
48 |     endif()
49 | endfunction()
50 | 
51 | # Enable address sanitizer (gcc/clang only)
52 | function(spdlog_enable_addr_sanitizer target_name)
53 |     if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
54 |         message(FATAL_ERROR "Sanitizer supported only for gcc/clang")
55 |     endif()
56 |     message(STATUS "Address sanitizer enabled")
57 |     target_compile_options(${target_name} PRIVATE -fsanitize=address,undefined)
58 |     target_compile_options(${target_name} PRIVATE -fno-sanitize=signed-integer-overflow)
59 |     target_compile_options(${target_name} PRIVATE -fno-sanitize-recover=all)
60 |     target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
61 |     target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined)
62 | endfunction()
63 | 
64 | # Enable thread sanitizer (gcc/clang only)
65 | function(spdlog_enable_thread_sanitizer target_name)
66 |     if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
67 |         message(FATAL_ERROR "Sanitizer supported only for gcc/clang")
68 |     endif()
69 |     message(STATUS "Thread sanitizer enabled")
70 |     target_compile_options(${target_name} PRIVATE -fsanitize=thread)
71 |     target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
72 |     target_link_libraries(${target_name} PRIVATE -fsanitize=thread)
73 | endfunction()
74 | 


--------------------------------------------------------------------------------
/cmake/version.rc.in:
--------------------------------------------------------------------------------
 1 | #define APSTUDIO_READONLY_SYMBOLS
 2 | #include <windows.h>
 3 | #undef APSTUDIO_READONLY_SYMBOLS
 4 | 
 5 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 6 | 
 7 | 
 8 | VS_VERSION_INFO VERSIONINFO
 9 |  FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
10 |  PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
11 |  FILEFLAGSMASK 0x3fL
12 | #ifdef _DEBUG
13 |  FILEFLAGS 0x1L
14 | #else
15 |  FILEFLAGS 0x0L
16 | #endif
17 |  FILEOS 0x40004L
18 |  FILETYPE 0x2L
19 |  FILESUBTYPE 0x0L
20 | BEGIN
21 |     BLOCK "StringFileInfo"
22 |     BEGIN
23 |         BLOCK "040904b0"
24 |         BEGIN
25 |             VALUE "FileDescription", "spdlog dll\0"
26 |             VALUE "FileVersion", "@SPDLOG_VERSION@.0\0"
27 |             VALUE "InternalName", "spdlog.dll\0"
28 |             VALUE "LegalCopyright", "Copyright (C) spdlog\0"
29 |             VALUE "ProductName", "spdlog\0"
30 |             VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0"
31 |         END
32 |     END
33 |     BLOCK "VarFileInfo"
34 |     BEGIN
35 |         VALUE "Translation", 0x409, 1200
36 |     END
37 | END
38 | 
39 | 
40 | 
41 | 
42 | 
43 | 


--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | # Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)
 2 | 
 3 | cmake_minimum_required(VERSION 3.11)
 4 | project(spdlog_examples CXX)
 5 | 
 6 | if(NOT TARGET spdlog)
 7 |     # Stand-alone build
 8 |     find_package(spdlog REQUIRED)
 9 | endif()
10 | 
11 | # ---------------------------------------------------------------------------------------
12 | # Example of using pre-compiled library
13 | # ---------------------------------------------------------------------------------------
14 | add_executable(example example.cpp)
15 | target_link_libraries(example PRIVATE spdlog::spdlog 
lt;
lt;BOOL:${MINGW}>:ws2_32>)
16 | 
17 | # ---------------------------------------------------------------------------------------
18 | # Example of using header-only library
19 | # ---------------------------------------------------------------------------------------
20 | if(SPDLOG_BUILD_EXAMPLE_HO)
21 |     add_executable(example_header_only example.cpp)
22 |     target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
23 | endif()
24 | 


--------------------------------------------------------------------------------
/include/spdlog/async.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | //
  7 | // Async logging using global thread pool
  8 | // All loggers created here share same global thread pool.
  9 | // Each log message is pushed to a queue along with a shared pointer to the
 10 | // logger.
 11 | // If a logger deleted while having pending messages in the queue, it's actual
 12 | // destruction will defer
 13 | // until all its messages are processed by the thread pool.
 14 | // This is because each message in the queue holds a shared_ptr to the
 15 | // originating logger.
 16 | 
 17 | #include <spdlog/async_logger.h>
 18 | #include <spdlog/details/registry.h>
 19 | #include <spdlog/details/thread_pool.h>
 20 | 
 21 | #include <functional>
 22 | #include <memory>
 23 | #include <mutex>
 24 | 
 25 | namespace spdlog {
 26 | 
 27 | namespace details {
 28 | static const size_t default_async_q_size = 8192;
 29 | }
 30 | 
 31 | // async logger factory - creates async loggers backed with thread pool.
 32 | // if a global thread pool doesn't already exist, create it with default queue
 33 | // size of 8192 items and single thread.
 34 | template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
 35 | struct async_factory_impl {
 36 |     template <typename Sink, typename... SinkArgs>
 37 |     static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
 38 |         auto &registry_inst = details::registry::instance();
 39 | 
 40 |         // create global thread pool if not already exists..
 41 | 
 42 |         auto &mutex = registry_inst.tp_mutex();
 43 |         std::lock_guard<std::recursive_mutex> tp_lock(mutex);
 44 |         auto tp = registry_inst.get_tp();
 45 |         if (tp == nullptr) {
 46 |             tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
 47 |             registry_inst.set_tp(tp);
 48 |         }
 49 | 
 50 |         auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
 51 |         auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink),
 52 |                                                          std::move(tp), OverflowPolicy);
 53 |         registry_inst.initialize_logger(new_logger);
 54 |         return new_logger;
 55 |     }
 56 | };
 57 | 
 58 | using async_factory = async_factory_impl<async_overflow_policy::block>;
 59 | using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
 60 | 
 61 | template <typename Sink, typename... SinkArgs>
 62 | inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name,
 63 |                                                     SinkArgs &&...sink_args) {
 64 |     return async_factory::create<Sink>(std::move(logger_name),
 65 |                                        std::forward<SinkArgs>(sink_args)...);
 66 | }
 67 | 
 68 | template <typename Sink, typename... SinkArgs>
 69 | inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name,
 70 |                                                        SinkArgs &&...sink_args) {
 71 |     return async_factory_nonblock::create<Sink>(std::move(logger_name),
 72 |                                                 std::forward<SinkArgs>(sink_args)...);
 73 | }
 74 | 
 75 | // set global thread pool.
 76 | inline void init_thread_pool(size_t q_size,
 77 |                              size_t thread_count,
 78 |                              std::function<void()> on_thread_start,
 79 |                              std::function<void()> on_thread_stop) {
 80 |     auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,
 81 |                                                      on_thread_stop);
 82 |     details::registry::instance().set_tp(std::move(tp));
 83 | }
 84 | 
 85 | inline void init_thread_pool(size_t q_size,
 86 |                              size_t thread_count,
 87 |                              std::function<void()> on_thread_start) {
 88 |     init_thread_pool(q_size, thread_count, on_thread_start, [] {});
 89 | }
 90 | 
 91 | inline void init_thread_pool(size_t q_size, size_t thread_count) {
 92 |     init_thread_pool(q_size, thread_count, [] {}, [] {});
 93 | }
 94 | 
 95 | // get the global thread pool.
 96 | inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() {
 97 |     return details::registry::instance().get_tp();
 98 | }
 99 | }  // namespace spdlog
100 | 


--------------------------------------------------------------------------------
/include/spdlog/async_logger-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/async_logger.h>
 8 | #endif
 9 | 
10 | #include <spdlog/details/thread_pool.h>
11 | #include <spdlog/sinks/sink.h>
12 | 
13 | #include <memory>
14 | #include <string>
15 | 
16 | SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
17 |                                                  sinks_init_list sinks_list,
18 |                                                  std::weak_ptr<details::thread_pool> tp,
19 |                                                  async_overflow_policy overflow_policy)
20 |     : async_logger(std::move(logger_name),
21 |                    sinks_list.begin(),
22 |                    sinks_list.end(),
23 |                    std::move(tp),
24 |                    overflow_policy) {}
25 | 
26 | SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
27 |                                                  sink_ptr single_sink,
28 |                                                  std::weak_ptr<details::thread_pool> tp,
29 |                                                  async_overflow_policy overflow_policy)
30 |     : async_logger(
31 |           std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}
32 | 
33 | // send the log message to the thread pool
34 | SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){
35 |     SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
36 |         pool_ptr -> post_log(shared_from_this(), msg, overflow_policy_);
37 | }
38 | else {
39 |     throw_spdlog_ex("async log: thread pool doesn't exist anymore");
40 | }
41 | }
42 | SPDLOG_LOGGER_CATCH(msg.source)
43 | }
44 | 
45 | // send flush request to the thread pool
46 | SPDLOG_INLINE void spdlog::async_logger::flush_(){
47 |     SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
48 |         pool_ptr -> post_flush(shared_from_this(), overflow_policy_);
49 | }
50 | else {
51 |     throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
52 | }
53 | }
54 | SPDLOG_LOGGER_CATCH(source_loc())
55 | }
56 | 
57 | //
58 | // backend functions - called from the thread pool to do the actual job
59 | //
60 | SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) {
61 |     for (auto &sink : sinks_) {
62 |         if (sink->should_log(msg.level)) {
63 |             SPDLOG_TRY { sink->log(msg); }
64 |             SPDLOG_LOGGER_CATCH(msg.source)
65 |         }
66 |     }
67 | 
68 |     if (should_flush_(msg)) {
69 |         backend_flush_();
70 |     }
71 | }
72 | 
73 | SPDLOG_INLINE void spdlog::async_logger::backend_flush_() {
74 |     for (auto &sink : sinks_) {
75 |         SPDLOG_TRY { sink->flush(); }
76 |         SPDLOG_LOGGER_CATCH(source_loc())
77 |     }
78 | }
79 | 
80 | SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
81 |     auto cloned = std::make_shared<spdlog::async_logger>(*this);
82 |     cloned->name_ = std::move(new_name);
83 |     return cloned;
84 | }
85 | 


--------------------------------------------------------------------------------
/include/spdlog/async_logger.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | // Fast asynchronous logger.
 7 | // Uses pre allocated queue.
 8 | // Creates a single back thread to pop messages from the queue and log them.
 9 | //
10 | // Upon each log write the logger:
11 | //    1. Checks if its log level is enough to log the message
12 | //    2. Push a new copy of the message to a queue (or block the caller until
13 | //    space is available in the queue)
14 | // Upon destruction, logs all remaining messages in the queue before
15 | // destructing..
16 | 
17 | #include <spdlog/logger.h>
18 | 
19 | namespace spdlog {
20 | 
21 | // Async overflow policy - block by default.
22 | enum class async_overflow_policy {
23 |     block,           // Block until message can be enqueued
24 |     overrun_oldest,  // Discard oldest message in the queue if full when trying to
25 |                      // add new item.
26 |     discard_new      // Discard new message if the queue is full when trying to add new item.
27 | };
28 | 
29 | namespace details {
30 | class thread_pool;
31 | }
32 | 
33 | class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>,
34 |                                       public logger {
35 |     friend class details::thread_pool;
36 | 
37 | public:
38 |     template <typename It>
39 |     async_logger(std::string logger_name,
40 |                  It begin,
41 |                  It end,
42 |                  std::weak_ptr<details::thread_pool> tp,
43 |                  async_overflow_policy overflow_policy = async_overflow_policy::block)
44 |         : logger(std::move(logger_name), begin, end),
45 |           thread_pool_(std::move(tp)),
46 |           overflow_policy_(overflow_policy) {}
47 | 
48 |     async_logger(std::string logger_name,
49 |                  sinks_init_list sinks_list,
50 |                  std::weak_ptr<details::thread_pool> tp,
51 |                  async_overflow_policy overflow_policy = async_overflow_policy::block);
52 | 
53 |     async_logger(std::string logger_name,
54 |                  sink_ptr single_sink,
55 |                  std::weak_ptr<details::thread_pool> tp,
56 |                  async_overflow_policy overflow_policy = async_overflow_policy::block);
57 | 
58 |     std::shared_ptr<logger> clone(std::string new_name) override;
59 | 
60 | protected:
61 |     void sink_it_(const details::log_msg &msg) override;
62 |     void flush_() override;
63 |     void backend_sink_it_(const details::log_msg &incoming_log_msg);
64 |     void backend_flush_();
65 | 
66 | private:
67 |     std::weak_ptr<details::thread_pool> thread_pool_;
68 |     async_overflow_policy overflow_policy_;
69 | };
70 | }  // namespace spdlog
71 | 
72 | #ifdef SPDLOG_HEADER_ONLY
73 |     #include "async_logger-inl.h"
74 | #endif
75 | 


--------------------------------------------------------------------------------
/include/spdlog/cfg/argv.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | #include <spdlog/cfg/helpers.h>
 6 | #include <spdlog/details/registry.h>
 7 | 
 8 | //
 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
10 | //
11 | // set all loggers to debug level:
12 | // example.exe "SPDLOG_LEVEL=debug"
13 | 
14 | // set logger1 to trace level
15 | // example.exe "SPDLOG_LEVEL=logger1=trace"
16 | 
17 | // turn off all logging except for logger1 and logger2:
18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
19 | 
20 | namespace spdlog {
21 | namespace cfg {
22 | 
23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels
24 | inline void load_argv_levels(int argc, const char **argv) {
25 |     const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
26 |     for (int i = 1; i < argc; i++) {
27 |         std::string arg = argv[i];
28 |         if (arg.find(spdlog_level_prefix) == 0) {
29 |             auto levels_string = arg.substr(spdlog_level_prefix.size());
30 |             helpers::load_levels(levels_string);
31 |         }
32 |     }
33 | }
34 | 
35 | inline void load_argv_levels(int argc, char **argv) {
36 |     load_argv_levels(argc, const_cast<const char **>(argv));
37 | }
38 | 
39 | }  // namespace cfg
40 | }  // namespace spdlog
41 | 


--------------------------------------------------------------------------------
/include/spdlog/cfg/env.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | #include <spdlog/cfg/helpers.h>
 6 | #include <spdlog/details/os.h>
 7 | #include <spdlog/details/registry.h>
 8 | 
 9 | //
10 | // Init levels and patterns from env variables SPDLOG_LEVEL
11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
12 | // Note - fallback to "info" level on unrecognized levels
13 | //
14 | // Examples:
15 | //
16 | // set global level to debug:
17 | // export SPDLOG_LEVEL=debug
18 | //
19 | // turn off all logging except for logger1:
20 | // export SPDLOG_LEVEL="*=off,logger1=debug"
21 | //
22 | 
23 | // turn off all logging except for logger1 and logger2:
24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
25 | 
26 | namespace spdlog {
27 | namespace cfg {
28 | inline void load_env_levels(const char* var = "SPDLOG_LEVEL") {
29 |     auto env_val = details::os::getenv(var);
30 |     if (!env_val.empty()) {
31 |         helpers::load_levels(env_val);
32 |     }
33 | }
34 | 
35 | }  // namespace cfg
36 | }  // namespace spdlog
37 | 


--------------------------------------------------------------------------------
/include/spdlog/cfg/helpers-inl.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | #ifndef SPDLOG_HEADER_ONLY
  7 |     #include <spdlog/cfg/helpers.h>
  8 | #endif
  9 | 
 10 | #include <spdlog/details/os.h>
 11 | #include <spdlog/details/registry.h>
 12 | 
 13 | #include <algorithm>
 14 | #include <sstream>
 15 | #include <string>
 16 | #include <utility>
 17 | 
 18 | namespace spdlog {
 19 | namespace cfg {
 20 | namespace helpers {
 21 | 
 22 | // inplace convert to lowercase
 23 | inline std::string &to_lower_(std::string &str) {
 24 |     std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
 25 |         return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
 26 |     });
 27 |     return str;
 28 | }
 29 | 
 30 | // inplace trim spaces
 31 | inline std::string &trim_(std::string &str) {
 32 |     const char *spaces = " \n\r\t";
 33 |     str.erase(str.find_last_not_of(spaces) + 1);
 34 |     str.erase(0, str.find_first_not_of(spaces));
 35 |     return str;
 36 | }
 37 | 
 38 | // return (name,value) trimmed pair from the given "name = value" string.
 39 | // return empty string on missing parts
 40 | // "key=val" => ("key", "val")
 41 | // " key  =  val " => ("key", "val")
 42 | // "key=" => ("key", "")
 43 | // "val" => ("", "val")
 44 | 
 45 | inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str) {
 46 |     auto n = str.find(sep);
 47 |     std::string k, v;
 48 |     if (n == std::string::npos) {
 49 |         v = str;
 50 |     } else {
 51 |         k = str.substr(0, n);
 52 |         v = str.substr(n + 1);
 53 |     }
 54 |     return std::make_pair(trim_(k), trim_(v));
 55 | }
 56 | 
 57 | // return vector of key/value pairs from a sequence of "K1=V1,K2=V2,.."
 58 | // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
 59 | inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str) {
 60 |     std::string token;
 61 |     std::istringstream token_stream(str);
 62 |     std::unordered_map<std::string, std::string> rv{};
 63 |     while (std::getline(token_stream, token, ',')) {
 64 |         if (token.empty()) {
 65 |             continue;
 66 |         }
 67 |         auto kv = extract_kv_('=', token);
 68 |         rv[kv.first] = kv.second;
 69 |     }
 70 |     return rv;
 71 | }
 72 | 
 73 | SPDLOG_INLINE void load_levels(const std::string &input) {
 74 |     if (input.empty() || input.size() >= 32768) {
 75 |         return;
 76 |     }
 77 | 
 78 |     auto key_vals = extract_key_vals_(input);
 79 |     std::unordered_map<std::string, level::level_enum> levels;
 80 |     level::level_enum global_level = level::info;
 81 |     bool global_level_found = false;
 82 | 
 83 |     for (auto &name_level : key_vals) {
 84 |         const auto &logger_name = name_level.first;
 85 |         const auto &level_name = to_lower_(name_level.second);
 86 |         auto level = level::from_str(level_name);
 87 |         // ignore unrecognized level names
 88 |         if (level == level::off && level_name != "off") {
 89 |             continue;
 90 |         }
 91 |         if (logger_name.empty())  // no logger name indicates global level
 92 |         {
 93 |             global_level_found = true;
 94 |             global_level = level;
 95 |         } else {
 96 |             levels[logger_name] = level;
 97 |         }
 98 |     }
 99 | 
100 |     details::registry::instance().set_levels(std::move(levels),
101 |                                              global_level_found ? &global_level : nullptr);
102 | }
103 | 
104 | }  // namespace helpers
105 | }  // namespace cfg
106 | }  // namespace spdlog
107 | 


--------------------------------------------------------------------------------
/include/spdlog/cfg/helpers.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <unordered_map>
 8 | 
 9 | namespace spdlog {
10 | namespace cfg {
11 | namespace helpers {
12 | //
13 | // Init levels from given string
14 | //
15 | // Examples:
16 | //
17 | // set global level to debug: "debug"
18 | // turn off all logging except for logger1: "off,logger1=debug"
19 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
20 | //
21 | SPDLOG_API void load_levels(const std::string &txt);
22 | }  // namespace helpers
23 | 
24 | }  // namespace cfg
25 | }  // namespace spdlog
26 | 
27 | #ifdef SPDLOG_HEADER_ONLY
28 |     #include "helpers-inl.h"
29 | #endif  // SPDLOG_HEADER_ONLY
30 | 


--------------------------------------------------------------------------------
/include/spdlog/common-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/common.h>
 8 | #endif
 9 | 
10 | #include <algorithm>
11 | #include <iterator>
12 | 
13 | namespace spdlog {
14 | namespace level {
15 | 
16 | #if __cplusplus >= 201703L
17 | constexpr
18 | #endif
19 |     static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
20 | 
21 | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
22 | 
23 | SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
24 |     return level_string_views[l];
25 | }
26 | 
27 | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
28 |     return short_level_names[l];
29 | }
30 | 
31 | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT {
32 |     auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
33 |     if (it != std::end(level_string_views))
34 |         return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));
35 | 
36 |     // check also for "warn" and "err" before giving up..
37 |     if (name == "warn") {
38 |         return level::warn;
39 |     }
40 |     if (name == "err") {
41 |         return level::err;
42 |     }
43 |     return level::off;
44 | }
45 | }  // namespace level
46 | 
47 | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
48 |     : msg_(std::move(msg)) {}
49 | 
50 | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) {
51 | #ifdef SPDLOG_USE_STD_FORMAT
52 |     msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what();
53 | #else
54 |     memory_buf_t outbuf;
55 |     fmt::format_system_error(outbuf, last_errno, msg.c_str());
56 |     msg_ = fmt::to_string(outbuf);
57 | #endif
58 | }
59 | 
60 | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); }
61 | 
62 | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) {
63 |     SPDLOG_THROW(spdlog_ex(msg, last_errno));
64 | }
65 | 
66 | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); }
67 | 
68 | }  // namespace spdlog
69 | 


--------------------------------------------------------------------------------
/include/spdlog/details/backtracer-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/details/backtracer.h>
 8 | #endif
 9 | namespace spdlog {
10 | namespace details {
11 | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) {
12 |     std::lock_guard<std::mutex> lock(other.mutex_);
13 |     enabled_ = other.enabled();
14 |     messages_ = other.messages_;
15 | }
16 | 
17 | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT {
18 |     std::lock_guard<std::mutex> lock(other.mutex_);
19 |     enabled_ = other.enabled();
20 |     messages_ = std::move(other.messages_);
21 | }
22 | 
23 | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) {
24 |     std::lock_guard<std::mutex> lock(mutex_);
25 |     enabled_ = other.enabled();
26 |     messages_ = std::move(other.messages_);
27 |     return *this;
28 | }
29 | 
30 | SPDLOG_INLINE void backtracer::enable(size_t size) {
31 |     std::lock_guard<std::mutex> lock{mutex_};
32 |     enabled_.store(true, std::memory_order_relaxed);
33 |     messages_ = circular_q<log_msg_buffer>{size};
34 | }
35 | 
36 | SPDLOG_INLINE void backtracer::disable() {
37 |     std::lock_guard<std::mutex> lock{mutex_};
38 |     enabled_.store(false, std::memory_order_relaxed);
39 | }
40 | 
41 | SPDLOG_INLINE bool backtracer::enabled() const { return enabled_.load(std::memory_order_relaxed); }
42 | 
43 | SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) {
44 |     std::lock_guard<std::mutex> lock{mutex_};
45 |     messages_.push_back(log_msg_buffer{msg});
46 | }
47 | 
48 | SPDLOG_INLINE bool backtracer::empty() const {
49 |     std::lock_guard<std::mutex> lock{mutex_};
50 |     return messages_.empty();
51 | }
52 | 
53 | // pop all items in the q and apply the given fun on each of them.
54 | SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun) {
55 |     std::lock_guard<std::mutex> lock{mutex_};
56 |     while (!messages_.empty()) {
57 |         auto &front_msg = messages_.front();
58 |         fun(front_msg);
59 |         messages_.pop_front();
60 |     }
61 | }
62 | }  // namespace details
63 | }  // namespace spdlog
64 | 


--------------------------------------------------------------------------------
/include/spdlog/details/backtracer.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/circular_q.h>
 7 | #include <spdlog/details/log_msg_buffer.h>
 8 | 
 9 | #include <atomic>
10 | #include <functional>
11 | #include <mutex>
12 | 
13 | // Store log messages in circular buffer.
14 | // Useful for storing debug data in case of error/warning happens.
15 | 
16 | namespace spdlog {
17 | namespace details {
18 | class SPDLOG_API backtracer {
19 |     mutable std::mutex mutex_;
20 |     std::atomic<bool> enabled_{false};
21 |     circular_q<log_msg_buffer> messages_;
22 | 
23 | public:
24 |     backtracer() = default;
25 |     backtracer(const backtracer &other);
26 | 
27 |     backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
28 |     backtracer &operator=(backtracer other);
29 | 
30 |     void enable(size_t size);
31 |     void disable();
32 |     bool enabled() const;
33 |     void push_back(const log_msg &msg);
34 |     bool empty() const;
35 | 
36 |     // pop all items in the q and apply the given fun on each of them.
37 |     void foreach_pop(std::function<void(const details::log_msg &)> fun);
38 | };
39 | 
40 | }  // namespace details
41 | }  // namespace spdlog
42 | 
43 | #ifdef SPDLOG_HEADER_ONLY
44 |     #include "backtracer-inl.h"
45 | #endif
46 | 


--------------------------------------------------------------------------------
/include/spdlog/details/circular_q.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | // circular q view of std::vector.
  5 | #pragma once
  6 | 
  7 | #include <cassert>
  8 | #include <vector>
  9 | 
 10 | #include "spdlog/common.h"
 11 | 
 12 | namespace spdlog {
 13 | namespace details {
 14 | template <typename T>
 15 | class circular_q {
 16 |     size_t max_items_ = 0;
 17 |     typename std::vector<T>::size_type head_ = 0;
 18 |     typename std::vector<T>::size_type tail_ = 0;
 19 |     size_t overrun_counter_ = 0;
 20 |     std::vector<T> v_;
 21 | 
 22 | public:
 23 |     using value_type = T;
 24 | 
 25 |     // empty ctor - create a disabled queue with no elements allocated at all
 26 |     circular_q() = default;
 27 | 
 28 |     explicit circular_q(size_t max_items)
 29 |         : max_items_(max_items + 1)  // one item is reserved as marker for full q
 30 |           ,
 31 |           v_(max_items_) {}
 32 | 
 33 |     circular_q(const circular_q &) = default;
 34 |     circular_q &operator=(const circular_q &) = default;
 35 | 
 36 |     // move cannot be default,
 37 |     // since we need to reset head_, tail_, etc to zero in the moved object
 38 |     circular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); }
 39 | 
 40 |     circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT {
 41 |         copy_moveable(std::move(other));
 42 |         return *this;
 43 |     }
 44 | 
 45 |     // push back, overrun (oldest) item if no room left
 46 |     void push_back(T &&item) {
 47 |         if (max_items_ > 0) {
 48 |             v_[tail_] = std::move(item);
 49 |             tail_ = (tail_ + 1) % max_items_;
 50 | 
 51 |             if (tail_ == head_)  // overrun last item if full
 52 |             {
 53 |                 head_ = (head_ + 1) % max_items_;
 54 |                 ++overrun_counter_;
 55 |             }
 56 |         }
 57 |     }
 58 | 
 59 |     // Return reference to the front item.
 60 |     // If there are no elements in the container, the behavior is undefined.
 61 |     const T &front() const { return v_[head_]; }
 62 | 
 63 |     T &front() { return v_[head_]; }
 64 | 
 65 |     // Return number of elements actually stored
 66 |     size_t size() const {
 67 |         if (tail_ >= head_) {
 68 |             return tail_ - head_;
 69 |         } else {
 70 |             return max_items_ - (head_ - tail_);
 71 |         }
 72 |     }
 73 | 
 74 |     // Return const reference to item by index.
 75 |     // If index is out of range 0…size()-1, the behavior is undefined.
 76 |     const T &at(size_t i) const {
 77 |         assert(i < size());
 78 |         return v_[(head_ + i) % max_items_];
 79 |     }
 80 | 
 81 |     // Pop item from front.
 82 |     // If there are no elements in the container, the behavior is undefined.
 83 |     void pop_front() { head_ = (head_ + 1) % max_items_; }
 84 | 
 85 |     bool empty() const { return tail_ == head_; }
 86 | 
 87 |     bool full() const {
 88 |         // head is ahead of the tail by 1
 89 |         if (max_items_ > 0) {
 90 |             return ((tail_ + 1) % max_items_) == head_;
 91 |         }
 92 |         return false;
 93 |     }
 94 | 
 95 |     size_t overrun_counter() const { return overrun_counter_; }
 96 | 
 97 |     void reset_overrun_counter() { overrun_counter_ = 0; }
 98 | 
 99 | private:
100 |     // copy from other&& and reset it to disabled state
101 |     void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT {
102 |         max_items_ = other.max_items_;
103 |         head_ = other.head_;
104 |         tail_ = other.tail_;
105 |         overrun_counter_ = other.overrun_counter_;
106 |         v_ = std::move(other.v_);
107 | 
108 |         // put &&other in disabled, but valid state
109 |         other.max_items_ = 0;
110 |         other.head_ = other.tail_ = 0;
111 |         other.overrun_counter_ = 0;
112 |     }
113 | };
114 | }  // namespace details
115 | }  // namespace spdlog
116 | 


--------------------------------------------------------------------------------
/include/spdlog/details/console_globals.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <mutex>
 7 | #include <spdlog/details/null_mutex.h>
 8 | 
 9 | namespace spdlog {
10 | namespace details {
11 | 
12 | struct console_mutex {
13 |     using mutex_t = std::mutex;
14 |     static mutex_t &mutex() {
15 |         static mutex_t s_mutex;
16 |         return s_mutex;
17 |     }
18 | };
19 | 
20 | struct console_nullmutex {
21 |     using mutex_t = null_mutex;
22 |     static mutex_t &mutex() {
23 |         static mutex_t s_mutex;
24 |         return s_mutex;
25 |     }
26 | };
27 | }  // namespace details
28 | }  // namespace spdlog
29 | 


--------------------------------------------------------------------------------
/include/spdlog/details/file_helper.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <tuple>
 8 | 
 9 | namespace spdlog {
10 | namespace details {
11 | 
12 | // Helper class for file sinks.
13 | // When failing to open a file, retry several times(5) with a delay interval(10 ms).
14 | // Throw spdlog_ex exception on errors.
15 | 
16 | class SPDLOG_API file_helper {
17 | public:
18 |     file_helper() = default;
19 |     explicit file_helper(const file_event_handlers &event_handlers);
20 | 
21 |     file_helper(const file_helper &) = delete;
22 |     file_helper &operator=(const file_helper &) = delete;
23 |     ~file_helper();
24 | 
25 |     void open(const filename_t &fname, bool truncate = false);
26 |     void reopen(bool truncate);
27 |     void flush();
28 |     void sync();
29 |     void close();
30 |     void write(const memory_buf_t &buf);
31 |     size_t size() const;
32 |     const filename_t &filename() const;
33 | 
34 |     //
35 |     // return file path and its extension:
36 |     //
37 |     // "mylog.txt" => ("mylog", ".txt")
38 |     // "mylog" => ("mylog", "")
39 |     // "mylog." => ("mylog.", "")
40 |     // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
41 |     //
42 |     // the starting dot in filenames is ignored (hidden files):
43 |     //
44 |     // ".mylog" => (".mylog". "")
45 |     // "my_folder/.mylog" => ("my_folder/.mylog", "")
46 |     // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
47 |     static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
48 | 
49 | private:
50 |     const int open_tries_ = 5;
51 |     const unsigned int open_interval_ = 10;
52 |     std::FILE *fd_{nullptr};
53 |     filename_t filename_;
54 |     file_event_handlers event_handlers_;
55 | };
56 | }  // namespace details
57 | }  // namespace spdlog
58 | 
59 | #ifdef SPDLOG_HEADER_ONLY
60 |     #include "file_helper-inl.h"
61 | #endif
62 | 


--------------------------------------------------------------------------------
/include/spdlog/details/log_msg-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/details/log_msg.h>
 8 | #endif
 9 | 
10 | #include <spdlog/details/os.h>
11 | 
12 | namespace spdlog {
13 | namespace details {
14 | 
15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time,
16 |                                spdlog::source_loc loc,
17 |                                string_view_t a_logger_name,
18 |                                spdlog::level::level_enum lvl,
19 |                                spdlog::string_view_t msg)
20 |     : logger_name(a_logger_name),
21 |       level(lvl),
22 |       time(log_time)
23 | #ifndef SPDLOG_NO_THREAD_ID
24 |       ,
25 |       thread_id(os::thread_id())
26 | #endif
27 |       ,
28 |       source(loc),
29 |       payload(msg) {
30 | }
31 | 
32 | SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc,
33 |                                string_view_t a_logger_name,
34 |                                spdlog::level::level_enum lvl,
35 |                                spdlog::string_view_t msg)
36 |     : log_msg(os::now(), loc, a_logger_name, lvl, msg) {}
37 | 
38 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name,
39 |                                spdlog::level::level_enum lvl,
40 |                                spdlog::string_view_t msg)
41 |     : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {}
42 | 
43 | }  // namespace details
44 | }  // namespace spdlog
45 | 


--------------------------------------------------------------------------------
/include/spdlog/details/log_msg.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <string>
 8 | 
 9 | namespace spdlog {
10 | namespace details {
11 | struct SPDLOG_API log_msg {
12 |     log_msg() = default;
13 |     log_msg(log_clock::time_point log_time,
14 |             source_loc loc,
15 |             string_view_t logger_name,
16 |             level::level_enum lvl,
17 |             string_view_t msg);
18 |     log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
19 |     log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
20 |     log_msg(const log_msg &other) = default;
21 |     log_msg &operator=(const log_msg &other) = default;
22 | 
23 |     string_view_t logger_name;
24 |     level::level_enum level{level::off};
25 |     log_clock::time_point time;
26 |     size_t thread_id{0};
27 | 
28 |     // wrapping the formatted text with color (updated by pattern_formatter).
29 |     mutable size_t color_range_start{0};
30 |     mutable size_t color_range_end{0};
31 | 
32 |     source_loc source;
33 |     string_view_t payload;
34 | };
35 | }  // namespace details
36 | }  // namespace spdlog
37 | 
38 | #ifdef SPDLOG_HEADER_ONLY
39 |     #include "log_msg-inl.h"
40 | #endif
41 | 


--------------------------------------------------------------------------------
/include/spdlog/details/log_msg_buffer-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/details/log_msg_buffer.h>
 8 | #endif
 9 | 
10 | namespace spdlog {
11 | namespace details {
12 | 
13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
14 |     : log_msg{orig_msg} {
15 |     buffer.append(logger_name.begin(), logger_name.end());
16 |     buffer.append(payload.begin(), payload.end());
17 |     update_string_views();
18 | }
19 | 
20 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
21 |     : log_msg{other} {
22 |     buffer.append(logger_name.begin(), logger_name.end());
23 |     buffer.append(payload.begin(), payload.end());
24 |     update_string_views();
25 | }
26 | 
27 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT
28 |     : log_msg{other},
29 |       buffer{std::move(other.buffer)} {
30 |     update_string_views();
31 | }
32 | 
33 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) {
34 |     log_msg::operator=(other);
35 |     buffer.clear();
36 |     buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
37 |     update_string_views();
38 |     return *this;
39 | }
40 | 
41 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT {
42 |     log_msg::operator=(other);
43 |     buffer = std::move(other.buffer);
44 |     update_string_views();
45 |     return *this;
46 | }
47 | 
48 | SPDLOG_INLINE void log_msg_buffer::update_string_views() {
49 |     logger_name = string_view_t{buffer.data(), logger_name.size()};
50 |     payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
51 | }
52 | 
53 | }  // namespace details
54 | }  // namespace spdlog
55 | 


--------------------------------------------------------------------------------
/include/spdlog/details/log_msg_buffer.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/log_msg.h>
 7 | 
 8 | namespace spdlog {
 9 | namespace details {
10 | 
11 | // Extend log_msg with internal buffer to store its payload.
12 | // This is needed since log_msg holds string_views that points to stack data.
13 | 
14 | class SPDLOG_API log_msg_buffer : public log_msg {
15 |     memory_buf_t buffer;
16 |     void update_string_views();
17 | 
18 | public:
19 |     log_msg_buffer() = default;
20 |     explicit log_msg_buffer(const log_msg &orig_msg);
21 |     log_msg_buffer(const log_msg_buffer &other);
22 |     log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
23 |     log_msg_buffer &operator=(const log_msg_buffer &other);
24 |     log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
25 | };
26 | 
27 | }  // namespace details
28 | }  // namespace spdlog
29 | 
30 | #ifdef SPDLOG_HEADER_ONLY
31 |     #include "log_msg_buffer-inl.h"
32 | #endif
33 | 


--------------------------------------------------------------------------------
/include/spdlog/details/null_mutex.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <atomic>
 7 | #include <utility>
 8 | // null, no cost dummy "mutex" and dummy "atomic" int
 9 | 
10 | namespace spdlog {
11 | namespace details {
12 | struct null_mutex {
13 |     void lock() const {}
14 |     void unlock() const {}
15 | };
16 | 
17 | struct null_atomic_int {
18 |     int value;
19 |     null_atomic_int() = default;
20 | 
21 |     explicit null_atomic_int(int new_value)
22 |         : value(new_value) {}
23 | 
24 |     int load(std::memory_order = std::memory_order_relaxed) const { return value; }
25 | 
26 |     void store(int new_value, std::memory_order = std::memory_order_relaxed) { value = new_value; }
27 | 
28 |     int exchange(int new_value, std::memory_order = std::memory_order_relaxed) {
29 |         std::swap(new_value, value);
30 |         return new_value;  // return value before the call
31 |     }
32 | };
33 | 
34 | }  // namespace details
35 | }  // namespace spdlog
36 | 


--------------------------------------------------------------------------------
/include/spdlog/details/periodic_worker-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/details/periodic_worker.h>
 8 | #endif
 9 | 
10 | namespace spdlog {
11 | namespace details {
12 | 
13 | // stop the worker thread and join it
14 | SPDLOG_INLINE periodic_worker::~periodic_worker() {
15 |     if (worker_thread_.joinable()) {
16 |         {
17 |             std::lock_guard<std::mutex> lock(mutex_);
18 |             active_ = false;
19 |         }
20 |         cv_.notify_one();
21 |         worker_thread_.join();
22 |     }
23 | }
24 | 
25 | }  // namespace details
26 | }  // namespace spdlog
27 | 


--------------------------------------------------------------------------------
/include/spdlog/details/periodic_worker.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | // periodic worker thread - periodically executes the given callback function.
 7 | //
 8 | // RAII over the owned thread:
 9 | //    creates the thread on construction.
10 | //    stops and joins the thread on destruction (if the thread is executing a callback, wait for it
11 | //    to finish first).
12 | 
13 | #include <chrono>
14 | #include <condition_variable>
15 | #include <functional>
16 | #include <mutex>
17 | #include <thread>
18 | namespace spdlog {
19 | namespace details {
20 | 
21 | class SPDLOG_API periodic_worker {
22 | public:
23 |     template <typename Rep, typename Period>
24 |     periodic_worker(const std::function<void()> &callback_fun,
25 |                     std::chrono::duration<Rep, Period> interval) {
26 |         active_ = (interval > std::chrono::duration<Rep, Period>::zero());
27 |         if (!active_) {
28 |             return;
29 |         }
30 | 
31 |         worker_thread_ = std::thread([this, callback_fun, interval]() {
32 |             for (;;) {
33 |                 std::unique_lock<std::mutex> lock(this->mutex_);
34 |                 if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) {
35 |                     return;  // active_ == false, so exit this thread
36 |                 }
37 |                 callback_fun();
38 |             }
39 |         });
40 |     }
41 |     std::thread &get_thread() { return worker_thread_; }
42 |     periodic_worker(const periodic_worker &) = delete;
43 |     periodic_worker &operator=(const periodic_worker &) = delete;
44 |     // stop the worker thread and join it
45 |     ~periodic_worker();
46 | 
47 | private:
48 |     bool active_;
49 |     std::thread worker_thread_;
50 |     std::mutex mutex_;
51 |     std::condition_variable cv_;
52 | };
53 | }  // namespace details
54 | }  // namespace spdlog
55 | 
56 | #ifdef SPDLOG_HEADER_ONLY
57 |     #include "periodic_worker-inl.h"
58 | #endif
59 | 


--------------------------------------------------------------------------------
/include/spdlog/details/synchronous_factory.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include "registry.h"
 7 | 
 8 | namespace spdlog {
 9 | 
10 | // Default logger factory-  creates synchronous loggers
11 | class logger;
12 | 
13 | struct synchronous_factory {
14 |     template <typename Sink, typename... SinkArgs>
15 |     static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...args) {
16 |         auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
17 |         auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));
18 |         details::registry::instance().initialize_logger(new_logger);
19 |         return new_logger;
20 |     }
21 | };
22 | }  // namespace spdlog
23 | 


--------------------------------------------------------------------------------
/include/spdlog/details/tcp_client.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | #ifdef _WIN32
  7 |     #error include tcp_client-windows.h instead
  8 | #endif
  9 | 
 10 | // tcp client helper
 11 | #include <spdlog/common.h>
 12 | #include <spdlog/details/os.h>
 13 | 
 14 | #include <arpa/inet.h>
 15 | #include <netdb.h>
 16 | #include <netinet/in.h>
 17 | #include <netinet/tcp.h>
 18 | #include <sys/socket.h>
 19 | #include <unistd.h>
 20 | 
 21 | #include <string>
 22 | 
 23 | namespace spdlog {
 24 | namespace details {
 25 | class tcp_client {
 26 |     int socket_ = -1;
 27 | 
 28 | public:
 29 |     bool is_connected() const { return socket_ != -1; }
 30 | 
 31 |     void close() {
 32 |         if (is_connected()) {
 33 |             ::close(socket_);
 34 |             socket_ = -1;
 35 |         }
 36 |     }
 37 | 
 38 |     int fd() const { return socket_; }
 39 | 
 40 |     ~tcp_client() { close(); }
 41 | 
 42 |     // try to connect or throw on failure
 43 |     void connect(const std::string &host, int port) {
 44 |         close();
 45 |         struct addrinfo hints {};
 46 |         memset(&hints, 0, sizeof(struct addrinfo));
 47 |         hints.ai_family = AF_UNSPEC;      // To work with IPv4, IPv6, and so on
 48 |         hints.ai_socktype = SOCK_STREAM;  // TCP
 49 |         hints.ai_flags = AI_NUMERICSERV;  // port passed as as numeric value
 50 |         hints.ai_protocol = 0;
 51 | 
 52 |         auto port_str = std::to_string(port);
 53 |         struct addrinfo *addrinfo_result;
 54 |         auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
 55 |         if (rv != 0) {
 56 |             throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv)));
 57 |         }
 58 | 
 59 |         // Try each address until we successfully connect(2).
 60 |         int last_errno = 0;
 61 |         for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) {
 62 | #if defined(SOCK_CLOEXEC)
 63 |             const int flags = SOCK_CLOEXEC;
 64 | #else
 65 |             const int flags = 0;
 66 | #endif
 67 |             socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol);
 68 |             if (socket_ == -1) {
 69 |                 last_errno = errno;
 70 |                 continue;
 71 |             }
 72 |             rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
 73 |             if (rv == 0) {
 74 |                 break;
 75 |             }
 76 |             last_errno = errno;
 77 |             ::close(socket_);
 78 |             socket_ = -1;
 79 |         }
 80 |         ::freeaddrinfo(addrinfo_result);
 81 |         if (socket_ == -1) {
 82 |             throw_spdlog_ex("::connect failed", last_errno);
 83 |         }
 84 | 
 85 |         // set TCP_NODELAY
 86 |         int enable_flag = 1;
 87 |         ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag),
 88 |                      sizeof(enable_flag));
 89 | 
 90 |         // prevent sigpipe on systems where MSG_NOSIGNAL is not available
 91 | #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
 92 |         ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char *>(&enable_flag),
 93 |                      sizeof(enable_flag));
 94 | #endif
 95 | 
 96 | #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
 97 |     #error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
 98 | #endif
 99 |     }
100 | 
101 |     // Send exactly n_bytes of the given data.
102 |     // On error close the connection and throw.
103 |     void send(const char *data, size_t n_bytes) {
104 |         size_t bytes_sent = 0;
105 |         while (bytes_sent < n_bytes) {
106 | #if defined(MSG_NOSIGNAL)
107 |             const int send_flags = MSG_NOSIGNAL;
108 | #else
109 |             const int send_flags = 0;
110 | #endif
111 |             auto write_result =
112 |                 ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags);
113 |             if (write_result < 0) {
114 |                 close();
115 |                 throw_spdlog_ex("write(2) failed", errno);
116 |             }
117 | 
118 |             if (write_result == 0)  // (probably should not happen but in any case..)
119 |             {
120 |                 break;
121 |             }
122 |             bytes_sent += static_cast<size_t>(write_result);
123 |         }
124 |     }
125 | };
126 | }  // namespace details
127 | }  // namespace spdlog
128 | 


--------------------------------------------------------------------------------
/include/spdlog/details/thread_pool.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | #include <spdlog/details/log_msg_buffer.h>
  7 | #include <spdlog/details/mpmc_blocking_q.h>
  8 | #include <spdlog/details/os.h>
  9 | 
 10 | #include <chrono>
 11 | #include <functional>
 12 | #include <memory>
 13 | #include <thread>
 14 | #include <vector>
 15 | 
 16 | namespace spdlog {
 17 | class async_logger;
 18 | 
 19 | namespace details {
 20 | 
 21 | using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
 22 | 
 23 | enum class async_msg_type { log, flush, terminate };
 24 | 
 25 | // Async msg to move to/from the queue
 26 | // Movable only. should never be copied
 27 | struct async_msg : log_msg_buffer {
 28 |     async_msg_type msg_type{async_msg_type::log};
 29 |     async_logger_ptr worker_ptr;
 30 | 
 31 |     async_msg() = default;
 32 |     ~async_msg() = default;
 33 | 
 34 |     // should only be moved in or out of the queue..
 35 |     async_msg(const async_msg &) = delete;
 36 | 
 37 | // support for vs2013 move
 38 | #if defined(_MSC_VER) && _MSC_VER <= 1800
 39 |     async_msg(async_msg &&other)
 40 |         : log_msg_buffer(std::move(other)),
 41 |           msg_type(other.msg_type),
 42 |           worker_ptr(std::move(other.worker_ptr)) {}
 43 | 
 44 |     async_msg &operator=(async_msg &&other) {
 45 |         *static_cast<log_msg_buffer *>(this) = std::move(other);
 46 |         msg_type = other.msg_type;
 47 |         worker_ptr = std::move(other.worker_ptr);
 48 |         return *this;
 49 |     }
 50 | #else  // (_MSC_VER) && _MSC_VER <= 1800
 51 |     async_msg(async_msg &&) = default;
 52 |     async_msg &operator=(async_msg &&) = default;
 53 | #endif
 54 | 
 55 |     // construct from log_msg with given type
 56 |     async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m)
 57 |         : log_msg_buffer{m},
 58 |           msg_type{the_type},
 59 |           worker_ptr{std::move(worker)} {}
 60 | 
 61 |     async_msg(async_logger_ptr &&worker, async_msg_type the_type)
 62 |         : log_msg_buffer{},
 63 |           msg_type{the_type},
 64 |           worker_ptr{std::move(worker)} {}
 65 | 
 66 |     explicit async_msg(async_msg_type the_type)
 67 |         : async_msg{nullptr, the_type} {}
 68 | };
 69 | 
 70 | class SPDLOG_API thread_pool {
 71 | public:
 72 |     using item_type = async_msg;
 73 |     using q_type = details::mpmc_blocking_queue<item_type>;
 74 | 
 75 |     thread_pool(size_t q_max_items,
 76 |                 size_t threads_n,
 77 |                 std::function<void()> on_thread_start,
 78 |                 std::function<void()> on_thread_stop);
 79 |     thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);
 80 |     thread_pool(size_t q_max_items, size_t threads_n);
 81 | 
 82 |     // message all threads to terminate gracefully and join them
 83 |     ~thread_pool();
 84 | 
 85 |     thread_pool(const thread_pool &) = delete;
 86 |     thread_pool &operator=(thread_pool &&) = delete;
 87 | 
 88 |     void post_log(async_logger_ptr &&worker_ptr,
 89 |                   const details::log_msg &msg,
 90 |                   async_overflow_policy overflow_policy);
 91 |     void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);
 92 |     size_t overrun_counter();
 93 |     void reset_overrun_counter();
 94 |     size_t discard_counter();
 95 |     void reset_discard_counter();
 96 |     size_t queue_size();
 97 | 
 98 | private:
 99 |     q_type q_;
100 | 
101 |     std::vector<std::thread> threads_;
102 | 
103 |     void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy);
104 |     void worker_loop_();
105 | 
106 |     // process next message in the queue
107 |     // return true if this thread should still be active (while no terminate msg
108 |     // was received)
109 |     bool process_next_msg_();
110 | };
111 | 
112 | }  // namespace details
113 | }  // namespace spdlog
114 | 
115 | #ifdef SPDLOG_HEADER_ONLY
116 |     #include "thread_pool-inl.h"
117 | #endif
118 | 


--------------------------------------------------------------------------------
/include/spdlog/details/udp_client-windows.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | // Helper RAII over winsock udp client socket.
 7 | // Will throw on construction if socket creation failed.
 8 | 
 9 | #include <spdlog/common.h>
10 | #include <spdlog/details/os.h>
11 | #include <spdlog/details/windows_include.h>
12 | #include <stdio.h>
13 | #include <stdlib.h>
14 | #include <string>
15 | #include <winsock2.h>
16 | #include <ws2tcpip.h>
17 | 
18 | #if defined(_MSC_VER)
19 |     #pragma comment(lib, "Ws2_32.lib")
20 |     #pragma comment(lib, "Mswsock.lib")
21 |     #pragma comment(lib, "AdvApi32.lib")
22 | #endif
23 | 
24 | namespace spdlog {
25 | namespace details {
26 | class udp_client {
27 |     static constexpr int TX_BUFFER_SIZE = 1024 * 10;
28 |     SOCKET socket_ = INVALID_SOCKET;
29 |     sockaddr_in addr_ = {};
30 | 
31 |     static void init_winsock_() {
32 |         WSADATA wsaData;
33 |         auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
34 |         if (rv != 0) {
35 |             throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
36 |         }
37 |     }
38 | 
39 |     static void throw_winsock_error_(const std::string &msg, int last_error) {
40 |         char buf[512];
41 |         ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
42 |                          last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf,
43 |                          (sizeof(buf) / sizeof(char)), NULL);
44 | 
45 |         throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf));
46 |     }
47 | 
48 |     void cleanup_() {
49 |         if (socket_ != INVALID_SOCKET) {
50 |             ::closesocket(socket_);
51 |         }
52 |         socket_ = INVALID_SOCKET;
53 |         ::WSACleanup();
54 |     }
55 | 
56 | public:
57 |     udp_client(const std::string &host, uint16_t port) {
58 |         init_winsock_();
59 | 
60 |         addr_.sin_family = PF_INET;
61 |         addr_.sin_port = htons(port);
62 |         addr_.sin_addr.s_addr = INADDR_ANY;
63 |         if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) {
64 |             int last_error = ::WSAGetLastError();
65 |             ::WSACleanup();
66 |             throw_winsock_error_("error: Invalid address!", last_error);
67 |         }
68 | 
69 |         socket_ = ::socket(PF_INET, SOCK_DGRAM, 0);
70 |         if (socket_ == INVALID_SOCKET) {
71 |             int last_error = ::WSAGetLastError();
72 |             ::WSACleanup();
73 |             throw_winsock_error_("error: Create Socket failed", last_error);
74 |         }
75 | 
76 |         int option_value = TX_BUFFER_SIZE;
77 |         if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
78 |                          reinterpret_cast<const char *>(&option_value), sizeof(option_value)) < 0) {
79 |             int last_error = ::WSAGetLastError();
80 |             cleanup_();
81 |             throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error);
82 |         }
83 |     }
84 | 
85 |     ~udp_client() { cleanup_(); }
86 | 
87 |     SOCKET fd() const { return socket_; }
88 | 
89 |     void send(const char *data, size_t n_bytes) {
90 |         socklen_t tolen = sizeof(struct sockaddr);
91 |         if (::sendto(socket_, data, static_cast<int>(n_bytes), 0, (struct sockaddr *)&addr_,
92 |                      tolen) == -1) {
93 |             throw_spdlog_ex("sendto(2) failed", errno);
94 |         }
95 |     }
96 | };
97 | }  // namespace details
98 | }  // namespace spdlog
99 | 


--------------------------------------------------------------------------------
/include/spdlog/details/udp_client.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | // Helper RAII over unix udp client socket.
 7 | // Will throw on construction if the socket creation failed.
 8 | 
 9 | #ifdef _WIN32
10 |     #error "include udp_client-windows.h instead"
11 | #endif
12 | 
13 | #include <arpa/inet.h>
14 | #include <cstring>
15 | #include <netdb.h>
16 | #include <netinet/in.h>
17 | #include <netinet/udp.h>
18 | #include <spdlog/common.h>
19 | #include <spdlog/details/os.h>
20 | #include <sys/socket.h>
21 | #include <unistd.h>
22 | 
23 | #include <string>
24 | 
25 | namespace spdlog {
26 | namespace details {
27 | 
28 | class udp_client {
29 |     static constexpr int TX_BUFFER_SIZE = 1024 * 10;
30 |     int socket_ = -1;
31 |     struct sockaddr_in sockAddr_;
32 | 
33 |     void cleanup_() {
34 |         if (socket_ != -1) {
35 |             ::close(socket_);
36 |             socket_ = -1;
37 |         }
38 |     }
39 | 
40 | public:
41 |     udp_client(const std::string &host, uint16_t port) {
42 |         socket_ = ::socket(PF_INET, SOCK_DGRAM, 0);
43 |         if (socket_ < 0) {
44 |             throw_spdlog_ex("error: Create Socket Failed!");
45 |         }
46 | 
47 |         int option_value = TX_BUFFER_SIZE;
48 |         if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
49 |                          reinterpret_cast<const char *>(&option_value), sizeof(option_value)) < 0) {
50 |             cleanup_();
51 |             throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!");
52 |         }
53 | 
54 |         sockAddr_.sin_family = AF_INET;
55 |         sockAddr_.sin_port = htons(port);
56 | 
57 |         if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) {
58 |             cleanup_();
59 |             throw_spdlog_ex("error: Invalid address!");
60 |         }
61 | 
62 |         ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero));
63 |     }
64 | 
65 |     ~udp_client() { cleanup_(); }
66 | 
67 |     int fd() const { return socket_; }
68 | 
69 |     // Send exactly n_bytes of the given data.
70 |     // On error close the connection and throw.
71 |     void send(const char *data, size_t n_bytes) {
72 |         ssize_t toslen = 0;
73 |         socklen_t tolen = sizeof(struct sockaddr);
74 |         if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) ==
75 |             -1) {
76 |             throw_spdlog_ex("sendto(2) failed", errno);
77 |         }
78 |     }
79 | };
80 | }  // namespace details
81 | }  // namespace spdlog
82 | 


--------------------------------------------------------------------------------
/include/spdlog/details/windows_include.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #ifndef NOMINMAX
 4 |     #define NOMINMAX  // prevent windows redefining min/max
 5 | #endif
 6 | 
 7 | #ifndef WIN32_LEAN_AND_MEAN
 8 |     #define WIN32_LEAN_AND_MEAN
 9 | #endif
10 | 
11 | #include <windows.h>
12 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/core.h:
--------------------------------------------------------------------------------
1 | // This file is only provided for compatibility and may be removed in future
2 | // versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h
3 | // otherwise.
4 | 
5 | #include "format.h"
6 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/fmt.license.rst:
--------------------------------------------------------------------------------
 1 | Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
 2 | 
 3 | Permission is hereby granted, free of charge, to any person obtaining
 4 | a copy of this software and associated documentation files (the
 5 | "Software"), to deal in the Software without restriction, including
 6 | without limitation the rights to use, copy, modify, merge, publish,
 7 | distribute, sublicense, and/or sell copies of the Software, and to
 8 | permit persons to whom the Software is furnished to do so, subject to
 9 | the following conditions:
10 | 
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 | 
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 | 
22 | --- Optional exception to the license ---
23 | 
24 | As an exception, if, as a result of your compiling your source code, portions
25 | of this Software are embedded into a machine-executable object form of such
26 | source code, you may redistribute such embedded portions in such object form
27 | without including the above copyright and permission notices.
28 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/chrono.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's chrono support
 9 | //
10 | #include <spdlog/tweakme.h>
11 | 
12 | #if !defined(SPDLOG_USE_STD_FORMAT)
13 |     #if !defined(SPDLOG_FMT_EXTERNAL)
14 |         #ifdef SPDLOG_HEADER_ONLY
15 |             #ifndef FMT_HEADER_ONLY
16 |                 #define FMT_HEADER_ONLY
17 |             #endif
18 |         #endif
19 |         #include <spdlog/fmt/bundled/chrono.h>
20 |     #else
21 |         #include <fmt/chrono.h>
22 |     #endif
23 | #endif
24 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/compile.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's compile-time support
 9 | //
10 | #include <spdlog/tweakme.h>
11 | 
12 | #if !defined(SPDLOG_USE_STD_FORMAT)
13 |     #if !defined(SPDLOG_FMT_EXTERNAL)
14 |         #ifdef SPDLOG_HEADER_ONLY
15 |             #ifndef FMT_HEADER_ONLY
16 |                 #define FMT_HEADER_ONLY
17 |             #endif
18 |         #endif
19 |         #include <spdlog/fmt/bundled/compile.h>
20 |     #else
21 |         #include <fmt/compile.h>
22 |     #endif
23 | #endif
24 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/fmt.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016-2018 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | 
 8 | //
 9 | // Include a bundled header-only copy of fmtlib or an external one.
10 | // By default spdlog include its own copy.
11 | //
12 | #include <spdlog/tweakme.h>
13 | 
14 | #if defined(SPDLOG_USE_STD_FORMAT)  // SPDLOG_USE_STD_FORMAT is defined - use std::format
15 |     #include <format>
16 | #elif !defined(SPDLOG_FMT_EXTERNAL)
17 |     #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY)
18 |         #define FMT_HEADER_ONLY
19 |     #endif
20 |     #ifndef FMT_USE_WINDOWS_H
21 |         #define FMT_USE_WINDOWS_H 0
22 |     #endif
23 |     #include <spdlog/fmt/bundled/format.h>
24 | #else  // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
25 |     #include <fmt/format.h>
26 | #endif
27 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/ostr.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's ostream support
 9 | //
10 | #include <spdlog/tweakme.h>
11 | 
12 | #if !defined(SPDLOG_USE_STD_FORMAT)
13 |     #if !defined(SPDLOG_FMT_EXTERNAL)
14 |         #ifdef SPDLOG_HEADER_ONLY
15 |             #ifndef FMT_HEADER_ONLY
16 |                 #define FMT_HEADER_ONLY
17 |             #endif
18 |         #endif
19 |         #include <spdlog/fmt/bundled/ostream.h>
20 |     #else
21 |         #include <fmt/ostream.h>
22 |     #endif
23 | #endif
24 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/ranges.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's ranges support
 9 | //
10 | #include <spdlog/tweakme.h>
11 | 
12 | #if !defined(SPDLOG_USE_STD_FORMAT)
13 |     #if !defined(SPDLOG_FMT_EXTERNAL)
14 |         #ifdef SPDLOG_HEADER_ONLY
15 |             #ifndef FMT_HEADER_ONLY
16 |                 #define FMT_HEADER_ONLY
17 |             #endif
18 |         #endif
19 |         #include <spdlog/fmt/bundled/ranges.h>
20 |     #else
21 |         #include <fmt/ranges.h>
22 |     #endif
23 | #endif
24 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/std.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's std support (for formatting e.g.
 9 | // std::filesystem::path, std::thread::id, std::monostate, std::variant, ...)
10 | //
11 | #include <spdlog/tweakme.h>
12 | 
13 | #if !defined(SPDLOG_USE_STD_FORMAT)
14 |     #if !defined(SPDLOG_FMT_EXTERNAL)
15 |         #ifdef SPDLOG_HEADER_ONLY
16 |             #ifndef FMT_HEADER_ONLY
17 |                 #define FMT_HEADER_ONLY
18 |             #endif
19 |         #endif
20 |         #include <spdlog/fmt/bundled/std.h>
21 |     #else
22 |         #include <fmt/std.h>
23 |     #endif
24 | #endif
25 | 


--------------------------------------------------------------------------------
/include/spdlog/fmt/xchar.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2016 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | //
 8 | // include bundled or external copy of fmtlib's xchar support
 9 | //
10 | #include <spdlog/tweakme.h>
11 | 
12 | #if !defined(SPDLOG_USE_STD_FORMAT)
13 |     #if !defined(SPDLOG_FMT_EXTERNAL)
14 |         #ifdef SPDLOG_HEADER_ONLY
15 |             #ifndef FMT_HEADER_ONLY
16 |                 #define FMT_HEADER_ONLY
17 |             #endif
18 |         #endif
19 |         #include <spdlog/fmt/bundled/xchar.h>
20 |     #else
21 |         #include <fmt/xchar.h>
22 |     #endif
23 | #endif
24 | 


--------------------------------------------------------------------------------
/include/spdlog/formatter.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/log_msg.h>
 7 | #include <spdlog/fmt/fmt.h>
 8 | 
 9 | namespace spdlog {
10 | 
11 | class formatter {
12 | public:
13 |     virtual ~formatter() = default;
14 |     virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0;
15 |     virtual std::unique_ptr<formatter> clone() const = 0;
16 | };
17 | }  // namespace spdlog
18 | 


--------------------------------------------------------------------------------
/include/spdlog/fwd.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | namespace spdlog {
 7 | class logger;
 8 | class formatter;
 9 | 
10 | namespace sinks {
11 | class sink;
12 | }
13 | 
14 | namespace level {
15 | enum level_enum : int;
16 | }
17 | 
18 | }  // namespace spdlog
19 | 


--------------------------------------------------------------------------------
/include/spdlog/mdc.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #if defined(SPDLOG_NO_TLS)
 7 |     #error "This header requires thread local storage support, but SPDLOG_NO_TLS is defined."
 8 | #endif
 9 | 
10 | #include <map>
11 | #include <string>
12 | 
13 | #include <spdlog/common.h>
14 | 
15 | // MDC is a simple map of key->string values stored in thread local storage whose content will be
16 | // printed by the loggers. Note: Not supported in async mode (thread local storage - so the async
17 | // thread pool have different copy).
18 | //
19 | // Usage example:
20 | // spdlog::mdc::put("mdc_key_1", "mdc_value_1");
21 | // spdlog::info("Hello, {}", "World!");  // => [2024-04-26 02:08:05.040] [info]
22 | // [mdc_key_1:mdc_value_1] Hello, World!
23 | 
24 | namespace spdlog {
25 | class SPDLOG_API mdc {
26 | public:
27 |     using mdc_map_t = std::map<std::string, std::string>;
28 | 
29 |     static void put(const std::string &key, const std::string &value) {
30 |         get_context()[key] = value;
31 |     }
32 | 
33 |     static std::string get(const std::string &key) {
34 |         auto &context = get_context();
35 |         auto it = context.find(key);
36 |         if (it != context.end()) {
37 |             return it->second;
38 |         }
39 |         return "";
40 |     }
41 | 
42 |     static void remove(const std::string &key) { get_context().erase(key); }
43 | 
44 |     static void clear() { get_context().clear(); }
45 | 
46 |     static mdc_map_t &get_context() {
47 |         static thread_local mdc_map_t context;
48 |         return context;
49 |     }
50 | };
51 | 
52 | }  // namespace spdlog
53 | 


--------------------------------------------------------------------------------
/include/spdlog/pattern_formatter.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | #include <spdlog/common.h>
  7 | #include <spdlog/details/log_msg.h>
  8 | #include <spdlog/details/os.h>
  9 | #include <spdlog/formatter.h>
 10 | 
 11 | #include <chrono>
 12 | #include <ctime>
 13 | #include <memory>
 14 | 
 15 | #include <string>
 16 | #include <unordered_map>
 17 | #include <vector>
 18 | 
 19 | namespace spdlog {
 20 | namespace details {
 21 | 
 22 | // padding information.
 23 | struct padding_info {
 24 |     enum class pad_side { left, right, center };
 25 | 
 26 |     padding_info() = default;
 27 |     padding_info(size_t width, padding_info::pad_side side, bool truncate)
 28 |         : width_(width),
 29 |           side_(side),
 30 |           truncate_(truncate),
 31 |           enabled_(true) {}
 32 | 
 33 |     bool enabled() const { return enabled_; }
 34 |     size_t width_ = 0;
 35 |     pad_side side_ = pad_side::left;
 36 |     bool truncate_ = false;
 37 |     bool enabled_ = false;
 38 | };
 39 | 
 40 | class SPDLOG_API flag_formatter {
 41 | public:
 42 |     explicit flag_formatter(padding_info padinfo)
 43 |         : padinfo_(padinfo) {}
 44 |     flag_formatter() = default;
 45 |     virtual ~flag_formatter() = default;
 46 |     virtual void format(const details::log_msg &msg,
 47 |                         const std::tm &tm_time,
 48 |                         memory_buf_t &dest) = 0;
 49 | 
 50 | protected:
 51 |     padding_info padinfo_;
 52 | };
 53 | 
 54 | }  // namespace details
 55 | 
 56 | class SPDLOG_API custom_flag_formatter : public details::flag_formatter {
 57 | public:
 58 |     virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
 59 | 
 60 |     void set_padding_info(const details::padding_info &padding) {
 61 |         flag_formatter::padinfo_ = padding;
 62 |     }
 63 | };
 64 | 
 65 | class SPDLOG_API pattern_formatter final : public formatter {
 66 | public:
 67 |     using custom_flags = std::unordered_map<char, std::unique_ptr<custom_flag_formatter>>;
 68 | 
 69 |     explicit pattern_formatter(std::string pattern,
 70 |                                pattern_time_type time_type = pattern_time_type::local,
 71 |                                std::string eol = spdlog::details::os::default_eol,
 72 |                                custom_flags custom_user_flags = custom_flags());
 73 | 
 74 |     // use default pattern is not given
 75 |     explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local,
 76 |                                std::string eol = spdlog::details::os::default_eol);
 77 | 
 78 |     pattern_formatter(const pattern_formatter &other) = delete;
 79 |     pattern_formatter &operator=(const pattern_formatter &other) = delete;
 80 | 
 81 |     std::unique_ptr<formatter> clone() const override;
 82 |     void format(const details::log_msg &msg, memory_buf_t &dest) override;
 83 | 
 84 |     template <typename T, typename... Args>
 85 |     pattern_formatter &add_flag(char flag, Args &&...args) {
 86 |         custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...);
 87 |         return *this;
 88 |     }
 89 |     void set_pattern(std::string pattern);
 90 |     void need_localtime(bool need = true);
 91 | 
 92 | private:
 93 |     std::string pattern_;
 94 |     std::string eol_;
 95 |     pattern_time_type pattern_time_type_;
 96 |     bool need_localtime_;
 97 |     std::tm cached_tm_;
 98 |     std::chrono::seconds last_log_secs_;
 99 |     std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
100 |     custom_flags custom_handlers_;
101 | 
102 |     std::tm get_time_(const details::log_msg &msg);
103 |     template <typename Padder>
104 |     void handle_flag_(char flag, details::padding_info padding);
105 | 
106 |     // Extract given pad spec (e.g. %8X)
107 |     // Advance the given it pass the end of the padding spec found (if any)
108 |     // Return padding.
109 |     static details::padding_info handle_padspec_(std::string::const_iterator &it,
110 |                                                  std::string::const_iterator end);
111 | 
112 |     void compile_pattern_(const std::string &pattern);
113 | };
114 | }  // namespace spdlog
115 | 
116 | #ifdef SPDLOG_HEADER_ONLY
117 |     #include "pattern_formatter-inl.h"
118 | #endif
119 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/base_sink-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/sinks/base_sink.h>
 8 | #endif
 9 | 
10 | #include <spdlog/common.h>
11 | #include <spdlog/pattern_formatter.h>
12 | 
13 | #include <memory>
14 | #include <mutex>
15 | 
16 | template <typename Mutex>
17 | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink()
18 |     : formatter_{details::make_unique<spdlog::pattern_formatter>()} {}
19 | 
20 | template <typename Mutex>
21 | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink(
22 |     std::unique_ptr<spdlog::formatter> formatter)
23 |     : formatter_{std::move(formatter)} {}
24 | 
25 | template <typename Mutex>
26 | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg) {
27 |     std::lock_guard<Mutex> lock(mutex_);
28 |     sink_it_(msg);
29 | }
30 | 
31 | template <typename Mutex>
32 | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush() {
33 |     std::lock_guard<Mutex> lock(mutex_);
34 |     flush_();
35 | }
36 | 
37 | template <typename Mutex>
38 | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern) {
39 |     std::lock_guard<Mutex> lock(mutex_);
40 |     set_pattern_(pattern);
41 | }
42 | 
43 | template <typename Mutex>
44 | void SPDLOG_INLINE
45 | spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) {
46 |     std::lock_guard<Mutex> lock(mutex_);
47 |     set_formatter_(std::move(sink_formatter));
48 | }
49 | 
50 | template <typename Mutex>
51 | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern) {
52 |     set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
53 | }
54 | 
55 | template <typename Mutex>
56 | void SPDLOG_INLINE
57 | spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) {
58 |     formatter_ = std::move(sink_formatter);
59 | }
60 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/base_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | //
 6 | // base sink templated over a mutex (either dummy or real)
 7 | // concrete implementation should override the sink_it_() and flush_()  methods.
 8 | // locking is taken care of in this class - no locking needed by the
 9 | // implementers..
10 | //
11 | 
12 | #include <spdlog/common.h>
13 | #include <spdlog/details/log_msg.h>
14 | #include <spdlog/sinks/sink.h>
15 | 
16 | namespace spdlog {
17 | namespace sinks {
18 | template <typename Mutex>
19 | class SPDLOG_API base_sink : public sink {
20 | public:
21 |     base_sink();
22 |     explicit base_sink(std::unique_ptr<spdlog::formatter> formatter);
23 |     ~base_sink() override = default;
24 | 
25 |     base_sink(const base_sink &) = delete;
26 |     base_sink(base_sink &&) = delete;
27 | 
28 |     base_sink &operator=(const base_sink &) = delete;
29 |     base_sink &operator=(base_sink &&) = delete;
30 | 
31 |     void log(const details::log_msg &msg) final override;
32 |     void flush() final override;
33 |     void set_pattern(const std::string &pattern) final override;
34 |     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final override;
35 | 
36 | protected:
37 |     // sink formatter
38 |     std::unique_ptr<spdlog::formatter> formatter_;
39 |     Mutex mutex_;
40 | 
41 |     virtual void sink_it_(const details::log_msg &msg) = 0;
42 |     virtual void flush_() = 0;
43 |     virtual void set_pattern_(const std::string &pattern);
44 |     virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter);
45 | };
46 | }  // namespace sinks
47 | }  // namespace spdlog
48 | 
49 | #ifdef SPDLOG_HEADER_ONLY
50 |     #include "base_sink-inl.h"
51 | #endif
52 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/basic_file_sink-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/sinks/basic_file_sink.h>
 8 | #endif
 9 | 
10 | #include <spdlog/common.h>
11 | #include <spdlog/details/os.h>
12 | 
13 | namespace spdlog {
14 | namespace sinks {
15 | 
16 | template <typename Mutex>
17 | SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename,
18 |                                                       bool truncate,
19 |                                                       const file_event_handlers &event_handlers)
20 |     : file_helper_{event_handlers} {
21 |     file_helper_.open(filename, truncate);
22 | }
23 | 
24 | template <typename Mutex>
25 | SPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const {
26 |     return file_helper_.filename();
27 | }
28 | 
29 | template <typename Mutex>
30 | SPDLOG_INLINE void basic_file_sink<Mutex>::truncate() {
31 |     std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
32 |     file_helper_.reopen(true);
33 | }
34 | 
35 | template <typename Mutex>
36 | SPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg) {
37 |     memory_buf_t formatted;
38 |     base_sink<Mutex>::formatter_->format(msg, formatted);
39 |     file_helper_.write(formatted);
40 | }
41 | 
42 | template <typename Mutex>
43 | SPDLOG_INLINE void basic_file_sink<Mutex>::flush_() {
44 |     file_helper_.flush();
45 | }
46 | 
47 | }  // namespace sinks
48 | }  // namespace spdlog
49 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/basic_file_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/file_helper.h>
 7 | #include <spdlog/details/null_mutex.h>
 8 | #include <spdlog/details/synchronous_factory.h>
 9 | #include <spdlog/sinks/base_sink.h>
10 | 
11 | #include <mutex>
12 | #include <string>
13 | 
14 | namespace spdlog {
15 | namespace sinks {
16 | /*
17 |  * Trivial file sink with single file as target
18 |  */
19 | template <typename Mutex>
20 | class basic_file_sink final : public base_sink<Mutex> {
21 | public:
22 |     explicit basic_file_sink(const filename_t &filename,
23 |                              bool truncate = false,
24 |                              const file_event_handlers &event_handlers = {});
25 |     const filename_t &filename() const;
26 |     void truncate();
27 | 
28 | protected:
29 |     void sink_it_(const details::log_msg &msg) override;
30 |     void flush_() override;
31 | 
32 | private:
33 |     details::file_helper file_helper_;
34 | };
35 | 
36 | using basic_file_sink_mt = basic_file_sink<std::mutex>;
37 | using basic_file_sink_st = basic_file_sink<details::null_mutex>;
38 | 
39 | }  // namespace sinks
40 | 
41 | //
42 | // factory functions
43 | //
44 | template <typename Factory = spdlog::synchronous_factory>
45 | inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name,
46 |                                                const filename_t &filename,
47 |                                                bool truncate = false,
48 |                                                const file_event_handlers &event_handlers = {}) {
49 |     return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate,
50 |                                                                event_handlers);
51 | }
52 | 
53 | template <typename Factory = spdlog::synchronous_factory>
54 | inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name,
55 |                                                const filename_t &filename,
56 |                                                bool truncate = false,
57 |                                                const file_event_handlers &event_handlers = {}) {
58 |     return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate,
59 |                                                                event_handlers);
60 | }
61 | 
62 | }  // namespace spdlog
63 | 
64 | #ifdef SPDLOG_HEADER_ONLY
65 |     #include "basic_file_sink-inl.h"
66 | #endif
67 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/callback_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/null_mutex.h>
 7 | #include <spdlog/details/synchronous_factory.h>
 8 | #include <spdlog/sinks/base_sink.h>
 9 | 
10 | #include <mutex>
11 | #include <string>
12 | 
13 | namespace spdlog {
14 | 
15 | // callbacks type
16 | typedef std::function<void(const details::log_msg &msg)> custom_log_callback;
17 | 
18 | namespace sinks {
19 | /*
20 |  * Trivial callback sink, gets a callback function and calls it on each log
21 |  */
22 | template <typename Mutex>
23 | class callback_sink final : public base_sink<Mutex> {
24 | public:
25 |     explicit callback_sink(const custom_log_callback &callback)
26 |         : callback_{callback} {}
27 | 
28 | protected:
29 |     void sink_it_(const details::log_msg &msg) override { callback_(msg); }
30 |     void flush_() override {}
31 | 
32 | private:
33 |     custom_log_callback callback_;
34 | };
35 | 
36 | using callback_sink_mt = callback_sink<std::mutex>;
37 | using callback_sink_st = callback_sink<details::null_mutex>;
38 | 
39 | }  // namespace sinks
40 | 
41 | //
42 | // factory functions
43 | //
44 | template <typename Factory = spdlog::synchronous_factory>
45 | inline std::shared_ptr<logger> callback_logger_mt(const std::string &logger_name,
46 |                                                   const custom_log_callback &callback) {
47 |     return Factory::template create<sinks::callback_sink_mt>(logger_name, callback);
48 | }
49 | 
50 | template <typename Factory = spdlog::synchronous_factory>
51 | inline std::shared_ptr<logger> callback_logger_st(const std::string &logger_name,
52 |                                                   const custom_log_callback &callback) {
53 |     return Factory::template create<sinks::callback_sink_st>(logger_name, callback);
54 | }
55 | 
56 | }  // namespace spdlog
57 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/dist_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include "base_sink.h"
 7 | #include <spdlog/details/log_msg.h>
 8 | #include <spdlog/details/null_mutex.h>
 9 | #include <spdlog/pattern_formatter.h>
10 | 
11 | #include <algorithm>
12 | #include <memory>
13 | #include <mutex>
14 | #include <vector>
15 | 
16 | // Distribution sink (mux). Stores a vector of sinks which get called when log
17 | // is called
18 | 
19 | namespace spdlog {
20 | namespace sinks {
21 | 
22 | template <typename Mutex>
23 | class dist_sink : public base_sink<Mutex> {
24 | public:
25 |     dist_sink() = default;
26 |     explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks)
27 |         : sinks_(sinks) {}
28 | 
29 |     dist_sink(const dist_sink &) = delete;
30 |     dist_sink &operator=(const dist_sink &) = delete;
31 | 
32 |     void add_sink(std::shared_ptr<sink> sub_sink) {
33 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
34 |         sinks_.push_back(sub_sink);
35 |     }
36 | 
37 |     void remove_sink(std::shared_ptr<sink> sub_sink) {
38 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
39 |         sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end());
40 |     }
41 | 
42 |     void set_sinks(std::vector<std::shared_ptr<sink>> sinks) {
43 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
44 |         sinks_ = std::move(sinks);
45 |     }
46 | 
47 |     std::vector<std::shared_ptr<sink>> &sinks() { return sinks_; }
48 | 
49 | protected:
50 |     void sink_it_(const details::log_msg &msg) override {
51 |         for (auto &sub_sink : sinks_) {
52 |             if (sub_sink->should_log(msg.level)) {
53 |                 sub_sink->log(msg);
54 |             }
55 |         }
56 |     }
57 | 
58 |     void flush_() override {
59 |         for (auto &sub_sink : sinks_) {
60 |             sub_sink->flush();
61 |         }
62 |     }
63 | 
64 |     void set_pattern_(const std::string &pattern) override {
65 |         set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
66 |     }
67 | 
68 |     void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override {
69 |         base_sink<Mutex>::formatter_ = std::move(sink_formatter);
70 |         for (auto &sub_sink : sinks_) {
71 |             sub_sink->set_formatter(base_sink<Mutex>::formatter_->clone());
72 |         }
73 |     }
74 |     std::vector<std::shared_ptr<sink>> sinks_;
75 | };
76 | 
77 | using dist_sink_mt = dist_sink<std::mutex>;
78 | using dist_sink_st = dist_sink<details::null_mutex>;
79 | 
80 | }  // namespace sinks
81 | }  // namespace spdlog
82 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/dup_filter_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include "dist_sink.h"
 7 | #include <spdlog/details/log_msg.h>
 8 | #include <spdlog/details/null_mutex.h>
 9 | 
10 | #include <chrono>
11 | #include <cstdio>
12 | #include <mutex>
13 | #include <string>
14 | 
15 | // Duplicate message removal sink.
16 | // Skip the message if previous one is identical and less than "max_skip_duration" have passed
17 | //
18 | // Example:
19 | //
20 | //     #include <spdlog/sinks/dup_filter_sink.h>
21 | //
22 | //     int main() {
23 | //         auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5),
24 | //         level::info); dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());
25 | //         spdlog::logger l("logger", dup_filter);
26 | //         l.info("Hello");
27 | //         l.info("Hello");
28 | //         l.info("Hello");
29 | //         l.info("Different Hello");
30 | //     }
31 | //
32 | // Will produce:
33 | //       [2019-06-25 17:50:56.511] [logger] [info] Hello
34 | //       [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
35 | //       [2019-06-25 17:50:56.512] [logger] [info] Different Hello
36 | 
37 | namespace spdlog {
38 | namespace sinks {
39 | template <typename Mutex>
40 | class dup_filter_sink : public dist_sink<Mutex> {
41 | public:
42 |     template <class Rep, class Period>
43 |     explicit dup_filter_sink(std::chrono::duration<Rep, Period> max_skip_duration)
44 |         : max_skip_duration_{max_skip_duration} {}
45 | 
46 | protected:
47 |     std::chrono::microseconds max_skip_duration_;
48 |     log_clock::time_point last_msg_time_;
49 |     std::string last_msg_payload_;
50 |     size_t skip_counter_ = 0;
51 |     level::level_enum skipped_msg_log_level_ = spdlog::level::level_enum::off;
52 | 
53 |     void sink_it_(const details::log_msg &msg) override {
54 |         bool filtered = filter_(msg);
55 |         if (!filtered) {
56 |             skip_counter_ += 1;
57 |             skipped_msg_log_level_ = msg.level;
58 |             return;
59 |         }
60 | 
61 |         // log the "skipped.." message
62 |         if (skip_counter_ > 0) {
63 |             char buf[64];
64 |             auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..",
65 |                                        static_cast<unsigned>(skip_counter_));
66 |             if (msg_size > 0 && static_cast<size_t>(msg_size) < sizeof(buf)) {
67 |                 details::log_msg skipped_msg{msg.source, msg.logger_name, skipped_msg_log_level_,
68 |                                              string_view_t{buf, static_cast<size_t>(msg_size)}};
69 |                 dist_sink<Mutex>::sink_it_(skipped_msg);
70 |             }
71 |         }
72 | 
73 |         // log current message
74 |         dist_sink<Mutex>::sink_it_(msg);
75 |         last_msg_time_ = msg.time;
76 |         skip_counter_ = 0;
77 |         last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size());
78 |     }
79 | 
80 |     // return whether the log msg should be displayed (true) or skipped (false)
81 |     bool filter_(const details::log_msg &msg) {
82 |         auto filter_duration = msg.time - last_msg_time_;
83 |         return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_);
84 |     }
85 | };
86 | 
87 | using dup_filter_sink_mt = dup_filter_sink<std::mutex>;
88 | using dup_filter_sink_st = dup_filter_sink<details::null_mutex>;
89 | 
90 | }  // namespace sinks
91 | }  // namespace spdlog
92 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/mongo_sink.h:
--------------------------------------------------------------------------------
  1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3 | 
  4 | #pragma once
  5 | 
  6 | //
  7 | // Custom sink for mongodb
  8 | // Building and using requires mongocxx library.
  9 | // For building mongocxx library check the url below
 10 | // http://mongocxx.org/mongocxx-v3/installation/
 11 | //
 12 | 
 13 | #include "spdlog/common.h"
 14 | #include "spdlog/details/log_msg.h"
 15 | #include "spdlog/sinks/base_sink.h"
 16 | #include <spdlog/details/synchronous_factory.h>
 17 | 
 18 | #include <bsoncxx/builder/stream/document.hpp>
 19 | #include <bsoncxx/types.hpp>
 20 | #include <bsoncxx/view_or_value.hpp>
 21 | 
 22 | #include <mongocxx/client.hpp>
 23 | #include <mongocxx/instance.hpp>
 24 | #include <mongocxx/uri.hpp>
 25 | 
 26 | namespace spdlog {
 27 | namespace sinks {
 28 | template <typename Mutex>
 29 | class mongo_sink : public base_sink<Mutex> {
 30 | public:
 31 |     mongo_sink(const std::string &db_name,
 32 |                const std::string &collection_name,
 33 |                const std::string &uri = "mongodb://localhost:27017") try
 34 |         : mongo_sink(std::make_shared<mongocxx::instance>(), db_name, collection_name, uri) {
 35 |     } catch (const std::exception &e) {
 36 |         throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what()));
 37 |     }
 38 | 
 39 |     mongo_sink(std::shared_ptr<mongocxx::instance> instance,
 40 |                const std::string &db_name,
 41 |                const std::string &collection_name,
 42 |                const std::string &uri = "mongodb://localhost:27017")
 43 |         : instance_(std::move(instance)),
 44 |           db_name_(db_name),
 45 |           coll_name_(collection_name) {
 46 |         try {
 47 |             client_ = spdlog::details::make_unique<mongocxx::client>(mongocxx::uri{uri});
 48 |         } catch (const std::exception &e) {
 49 |             throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what()));
 50 |         }
 51 |     }
 52 | 
 53 |     ~mongo_sink() { flush_(); }
 54 | 
 55 | protected:
 56 |     void sink_it_(const details::log_msg &msg) override {
 57 |         using bsoncxx::builder::stream::document;
 58 |         using bsoncxx::builder::stream::finalize;
 59 | 
 60 |         if (client_ != nullptr) {
 61 |             auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level"
 62 |                                   << level::to_string_view(msg.level).data() << "level_num"
 63 |                                   << msg.level << "message"
 64 |                                   << std::string(msg.payload.begin(), msg.payload.end())
 65 |                                   << "logger_name"
 66 |                                   << std::string(msg.logger_name.begin(), msg.logger_name.end())
 67 |                                   << "thread_id" << static_cast<int>(msg.thread_id) << finalize;
 68 |             client_->database(db_name_).collection(coll_name_).insert_one(doc.view());
 69 |         }
 70 |     }
 71 | 
 72 |     void flush_() override {}
 73 | 
 74 | private:
 75 |     std::shared_ptr<mongocxx::instance> instance_;
 76 |     std::string db_name_;
 77 |     std::string coll_name_;
 78 |     std::unique_ptr<mongocxx::client> client_ = nullptr;
 79 | };
 80 | 
 81 | #include "spdlog/details/null_mutex.h"
 82 | #include <mutex>
 83 | using mongo_sink_mt = mongo_sink<std::mutex>;
 84 | using mongo_sink_st = mongo_sink<spdlog::details::null_mutex>;
 85 | 
 86 | }  // namespace sinks
 87 | 
 88 | template <typename Factory = spdlog::synchronous_factory>
 89 | inline std::shared_ptr<logger> mongo_logger_mt(
 90 |     const std::string &logger_name,
 91 |     const std::string &db_name,
 92 |     const std::string &collection_name,
 93 |     const std::string &uri = "mongodb://localhost:27017") {
 94 |     return Factory::template create<sinks::mongo_sink_mt>(logger_name, db_name, collection_name,
 95 |                                                           uri);
 96 | }
 97 | 
 98 | template <typename Factory = spdlog::synchronous_factory>
 99 | inline std::shared_ptr<logger> mongo_logger_st(
100 |     const std::string &logger_name,
101 |     const std::string &db_name,
102 |     const std::string &collection_name,
103 |     const std::string &uri = "mongodb://localhost:27017") {
104 |     return Factory::template create<sinks::mongo_sink_st>(logger_name, db_name, collection_name,
105 |                                                           uri);
106 | }
107 | 
108 | }  // namespace spdlog
109 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/msvc_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2016 Alexander Dalshov & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #if defined(_WIN32)
 7 | 
 8 |     #include <spdlog/details/null_mutex.h>
 9 |     #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
10 |         #include <spdlog/details/os.h>
11 |     #endif
12 |     #include <spdlog/sinks/base_sink.h>
13 | 
14 |     #include <mutex>
15 |     #include <string>
16 | 
17 |     // Avoid including windows.h (https://stackoverflow.com/a/30741042)
18 |     #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
19 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString);
20 |     #else
21 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString);
22 |     #endif
23 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
24 | 
25 | namespace spdlog {
26 | namespace sinks {
27 | /*
28 |  * MSVC sink (logging using OutputDebugStringA)
29 |  */
30 | template <typename Mutex>
31 | class msvc_sink : public base_sink<Mutex> {
32 | public:
33 |     msvc_sink() = default;
34 |     msvc_sink(bool check_debugger_present)
35 |         : check_debugger_present_{check_debugger_present} {}
36 | 
37 | protected:
38 |     void sink_it_(const details::log_msg &msg) override {
39 |         if (check_debugger_present_ && !IsDebuggerPresent()) {
40 |             return;
41 |         }
42 |         memory_buf_t formatted;
43 |         base_sink<Mutex>::formatter_->format(msg, formatted);
44 |         formatted.push_back('\0');  // add a null terminator for OutputDebugString
45 |     #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
46 |         wmemory_buf_t wformatted;
47 |         details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted);
48 |         OutputDebugStringW(wformatted.data());
49 |     #else
50 |         OutputDebugStringA(formatted.data());
51 |     #endif
52 |     }
53 | 
54 |     void flush_() override {}
55 | 
56 |     bool check_debugger_present_ = true;
57 | };
58 | 
59 | using msvc_sink_mt = msvc_sink<std::mutex>;
60 | using msvc_sink_st = msvc_sink<details::null_mutex>;
61 | 
62 | using windebug_sink_mt = msvc_sink_mt;
63 | using windebug_sink_st = msvc_sink_st;
64 | 
65 | }  // namespace sinks
66 | }  // namespace spdlog
67 | 
68 | #endif
69 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/null_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/null_mutex.h>
 7 | #include <spdlog/details/synchronous_factory.h>
 8 | #include <spdlog/sinks/base_sink.h>
 9 | 
10 | #include <mutex>
11 | 
12 | namespace spdlog {
13 | namespace sinks {
14 | 
15 | template <typename Mutex>
16 | class null_sink final : public base_sink<Mutex> {
17 | protected:
18 |     void sink_it_(const details::log_msg &) override {}
19 |     void flush_() override {}
20 | };
21 | 
22 | using null_sink_mt = null_sink<details::null_mutex>;
23 | using null_sink_st = null_sink<details::null_mutex>;
24 | 
25 | }  // namespace sinks
26 | 
27 | template <typename Factory = spdlog::synchronous_factory>
28 | inline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) {
29 |     auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name);
30 |     null_logger->set_level(level::off);
31 |     return null_logger;
32 | }
33 | 
34 | template <typename Factory = spdlog::synchronous_factory>
35 | inline std::shared_ptr<logger> null_logger_st(const std::string &logger_name) {
36 |     auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name);
37 |     null_logger->set_level(level::off);
38 |     return null_logger;
39 | }
40 | 
41 | }  // namespace spdlog
42 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/ostream_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/null_mutex.h>
 7 | #include <spdlog/sinks/base_sink.h>
 8 | 
 9 | #include <mutex>
10 | #include <ostream>
11 | 
12 | namespace spdlog {
13 | namespace sinks {
14 | template <typename Mutex>
15 | class ostream_sink final : public base_sink<Mutex> {
16 | public:
17 |     explicit ostream_sink(std::ostream &os, bool force_flush = false)
18 |         : ostream_(os),
19 |           force_flush_(force_flush) {}
20 |     ostream_sink(const ostream_sink &) = delete;
21 |     ostream_sink &operator=(const ostream_sink &) = delete;
22 | 
23 | protected:
24 |     void sink_it_(const details::log_msg &msg) override {
25 |         memory_buf_t formatted;
26 |         base_sink<Mutex>::formatter_->format(msg, formatted);
27 |         ostream_.write(formatted.data(), static_cast<std::streamsize>(formatted.size()));
28 |         if (force_flush_) {
29 |             ostream_.flush();
30 |         }
31 |     }
32 | 
33 |     void flush_() override { ostream_.flush(); }
34 | 
35 |     std::ostream &ostream_;
36 |     bool force_flush_;
37 | };
38 | 
39 | using ostream_sink_mt = ostream_sink<std::mutex>;
40 | using ostream_sink_st = ostream_sink<details::null_mutex>;
41 | 
42 | }  // namespace sinks
43 | }  // namespace spdlog
44 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/ringbuffer_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include "spdlog/details/circular_q.h"
 7 | #include "spdlog/details/log_msg_buffer.h"
 8 | #include "spdlog/details/null_mutex.h"
 9 | #include "spdlog/sinks/base_sink.h"
10 | 
11 | #include <mutex>
12 | #include <string>
13 | #include <vector>
14 | 
15 | namespace spdlog {
16 | namespace sinks {
17 | /*
18 |  * Ring buffer sink
19 |  */
20 | template <typename Mutex>
21 | class ringbuffer_sink final : public base_sink<Mutex> {
22 | public:
23 |     explicit ringbuffer_sink(size_t n_items)
24 |         : q_{n_items} {
25 |         if (n_items == 0) {
26 |             throw_spdlog_ex("ringbuffer_sink: n_items cannot be zero");
27 |         }
28 |     }
29 | 
30 |     std::vector<details::log_msg_buffer> last_raw(size_t lim = 0) {
31 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
32 |         auto items_available = q_.size();
33 |         auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available;
34 |         std::vector<details::log_msg_buffer> ret;
35 |         ret.reserve(n_items);
36 |         for (size_t i = (items_available - n_items); i < items_available; i++) {
37 |             ret.push_back(q_.at(i));
38 |         }
39 |         return ret;
40 |     }
41 | 
42 |     std::vector<std::string> last_formatted(size_t lim = 0) {
43 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
44 |         auto items_available = q_.size();
45 |         auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available;
46 |         std::vector<std::string> ret;
47 |         ret.reserve(n_items);
48 |         for (size_t i = (items_available - n_items); i < items_available; i++) {
49 |             memory_buf_t formatted;
50 |             base_sink<Mutex>::formatter_->format(q_.at(i), formatted);
51 |             ret.push_back(SPDLOG_BUF_TO_STRING(formatted));
52 |         }
53 |         return ret;
54 |     }
55 | 
56 | protected:
57 |     void sink_it_(const details::log_msg &msg) override {
58 |         q_.push_back(details::log_msg_buffer{msg});
59 |     }
60 |     void flush_() override {}
61 | 
62 | private:
63 |     details::circular_q<details::log_msg_buffer> q_;
64 | };
65 | 
66 | using ringbuffer_sink_mt = ringbuffer_sink<std::mutex>;
67 | using ringbuffer_sink_st = ringbuffer_sink<details::null_mutex>;
68 | 
69 | }  // namespace sinks
70 | 
71 | }  // namespace spdlog
72 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/rotating_file_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/file_helper.h>
 7 | #include <spdlog/details/null_mutex.h>
 8 | #include <spdlog/details/synchronous_factory.h>
 9 | #include <spdlog/sinks/base_sink.h>
10 | 
11 | #include <mutex>
12 | #include <string>
13 | 
14 | namespace spdlog {
15 | namespace sinks {
16 | 
17 | //
18 | // Rotating file sink based on size
19 | //
20 | template <typename Mutex>
21 | class rotating_file_sink final : public base_sink<Mutex> {
22 | public:
23 |     static constexpr size_t MaxFiles = 200000;
24 |     rotating_file_sink(filename_t base_filename,
25 |                        std::size_t max_size,
26 |                        std::size_t max_files,
27 |                        bool rotate_on_open = false,
28 |                        const file_event_handlers &event_handlers = {});
29 |     static filename_t calc_filename(const filename_t &filename, std::size_t index);
30 |     filename_t filename();
31 |     void rotate_now();
32 |     void set_max_size(std::size_t max_size);
33 |     std::size_t get_max_size();
34 |     void set_max_files(std::size_t max_files);
35 |     std::size_t get_max_files();
36 | 
37 | protected:
38 |     void sink_it_(const details::log_msg &msg) override;
39 |     void flush_() override;
40 | 
41 | private:
42 |     // Rotate files:
43 |     // log.txt -> log.1.txt
44 |     // log.1.txt -> log.2.txt
45 |     // log.2.txt -> log.3.txt
46 |     // log.3.txt -> delete
47 |     void rotate_();
48 | 
49 |     // delete the target if exists, and rename the src file to target
50 |     // return true on success, false otherwise.
51 |     bool rename_file_(const filename_t &src_filename, const filename_t &target_filename);
52 | 
53 |     filename_t base_filename_;
54 |     std::size_t max_size_;
55 |     std::size_t max_files_;
56 |     std::size_t current_size_;
57 |     details::file_helper file_helper_;
58 | };
59 | 
60 | using rotating_file_sink_mt = rotating_file_sink<std::mutex>;
61 | using rotating_file_sink_st = rotating_file_sink<details::null_mutex>;
62 | 
63 | }  // namespace sinks
64 | 
65 | //
66 | // factory functions
67 | //
68 | template <typename Factory = spdlog::synchronous_factory>
69 | std::shared_ptr<logger> rotating_logger_mt(const std::string &logger_name,
70 |                                            const filename_t &filename,
71 |                                            size_t max_file_size,
72 |                                            size_t max_files,
73 |                                            bool rotate_on_open = false,
74 |                                            const file_event_handlers &event_handlers = {}) {
75 |     return Factory::template create<sinks::rotating_file_sink_mt>(
76 |         logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers);
77 | }
78 | 
79 | template <typename Factory = spdlog::synchronous_factory>
80 | std::shared_ptr<logger> rotating_logger_st(const std::string &logger_name,
81 |                                            const filename_t &filename,
82 |                                            size_t max_file_size,
83 |                                            size_t max_files,
84 |                                            bool rotate_on_open = false,
85 |                                            const file_event_handlers &event_handlers = {}) {
86 |     return Factory::template create<sinks::rotating_file_sink_st>(
87 |         logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers);
88 | }
89 | }  // namespace spdlog
90 | 
91 | #ifdef SPDLOG_HEADER_ONLY
92 |     #include "rotating_file_sink-inl.h"
93 | #endif
94 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/sink-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/sinks/sink.h>
 8 | #endif
 9 | 
10 | #include <spdlog/common.h>
11 | 
12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const {
13 |     return msg_level >= level_.load(std::memory_order_relaxed);
14 | }
15 | 
16 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) {
17 |     level_.store(log_level, std::memory_order_relaxed);
18 | }
19 | 
20 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const {
21 |     return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
22 | }
23 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/details/log_msg.h>
 7 | #include <spdlog/formatter.h>
 8 | 
 9 | namespace spdlog {
10 | 
11 | namespace sinks {
12 | class SPDLOG_API sink {
13 | public:
14 |     virtual ~sink() = default;
15 |     virtual void log(const details::log_msg &msg) = 0;
16 |     virtual void flush() = 0;
17 |     virtual void set_pattern(const std::string &pattern) = 0;
18 |     virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;
19 | 
20 |     void set_level(level::level_enum log_level);
21 |     level::level_enum level() const;
22 |     bool should_log(level::level_enum msg_level) const;
23 | 
24 | protected:
25 |     // sink log level - default is all
26 |     level_t level_{level::trace};
27 | };
28 | 
29 | }  // namespace sinks
30 | }  // namespace spdlog
31 | 
32 | #ifdef SPDLOG_HEADER_ONLY
33 |     #include "sink-inl.h"
34 | #endif
35 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/stdout_color_sinks-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/sinks/stdout_color_sinks.h>
 8 | #endif
 9 | 
10 | #include <spdlog/common.h>
11 | #include <spdlog/logger.h>
12 | 
13 | namespace spdlog {
14 | 
15 | template <typename Factory>
16 | SPDLOG_INLINE std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name,
17 |                                                       color_mode mode) {
18 |     return Factory::template create<sinks::stdout_color_sink_mt>(logger_name, mode);
19 | }
20 | 
21 | template <typename Factory>
22 | SPDLOG_INLINE std::shared_ptr<logger> stdout_color_st(const std::string &logger_name,
23 |                                                       color_mode mode) {
24 |     return Factory::template create<sinks::stdout_color_sink_st>(logger_name, mode);
25 | }
26 | 
27 | template <typename Factory>
28 | SPDLOG_INLINE std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name,
29 |                                                       color_mode mode) {
30 |     return Factory::template create<sinks::stderr_color_sink_mt>(logger_name, mode);
31 | }
32 | 
33 | template <typename Factory>
34 | SPDLOG_INLINE std::shared_ptr<logger> stderr_color_st(const std::string &logger_name,
35 |                                                       color_mode mode) {
36 |     return Factory::template create<sinks::stderr_color_sink_st>(logger_name, mode);
37 | }
38 | }  // namespace spdlog
39 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/stdout_color_sinks.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifdef _WIN32
 7 |     #include <spdlog/sinks/wincolor_sink.h>
 8 | #else
 9 |     #include <spdlog/sinks/ansicolor_sink.h>
10 | #endif
11 | 
12 | #include <spdlog/details/synchronous_factory.h>
13 | 
14 | namespace spdlog {
15 | namespace sinks {
16 | #ifdef _WIN32
17 | using stdout_color_sink_mt = wincolor_stdout_sink_mt;
18 | using stdout_color_sink_st = wincolor_stdout_sink_st;
19 | using stderr_color_sink_mt = wincolor_stderr_sink_mt;
20 | using stderr_color_sink_st = wincolor_stderr_sink_st;
21 | #else
22 | using stdout_color_sink_mt = ansicolor_stdout_sink_mt;
23 | using stdout_color_sink_st = ansicolor_stdout_sink_st;
24 | using stderr_color_sink_mt = ansicolor_stderr_sink_mt;
25 | using stderr_color_sink_st = ansicolor_stderr_sink_st;
26 | #endif
27 | }  // namespace sinks
28 | 
29 | template <typename Factory = spdlog::synchronous_factory>
30 | std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name,
31 |                                         color_mode mode = color_mode::automatic);
32 | 
33 | template <typename Factory = spdlog::synchronous_factory>
34 | std::shared_ptr<logger> stdout_color_st(const std::string &logger_name,
35 |                                         color_mode mode = color_mode::automatic);
36 | 
37 | template <typename Factory = spdlog::synchronous_factory>
38 | std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name,
39 |                                         color_mode mode = color_mode::automatic);
40 | 
41 | template <typename Factory = spdlog::synchronous_factory>
42 | std::shared_ptr<logger> stderr_color_st(const std::string &logger_name,
43 |                                         color_mode mode = color_mode::automatic);
44 | 
45 | }  // namespace spdlog
46 | 
47 | #ifdef SPDLOG_HEADER_ONLY
48 |     #include "stdout_color_sinks-inl.h"
49 | #endif
50 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/stdout_sinks.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <cstdio>
 7 | #include <spdlog/details/console_globals.h>
 8 | #include <spdlog/details/synchronous_factory.h>
 9 | #include <spdlog/sinks/sink.h>
10 | 
11 | #ifdef _WIN32
12 |     #include <spdlog/details/windows_include.h>
13 | #endif
14 | 
15 | namespace spdlog {
16 | 
17 | namespace sinks {
18 | 
19 | template <typename ConsoleMutex>
20 | class stdout_sink_base : public sink {
21 | public:
22 |     using mutex_t = typename ConsoleMutex::mutex_t;
23 |     explicit stdout_sink_base(FILE *file);
24 |     ~stdout_sink_base() override = default;
25 | 
26 |     stdout_sink_base(const stdout_sink_base &other) = delete;
27 |     stdout_sink_base(stdout_sink_base &&other) = delete;
28 | 
29 |     stdout_sink_base &operator=(const stdout_sink_base &other) = delete;
30 |     stdout_sink_base &operator=(stdout_sink_base &&other) = delete;
31 | 
32 |     void log(const details::log_msg &msg) override;
33 |     void flush() override;
34 |     void set_pattern(const std::string &pattern) override;
35 | 
36 |     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;
37 | 
38 | protected:
39 |     mutex_t &mutex_;
40 |     FILE *file_;
41 |     std::unique_ptr<spdlog::formatter> formatter_;
42 | #ifdef _WIN32
43 |     HANDLE handle_;
44 | #endif  // WIN32
45 | };
46 | 
47 | template <typename ConsoleMutex>
48 | class stdout_sink : public stdout_sink_base<ConsoleMutex> {
49 | public:
50 |     stdout_sink();
51 | };
52 | 
53 | template <typename ConsoleMutex>
54 | class stderr_sink : public stdout_sink_base<ConsoleMutex> {
55 | public:
56 |     stderr_sink();
57 | };
58 | 
59 | using stdout_sink_mt = stdout_sink<details::console_mutex>;
60 | using stdout_sink_st = stdout_sink<details::console_nullmutex>;
61 | 
62 | using stderr_sink_mt = stderr_sink<details::console_mutex>;
63 | using stderr_sink_st = stderr_sink<details::console_nullmutex>;
64 | 
65 | }  // namespace sinks
66 | 
67 | // factory methods
68 | template <typename Factory = spdlog::synchronous_factory>
69 | std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name);
70 | 
71 | template <typename Factory = spdlog::synchronous_factory>
72 | std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name);
73 | 
74 | template <typename Factory = spdlog::synchronous_factory>
75 | std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name);
76 | 
77 | template <typename Factory = spdlog::synchronous_factory>
78 | std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);
79 | 
80 | }  // namespace spdlog
81 | 
82 | #ifdef SPDLOG_HEADER_ONLY
83 |     #include "stdout_sinks-inl.h"
84 | #endif
85 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/tcp_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <spdlog/details/null_mutex.h>
 8 | #include <spdlog/sinks/base_sink.h>
 9 | #ifdef _WIN32
10 |     #include <spdlog/details/tcp_client-windows.h>
11 | #else
12 |     #include <spdlog/details/tcp_client.h>
13 | #endif
14 | 
15 | #include <chrono>
16 | #include <functional>
17 | #include <mutex>
18 | #include <string>
19 | 
20 | #pragma once
21 | 
22 | // Simple tcp client sink
23 | // Connects to remote address and send the formatted log.
24 | // Will attempt to reconnect if connection drops.
25 | // If more complicated behaviour is needed (i.e get responses), you can inherit it and override the
26 | // sink_it_ method.
27 | 
28 | namespace spdlog {
29 | namespace sinks {
30 | 
31 | struct tcp_sink_config {
32 |     std::string server_host;
33 |     int server_port;
34 |     bool lazy_connect = false;  // if true connect on first log call instead of on construction
35 | 
36 |     tcp_sink_config(std::string host, int port)
37 |         : server_host{std::move(host)},
38 |           server_port{port} {}
39 | };
40 | 
41 | template <typename Mutex>
42 | class tcp_sink : public spdlog::sinks::base_sink<Mutex> {
43 | public:
44 |     // connect to tcp host/port or throw if failed
45 |     // host can be hostname or ip address
46 | 
47 |     explicit tcp_sink(tcp_sink_config sink_config)
48 |         : config_{std::move(sink_config)} {
49 |         if (!config_.lazy_connect) {
50 |             this->client_.connect(config_.server_host, config_.server_port);
51 |         }
52 |     }
53 | 
54 |     ~tcp_sink() override = default;
55 | 
56 | protected:
57 |     void sink_it_(const spdlog::details::log_msg &msg) override {
58 |         spdlog::memory_buf_t formatted;
59 |         spdlog::sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
60 |         if (!client_.is_connected()) {
61 |             client_.connect(config_.server_host, config_.server_port);
62 |         }
63 |         client_.send(formatted.data(), formatted.size());
64 |     }
65 | 
66 |     void flush_() override {}
67 |     tcp_sink_config config_;
68 |     details::tcp_client client_;
69 | };
70 | 
71 | using tcp_sink_mt = tcp_sink<std::mutex>;
72 | using tcp_sink_st = tcp_sink<spdlog::details::null_mutex>;
73 | 
74 | }  // namespace sinks
75 | }  // namespace spdlog
76 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/udp_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <spdlog/details/null_mutex.h>
 8 | #include <spdlog/sinks/base_sink.h>
 9 | #ifdef _WIN32
10 |     #include <spdlog/details/udp_client-windows.h>
11 | #else
12 |     #include <spdlog/details/udp_client.h>
13 | #endif
14 | 
15 | #include <chrono>
16 | #include <functional>
17 | #include <mutex>
18 | #include <string>
19 | 
20 | // Simple udp client sink
21 | // Sends formatted log via udp
22 | 
23 | namespace spdlog {
24 | namespace sinks {
25 | 
26 | struct udp_sink_config {
27 |     std::string server_host;
28 |     uint16_t server_port;
29 | 
30 |     udp_sink_config(std::string host, uint16_t port)
31 |         : server_host{std::move(host)},
32 |           server_port{port} {}
33 | };
34 | 
35 | template <typename Mutex>
36 | class udp_sink : public spdlog::sinks::base_sink<Mutex> {
37 | public:
38 |     // host can be hostname or ip address
39 |     explicit udp_sink(udp_sink_config sink_config)
40 |         : client_{sink_config.server_host, sink_config.server_port} {}
41 | 
42 |     ~udp_sink() override = default;
43 | 
44 | protected:
45 |     void sink_it_(const spdlog::details::log_msg &msg) override {
46 |         spdlog::memory_buf_t formatted;
47 |         spdlog::sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
48 |         client_.send(formatted.data(), formatted.size());
49 |     }
50 | 
51 |     void flush_() override {}
52 |     details::udp_client client_;
53 | };
54 | 
55 | using udp_sink_mt = udp_sink<std::mutex>;
56 | using udp_sink_st = udp_sink<spdlog::details::null_mutex>;
57 | 
58 | }  // namespace sinks
59 | 
60 | //
61 | // factory functions
62 | //
63 | template <typename Factory = spdlog::synchronous_factory>
64 | inline std::shared_ptr<logger> udp_logger_mt(const std::string &logger_name,
65 |                                              sinks::udp_sink_config skin_config) {
66 |     return Factory::template create<sinks::udp_sink_mt>(logger_name, skin_config);
67 | }
68 | 
69 | }  // namespace spdlog
70 | 


--------------------------------------------------------------------------------
/include/spdlog/sinks/wincolor_sink.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <spdlog/common.h>
 7 | #include <spdlog/details/console_globals.h>
 8 | #include <spdlog/details/null_mutex.h>
 9 | #include <spdlog/sinks/sink.h>
10 | 
11 | #include <array>
12 | #include <cstdint>
13 | #include <memory>
14 | #include <mutex>
15 | #include <string>
16 | 
17 | namespace spdlog {
18 | namespace sinks {
19 | /*
20 |  * Windows color console sink. Uses WriteConsoleA to write to the console with
21 |  * colors
22 |  */
23 | template <typename ConsoleMutex>
24 | class wincolor_sink : public sink {
25 | public:
26 |     wincolor_sink(void *out_handle, color_mode mode);
27 |     ~wincolor_sink() override;
28 | 
29 |     wincolor_sink(const wincolor_sink &other) = delete;
30 |     wincolor_sink &operator=(const wincolor_sink &other) = delete;
31 | 
32 |     // change the color for the given level
33 |     void set_color(level::level_enum level, std::uint16_t color);
34 |     void log(const details::log_msg &msg) override;
35 |     void flush() override;
36 |     void set_pattern(const std::string &pattern) override;
37 |     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;
38 |     void set_color_mode(color_mode mode);
39 | 
40 | protected:
41 |     using mutex_t = typename ConsoleMutex::mutex_t;
42 |     void *out_handle_;
43 |     mutex_t &mutex_;
44 |     bool should_do_colors_;
45 |     std::unique_ptr<spdlog::formatter> formatter_;
46 |     std::array<std::uint16_t, level::n_levels> colors_;
47 | 
48 |     // set foreground color and return the orig console attributes (for resetting later)
49 |     std::uint16_t set_foreground_color_(std::uint16_t attribs);
50 | 
51 |     // print a range of formatted message to console
52 |     void print_range_(const memory_buf_t &formatted, size_t start, size_t end);
53 | 
54 |     // in case we are redirected to file (not in console mode)
55 |     void write_to_file_(const memory_buf_t &formatted);
56 | 
57 |     void set_color_mode_impl(color_mode mode);
58 | };
59 | 
60 | template <typename ConsoleMutex>
61 | class wincolor_stdout_sink : public wincolor_sink<ConsoleMutex> {
62 | public:
63 |     explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic);
64 | };
65 | 
66 | template <typename ConsoleMutex>
67 | class wincolor_stderr_sink : public wincolor_sink<ConsoleMutex> {
68 | public:
69 |     explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic);
70 | };
71 | 
72 | using wincolor_stdout_sink_mt = wincolor_stdout_sink<details::console_mutex>;
73 | using wincolor_stdout_sink_st = wincolor_stdout_sink<details::console_nullmutex>;
74 | 
75 | using wincolor_stderr_sink_mt = wincolor_stderr_sink<details::console_mutex>;
76 | using wincolor_stderr_sink_st = wincolor_stderr_sink<details::console_nullmutex>;
77 | }  // namespace sinks
78 | }  // namespace spdlog
79 | 
80 | #ifdef SPDLOG_HEADER_ONLY
81 |     #include "wincolor_sink-inl.h"
82 | #endif
83 | 


--------------------------------------------------------------------------------
/include/spdlog/spdlog-inl.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #ifndef SPDLOG_HEADER_ONLY
 7 |     #include <spdlog/spdlog.h>
 8 | #endif
 9 | 
10 | #include <spdlog/common.h>
11 | #include <spdlog/pattern_formatter.h>
12 | 
13 | namespace spdlog {
14 | 
15 | SPDLOG_INLINE void initialize_logger(std::shared_ptr<logger> logger) {
16 |     details::registry::instance().initialize_logger(std::move(logger));
17 | }
18 | 
19 | SPDLOG_INLINE std::shared_ptr<logger> get(const std::string &name) {
20 |     return details::registry::instance().get(name);
21 | }
22 | 
23 | SPDLOG_INLINE void set_formatter(std::unique_ptr<spdlog::formatter> formatter) {
24 |     details::registry::instance().set_formatter(std::move(formatter));
25 | }
26 | 
27 | SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) {
28 |     set_formatter(
29 |         std::unique_ptr<spdlog::formatter>(new pattern_formatter(std::move(pattern), time_type)));
30 | }
31 | 
32 | SPDLOG_INLINE void enable_backtrace(size_t n_messages) {
33 |     details::registry::instance().enable_backtrace(n_messages);
34 | }
35 | 
36 | SPDLOG_INLINE void disable_backtrace() { details::registry::instance().disable_backtrace(); }
37 | 
38 | SPDLOG_INLINE void dump_backtrace() { default_logger_raw()->dump_backtrace(); }
39 | 
40 | SPDLOG_INLINE level::level_enum get_level() { return default_logger_raw()->level(); }
41 | 
42 | SPDLOG_INLINE bool should_log(level::level_enum log_level) {
43 |     return default_logger_raw()->should_log(log_level);
44 | }
45 | 
46 | SPDLOG_INLINE void set_level(level::level_enum log_level) {
47 |     details::registry::instance().set_level(log_level);
48 | }
49 | 
50 | SPDLOG_INLINE void flush_on(level::level_enum log_level) {
51 |     details::registry::instance().flush_on(log_level);
52 | }
53 | 
54 | SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) {
55 |     details::registry::instance().set_error_handler(handler);
56 | }
57 | 
58 | SPDLOG_INLINE void register_logger(std::shared_ptr<logger> logger) {
59 |     details::registry::instance().register_logger(std::move(logger));
60 | }
61 | 
62 | SPDLOG_INLINE void register_or_replace(std::shared_ptr<logger> logger) {
63 |     details::registry::instance().register_or_replace(std::move(logger));
64 | }
65 | 
66 | SPDLOG_INLINE void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun) {
67 |     details::registry::instance().apply_all(fun);
68 | }
69 | 
70 | SPDLOG_INLINE void drop(const std::string &name) { details::registry::instance().drop(name); }
71 | 
72 | SPDLOG_INLINE void drop_all() { details::registry::instance().drop_all(); }
73 | 
74 | SPDLOG_INLINE void shutdown() { details::registry::instance().shutdown(); }
75 | 
76 | SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) {
77 |     details::registry::instance().set_automatic_registration(automatic_registration);
78 | }
79 | 
80 | SPDLOG_INLINE std::shared_ptr<spdlog::logger> default_logger() {
81 |     return details::registry::instance().default_logger();
82 | }
83 | 
84 | SPDLOG_INLINE spdlog::logger *default_logger_raw() {
85 |     return details::registry::instance().get_default_raw();
86 | }
87 | 
88 | SPDLOG_INLINE void set_default_logger(std::shared_ptr<spdlog::logger> default_logger) {
89 |     details::registry::instance().set_default_logger(std::move(default_logger));
90 | }
91 | 
92 | SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr<logger> logger) {
93 |     details::registry::instance().apply_logger_env_levels(std::move(logger));
94 | }
95 | 
96 | }  // namespace spdlog
97 | 


--------------------------------------------------------------------------------
/include/spdlog/stopwatch.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #include <chrono>
 7 | #include <spdlog/fmt/fmt.h>
 8 | 
 9 | // Stopwatch support for spdlog  (using std::chrono::steady_clock).
10 | // Displays elapsed seconds since construction as double.
11 | //
12 | // Usage:
13 | //
14 | // spdlog::stopwatch sw;
15 | // ...
16 | // spdlog::debug("Elapsed: {} seconds", sw);    =>  "Elapsed 0.005116733 seconds"
17 | // spdlog::info("Elapsed: {:.6} seconds", sw);  =>  "Elapsed 0.005163 seconds"
18 | //
19 | //
20 | // If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use
21 | // "duration_cast<..>(sw.elapsed())":
22 | //
23 | // #include <spdlog/fmt/chrono.h>
24 | //..
25 | // using std::chrono::duration_cast;
26 | // using std::chrono::milliseconds;
27 | // spdlog::info("Elapsed {}", duration_cast<milliseconds>(sw.elapsed())); => "Elapsed 5ms"
28 | 
29 | namespace spdlog {
30 | class stopwatch {
31 |     using clock = std::chrono::steady_clock;
32 |     std::chrono::time_point<clock> start_tp_;
33 | 
34 | public:
35 |     stopwatch()
36 |         : start_tp_{clock::now()} {}
37 | 
38 |     std::chrono::duration<double> elapsed() const {
39 |         return std::chrono::duration<double>(clock::now() - start_tp_);
40 |     }
41 | 
42 |     std::chrono::milliseconds elapsed_ms() const {
43 |         return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_tp_);
44 |     }
45 | 
46 |     void reset() { start_tp_ = clock::now(); }
47 | };
48 | }  // namespace spdlog
49 | 
50 | // Support for fmt formatting  (e.g. "{:012.9}" or just "{}")
51 | namespace
52 | #ifdef SPDLOG_USE_STD_FORMAT
53 |     std
54 | #else
55 |     fmt
56 | #endif
57 | {
58 | 
59 | template <>
60 | struct formatter<spdlog::stopwatch> : formatter<double> {
61 |     template <typename FormatContext>
62 |     auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) {
63 |         return formatter<double>::format(sw.elapsed().count(), ctx);
64 |     }
65 | };
66 | }  // namespace std
67 | 


--------------------------------------------------------------------------------
/include/spdlog/version.h:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #pragma once
 5 | 
 6 | #define SPDLOG_VER_MAJOR 1
 7 | #define SPDLOG_VER_MINOR 15
 8 | #define SPDLOG_VER_PATCH 3
 9 | 
10 | #define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch)
11 | #define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH)
12 | 


--------------------------------------------------------------------------------
/logos/spdlog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gabime/spdlog/737347d2df9180f07bb133c15c3e3e630fcecdee/logos/spdlog.png


--------------------------------------------------------------------------------
/scripts/ci_setup_clang.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | set -ex
 4 | 
 5 | VERSION=$1
 6 | 
 7 | apt-get update
 8 | apt-get install -y libc++-${VERSION}-dev libc++abi-${VERSION}-dev
 9 | 
10 | if [[ "${VERSION}" -ge 12 ]]; then
11 |     apt-get install -y --no-install-recommends libunwind-${VERSION}-dev
12 | fi
13 | 


--------------------------------------------------------------------------------
/scripts/extract_version.py:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python3
 2 | 
 3 | import os
 4 | import re
 5 | 
 6 | base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 7 | config_h = os.path.join(base_path, 'include', 'spdlog', 'version.h')
 8 | data = {'MAJOR': 0, 'MINOR': 0, 'PATCH': 0}
 9 | reg = re.compile(r'^\s*#define\s+SPDLOG_VER_([A-Z]+)\s+([0-9]+).*
#39;)
10 | 
11 | with open(config_h, 'r') as fp:
12 |     for l in fp:
13 |         m = reg.match(l)
14 |         if m:
15 |             data[m.group(1)] = int(m.group(2))
16 | 
17 | print(f"{data['MAJOR']}.{data['MINOR']}.{data['PATCH']}")
18 | 


--------------------------------------------------------------------------------
/scripts/format.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | cd "$(dirname "$0")"/..
 4 | pwd
 5 | find_sources="find include src tests example bench -not ( -path include/spdlog/fmt/bundled -prune ) -type f -name *\.h -o -name *\.cpp"
 6 | echo -n "Running dos2unix     "
 7 | $find_sources | xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'"
 8 | echo
 9 | echo -n "Running clang-format "
10 | 
11 | $find_sources | xargs -I {} sh -c "clang-format -i {}; echo -n '.'"
12 | 
13 | echo
14 | echo -n "Running cmake-format "
15 | find . -type f -name "CMakeLists.txt" -o -name "*\.cmake"|grep -v bundled|grep -v build|xargs -I {} sh -c "cmake-format --line-width 120 --tab-size 4 --max-subgroups-hwrap 4 -i {}; echo -n '.'"
16 | echo
17 | 
18 | 
19 | 
20 | 


--------------------------------------------------------------------------------
/src/async.cpp:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #ifndef SPDLOG_COMPILED_LIB
 5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 6 | #endif
 7 | 
 8 | #include <spdlog/async.h>
 9 | #include <spdlog/async_logger-inl.h>
10 | #include <spdlog/details/periodic_worker-inl.h>
11 | #include <spdlog/details/thread_pool-inl.h>
12 | 


--------------------------------------------------------------------------------
/src/bundled_fmtlib_format.cpp:
--------------------------------------------------------------------------------
 1 | // Slightly modified version of fmt lib's format.cc source file.
 2 | // Copyright (c) 2012 - 2016, Victor Zverovich
 3 | // All rights reserved.
 4 | 
 5 | #ifndef SPDLOG_COMPILED_LIB
 6 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 7 | #endif
 8 | 
 9 | #if !defined(SPDLOG_FMT_EXTERNAL) && !defined(SPDLOG_USE_STD_FORMAT)
10 | 
11 |     #include <spdlog/fmt/bundled/format-inl.h>
12 | 
13 | FMT_BEGIN_NAMESPACE
14 | namespace detail {
15 | 
16 | template FMT_API auto dragonbox::to_decimal(float x) noexcept -> dragonbox::decimal_fp<float>;
17 | template FMT_API auto dragonbox::to_decimal(double x) noexcept -> dragonbox::decimal_fp<double>;
18 | 
19 |     #if FMT_USE_LOCALE
20 | // DEPRECATED! locale_ref in the detail namespace
21 | template FMT_API locale_ref::locale_ref(const std::locale& loc);
22 | template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
23 |     #endif
24 | 
25 | // Explicit instantiations for char.
26 | 
27 | template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result<char>;
28 | template FMT_API auto decimal_point_impl(locale_ref) -> char;
29 | 
30 | // DEPRECATED!
31 | template FMT_API void buffer<char>::append(const char*, const char*);
32 | 
33 | // DEPRECATED!
34 | template FMT_API void vformat_to(buffer<char>&,
35 |                                  string_view,
36 |                                  typename vformat_args<>::type,
37 |                                  locale_ref);
38 | 
39 | // Explicit instantiations for wchar_t.
40 | 
41 | template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result<wchar_t>;
42 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
43 | 
44 | template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
45 | 
46 | }  // namespace detail
47 | FMT_END_NAMESPACE
48 | 
49 | #endif  // !SPDLOG_FMT_EXTERNAL
50 | 


--------------------------------------------------------------------------------
/src/cfg.cpp:
--------------------------------------------------------------------------------
1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
3 | 
4 | #ifndef SPDLOG_COMPILED_LIB
5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
6 | #endif
7 | 
8 | #include <spdlog/cfg/helpers-inl.h>
9 | 


--------------------------------------------------------------------------------
/src/color_sinks.cpp:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #ifndef SPDLOG_COMPILED_LIB
 5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 6 | #endif
 7 | 
 8 | #include <mutex>
 9 | 
10 | #include <spdlog/async.h>
11 | #include <spdlog/details/null_mutex.h>
12 | //
13 | // color sinks
14 | //
15 | #ifdef _WIN32
16 |     #include <spdlog/sinks/wincolor_sink-inl.h>
17 | template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_mutex>;
18 | template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_nullmutex>;
19 | template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_mutex>;
20 | template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_nullmutex>;
21 | template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_mutex>;
22 | template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_nullmutex>;
23 | #else
24 |     #include "spdlog/sinks/ansicolor_sink-inl.h"
25 | template class SPDLOG_API spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>;
26 | template class SPDLOG_API spdlog::sinks::ansicolor_sink<spdlog::details::console_nullmutex>;
27 | template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<spdlog::details::console_mutex>;
28 | template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<spdlog::details::console_nullmutex>;
29 | template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<spdlog::details::console_mutex>;
30 | template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<spdlog::details::console_nullmutex>;
31 | #endif
32 | 
33 | // factory methods for color loggers
34 | #include "spdlog/sinks/stdout_color_sinks-inl.h"
35 | template SPDLOG_API std::shared_ptr<spdlog::logger>
36 | spdlog::stdout_color_mt<spdlog::synchronous_factory>(const std::string &logger_name,
37 |                                                      color_mode mode);
38 | template SPDLOG_API std::shared_ptr<spdlog::logger>
39 | spdlog::stdout_color_st<spdlog::synchronous_factory>(const std::string &logger_name,
40 |                                                      color_mode mode);
41 | template SPDLOG_API std::shared_ptr<spdlog::logger>
42 | spdlog::stderr_color_mt<spdlog::synchronous_factory>(const std::string &logger_name,
43 |                                                      color_mode mode);
44 | template SPDLOG_API std::shared_ptr<spdlog::logger>
45 | spdlog::stderr_color_st<spdlog::synchronous_factory>(const std::string &logger_name,
46 |                                                      color_mode mode);
47 | 
48 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(
49 |     const std::string &logger_name, color_mode mode);
50 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(
51 |     const std::string &logger_name, color_mode mode);
52 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(
53 |     const std::string &logger_name, color_mode mode);
54 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(
55 |     const std::string &logger_name, color_mode mode);
56 | 


--------------------------------------------------------------------------------
/src/file_sinks.cpp:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #ifndef SPDLOG_COMPILED_LIB
 5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 6 | #endif
 7 | 
 8 | #include <spdlog/details/file_helper-inl.h>
 9 | #include <spdlog/details/null_mutex.h>
10 | #include <spdlog/sinks/base_sink-inl.h>
11 | #include <spdlog/sinks/basic_file_sink-inl.h>
12 | 
13 | #include <mutex>
14 | 
15 | template class SPDLOG_API spdlog::sinks::basic_file_sink<std::mutex>;
16 | template class SPDLOG_API spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>;
17 | 
18 | #include <spdlog/sinks/rotating_file_sink-inl.h>
19 | template class SPDLOG_API spdlog::sinks::rotating_file_sink<std::mutex>;
20 | template class SPDLOG_API spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>;
21 | 


--------------------------------------------------------------------------------
/src/spdlog.cpp:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #ifndef SPDLOG_COMPILED_LIB
 5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 6 | #endif
 7 | 
 8 | #include <spdlog/common-inl.h>
 9 | #include <spdlog/details/backtracer-inl.h>
10 | #include <spdlog/details/log_msg-inl.h>
11 | #include <spdlog/details/log_msg_buffer-inl.h>
12 | #include <spdlog/details/null_mutex.h>
13 | #include <spdlog/details/os-inl.h>
14 | #include <spdlog/details/registry-inl.h>
15 | #include <spdlog/logger-inl.h>
16 | #include <spdlog/pattern_formatter-inl.h>
17 | #include <spdlog/sinks/base_sink-inl.h>
18 | #include <spdlog/sinks/sink-inl.h>
19 | #include <spdlog/spdlog-inl.h>
20 | 
21 | #include <mutex>
22 | 
23 | // template instantiate logger constructor with sinks init list
24 | template SPDLOG_API spdlog::logger::logger(std::string name,
25 |                                            sinks_init_list::iterator begin,
26 |                                            sinks_init_list::iterator end);
27 | template class SPDLOG_API spdlog::sinks::base_sink<std::mutex>;
28 | template class SPDLOG_API spdlog::sinks::base_sink<spdlog::details::null_mutex>;
29 | 


--------------------------------------------------------------------------------
/src/stdout_sinks.cpp:
--------------------------------------------------------------------------------
 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 3 | 
 4 | #ifndef SPDLOG_COMPILED_LIB
 5 |     #error Please define SPDLOG_COMPILED_LIB to compile this file.
 6 | #endif
 7 | 
 8 | #include <mutex>
 9 | 
10 | #include <spdlog/async.h>
11 | #include <spdlog/details/null_mutex.h>
12 | #include <spdlog/sinks/stdout_sinks-inl.h>
13 | 
14 | template class SPDLOG_API spdlog::sinks::stdout_sink_base<spdlog::details::console_mutex>;
15 | template class SPDLOG_API spdlog::sinks::stdout_sink_base<spdlog::details::console_nullmutex>;
16 | template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::console_mutex>;
17 | template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::console_nullmutex>;
18 | template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::console_mutex>;
19 | template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::console_nullmutex>;
20 | 
21 | template SPDLOG_API std::shared_ptr<spdlog::logger>
22 | spdlog::stdout_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);
23 | template SPDLOG_API std::shared_ptr<spdlog::logger>
24 | spdlog::stdout_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);
25 | template SPDLOG_API std::shared_ptr<spdlog::logger>
26 | spdlog::stderr_logger_mt<spdlog::synchronous_factory>(const std::string &logger_name);
27 | template SPDLOG_API std::shared_ptr<spdlog::logger>
28 | spdlog::stderr_logger_st<spdlog::synchronous_factory>(const std::string &logger_name);
29 | 
30 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::async_factory>(
31 |     const std::string &logger_name);
32 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::async_factory>(
33 |     const std::string &logger_name);
34 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::async_factory>(
35 |     const std::string &logger_name);
36 | template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::async_factory>(
37 |     const std::string &logger_name);
38 | 


--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | cmake_minimum_required(VERSION 3.11)
 2 | project(spdlog_utests CXX)
 3 | 
 4 | if(NOT TARGET spdlog)
 5 |     # Stand-alone build
 6 |     find_package(spdlog REQUIRED)
 7 | endif()
 8 | 
 9 | include(../cmake/utils.cmake)
10 | 
11 | find_package(PkgConfig)
12 | if(PkgConfig_FOUND)
13 |     pkg_check_modules(systemd libsystemd)
14 | endif()
15 | 
16 | find_package(Catch2 3 QUIET)
17 | if(Catch2_FOUND)
18 |     message(STATUS "Packaged version of Catch will be used.")
19 | else()
20 |     message(STATUS "Bundled version of Catch will be downloaded and used.")
21 |     include(FetchContent)
22 |     FetchContent_Declare(
23 |         Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git
24 |         GIT_TAG 53d0d913a422d356b23dd927547febdf69ee9081 # v3.5.0
25 |     )
26 |     FetchContent_MakeAvailable(Catch2)
27 | endif()
28 | 
29 | set(SPDLOG_UTESTS_SOURCES
30 |     test_file_helper.cpp
31 |     test_file_logging.cpp
32 |     test_daily_logger.cpp
33 |     test_misc.cpp
34 |     test_eventlog.cpp
35 |     test_pattern_formatter.cpp
36 |     test_async.cpp
37 |     test_registry.cpp
38 |     test_macros.cpp
39 |     utils.cpp
40 |     main.cpp
41 |     test_mpmc_q.cpp
42 |     test_dup_filter.cpp
43 |     test_fmt_helper.cpp
44 |     test_stdout_api.cpp
45 |     test_backtrace.cpp
46 |     test_create_dir.cpp
47 |     test_custom_callbacks.cpp
48 |     test_cfg.cpp
49 |     test_time_point.cpp
50 |     test_stopwatch.cpp
51 |     test_circular_q.cpp
52 |     test_bin_to_hex.cpp
53 |     test_ringbuffer.cpp)
54 | 
55 | if(NOT SPDLOG_NO_EXCEPTIONS)
56 |     list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp)
57 | endif()
58 | 
59 | if(systemd_FOUND)
60 |     list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp)
61 | endif()
62 | 
63 | enable_testing()
64 | 
65 | function(spdlog_prepare_test test_target spdlog_lib)
66 |     add_executable(${test_target} ${SPDLOG_UTESTS_SOURCES})
67 |     spdlog_enable_warnings(${test_target})
68 |     target_link_libraries(${test_target} PRIVATE ${spdlog_lib})
69 |     if(systemd_FOUND)
70 |         target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES})
71 |     endif()
72 |     target_link_libraries(${test_target} PRIVATE Catch2::Catch2WithMain)
73 |     if(SPDLOG_SANITIZE_ADDRESS)
74 |         spdlog_enable_addr_sanitizer(${test_target})
75 |     elseif(SPDLOG_SANITIZE_THREAD)
76 |         spdlog_enable_thread_sanitizer(${test_target})
77 |     endif()
78 |     add_test(NAME ${test_target} COMMAND ${test_target})
79 |     set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON)
80 | endfunction()
81 | 
82 | # The compiled library tests
83 | if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_ALL)
84 |     spdlog_prepare_test(spdlog-utests spdlog::spdlog)
85 | endif()
86 | 
87 | # The header-only library version tests
88 | if(SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL)
89 |     spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only)
90 | endif()
91 | 


--------------------------------------------------------------------------------
/tests/includes.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #if defined(__GNUC__) && __GNUC__ == 12
 4 |     #pragma GCC diagnostic push
 5 |     #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"  // Workaround for GCC 12
 6 | #endif
 7 | #include <catch2/catch_all.hpp>
 8 | #if defined(__GNUC__) && __GNUC__ == 12
 9 |     #pragma GCC diagnostic pop
10 | #endif
11 | 
12 | #include "utils.h"
13 | #include <chrono>
14 | #include <cstdio>
15 | #include <exception>
16 | #include <fstream>
17 | #include <iostream>
18 | #include <ostream>
19 | #include <sstream>
20 | #include <string>
21 | #include <iomanip>
22 | #include <stdlib.h>
23 | 
24 | #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
25 | 
26 | #include "spdlog/spdlog.h"
27 | #include "spdlog/async.h"
28 | #include "spdlog/details/fmt_helper.h"
29 | #include "spdlog/details/os.h"
30 | 
31 | #ifndef SPDLOG_NO_TLS
32 |     #include "spdlog/mdc.h"
33 | #endif
34 | 
35 | #include "spdlog/sinks/basic_file_sink.h"
36 | #include "spdlog/sinks/daily_file_sink.h"
37 | #include "spdlog/sinks/null_sink.h"
38 | #include "spdlog/sinks/ostream_sink.h"
39 | #include "spdlog/sinks/rotating_file_sink.h"
40 | #include "spdlog/sinks/stdout_color_sinks.h"
41 | #include "spdlog/sinks/msvc_sink.h"
42 | #include "spdlog/pattern_formatter.h"
43 | 


--------------------------------------------------------------------------------
/tests/main.cpp:
--------------------------------------------------------------------------------
 1 | #if defined(__GNUC__) && __GNUC__ == 12
 2 |     #pragma GCC diagnostic push
 3 |     #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"  // Workaround for GCC 12
 4 | #endif
 5 | 
 6 | #include <catch2/catch_all.hpp>
 7 | 
 8 | #if defined(__GNUC__) && __GNUC__ == 12
 9 |     #pragma GCC diagnostic pop
10 | #endif
11 | 


--------------------------------------------------------------------------------
/tests/test_backtrace.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "test_sink.h"
 3 | #include "spdlog/async.h"
 4 | 
 5 | TEST_CASE("bactrace1", "[bactrace]") {
 6 |     using spdlog::sinks::test_sink_st;
 7 |     auto test_sink = std::make_shared<test_sink_st>();
 8 |     size_t backtrace_size = 5;
 9 | 
10 |     spdlog::logger logger("test-backtrace", test_sink);
11 |     logger.set_pattern("%v");
12 |     logger.enable_backtrace(backtrace_size);
13 | 
14 |     logger.info("info message");
15 |     for (int i = 0; i < 100; i++) logger.debug("debug message {}", i);
16 | 
17 |     REQUIRE(test_sink->lines().size() == 1);
18 |     REQUIRE(test_sink->lines()[0] == "info message");
19 | 
20 |     logger.dump_backtrace();
21 |     REQUIRE(test_sink->lines().size() == backtrace_size + 3);
22 |     REQUIRE(test_sink->lines()[1] == "****************** Backtrace Start ******************");
23 |     REQUIRE(test_sink->lines()[2] == "debug message 95");
24 |     REQUIRE(test_sink->lines()[3] == "debug message 96");
25 |     REQUIRE(test_sink->lines()[4] == "debug message 97");
26 |     REQUIRE(test_sink->lines()[5] == "debug message 98");
27 |     REQUIRE(test_sink->lines()[6] == "debug message 99");
28 |     REQUIRE(test_sink->lines()[7] == "****************** Backtrace End ********************");
29 | }
30 | 
31 | TEST_CASE("bactrace-empty", "[bactrace]") {
32 |     using spdlog::sinks::test_sink_st;
33 |     auto test_sink = std::make_shared<test_sink_st>();
34 |     size_t backtrace_size = 5;
35 | 
36 |     spdlog::logger logger("test-backtrace", test_sink);
37 |     logger.set_pattern("%v");
38 |     logger.enable_backtrace(backtrace_size);
39 |     logger.dump_backtrace();
40 |     REQUIRE(test_sink->lines().size() == 0);
41 | }
42 | 
43 | TEST_CASE("bactrace-async", "[bactrace]") {
44 |     using spdlog::sinks::test_sink_mt;
45 |     auto test_sink = std::make_shared<test_sink_mt>();
46 |     using spdlog::details::os::sleep_for_millis;
47 | 
48 |     size_t backtrace_size = 5;
49 | 
50 |     spdlog::init_thread_pool(120, 1);
51 |     auto logger = std::make_shared<spdlog::async_logger>("test-bactrace-async", test_sink,
52 |                                                          spdlog::thread_pool());
53 |     logger->set_pattern("%v");
54 |     logger->enable_backtrace(backtrace_size);
55 | 
56 |     logger->info("info message");
57 |     for (int i = 0; i < 100; i++) logger->debug("debug message {}", i);
58 | 
59 |     sleep_for_millis(100);
60 |     REQUIRE(test_sink->lines().size() == 1);
61 |     REQUIRE(test_sink->lines()[0] == "info message");
62 | 
63 |     logger->dump_backtrace();
64 |     sleep_for_millis(100);  //  give time for the async dump to complete
65 |     REQUIRE(test_sink->lines().size() == backtrace_size + 3);
66 |     REQUIRE(test_sink->lines()[1] == "****************** Backtrace Start ******************");
67 |     REQUIRE(test_sink->lines()[2] == "debug message 95");
68 |     REQUIRE(test_sink->lines()[3] == "debug message 96");
69 |     REQUIRE(test_sink->lines()[4] == "debug message 97");
70 |     REQUIRE(test_sink->lines()[5] == "debug message 98");
71 |     REQUIRE(test_sink->lines()[6] == "debug message 99");
72 |     REQUIRE(test_sink->lines()[7] == "****************** Backtrace End ********************");
73 | }
74 | 


--------------------------------------------------------------------------------
/tests/test_bin_to_hex.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "test_sink.h"
 3 | #include "spdlog/fmt/bin_to_hex.h"
 4 | 
 5 | TEST_CASE("to_hex", "[to_hex]") {
 6 |     std::ostringstream oss;
 7 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
 8 |     spdlog::logger oss_logger("oss", oss_sink);
 9 | 
10 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0xc, 0xff, 0xff};
11 |     oss_logger.info("{}", spdlog::to_hex(v));
12 | 
13 |     auto output = oss.str();
14 |     REQUIRE(ends_with(output,
15 |                       "0000: 09 0a 0b 0c ff ff" + std::string(spdlog::details::os::default_eol)));
16 | }
17 | 
18 | TEST_CASE("to_hex_upper", "[to_hex]") {
19 |     std::ostringstream oss;
20 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
21 |     spdlog::logger oss_logger("oss", oss_sink);
22 | 
23 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0xc, 0xff, 0xff};
24 |     oss_logger.info("{:X}", spdlog::to_hex(v));
25 | 
26 |     auto output = oss.str();
27 |     REQUIRE(ends_with(output,
28 |                       "0000: 09 0A 0B 0C FF FF" + std::string(spdlog::details::os::default_eol)));
29 | }
30 | 
31 | TEST_CASE("to_hex_no_delimiter", "[to_hex]") {
32 |     std::ostringstream oss;
33 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
34 |     spdlog::logger oss_logger("oss", oss_sink);
35 | 
36 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0xc, 0xff, 0xff};
37 |     oss_logger.info("{:sX}", spdlog::to_hex(v));
38 | 
39 |     auto output = oss.str();
40 |     REQUIRE(
41 |         ends_with(output, "0000: 090A0B0CFFFF" + std::string(spdlog::details::os::default_eol)));
42 | }
43 | 
44 | TEST_CASE("to_hex_show_ascii", "[to_hex]") {
45 |     std::ostringstream oss;
46 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
47 |     spdlog::logger oss_logger("oss", oss_sink);
48 | 
49 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
50 |     oss_logger.info("{:Xsa}", spdlog::to_hex(v, 8));
51 | 
52 |     REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF  ...A.K.." +
53 |                                      std::string(spdlog::details::os::default_eol)));
54 | }
55 | 
56 | TEST_CASE("to_hex_different_size_per_line", "[to_hex]") {
57 |     std::ostringstream oss;
58 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
59 |     spdlog::logger oss_logger("oss", oss_sink);
60 | 
61 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
62 | 
63 |     oss_logger.info("{:Xsa}", spdlog::to_hex(v, 10));
64 |     REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF  ...A.K.." +
65 |                                      std::string(spdlog::details::os::default_eol)));
66 | 
67 |     oss_logger.info("{:Xs}", spdlog::to_hex(v, 10));
68 |     REQUIRE(ends_with(oss.str(),
69 |                       "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
70 | 
71 |     oss_logger.info("{:Xsa}", spdlog::to_hex(v, 6));
72 |     REQUIRE(ends_with(
73 |         oss.str(), "0000: 090A0B410C4B  ...A.K" + std::string(spdlog::details::os::default_eol) +
74 |                        "0006: FFFF          .." + std::string(spdlog::details::os::default_eol)));
75 | 
76 |     oss_logger.info("{:Xs}", spdlog::to_hex(v, 6));
77 |     REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B" +
78 |                                      std::string(spdlog::details::os::default_eol) + "0006: FFFF" +
79 |                                      std::string(spdlog::details::os::default_eol)));
80 | }
81 | 
82 | TEST_CASE("to_hex_no_ascii", "[to_hex]") {
83 |     std::ostringstream oss;
84 |     auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
85 |     spdlog::logger oss_logger("oss", oss_sink);
86 | 
87 |     std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
88 |     oss_logger.info("{:Xs}", spdlog::to_hex(v, 8));
89 | 
90 |     REQUIRE(ends_with(oss.str(),
91 |                       "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
92 | 
93 |     oss_logger.info("{:Xsna}", spdlog::to_hex(v, 8));
94 | 
95 |     REQUIRE(
96 |         ends_with(oss.str(), "090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
97 | }
98 | 


--------------------------------------------------------------------------------
/tests/test_circular_q.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "spdlog/details/circular_q.h"
 3 | 
 4 | using q_type = spdlog::details::circular_q<size_t>;
 5 | TEST_CASE("test_size", "[circular_q]") {
 6 |     const size_t q_size = 4;
 7 |     q_type q(q_size);
 8 |     REQUIRE(q.size() == 0);
 9 |     REQUIRE(q.empty() == true);
10 |     for (size_t i = 0; i < q_size; i++) {
11 |         q.push_back(std::move(i));
12 |     }
13 |     REQUIRE(q.size() == q_size);
14 |     q.push_back(999);
15 |     REQUIRE(q.size() == q_size);
16 | }
17 | 
18 | TEST_CASE("test_rolling", "[circular_q]") {
19 |     const size_t q_size = 4;
20 |     q_type q(q_size);
21 | 
22 |     for (size_t i = 0; i < q_size + 2; i++) {
23 |         q.push_back(std::move(i));
24 |     }
25 | 
26 |     REQUIRE(q.size() == q_size);
27 | 
28 |     REQUIRE(q.front() == 2);
29 |     q.pop_front();
30 | 
31 |     REQUIRE(q.front() == 3);
32 |     q.pop_front();
33 | 
34 |     REQUIRE(q.front() == 4);
35 |     q.pop_front();
36 | 
37 |     REQUIRE(q.front() == 5);
38 |     q.pop_front();
39 | 
40 |     REQUIRE(q.empty());
41 | 
42 |     q.push_back(6);
43 |     REQUIRE(q.front() == 6);
44 | }
45 | 
46 | TEST_CASE("test_empty", "[circular_q]") {
47 |     q_type q(0);
48 |     q.push_back(1);
49 |     REQUIRE(q.empty());
50 | }


--------------------------------------------------------------------------------
/tests/test_custom_callbacks.cpp:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * This content is released under the MIT License as specified in
 3 |  * https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
 4 |  */
 5 | #include "includes.h"
 6 | #include "test_sink.h"
 7 | #include "spdlog/sinks/callback_sink.h"
 8 | #include "spdlog/async.h"
 9 | #include "spdlog/common.h"
10 | 
11 | TEST_CASE("custom_callback_logger", "[custom_callback_logger]") {
12 |     std::vector<std::string> lines;
13 |     spdlog::pattern_formatter formatter;
14 |     auto callback_logger =
15 |         std::make_shared<spdlog::sinks::callback_sink_st>([&](const spdlog::details::log_msg &msg) {
16 |             spdlog::memory_buf_t formatted;
17 |             formatter.format(msg, formatted);
18 |             auto eol_len = strlen(spdlog::details::os::default_eol);
19 |             using diff_t =
20 |                 typename std::iterator_traits<decltype(formatted.end())>::difference_type;
21 |             lines.emplace_back(formatted.begin(), formatted.end() - static_cast<diff_t>(eol_len));
22 |         });
23 |     std::shared_ptr<spdlog::sinks::test_sink_st> test_sink(new spdlog::sinks::test_sink_st);
24 | 
25 |     spdlog::logger logger("test-callback", {callback_logger, test_sink});
26 | 
27 |     logger.info("test message 1");
28 |     logger.info("test message 2");
29 |     logger.info("test message 3");
30 | 
31 |     std::vector<std::string> ref_lines = test_sink->lines();
32 | 
33 |     REQUIRE(lines[0] == ref_lines[0]);
34 |     REQUIRE(lines[1] == ref_lines[1]);
35 |     REQUIRE(lines[2] == ref_lines[2]);
36 |     spdlog::drop_all();
37 | }
38 | 


--------------------------------------------------------------------------------
/tests/test_dup_filter.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "spdlog/sinks/dup_filter_sink.h"
 3 | #include "test_sink.h"
 4 | 
 5 | TEST_CASE("dup_filter_test1", "[dup_filter_sink]") {
 6 |     using spdlog::sinks::dup_filter_sink_st;
 7 |     using spdlog::sinks::test_sink_mt;
 8 | 
 9 |     dup_filter_sink_st dup_sink{std::chrono::seconds{5}};
10 |     auto test_sink = std::make_shared<test_sink_mt>();
11 |     dup_sink.add_sink(test_sink);
12 | 
13 |     for (int i = 0; i < 10; i++) {
14 |         dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
15 |     }
16 | 
17 |     REQUIRE(test_sink->msg_counter() == 1);
18 | }
19 | 
20 | TEST_CASE("dup_filter_test2", "[dup_filter_sink]") {
21 |     using spdlog::sinks::dup_filter_sink_st;
22 |     using spdlog::sinks::test_sink_mt;
23 | 
24 |     dup_filter_sink_st dup_sink{std::chrono::seconds{0}};
25 |     auto test_sink = std::make_shared<test_sink_mt>();
26 |     dup_sink.add_sink(test_sink);
27 | 
28 |     for (int i = 0; i < 10; i++) {
29 |         dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
30 |         std::this_thread::sleep_for(std::chrono::milliseconds(5));
31 |     }
32 | 
33 |     REQUIRE(test_sink->msg_counter() == 10);
34 | }
35 | 
36 | TEST_CASE("dup_filter_test3", "[dup_filter_sink]") {
37 |     using spdlog::sinks::dup_filter_sink_st;
38 |     using spdlog::sinks::test_sink_mt;
39 | 
40 |     dup_filter_sink_st dup_sink{std::chrono::seconds{1}};
41 |     auto test_sink = std::make_shared<test_sink_mt>();
42 |     dup_sink.add_sink(test_sink);
43 | 
44 |     for (int i = 0; i < 10; i++) {
45 |         dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
46 |         dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"});
47 |     }
48 | 
49 |     REQUIRE(test_sink->msg_counter() == 20);
50 | }
51 | 
52 | TEST_CASE("dup_filter_test4", "[dup_filter_sink]") {
53 |     using spdlog::sinks::dup_filter_sink_mt;
54 |     using spdlog::sinks::test_sink_mt;
55 | 
56 |     dup_filter_sink_mt dup_sink{std::chrono::milliseconds{10}};
57 |     auto test_sink = std::make_shared<test_sink_mt>();
58 |     dup_sink.add_sink(test_sink);
59 | 
60 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"});
61 |     std::this_thread::sleep_for(std::chrono::milliseconds(50));
62 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"});
63 |     REQUIRE(test_sink->msg_counter() == 2);
64 | }
65 | 
66 | TEST_CASE("dup_filter_test5", "[dup_filter_sink]") {
67 |     using spdlog::sinks::dup_filter_sink_mt;
68 |     using spdlog::sinks::test_sink_mt;
69 | 
70 |     dup_filter_sink_mt dup_sink{std::chrono::seconds{5}};
71 |     auto test_sink = std::make_shared<test_sink_mt>();
72 |     test_sink->set_pattern("%v");
73 |     dup_sink.add_sink(test_sink);
74 | 
75 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
76 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
77 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"});
78 |     dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"});
79 | 
80 |     REQUIRE(test_sink->msg_counter() ==
81 |             3);  // skip 2 messages but log the "skipped.." message before message2
82 |     REQUIRE(test_sink->lines()[1] == "Skipped 2 duplicate messages..");
83 | }
84 | 


--------------------------------------------------------------------------------
/tests/test_eventlog.cpp:
--------------------------------------------------------------------------------
 1 | #if _WIN32
 2 | 
 3 |     #include "includes.h"
 4 |     #include "test_sink.h"
 5 | 
 6 |     #include "spdlog/sinks/win_eventlog_sink.h"
 7 | 
 8 | static const LPCSTR TEST_SOURCE = "spdlog_test";
 9 | 
10 | static void test_single_print(std::function<void(std::string const &)> do_log,
11 |                               std::string const &expected_contents,
12 |                               WORD expected_ev_type) {
13 |     using namespace std::chrono;
14 |     do_log(expected_contents);
15 |     const auto expected_time_generated =
16 |         duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
17 | 
18 |     struct handle_t {
19 |         HANDLE handle_;
20 | 
21 |         ~handle_t() {
22 |             if (handle_) {
23 |                 REQUIRE(CloseEventLog(handle_));
24 |             }
25 |         }
26 |     } event_log{::OpenEventLogA(nullptr, TEST_SOURCE)};
27 | 
28 |     REQUIRE(event_log.handle_);
29 | 
30 |     DWORD read_bytes{}, size_needed{};
31 |     auto ok = ::ReadEventLogA(event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ,
32 |                               0, &read_bytes, 0, &read_bytes, &size_needed);
33 |     REQUIRE(!ok);
34 |     REQUIRE(::GetLastError() == ERROR_INSUFFICIENT_BUFFER);
35 | 
36 |     std::vector<char> record_buffer(size_needed);
37 |     PEVENTLOGRECORD record = (PEVENTLOGRECORD)record_buffer.data();
38 | 
39 |     ok = ::ReadEventLogA(event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0,
40 |                          record, size_needed, &read_bytes, &size_needed);
41 |     REQUIRE(ok);
42 | 
43 |     REQUIRE(record->NumStrings == 1);
44 |     REQUIRE(record->EventType == expected_ev_type);
45 |     REQUIRE((expected_time_generated - record->TimeGenerated) <= 3u);
46 | 
47 |     std::string message_in_log(((char *)record + record->StringOffset));
48 |     REQUIRE(message_in_log == expected_contents + spdlog::details::os::default_eol);
49 | }
50 | 
51 | TEST_CASE("eventlog", "[eventlog]") {
52 |     using namespace spdlog;
53 | 
54 |     auto test_sink = std::make_shared<sinks::win_eventlog_sink_mt>(TEST_SOURCE);
55 | 
56 |     spdlog::logger test_logger("eventlog", test_sink);
57 |     test_logger.set_level(level::trace);
58 | 
59 |     test_sink->set_pattern("%v");
60 | 
61 |     test_single_print([&test_logger](std::string const &msg) { test_logger.trace(msg); },
62 |                       "my trace message", EVENTLOG_SUCCESS);
63 |     test_single_print([&test_logger](std::string const &msg) { test_logger.debug(msg); },
64 |                       "my debug message", EVENTLOG_SUCCESS);
65 |     test_single_print([&test_logger](std::string const &msg) { test_logger.info(msg); },
66 |                       "my info message", EVENTLOG_INFORMATION_TYPE);
67 |     test_single_print([&test_logger](std::string const &msg) { test_logger.warn(msg); },
68 |                       "my warn message", EVENTLOG_WARNING_TYPE);
69 |     test_single_print([&test_logger](std::string const &msg) { test_logger.error(msg); },
70 |                       "my error message", EVENTLOG_ERROR_TYPE);
71 |     test_single_print([&test_logger](std::string const &msg) { test_logger.critical(msg); },
72 |                       "my critical message", EVENTLOG_ERROR_TYPE);
73 | }
74 | 
75 | #endif  //_WIN32
76 | 


--------------------------------------------------------------------------------
/tests/test_fmt_helper.cpp:
--------------------------------------------------------------------------------
 1 | 
 2 | #include "includes.h"
 3 | 
 4 | using spdlog::memory_buf_t;
 5 | using spdlog::details::to_string_view;
 6 | 
 7 | void test_pad2(int n, const char *expected) {
 8 |     memory_buf_t buf;
 9 |     spdlog::details::fmt_helper::pad2(n, buf);
10 | 
11 |     REQUIRE(to_string_view(buf) == expected);
12 | }
13 | 
14 | void test_pad3(uint32_t n, const char *expected) {
15 |     memory_buf_t buf;
16 |     spdlog::details::fmt_helper::pad3(n, buf);
17 | 
18 |     REQUIRE(to_string_view(buf) == expected);
19 | }
20 | 
21 | void test_pad6(std::size_t n, const char *expected) {
22 |     memory_buf_t buf;
23 |     spdlog::details::fmt_helper::pad6(n, buf);
24 | 
25 |     REQUIRE(to_string_view(buf) == expected);
26 | }
27 | 
28 | void test_pad9(std::size_t n, const char *expected) {
29 |     memory_buf_t buf;
30 |     spdlog::details::fmt_helper::pad9(n, buf);
31 | 
32 |     REQUIRE(to_string_view(buf) == expected);
33 | }
34 | 
35 | TEST_CASE("pad2", "[fmt_helper]") {
36 |     test_pad2(0, "00");
37 |     test_pad2(3, "03");
38 |     test_pad2(10, "10");
39 |     test_pad2(23, "23");
40 |     test_pad2(99, "99");
41 |     test_pad2(100, "100");
42 |     test_pad2(123, "123");
43 |     test_pad2(1234, "1234");
44 |     test_pad2(-5, "-5");
45 | }
46 | 
47 | TEST_CASE("pad3", "[fmt_helper]") {
48 |     test_pad3(0, "000");
49 |     test_pad3(3, "003");
50 |     test_pad3(10, "010");
51 |     test_pad3(23, "023");
52 |     test_pad3(99, "099");
53 |     test_pad3(100, "100");
54 |     test_pad3(123, "123");
55 |     test_pad3(999, "999");
56 |     test_pad3(1000, "1000");
57 |     test_pad3(1234, "1234");
58 | }
59 | 
60 | TEST_CASE("pad6", "[fmt_helper]") {
61 |     test_pad6(0, "000000");
62 |     test_pad6(3, "000003");
63 |     test_pad6(23, "000023");
64 |     test_pad6(123, "000123");
65 |     test_pad6(1234, "001234");
66 |     test_pad6(12345, "012345");
67 |     test_pad6(123456, "123456");
68 | }
69 | 
70 | TEST_CASE("pad9", "[fmt_helper]") {
71 |     test_pad9(0, "000000000");
72 |     test_pad9(3, "000000003");
73 |     test_pad9(23, "000000023");
74 |     test_pad9(123, "000000123");
75 |     test_pad9(1234, "000001234");
76 |     test_pad9(12345, "000012345");
77 |     test_pad9(123456, "000123456");
78 |     test_pad9(1234567, "001234567");
79 |     test_pad9(12345678, "012345678");
80 |     test_pad9(123456789, "123456789");
81 |     test_pad9(1234567891, "1234567891");
82 | }
83 | 


--------------------------------------------------------------------------------
/tests/test_macros.cpp:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * This content is released under the MIT License as specified in
 3 |  * https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
 4 |  */
 5 | 
 6 | #include "includes.h"
 7 | 
 8 | #if SPDLOG_ACTIVE_LEVEL != SPDLOG_LEVEL_DEBUG
 9 |     #error "Invalid SPDLOG_ACTIVE_LEVEL in test. Should be SPDLOG_LEVEL_DEBUG"
10 | #endif
11 | 
12 | #define TEST_FILENAME "test_logs/simple_log"
13 | 
14 | TEST_CASE("debug and trace w/o format string", "[macros]") {
15 |     prepare_logdir();
16 |     spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
17 | 
18 |     auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
19 |     logger->set_pattern("%v");
20 |     logger->set_level(spdlog::level::trace);
21 | 
22 |     SPDLOG_LOGGER_TRACE(logger, "Test message 1");
23 |     SPDLOG_LOGGER_DEBUG(logger, "Test message 2");
24 |     logger->flush();
25 | 
26 |     using spdlog::details::os::default_eol;
27 |     REQUIRE(ends_with(file_contents(TEST_FILENAME),
28 |                       spdlog::fmt_lib::format("Test message 2{}", default_eol)));
29 |     REQUIRE(count_lines(TEST_FILENAME) == 1);
30 | 
31 |     auto orig_default_logger = spdlog::default_logger();
32 |     spdlog::set_default_logger(logger);
33 | 
34 |     SPDLOG_TRACE("Test message 3");
35 |     SPDLOG_DEBUG("Test message {}", 4);
36 |     logger->flush();
37 | 
38 |     require_message_count(TEST_FILENAME, 2);
39 |     REQUIRE(ends_with(file_contents(TEST_FILENAME),
40 |                       spdlog::fmt_lib::format("Test message 4{}", default_eol)));
41 |     spdlog::set_default_logger(std::move(orig_default_logger));
42 | }
43 | 
44 | TEST_CASE("disable param evaluation", "[macros]") {
45 |     SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated"));
46 | }
47 | 
48 | TEST_CASE("pass logger pointer", "[macros]") {
49 |     auto logger = spdlog::create<spdlog::sinks::null_sink_mt>("refmacro");
50 |     auto &ref = *logger;
51 |     SPDLOG_LOGGER_TRACE(&ref, "Test message 1");
52 |     SPDLOG_LOGGER_DEBUG(&ref, "Test message 2");
53 | }
54 | 


--------------------------------------------------------------------------------
/tests/test_mpmc_q.cpp:
--------------------------------------------------------------------------------
  1 | #include "includes.h"
  2 | 
  3 | using std::chrono::milliseconds;
  4 | using test_clock = std::chrono::high_resolution_clock;
  5 | 
  6 | static milliseconds millis_from(const test_clock::time_point &tp0) {
  7 |     return std::chrono::duration_cast<milliseconds>(test_clock::now() - tp0);
  8 | }
  9 | TEST_CASE("dequeue-empty-nowait", "[mpmc_blocking_q]") {
 10 |     size_t q_size = 100;
 11 |     milliseconds tolerance_wait(20);
 12 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 13 |     int popped_item = 0;
 14 | 
 15 |     auto start = test_clock::now();
 16 |     auto rv = q.dequeue_for(popped_item, milliseconds::zero());
 17 |     auto delta_ms = millis_from(start);
 18 | 
 19 |     REQUIRE(rv == false);
 20 |     INFO("Delta " << delta_ms.count() << " millis");
 21 |     REQUIRE(delta_ms <= tolerance_wait);
 22 | }
 23 | 
 24 | TEST_CASE("dequeue-empty-wait", "[mpmc_blocking_q]") {
 25 |     size_t q_size = 100;
 26 |     milliseconds wait_ms(250);
 27 |     milliseconds tolerance_wait(250);
 28 | 
 29 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 30 |     int popped_item = 0;
 31 |     auto start = test_clock::now();
 32 |     auto rv = q.dequeue_for(popped_item, wait_ms);
 33 |     auto delta_ms = millis_from(start);
 34 | 
 35 |     REQUIRE(rv == false);
 36 | 
 37 |     INFO("Delta " << delta_ms.count() << " millis");
 38 |     REQUIRE(delta_ms >= wait_ms - tolerance_wait);
 39 |     REQUIRE(delta_ms <= wait_ms + tolerance_wait);
 40 | }
 41 | 
 42 | TEST_CASE("dequeue-full-nowait", "[mpmc_blocking_q]") {
 43 |     spdlog::details::mpmc_blocking_queue<int> q(1);
 44 |     q.enqueue(42);
 45 | 
 46 |     int item = 0;
 47 |     q.dequeue_for(item, milliseconds::zero());
 48 |     REQUIRE(item == 42);
 49 | }
 50 | 
 51 | TEST_CASE("dequeue-full-wait", "[mpmc_blocking_q]") {
 52 |     spdlog::details::mpmc_blocking_queue<int> q(1);
 53 |     q.enqueue(42);
 54 | 
 55 |     int item = 0;
 56 |     q.dequeue(item);
 57 |     REQUIRE(item == 42);
 58 | }
 59 | 
 60 | TEST_CASE("enqueue_nowait", "[mpmc_blocking_q]") {
 61 |     size_t q_size = 1;
 62 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 63 |     milliseconds tolerance_wait(10);
 64 | 
 65 |     q.enqueue(1);
 66 |     REQUIRE(q.overrun_counter() == 0);
 67 | 
 68 |     auto start = test_clock::now();
 69 |     q.enqueue_nowait(2);
 70 |     auto delta_ms = millis_from(start);
 71 | 
 72 |     INFO("Delta " << delta_ms.count() << " millis");
 73 |     REQUIRE(delta_ms <= tolerance_wait);
 74 |     REQUIRE(q.overrun_counter() == 1);
 75 | }
 76 | 
 77 | TEST_CASE("bad_queue", "[mpmc_blocking_q]") {
 78 |     size_t q_size = 0;
 79 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 80 |     q.enqueue_nowait(1);
 81 |     REQUIRE(q.overrun_counter() == 1);
 82 |     int i = 0;
 83 |     REQUIRE(q.dequeue_for(i, milliseconds(0)) == false);
 84 | }
 85 | 
 86 | TEST_CASE("empty_queue", "[mpmc_blocking_q]") {
 87 |     size_t q_size = 10;
 88 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 89 |     int i = 0;
 90 |     REQUIRE(q.dequeue_for(i, milliseconds(10)) == false);
 91 | }
 92 | 
 93 | TEST_CASE("full_queue", "[mpmc_blocking_q]") {
 94 |     size_t q_size = 100;
 95 |     spdlog::details::mpmc_blocking_queue<int> q(q_size);
 96 |     for (int i = 0; i < static_cast<int>(q_size); i++) {
 97 |         q.enqueue(i + 0);  // i+0 to force rvalue and avoid tidy warnings on the same time if we
 98 |                            // std::move(i) instead
 99 |     }
100 | 
101 |     q.enqueue_nowait(123456);
102 |     REQUIRE(q.overrun_counter() == 1);
103 | 
104 |     for (int i = 1; i < static_cast<int>(q_size); i++) {
105 |         int item = -1;
106 |         q.dequeue(item);
107 |         REQUIRE(item == i);
108 |     }
109 | 
110 |     // last item pushed has overridden the oldest.
111 |     int item = -1;
112 |     q.dequeue(item);
113 |     REQUIRE(item == 123456);
114 | }
115 | 


--------------------------------------------------------------------------------
/tests/test_ringbuffer.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "spdlog/sinks/ringbuffer_sink.h"
 3 | 
 4 | TEST_CASE("ringbuffer invalid size", "[ringbuffer]") {
 5 |     REQUIRE_THROWS_AS(spdlog::sinks::ringbuffer_sink_mt(0), spdlog::spdlog_ex);
 6 | }
 7 | 
 8 | TEST_CASE("ringbuffer stores formatted messages", "[ringbuffer]") {
 9 |     spdlog::sinks::ringbuffer_sink_st sink(3);
10 |     sink.set_pattern("%v");
11 | 
12 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg1"});
13 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg2"});
14 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "msg3"});
15 | 
16 |     auto formatted = sink.last_formatted();
17 |     REQUIRE(formatted.size() == 3);
18 |     using spdlog::details::os::default_eol;
19 |     REQUIRE(formatted[0] == spdlog::fmt_lib::format("msg1{}", default_eol));
20 |     REQUIRE(formatted[1] == spdlog::fmt_lib::format("msg2{}", default_eol));
21 |     REQUIRE(formatted[2] == spdlog::fmt_lib::format("msg3{}", default_eol));
22 | }
23 | 
24 | TEST_CASE("ringbuffer overrun keeps last items", "[ringbuffer]") {
25 |     spdlog::sinks::ringbuffer_sink_st sink(2);
26 |     sink.set_pattern("%v");
27 | 
28 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "first"});
29 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "second"});
30 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "third"});
31 | 
32 |     auto formatted = sink.last_formatted();
33 |     REQUIRE(formatted.size() == 2);
34 |     using spdlog::details::os::default_eol;
35 |     REQUIRE(formatted[0] == spdlog::fmt_lib::format("second{}", default_eol));
36 |     REQUIRE(formatted[1] == spdlog::fmt_lib::format("third{}", default_eol));
37 | }
38 | 
39 | TEST_CASE("ringbuffer retrieval limit", "[ringbuffer]") {
40 |     spdlog::sinks::ringbuffer_sink_st sink(3);
41 |     sink.set_pattern("%v");
42 | 
43 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "A"});
44 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "B"});
45 |     sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "C"});
46 | 
47 |     auto formatted = sink.last_formatted(2);
48 |     REQUIRE(formatted.size() == 2);
49 |     using spdlog::details::os::default_eol;
50 |     REQUIRE(formatted[0] == spdlog::fmt_lib::format("B{}", default_eol));
51 |     REQUIRE(formatted[1] == spdlog::fmt_lib::format("C{}", default_eol));
52 | }
53 | 
54 | 


--------------------------------------------------------------------------------
/tests/test_sink.h:
--------------------------------------------------------------------------------
 1 | //
 2 | // Copyright(c) 2018 Gabi Melman.
 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 4 | //
 5 | 
 6 | #pragma once
 7 | 
 8 | #include "spdlog/details/null_mutex.h"
 9 | #include "spdlog/sinks/base_sink.h"
10 | #include "spdlog/fmt/fmt.h"
11 | #include <chrono>
12 | #include <mutex>
13 | #include <thread>
14 | 
15 | namespace spdlog {
16 | namespace sinks {
17 | 
18 | template <class Mutex>
19 | class test_sink : public base_sink<Mutex> {
20 |     const size_t lines_to_save = 100;
21 | 
22 | public:
23 |     size_t msg_counter() {
24 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
25 |         return msg_counter_;
26 |     }
27 | 
28 |     size_t flush_counter() {
29 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
30 |         return flush_counter_;
31 |     }
32 | 
33 |     void set_delay(std::chrono::milliseconds delay) {
34 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
35 |         delay_ = delay;
36 |     }
37 | 
38 |     // return last output without the eol
39 |     std::vector<std::string> lines() {
40 |         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
41 |         return lines_;
42 |     }
43 | 
44 | protected:
45 |     void sink_it_(const details::log_msg &msg) override {
46 |         memory_buf_t formatted;
47 |         base_sink<Mutex>::formatter_->format(msg, formatted);
48 |         // save the line without the eol
49 |         auto eol_len = strlen(details::os::default_eol);
50 |         using diff_t = typename std::iterator_traits<decltype(formatted.end())>::difference_type;
51 |         if (lines_.size() < lines_to_save) {
52 |             lines_.emplace_back(formatted.begin(), formatted.end() - static_cast<diff_t>(eol_len));
53 |         }
54 |         msg_counter_++;
55 |         std::this_thread::sleep_for(delay_);
56 |     }
57 | 
58 |     void flush_() override { flush_counter_++; }
59 | 
60 |     size_t msg_counter_{0};
61 |     size_t flush_counter_{0};
62 |     std::chrono::milliseconds delay_{std::chrono::milliseconds::zero()};
63 |     std::vector<std::string> lines_;
64 | };
65 | 
66 | using test_sink_mt = test_sink<std::mutex>;
67 | using test_sink_st = test_sink<details::null_mutex>;
68 | 
69 | }  // namespace sinks
70 | }  // namespace spdlog
71 | 


--------------------------------------------------------------------------------
/tests/test_stdout_api.cpp:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * This content is released under the MIT License as specified in
 3 |  * https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
 4 |  */
 5 | #include "includes.h"
 6 | #include "spdlog/sinks/stdout_sinks.h"
 7 | #include "spdlog/sinks/stdout_color_sinks.h"
 8 | TEST_CASE("stdout_st", "[stdout]") {
 9 |     auto l = spdlog::stdout_logger_st("test");
10 |     l->set_pattern("%+");
11 |     l->set_level(spdlog::level::trace);
12 |     l->trace("Test stdout_st");
13 |     spdlog::drop_all();
14 | }
15 | 
16 | TEST_CASE("stdout_mt", "[stdout]") {
17 |     auto l = spdlog::stdout_logger_mt("test");
18 |     l->set_pattern("%+");
19 |     l->set_level(spdlog::level::debug);
20 |     l->debug("Test stdout_mt");
21 |     spdlog::drop_all();
22 | }
23 | 
24 | TEST_CASE("stderr_st", "[stderr]") {
25 |     auto l = spdlog::stderr_logger_st("test");
26 |     l->set_pattern("%+");
27 |     l->info("Test stderr_st");
28 |     spdlog::drop_all();
29 | }
30 | 
31 | TEST_CASE("stderr_mt", "[stderr]") {
32 |     auto l = spdlog::stderr_logger_mt("test");
33 |     l->set_pattern("%+");
34 |     l->info("Test stderr_mt");
35 |     l->warn("Test stderr_mt");
36 |     l->error("Test stderr_mt");
37 |     l->critical("Test stderr_mt");
38 |     spdlog::drop_all();
39 | }
40 | 
41 | // color loggers
42 | TEST_CASE("stdout_color_st", "[stdout]") {
43 |     auto l = spdlog::stdout_color_st("test");
44 |     l->set_pattern("%+");
45 |     l->info("Test stdout_color_st");
46 |     spdlog::drop_all();
47 | }
48 | 
49 | TEST_CASE("stdout_color_mt", "[stdout]") {
50 |     auto l = spdlog::stdout_color_mt("test");
51 |     l->set_pattern("%+");
52 |     l->set_level(spdlog::level::trace);
53 |     l->trace("Test stdout_color_mt");
54 |     spdlog::drop_all();
55 | }
56 | 
57 | TEST_CASE("stderr_color_st", "[stderr]") {
58 |     auto l = spdlog::stderr_color_st("test");
59 |     l->set_pattern("%+");
60 |     l->set_level(spdlog::level::debug);
61 |     l->debug("Test stderr_color_st");
62 |     spdlog::drop_all();
63 | }
64 | 
65 | TEST_CASE("stderr_color_mt", "[stderr]") {
66 |     auto l = spdlog::stderr_color_mt("test");
67 |     l->set_pattern("%+");
68 |     l->info("Test stderr_color_mt");
69 |     l->warn("Test stderr_color_mt");
70 |     l->error("Test stderr_color_mt");
71 |     l->critical("Test stderr_color_mt");
72 |     spdlog::drop_all();
73 | }
74 | 
75 | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
76 | 
77 | TEST_CASE("wchar_api", "[stdout]") {
78 |     auto l = spdlog::stdout_logger_st("wchar_logger");
79 |     l->set_pattern("%+");
80 |     l->set_level(spdlog::level::trace);
81 |     l->trace(L"Test wchar_api");
82 |     l->trace(L"Test wchar_api {}", L"param");
83 |     l->trace(L"Test wchar_api {}", 1);
84 |     l->trace(L"Test wchar_api {}", std::wstring{L"wstring param"});
85 |     l->trace(std::wstring{L"Test wchar_api wstring"});
86 |     SPDLOG_LOGGER_DEBUG(l, L"Test SPDLOG_LOGGER_DEBUG {}", L"param");
87 |     spdlog::drop_all();
88 | }
89 | 
90 | #endif
91 | 


--------------------------------------------------------------------------------
/tests/test_stopwatch.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "test_sink.h"
 3 | #include "spdlog/stopwatch.h"
 4 | 
 5 | TEST_CASE("stopwatch1", "[stopwatch]") {
 6 |     using std::chrono::milliseconds;
 7 |     using clock = std::chrono::steady_clock;
 8 |     milliseconds wait_ms(500);
 9 |     milliseconds tolerance_ms(250);
10 |     auto start = clock::now();
11 |     spdlog::stopwatch sw;
12 |     std::this_thread::sleep_for(wait_ms);
13 |     auto stop = clock::now();
14 |     auto diff_ms = std::chrono::duration_cast<milliseconds>(stop - start);
15 |     REQUIRE(sw.elapsed() >= diff_ms);
16 |     REQUIRE(sw.elapsed() <= diff_ms + tolerance_ms);
17 | }
18 | 
19 | TEST_CASE("stopwatch2", "[stopwatch]") {
20 |     using spdlog::sinks::test_sink_st;
21 |     using std::chrono::duration_cast;
22 |     using std::chrono::milliseconds;
23 |     using clock = std::chrono::steady_clock;
24 | 
25 |     clock::duration wait_duration(milliseconds(500));
26 |     clock::duration tolerance_duration(milliseconds(250));
27 | 
28 |     auto test_sink = std::make_shared<test_sink_st>();
29 | 
30 |     auto start = clock::now();
31 |     spdlog::stopwatch sw;
32 |     spdlog::logger logger("test-stopwatch", test_sink);
33 |     logger.set_pattern("%v");
34 |     std::this_thread::sleep_for(wait_duration);
35 |     auto stop = clock::now();
36 |     logger.info("{}", sw);
37 |     auto val = std::stod(test_sink->lines()[0]);
38 |     auto diff_duration = duration_cast<std::chrono::duration<double>>(stop - start);
39 | 
40 |     REQUIRE(val >= (diff_duration).count() - 0.001);
41 |     REQUIRE(val <= (diff_duration + tolerance_duration).count());
42 | }
43 | 


--------------------------------------------------------------------------------
/tests/test_systemd.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "spdlog/sinks/systemd_sink.h"
 3 | 
 4 | TEST_CASE("systemd", "[all]") {
 5 |     auto systemd_sink = std::make_shared<spdlog::sinks::systemd_sink_st>();
 6 |     spdlog::logger logger("spdlog_systemd_test", systemd_sink);
 7 |     logger.set_level(spdlog::level::trace);
 8 |     logger.trace("test spdlog trace");
 9 |     logger.debug("test spdlog debug");
10 |     SPDLOG_LOGGER_INFO((&logger), "test spdlog info");
11 |     SPDLOG_LOGGER_WARN((&logger), "test spdlog warn");
12 |     SPDLOG_LOGGER_ERROR((&logger), "test spdlog error");
13 |     SPDLOG_LOGGER_CRITICAL((&logger), "test spdlog critical");
14 | }
15 | 


--------------------------------------------------------------------------------
/tests/test_time_point.cpp:
--------------------------------------------------------------------------------
 1 | #include "includes.h"
 2 | #include "test_sink.h"
 3 | #include "spdlog/async.h"
 4 | 
 5 | TEST_CASE("time_point1", "[time_point log_msg]") {
 6 |     std::shared_ptr<spdlog::sinks::test_sink_st> test_sink(new spdlog::sinks::test_sink_st);
 7 |     spdlog::logger logger("test-time_point", test_sink);
 8 | 
 9 |     spdlog::source_loc source{};
10 |     std::chrono::system_clock::time_point tp{std::chrono::system_clock::now()};
11 |     test_sink->set_pattern("%T.%F");  // interested in the time_point
12 | 
13 |     // all the following should have the same time
14 |     test_sink->set_delay(std::chrono::milliseconds(10));
15 |     for (int i = 0; i < 5; i++) {
16 |         spdlog::details::log_msg msg{tp, source, "test_logger", spdlog::level::info, "message"};
17 |         test_sink->log(msg);
18 |     }
19 | 
20 |     logger.log(tp, source, spdlog::level::info, "formatted message");
21 |     logger.log(tp, source, spdlog::level::info, "formatted message");
22 |     logger.log(tp, source, spdlog::level::info, "formatted message");
23 |     logger.log(tp, source, spdlog::level::info, "formatted message");
24 |     logger.log(source, spdlog::level::info,
25 |                "formatted message");  // last line has different time_point
26 | 
27 |     // now the real test... that the times are the same.
28 |     std::vector<std::string> lines = test_sink->lines();
29 |     REQUIRE(lines[0] == lines[1]);
30 |     REQUIRE(lines[2] == lines[3]);
31 |     REQUIRE(lines[4] == lines[5]);
32 |     REQUIRE(lines[6] == lines[7]);
33 |     REQUIRE(lines[8] != lines[9]);
34 |     spdlog::drop_all();
35 | }
36 | 


--------------------------------------------------------------------------------
/tests/utils.cpp:
--------------------------------------------------------------------------------
  1 | #include "includes.h"
  2 | 
  3 | #ifdef _WIN32
  4 |     #include <windows.h>
  5 | #else
  6 |     #include <sys/types.h>
  7 |     #include <dirent.h>
  8 | #endif
  9 | 
 10 | void prepare_logdir() {
 11 |     spdlog::drop_all();
 12 | #ifdef _WIN32
 13 |     system("rmdir /S /Q test_logs");
 14 | #else
 15 |     auto rv = system("rm -rf test_logs");
 16 |     if (rv != 0) {
 17 |         throw std::runtime_error("Failed to rm -rf test_logs");
 18 |     }
 19 | #endif
 20 | }
 21 | 
 22 | std::string file_contents(const std::string &filename) {
 23 |     std::ifstream ifs(filename, std::ios_base::binary);
 24 |     if (!ifs) {
 25 |         throw std::runtime_error("Failed open file ");
 26 |     }
 27 |     return std::string((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
 28 | }
 29 | 
 30 | std::size_t count_lines(const std::string &filename) {
 31 |     std::ifstream ifs(filename);
 32 |     if (!ifs) {
 33 |         throw std::runtime_error("Failed open file ");
 34 |     }
 35 | 
 36 |     std::string line;
 37 |     size_t counter = 0;
 38 |     while (std::getline(ifs, line)) counter++;
 39 |     return counter;
 40 | }
 41 | 
 42 | void require_message_count(const std::string &filename, const std::size_t messages) {
 43 |     if (strlen(spdlog::details::os::default_eol) == 0) {
 44 |         REQUIRE(count_lines(filename) == 1);
 45 |     } else {
 46 |         REQUIRE(count_lines(filename) == messages);
 47 |     }
 48 | }
 49 | 
 50 | std::size_t get_filesize(const std::string &filename) {
 51 |     std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary);
 52 |     if (!ifs) {
 53 |         throw std::runtime_error("Failed open file " + filename);
 54 |     }
 55 |     return static_cast<std::size_t>(ifs.tellg());
 56 | }
 57 | 
 58 | // source: https://stackoverflow.com/a/2072890/192001
 59 | bool ends_with(std::string const &value, std::string const &ending) {
 60 |     if (ending.size() > value.size()) {
 61 |         return false;
 62 |     }
 63 |     return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
 64 | }
 65 | 
 66 | #ifdef _WIN32
 67 | // Based on: https://stackoverflow.com/a/37416569/192001
 68 | std::size_t count_files(const std::string &folder) {
 69 |     size_t counter = 0;
 70 |     WIN32_FIND_DATAA ffd;
 71 | 
 72 |     // Start iterating over the files in the folder directory.
 73 |     HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd);
 74 |     if (hFind != INVALID_HANDLE_VALUE) {
 75 |         do  // Managed to locate and create an handle to that folder.
 76 |         {
 77 |             if (ffd.cFileName[0] != '.') counter++;
 78 |         } while (::FindNextFileA(hFind, &ffd) != 0);
 79 |         ::FindClose(hFind);
 80 |     } else {
 81 |         throw std::runtime_error("Failed open folder " + folder);
 82 |     }
 83 | 
 84 |     return counter;
 85 | }
 86 | #else
 87 | // Based on: https://stackoverflow.com/a/2802255/192001
 88 | std::size_t count_files(const std::string &folder) {
 89 |     size_t counter = 0;
 90 |     DIR *dp = opendir(folder.c_str());
 91 |     if (dp == nullptr) {
 92 |         throw std::runtime_error("Failed open folder " + folder);
 93 |     }
 94 | 
 95 |     struct dirent *ep = nullptr;
 96 |     while ((ep = readdir(dp)) != nullptr) {
 97 |         if (ep->d_name[0] != '.') counter++;
 98 |     }
 99 |     (void)closedir(dp);
100 |     return counter;
101 | }
102 | #endif
103 | 


--------------------------------------------------------------------------------
/tests/utils.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include <cstddef>
 4 | #include <string>
 5 | 
 6 | std::size_t count_files(const std::string &folder);
 7 | 
 8 | void prepare_logdir();
 9 | 
10 | std::string file_contents(const std::string &filename);
11 | 
12 | std::size_t count_lines(const std::string &filename);
13 | 
14 | void require_message_count(const std::string &filename, const std::size_t messages);
15 | 
16 | std::size_t get_filesize(const std::string &filename);
17 | 
18 | bool ends_with(std::string const &value, std::string const &ending);


--------------------------------------------------------------------------------