Full Code of gabime/spdlog for AI

v1.x 45b67eee6685 cached
175 files
1.1 MB
324.7k tokens
629 symbols
1 requests
Download .txt
Showing preview only (1,228K chars total). Download the full file or copy to clipboard to get everything.
Repository: gabime/spdlog
Branch: v1.x
Commit: 45b67eee6685
Files: 175
Total size: 1.1 MB

Directory structure:
gitextract_woroxd9g/

├── .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
├── 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
    ├── test_timezone.cpp
    ├── utils.cpp
    └── utils.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
Language:        Cpp
BasedOnStyle:  Google
AccessModifierOffset: -4
Standard:        c++17
IndentWidth:     4
TabWidth:        4
UseTab:          Never
ColumnLimit:     100
AlignAfterOpenBracket: Align
BinPackParameters: false
AlignEscapedNewlines: Left
AlwaysBreakTemplateDeclarations: Yes
PackConstructorInitializers: Never
BreakConstructorInitializersBeforeComma: false
IndentPPDirectives: None
SortIncludes:    Never
...


================================================
FILE: .clang-tidy
================================================
Checks: 'cppcoreguidelines-*,
performance-*,
modernize-*,
google-*,
misc-*
cert-*,
readability-*,
clang-analyzer-*,
-performance-unnecessary-value-param,
-modernize-use-trailing-return-type,
-google-runtime-references,
-misc-non-private-member-variables-in-classes,
-readability-braces-around-statements,
-google-readability-braces-around-statements,
-cppcoreguidelines-avoid-magic-numbers,
-readability-magic-numbers,
-readability-magic-numbers,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-avoid-c-arrays,
-modernize-avoid-c-arrays,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-readability-named-parameter,
-cert-env33-c
'


WarningsAsErrors: ''
HeaderFilterRegex: '*spdlog/[^f].*'
FormatStyle:     none

CheckOptions:    
  - key:             google-readability-braces-around-statements.ShortStatementLines
    value:           '1'
  - key:             google-readability-function-size.StatementThreshold
    value:           '800'
  - key:             google-readability-namespace-comments.ShortNamespaceLines
    value:           '10'
  - key:             google-readability-namespace-comments.SpacesBeforeComments
    value:           '2'
  - key:             modernize-loop-convert.MaxCopySize
    value:           '16'
  - key:             modernize-loop-convert.MinConfidence
    value:           reasonable
  - key:             modernize-loop-convert.NamingStyle
    value:           CamelCase
  - key:             modernize-pass-by-value.IncludeStyle
    value:           llvm
  - key:             modernize-replace-auto-ptr.IncludeStyle
    value:           llvm
  - key:             modernize-use-nullptr.NullMacros
    value:           'NULL'



================================================
FILE: .git-blame-ignore-revs
================================================
# clang-format
1a0bfc7a89f2d58e22605a4dc7e18a9a555b65aa
95c226e9c92928e20ccdac0d060e7241859e282b
9d52261185b5f2c454c381d626ec5c84d7b195f4
4b2a8219d5d1b40062d030441adde7d1fb0d4f84
0a53eafe18d983c7c8ba4cadd02d0cc7f7308f28


================================================
FILE: .gitattributes
================================================
* text=false


================================================
FILE: .github/workflows/coverity_scan.yml
================================================
name: coverity-linux

on: [push, pull_request]

permissions:
  contents: read

jobs:
  coverity_scan:
    runs-on: ubuntu-latest
    name: Coverity Scan
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y curl build-essential cmake pkg-config libsystemd-dev

      - name: Download Coverity Tool
        run: |
          curl -s -L --output coverity_tool.tgz "https://scan.coverity.com/download/linux64?token=${{ secrets.COVERITY_TOKEN }}&project=gabime%2Fspdlog"
          mkdir coverity_tool
          tar -C coverity_tool --strip-components=1 -xf coverity_tool.tgz
          echo "$PWD/coverity_tool/bin" >> $GITHUB_PATH

      - name: Build with Coverity
        run: |
          mkdir build && cd build
          cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=17
          cd ..
          cov-build --dir cov-int make -C build -j4

      - name: Submit results to Coverity
        run: |
          tar czf cov-int.tgz cov-int
          response=$(curl --silent --show-error --fail \
            --form email="${{ secrets.EMAIL }}" \
            --form token="${{ secrets.COVERITY_TOKEN }}" \
            --form file=@cov-int.tgz \
            --form version="GitHub PR #${{ github.event.pull_request.number }}" \
            --form description="CI run for PR" \
            https://scan.coverity.com/builds?project=gabime%2Fspdlog)

          echo "$response"

          if echo "$response" | grep -qi "Build successfully submitted"; then
            echo "Coverity upload succeeded"
          else
            echo "Coverity upload failed or was rejected"
            exit 1
          fi


================================================
FILE: .github/workflows/linux.yml
================================================
name: linux

on: [push, pull_request]

permissions:
  contents: read

jobs:
  # -----------------------------------------------------------------------
  # Linux build matrix
  # -----------------------------------------------------------------------
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
    strategy:
      fail-fast: false
      matrix:
        config:
          - { compiler: gcc, version: 9, build_type: Release, cppstd: 11 }
          - { compiler: gcc, version: 11, build_type: Debug, cppstd: 17 }
          - { compiler: gcc, version: 12, build_type: Release, cppstd: 20 }
          - { compiler: gcc, version: 12, build_type: Debug, cppstd: 20, asan: ON }
          - { compiler: clang, version: 12, build_type: Debug, cppstd: 17 }
          - { compiler: clang, version: 15, build_type: Release, cppstd: 20, tsan: ON }
    container:
      image: ${{ matrix.config.compiler == 'clang' && 'teeks99/clang-ubuntu' || matrix.config.compiler }}:${{ matrix.config.version }}
    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' || '' }})"
    steps:
      - uses: actions/checkout@v4
      - name: Setup
        run: |
          apt-get update
          apt-get install -y curl git pkg-config libsystemd-dev
          CMAKE_VERSION="3.24.2"
          curl -sSL https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.sh -o install-cmake.sh
          chmod +x install-cmake.sh
          ./install-cmake.sh --prefix=/usr/local --skip-license
      - name: Setup Compiler
        if: matrix.config.compiler == 'clang'
        run: |
          scripts/ci_setup_clang.sh "${{ matrix.config.version }}"
          echo "CXXFLAGS=-stdlib=libc++" >> $GITHUB_ENV          
          echo "CC=clang-${{ matrix.config.version }}" >> $GITHUB_ENV
          echo "CXX=clang++-${{ matrix.config.version }}" >> $GITHUB_ENV
      - name: Build
        run: |
          mkdir -p build && cd build
          cmake .. \
            -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
            -DCMAKE_CXX_STANDARD=${{ matrix.config.cppstd }} \
            -DSPDLOG_BUILD_EXAMPLE=${{ matrix.config.examples || 'ON' }} \
            -DSPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.examples || 'ON' }} \
            -DSPDLOG_BUILD_WARNINGS=ON \
            -DSPDLOG_BUILD_BENCH=OFF \
            -DSPDLOG_BUILD_TESTS=ON \
            -DSPDLOG_BUILD_TESTS_HO=OFF \
            -DSPDLOG_SANITIZE_ADDRESS=${{ matrix.config.asan || 'OFF' }} \
            -DSPDLOG_SANITIZE_THREAD=${{ matrix.config.tsan || 'OFF' }}
          make -j 4
          ctest -j 4 --output-on-failure

  # -----------------------------------------------------------------------
  # OS X build matrix
  # -----------------------------------------------------------------------
  build_osx:
    runs-on: macOS-latest
    name: "OS X Clang (C++11, Release)"
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: |
          mkdir -p build && cd build
          cmake .. \
            -DCMAKE_BUILD_TYPE=Release \
            -DCMAKE_CXX_STANDARD=11 \
            -DSPDLOG_BUILD_EXAMPLE=ON \
            -DSPDLOG_BUILD_EXAMPLE_HO=ON \
            -DSPDLOG_BUILD_WARNINGS=ON \
            -DSPDLOG_BUILD_BENCH=OFF \
            -DSPDLOG_BUILD_TESTS=ON \
            -DSPDLOG_BUILD_TESTS_HO=OFF \
            -DSPDLOG_SANITIZE_ADDRESS=OFF
          make -j 4
          ctest -j 4 --output-on-failure


================================================
FILE: .github/workflows/macos.yml
================================================
name: macos

on: [push, pull_request]

permissions:
  contents: read

jobs:
  build:
    runs-on: macOS-latest
    name: "macOS Clang (C++11, Release)"
    strategy:
      fail-fast: true
      matrix:
        config:
            - USE_STD_FORMAT: 'ON'
              BUILD_EXAMPLE: 'OFF'
            - USE_STD_FORMAT: 'OFF'
              BUILD_EXAMPLE: 'ON'
              
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: |
          mkdir -p build && cd build
          cmake .. \
            -DCMAKE_BUILD_TYPE=Release \
            -DCMAKE_CXX_STANDARD=11 \
            -DSPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} \
            -DSPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} \
            -DSPDLOG_BUILD_WARNINGS=ON \
            -DSPDLOG_BUILD_BENCH=OFF \
            -DSPDLOG_BUILD_TESTS=ON \
            -DSPDLOG_BUILD_TESTS_HO=OFF \
            -DSPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} \
            -DSPDLOG_SANITIZE_ADDRESS=OFF
          make -j 4
          ctest -j 4 --output-on-failure


================================================
FILE: .github/workflows/windows.yml
================================================
name: windows

on: [push, pull_request]

permissions:
  contents: read

jobs:
  build:
    runs-on: windows-latest
    strategy:
      fail-fast: true
      matrix:
        config:
          - GENERATOR: "Visual Studio 17 2022"
            BUILD_TYPE: Release
            BUILD_SHARED: 'ON'
            FATAL_ERRORS: 'ON'
            WCHAR: 'OFF'
            WCHAR_FILES: 'OFF'
            BUILD_EXAMPLE: 'OFF'
            USE_STD_FORMAT: 'ON'
            CXX_STANDARD: 20
          - GENERATOR: "Visual Studio 17 2022"
            BUILD_TYPE: Release
            BUILD_SHARED: 'ON'
            FATAL_ERRORS: 'ON'
            WCHAR: 'ON'
            WCHAR_FILES: 'ON'
            BUILD_EXAMPLE: 'OFF'
            USE_STD_FORMAT: 'ON'
            CXX_STANDARD: 20
          - GENERATOR: "Visual Studio 17 2022"
            BUILD_TYPE: Release
            BUILD_SHARED: 'ON'
            FATAL_ERRORS: 'ON'
            WCHAR: 'OFF'
            WCHAR_FILES: 'OFF'
            BUILD_EXAMPLE: 'ON'
            USE_STD_FORMAT: 'OFF'
            CXX_STANDARD: 17

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: CMake ${{ matrix.config.GENERATOR }} CXX=${{matrix.config.CXX_STANDARD}} WCHAR=${{matrix.config.WCHAR_FILES}} STD_FORMAT=${{matrix.config.USE_STD_FORMAT}}
        shell: pwsh
        run: |
          mkdir build
          cd build
          cmake -G "${{ matrix.config.GENERATOR }}"  -A x64 `
            -D CMAKE_BUILD_TYPE=${{ matrix.config.BUILD_TYPE }} `
            -D BUILD_SHARED_LIBS=${{ matrix.config.BUILD_SHARED }} `
            -D SPDLOG_WCHAR_SUPPORT=${{ matrix.config.WCHAR }} `
            -D SPDLOG_WCHAR_FILENAMES=${{ matrix.config.WCHAR_FILES }} `
            -D SPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} `
            -D SPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} `
            -D SPDLOG_BUILD_TESTS=ON `
            -D SPDLOG_BUILD_TESTS_HO=OFF `
            -D SPDLOG_BUILD_WARNINGS=${{ matrix.config.FATAL_ERRORS }} `
            -D SPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} `
            -D CMAKE_CXX_STANDARD=${{ matrix.config.CXX_STANDARD }} ..

      - name: Build
        shell: pwsh
        run: |
          cd build
          cmake --build  . --parallel --config ${{ matrix.config.BUILD_TYPE }}

      - name: Run Tests
        shell: pwsh
        env:
          PATH: ${{ env.PATH }};${{ github.workspace }}\build\_deps\catch2-build\src\${{ matrix.config.BUILD_TYPE }};${{ github.workspace }}\build\${{ matrix.config.BUILD_TYPE }}
        run: |
          build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe


  


================================================
FILE: .gitignore
================================================
# Auto generated files
[Dd]ebug/
[Rr]elease/
build/*
*.slo
*.lo
*.o
*.obj
*.suo
*.tlog
*.ilk
*.log
*.pdb
*.idb
*.iobj
*.ipdb
*.opensdf
*.sdf

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

# Codelite
.codelite

# KDevelop
*.kdev4

# .orig files
*.orig

# example  files
example/*
!example/example.cpp
!example/bench.cpp
!example/utils.h
!example/Makefile*
!example/example.sln
!example/example.vcxproj
!example/CMakeLists.txt
!example/meson.build
!example/multisink.cpp
!example/jni

# generated files
generated
version.rc

# Cmake
CMakeCache.txt
CMakeFiles
CMakeScripts
Makefile
cmake_install.cmake
install_manifest.txt
/tests/tests.VC.VC.opendb
/tests/tests.VC.db
/tests/tests
/tests/logs/*
spdlogConfig.cmake
spdlogConfigVersion.cmake
compile_commands.json

# idea
.idea/
.cache/
.vscode/
cmake-build-*/
*.db
*.ipch
*.filters
*.db-wal
*.opendb
*.db-shm
*.vcxproj
*.tcl
*.user
*.sln

# macos
*.DS_store
*.xcodeproj/
/.vs
/out/build
/CMakeSettings.json


================================================
FILE: CMakeLists.txt
================================================
# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)

cmake_minimum_required(VERSION 3.10...3.21)

# ---------------------------------------------------------------------------------------
# Start spdlog project
# ---------------------------------------------------------------------------------------
include(cmake/utils.cmake)
include(cmake/ide.cmake)

spdlog_extract_version()

project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX)
message(STATUS "Build spdlog: ${SPDLOG_VERSION}")

include(GNUInstallDirs)

# ---------------------------------------------------------------------------------------
# Set default build to release
# ---------------------------------------------------------------------------------------
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    # Set CMAKE_BUILD_TYPE only if this project is top-level
    if((DEFINED PROJECT_IS_TOP_LEVEL AND PROJECT_IS_TOP_LEVEL) OR (NOT DEFINED PROJECT_IS_TOP_LEVEL
                                                                   AND CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR))
        set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
    endif()
endif()

# ---------------------------------------------------------------------------------------
# Compiler config
# ---------------------------------------------------------------------------------------
if(SPDLOG_USE_STD_FORMAT)
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
elseif(NOT CMAKE_CXX_STANDARD)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

set(CMAKE_CXX_EXTENSIONS OFF)

if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS" OR CMAKE_SYSTEM_NAME MATCHES "MINGW")
    set(CMAKE_CXX_EXTENSIONS ON)
endif()

# ---------------------------------------------------------------------------------------
# Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog
# ---------------------------------------------------------------------------------------
# Check if spdlog is being used directly or via add_subdirectory, but allow overriding
if(NOT DEFINED SPDLOG_MASTER_PROJECT)
    if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
        set(SPDLOG_MASTER_PROJECT ON)
    else()
        set(SPDLOG_MASTER_PROJECT OFF)
    endif()
endif()

option(SPDLOG_BUILD_ALL "Build all artifacts" OFF)

# build shared option
option(SPDLOG_BUILD_SHARED "Build shared library" OFF)

# precompiled headers option
option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF)

# build position independent code
option(SPDLOG_BUILD_PIC "Build position independent code (-fPIC)" OFF)

# debug build postfix
set(SPDLOG_DEBUG_POSTFIX "d" CACHE STRING "Filename postfix for libraries in debug builds")

# example options
option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF)

# testing options
option(SPDLOG_BUILD_TESTS "Build tests" OFF)
option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF)

# bench options
option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF)

# sanitizer options
option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
option(SPDLOG_SANITIZE_THREAD "Enable thread sanitizer in tests" OFF)
if(SPDLOG_SANITIZE_ADDRESS AND SPDLOG_SANITIZE_THREAD)
    message(FATAL_ERROR "SPDLOG_SANITIZE_ADDRESS and SPDLOG_SANITIZE_THREAD are mutually exclusive")
endif()

# warning options
option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)

# install options
option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF)
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF)
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
option(SPDLOG_NO_TZ_OFFSET "Omit %z timezone offset (use on platforms without tm_gmtoff)" OFF)

if(SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO)
    message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
endif()

if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL_HO)
    message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
endif()

if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL)
    message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive")
endif()

# misc tweakme options
if(WIN32)
    option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
    option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
    option(SPDLOG_WCHAR_CONSOLE "Support wchar output to console" OFF)
else()
    set(SPDLOG_WCHAR_SUPPORT OFF CACHE BOOL "non supported option" FORCE)
    set(SPDLOG_WCHAR_FILENAMES OFF CACHE BOOL "non supported option" FORCE)
    set(SPDLOG_WCHAR_CONSOLE OFF CACHE BOOL "non supported option" FORCE)
endif()

if(MSVC)
    option(SPDLOG_MSVC_UTF8 "Enable/disable msvc /utf-8 flag required by fmt lib" ON)
endif()

if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
    option(SPDLOG_CLOCK_COARSE "Use CLOCK_REALTIME_COARSE instead of the regular clock," OFF)
else()
    set(SPDLOG_CLOCK_COARSE OFF CACHE BOOL "non supported option" FORCE)
endif()

option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF)
option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF)
option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF)
option(
    SPDLOG_NO_ATOMIC_LEVELS
    "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently"
    OFF)
option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF)
option(SPDLOG_FWRITE_UNLOCKED "Use the unlocked variant of fwrite. Leave this on unless your libc doesn't have it" ON)

# clang-tidy
option(SPDLOG_TIDY "run clang-tidy" OFF)

if(SPDLOG_TIDY)
    set(CMAKE_CXX_CLANG_TIDY "clang-tidy")
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    message(STATUS "Enabled clang-tidy")
endif()

if(SPDLOG_BUILD_PIC)
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

find_package(Threads REQUIRED)
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
# ---------------------------------------------------------------------------------------
# Static/Shared library
# ---------------------------------------------------------------------------------------
set(SPDLOG_SRCS src/spdlog.cpp src/stdout_sinks.cpp src/color_sinks.cpp src/file_sinks.cpp src/async.cpp src/cfg.cpp)

if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
    list(APPEND SPDLOG_SRCS src/bundled_fmtlib_format.cpp)
endif()

if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS)
    if(WIN32)
        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
        list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
    endif()
    add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
    target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB)
    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
        target_compile_options(spdlog PUBLIC $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251
                                             /wd4275>)
    endif()
    if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
        target_compile_definitions(spdlog PRIVATE FMT_LIB_EXPORT PUBLIC FMT_SHARED)
    endif()
else()
    add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
endif()

add_library(spdlog::spdlog ALIAS spdlog)

set(SPDLOG_INCLUDES_LEVEL "")
if(SPDLOG_SYSTEM_INCLUDES)
    set(SPDLOG_INCLUDES_LEVEL "SYSTEM")
endif()

target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB)
target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
                                                                  "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(spdlog PUBLIC Threads::Threads)
spdlog_enable_warnings(spdlog)

set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION
                                                                  ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR})
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX "${SPDLOG_DEBUG_POSTFIX}")

if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH)
    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pch.h.in ${PROJECT_BINARY_DIR}/spdlog_pch.h @ONLY)
    target_precompile_headers(spdlog PRIVATE ${PROJECT_BINARY_DIR}/spdlog_pch.h)
endif()

# sanitizer support
if(SPDLOG_SANITIZE_ADDRESS)
    spdlog_enable_addr_sanitizer(spdlog)
elseif(SPDLOG_SANITIZE_THREAD)
    spdlog_enable_thread_sanitizer(spdlog)
endif()

# ---------------------------------------------------------------------------------------
# Header only version
# ---------------------------------------------------------------------------------------
add_library(spdlog_header_only INTERFACE)
add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only)

target_include_directories(
    spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
                                                          "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(spdlog_header_only INTERFACE Threads::Threads)

# ---------------------------------------------------------------------------------------
# Use fmt package if using external fmt
# ---------------------------------------------------------------------------------------
if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
    if(NOT TARGET fmt::fmt)
        find_package(fmt CONFIG REQUIRED)
    endif()
    target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
    target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)

    # use external fmt-header-only
    if(SPDLOG_FMT_EXTERNAL_HO)
        target_link_libraries(spdlog PUBLIC fmt::fmt-header-only)
        target_link_libraries(spdlog_header_only INTERFACE fmt::fmt-header-only)
    else() # use external compile fmt
        target_link_libraries(spdlog PUBLIC fmt::fmt)
        target_link_libraries(spdlog_header_only INTERFACE fmt::fmt)
    endif()

    set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
endif()

# ---------------------------------------------------------------------------------------
# Check if fwrite_unlocked/_fwrite_nolock is available
# ---------------------------------------------------------------------------------------
if(SPDLOG_FWRITE_UNLOCKED)
    include(CheckSymbolExists)
    if(WIN32)
        check_symbol_exists(_fwrite_nolock "stdio.h" HAVE_FWRITE_UNLOCKED)
    else()
        check_symbol_exists(fwrite_unlocked "stdio.h" HAVE_FWRITE_UNLOCKED)
    endif()
    if(HAVE_FWRITE_UNLOCKED)
        target_compile_definitions(spdlog PRIVATE SPDLOG_FWRITE_UNLOCKED)
        target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FWRITE_UNLOCKED)
    endif()
endif()

# ---------------------------------------------------------------------------------------
# Add required libraries for Android CMake build
# ---------------------------------------------------------------------------------------
if(ANDROID)
    target_link_libraries(spdlog PUBLIC log)
    target_link_libraries(spdlog_header_only INTERFACE log)
endif()

# ---------------------------------------------------------------------------------------
# Misc definitions according to tweak options
# ---------------------------------------------------------------------------------------
set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT})
set(SPDLOG_UTF8_TO_WCHAR_CONSOLE ${SPDLOG_WCHAR_CONSOLE})
foreach(
    SPDLOG_OPTION
    SPDLOG_WCHAR_TO_UTF8_SUPPORT
    SPDLOG_UTF8_TO_WCHAR_CONSOLE
    SPDLOG_WCHAR_FILENAMES
    SPDLOG_NO_EXCEPTIONS
    SPDLOG_CLOCK_COARSE
    SPDLOG_PREVENT_CHILD_FD
    SPDLOG_NO_THREAD_ID
    SPDLOG_NO_TLS
    SPDLOG_NO_ATOMIC_LEVELS
    SPDLOG_DISABLE_DEFAULT_LOGGER
    SPDLOG_USE_STD_FORMAT
    SPDLOG_NO_TZ_OFFSET)
    if(${SPDLOG_OPTION})
        target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION})
        target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION})
    endif()
endforeach()

if(MSVC)
    target_compile_options(spdlog PRIVATE "/Zc:__cplusplus")
    target_compile_options(spdlog_header_only INTERFACE "/Zc:__cplusplus")
    if(SPDLOG_MSVC_UTF8)
        # fmtlib requires the /utf-8 flag when building with msvc. see https://github.com/fmtlib/fmt/pull/4159 on the
        # purpose of the additional
        # "$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>"
        target_compile_options(spdlog PUBLIC $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
        target_compile_options(spdlog_header_only
                               INTERFACE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
    endif()
endif()

# ---------------------------------------------------------------------------------------
# If exceptions are disabled, disable them in the bundled fmt as well
# ---------------------------------------------------------------------------------------
if(SPDLOG_NO_EXCEPTIONS)
    if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
        target_compile_definitions(spdlog PUBLIC FMT_USE_EXCEPTIONS=0)
    endif()
    if(NOT MSVC)
        target_compile_options(spdlog PRIVATE -fno-exceptions)
    else()
        target_compile_options(spdlog PRIVATE /EHs-c-)
        target_compile_definitions(spdlog PRIVATE _HAS_EXCEPTIONS=0)
    endif()
endif()
# ---------------------------------------------------------------------------------------
# Build binaries
# ---------------------------------------------------------------------------------------
if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO OR SPDLOG_BUILD_ALL)
    message(STATUS "Generating example(s)")
    add_subdirectory(example)
    spdlog_enable_warnings(example)
    if(SPDLOG_BUILD_EXAMPLE_HO)
        spdlog_enable_warnings(example_header_only)
    endif()
endif()

if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL)
    message(STATUS "Generating tests")
    enable_testing()
    add_subdirectory(tests)
endif()

if(SPDLOG_BUILD_BENCH OR SPDLOG_BUILD_ALL)
    message(STATUS "Generating benchmarks")
    add_subdirectory(bench)
endif()

# ---------------------------------------------------------------------------------------
# Install
# ---------------------------------------------------------------------------------------
if(SPDLOG_INSTALL)
    message(STATUS "Generating install")
    set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in")
    set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
    set(config_targets_file "spdlogConfigTargets.cmake")
    set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake")
    set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog")
    set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
    set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")

    # ---------------------------------------------------------------------------------------
    # Include files
    # ---------------------------------------------------------------------------------------
    install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE)
    install(
        TARGETS spdlog spdlog_header_only
        EXPORT spdlog
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

    if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
        install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
                DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/")
    endif()

    # ---------------------------------------------------------------------------------------
    # Install pkg-config file
    # ---------------------------------------------------------------------------------------
    if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
        set(PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
    else()
        set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
    endif()
    if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
        set(PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
    else()
        set(PKG_CONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
    endif()
    get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS)
    string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}")
    string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}")
    configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY)
    install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}")

    # ---------------------------------------------------------------------------------------
    # Install CMake config files
    # ---------------------------------------------------------------------------------------
    export(TARGETS spdlog spdlog_header_only NAMESPACE spdlog::
           FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}")
    install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: FILE ${config_targets_file})

    include(CMakePackageConfigHelpers)
    configure_package_config_file("${project_config_in}" "${project_config_out}" INSTALL_DESTINATION ${export_dest_dir})

    write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
    install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}")

    # ---------------------------------------------------------------------------------------
    # Support creation of installable packages
    # ---------------------------------------------------------------------------------------
    include(cmake/spdlogCPack.cmake)
endif()


================================================
FILE: INSTALL
================================================
Header Only Version
==================================================================
Just copy the files to your build tree and use a C++11 compiler.  
Or use CMake:
``` 
  add_executable(example_header_only example.cpp)
  target_link_libraries(example_header_only spdlog::spdlog_header_only)
```

Compiled Library Version
==================================================================
CMake:
```  
  add_executable(example example.cpp)
  target_link_libraries(example spdlog::spdlog)
```

Or copy files src/*.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler.

Important Information for Compilation:
==================================================================
* 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

Tested on:  
gcc 4.8.1 and above
clang 3.5
Visual Studio 2013

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 - present, Gabi Melman and spdlog contributors.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

-- NOTE: Third party dependency used by this software --
This software depends on the fmt lib (MIT License),
and users must comply to its license: https://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE


================================================
FILE: README.md
================================================
# spdlog

 
[![ci](https://github.com/gabime/spdlog/actions/workflows/linux.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/linux.yml)&nbsp;
[![ci](https://github.com/gabime/spdlog/actions/workflows/windows.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/windows.yml)&nbsp;
[![ci](https://github.com/gabime/spdlog/actions/workflows/macos.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/macos.yml)&nbsp;
[![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true&branch=v1.x)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest)

Fast C++ logging library


## Install
#### Header-only version
Copy the include [folder](include/spdlog) to your build tree and use a C++11 compiler.

#### Compiled version (recommended - much faster compile times)
```console
$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && cmake --build .
```
see example [CMakeLists.txt](example/CMakeLists.txt) on how to use.

## Platforms
* Linux, FreeBSD, OpenBSD, Solaris, AIX
* Windows (msvc 2013+, cygwin)
* macOS (clang 3.5+)
* Android

## Package managers:
* Debian: `sudo apt install libspdlog-dev`
* Homebrew: `brew install spdlog`
* MacPorts: `sudo port install spdlog`
* FreeBSD:  `pkg install spdlog`
* Fedora: `dnf install spdlog`
* Gentoo: `emerge dev-libs/spdlog`
* Arch Linux: `pacman -S spdlog`
* openSUSE: `sudo zypper in spdlog-devel`
* ALT Linux: `apt-get install libspdlog-devel`
* vcpkg: `vcpkg install spdlog`
* conan: `conan install --requires=spdlog/[*]`
* conda: `conda install -c conda-forge spdlog`
* build2: ```depends: spdlog ^1.8.2```


## Features
* Very fast (see [benchmarks](#benchmarks) below).
* Headers only or compiled
* Feature-rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library.
* Asynchronous mode (optional)
* [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting.
* Multi/Single threaded loggers.
* Various log targets:
  * Rotating log files.
  * Daily log files.
  * Console logging (colors supported).
  * syslog.
  * Windows event log.
  * Windows debugger (```OutputDebugString(..)```).
  * Log to Qt widgets ([example](#log-to-qt-with-nice-colors)).
  * Easily [extendable](https://github.com/gabime/spdlog/wiki/Sinks#implementing-your-own-sink) with custom log targets.
* Log filtering - log levels can be modified at runtime as well as compile time.
* Support for loading log levels from argv or environment var.
* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand.

## Usage samples

#### Basic usage
```c++
#include "spdlog/spdlog.h"

int main() 
{
    spdlog::info("Welcome to spdlog!");
    spdlog::error("Some error message with arg: {}", 1);
    
    spdlog::warn("Easy padding in numbers like {:08d}", 12);
    spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
    spdlog::info("Support for floats {:03.2f}", 1.23456);
    spdlog::info("Positional args are {1} {0}..", "too", "supported");
    spdlog::info("{:<30}", "left aligned");
    
    spdlog::set_level(spdlog::level::debug); // Set *global* log level to debug
    spdlog::debug("This message should be displayed..");    
    
    // change log pattern
    spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
    
    // Compile time log levels
    // Note that this does not change the current log level, it will only
    // remove (depending on SPDLOG_ACTIVE_LEVEL) the call on the release code.
    SPDLOG_TRACE("Some trace message with param {}", 42);
    SPDLOG_DEBUG("Some debug message");
}

```
---
#### Create stdout/stderr logger object
```c++
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
    // create a color multi-threaded logger
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
```

---
#### Basic file logger
```c++
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
    try 
    {
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}
```
---
#### Rotating files
```c++
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5 MB size max and 3 rotated files
    auto max_size = 1048576 * 5;
    auto max_files = 3;
    auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files);
}
```

---
#### Daily files
```c++

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day at 2:30 am
    auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

```

---
#### Backtrace support
```c++
// Debug messages can be stored in a ring buffer instead of being logged immediately.
// This is useful to display debug logs only when needed (e.g. when an error happens).
// When needed, call dump_backtrace() to dump them to your log.

spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. 
// or my_logger->enable_backtrace(32)..
for(int i = 0; i < 100; i++)
{
  spdlog::debug("Backtrace message {}", i); // not logged yet..
}
// e.g. if some error happened:
spdlog::dump_backtrace(); // log them now! show the last 32 messages
// or my_logger->dump_backtrace(32)..
```

---
#### Periodic flush
```c++
// periodically flush all *registered* loggers every 3 seconds:
// warning: only use if all your loggers are thread-safe ("_mt" loggers)
spdlog::flush_every(std::chrono::seconds(3));

```

---
#### Stopwatch
```c++
// Stopwatch support for spdlog
#include "spdlog/stopwatch.h"
void stopwatch_example()
{
    spdlog::stopwatch sw;    
    spdlog::debug("Elapsed {}", sw);
    spdlog::debug("Elapsed {:.3}", sw);       
}

```

---
#### Log binary data in hex
```c++
// many types of std::container<char> types can be used.
// ranges are supported too.
// format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output into lines.
// {:a} - show ASCII if :n is not set.

#include "spdlog/fmt/bin_to_hex.h"

void binary_example()
{
    auto console = spdlog::get("console");
    std::array<char, 80> buf;
    console->info("Binary example: {}", spdlog::to_hex(buf));
    console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
}

```

---
#### Logger with multi sinks - each with a different format and log level
```c++

// create a logger with 2 targets, with different log levels and formats.
// The console will show only warnings or errors, while the file will log all. 
void multi_sink_example()
{
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.set_level(spdlog::level::debug);
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}
```

---
#### Register several loggers - change global level
```c++

// Creation of loggers. Set levels to all registered loggers. 
void set_level_example()
{
    auto logger1 = spdlog::basic_logger_mt("logger1", "logs/logger1.txt");
    auto logger2 = spdlog::basic_logger_mt("logger2", "logs/logger2.txt");

    spdlog::set_default_logger(logger2);
    spdlog::default_logger()->set_level(spdlog::level::trace); // set level for the default logger (logger2) to trace

    spdlog::trace("trace message to the logger2 (specified as default)");

    spdlog::set_level(spdlog::level::off) // (sic!) set level for *all* registered loggers to off (disable)
  
    logger1.warn("warn message will not appear because the level set to off");
    logger2.warn("warn message will not appear because the level set to off");
    spdlog::warn("warn message will not appear because the level set to off");
}
```

---
#### User-defined callbacks about log events
```c++

// create a logger with a lambda function callback, the callback will be called
// each time something is logged to the logger
void callback_example()
{
    auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg &msg) {
         // for example you can be notified by sending an email to yourself
    });
    callback_sink->set_level(spdlog::level::err);

    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink});

    logger.info("some info log");
    logger.error("critical issue"); // will notify you
}
```

---
#### Asynchronous logging
```c++
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");   
}

```

---
#### Asynchronous logger with multi sinks
```c++
#include "spdlog/async.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"

void multi_sink_example2()
{
    spdlog::init_thread_pool(8192, 1);
    auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
    auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
    std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
    auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    spdlog::register_logger(logger);
}
```
 
---
#### User-defined types
```c++
template<>
struct fmt::formatter<my_type> : fmt::formatter<std::string>
{
    auto format(my_type my, format_context &ctx) const -> decltype(ctx.out())
    {
        return fmt::format_to(ctx.out(), "[my_type i={}]", my.i);
    }
};

void user_defined_example()
{
    spdlog::info("user defined type: {}", my_type(14));
}

```

---
#### User-defined flags in the log pattern
```c++ 
// Log patterns can contain custom flags.
// the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> instance.
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
    {
        std::string some_txt = "custom-flag";
        dest.append(some_txt.data(), some_txt.data() + some_txt.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override
    {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_flags_example()
{    
    auto formatter = std::make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

```

---
#### Custom error handler
```c++
void err_handler_example()
{
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
    spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

```

---
#### syslog
```c++
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}
```
---
#### Android example
```c++
#include "spdlog/sinks/android_sink.h"
void android_example()
{
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger_mt("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}
```

---
#### Load log levels from the env variable or argv

```c++
#include "spdlog/cfg/env.h"
int main (int argc, char *argv[])
{
    spdlog::cfg::load_env_levels();
    // or specify the env variable name:
    // MYAPP_LEVEL=info,mylogger=trace && ./example
    // spdlog::cfg::load_env_levels("MYAPP_LEVEL");
    // or from the command line:
    // ./example SPDLOG_LEVEL=info,mylogger=trace
    // #include "spdlog/cfg/argv.h" // for loading levels from argv
    // spdlog::cfg::load_argv_levels(argc, argv);
}
```
So then you can:

```console
$ export SPDLOG_LEVEL=info,mylogger=trace
$ ./example
```


---
#### Log file open/close event handlers
```c++
// You can get callbacks from spdlog before/after a log file has been opened or closed. 
// This is useful for cleanup procedures or for adding something to the start/end of the log file.
void file_events_example()
{
    // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
    spdlog::file_event_handlers handlers;
    handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); };
    handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); };
    handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); };
    handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
    auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers);        
}
```

---
#### Replace the Default Logger
```c++
void replace_default_logger_example()
{
    auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true);
    spdlog::set_default_logger(new_logger);
    spdlog::info("new logger log message");
}
```

---
#### Log to Qt with nice colors
```c++
#include "spdlog/spdlog.h"
#include "spdlog/sinks/qt_sinks.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    setMinimumSize(640, 480);
    auto log_widget = new QTextEdit(this);
    setCentralWidget(log_widget);
    int max_lines = 500; // keep the text widget to max 500 lines. remove old lines if needed.
    auto logger = spdlog::qt_color_logger_mt("qt_logger", log_widget, max_lines);
    logger->info("Some info message");
}
```
---

#### Mapped Diagnostic Context
```c++
// Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread local storage.
// Each thread maintains its own MDC, which loggers use to append diagnostic information to log outputs.
// Note: it is not supported in asynchronous mode due to its reliance on thread-local storage.
#include "spdlog/mdc.h"
void mdc_example()
{
    spdlog::mdc::put("key1", "value1");
    spdlog::mdc::put("key2", "value2");
    // if not using the default format, use the %& formatter to print mdc data
    // spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v");
}
```
---
## Benchmarks

Below are some [benchmarks](bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz

#### Synchronous mode
```
[info] **************************************************************
[info] Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st         Elapsed: 0.17 secs        5,777,626/sec
[info] rotating_st      Elapsed: 0.18 secs        5,475,894/sec
[info] daily_st         Elapsed: 0.20 secs        5,062,659/sec
[info] empty_logger     Elapsed: 0.07 secs       14,127,300/sec
[info] **************************************************************
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st         Elapsed: 0.41 secs        2,412,483/sec
[info] rotating_st      Elapsed: 0.72 secs        1,389,196/sec
[info] daily_st         Elapsed: 0.42 secs        2,393,298/sec
[info] null_st          Elapsed: 0.04 secs       27,446,957/sec
[info] **************************************************************
[info] 10 threads, competing over the same logger object, 1,000,000 iterations
[info] **************************************************************
[info] basic_mt         Elapsed: 0.60 secs        1,659,613/sec
[info] rotating_mt      Elapsed: 0.62 secs        1,612,493/sec
[info] daily_mt         Elapsed: 0.61 secs        1,638,305/sec
[info] null_mt          Elapsed: 0.16 secs        6,272,758/sec
```
#### Asynchronous mode
```
[info] -------------------------------------------------
[info] Messages     : 1,000,000
[info] Threads      : 10
[info] Queue        : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB 
[info] -------------------------------------------------
[info] 
[info] *********************************
[info] Queue Overflow Policy: block
[info] *********************************
[info] Elapsed: 1.70784 secs     585,535/sec
[info] Elapsed: 1.69805 secs     588,910/sec
[info] Elapsed: 1.7026 secs      587,337/sec
[info] 
[info] *********************************
[info] Queue Overflow Policy: overrun
[info] *********************************
[info] Elapsed: 0.372816 secs    2,682,285/sec
[info] Elapsed: 0.379758 secs    2,633,255/sec
[info] Elapsed: 0.373532 secs    2,677,147/sec

```

## Documentation

Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki) pages.

---

### Powered by
<a href="https://jb.gg/OpenSource">
  <img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" alt="JetBrains logo" width="200">
</a>


================================================
FILE: appveyor.yml
================================================
version: 1.0.{build}
image: Visual Studio 2017
environment:
  matrix:
    - GENERATOR: '"Visual Studio 15 2017 Win64"'
      BUILD_TYPE: Debug
      BUILD_SHARED: 'OFF'
      FATAL_ERRORS: 'OFF'
      WCHAR: 'ON'
      WCHAR_FILES: 'OFF'
      BUILD_EXAMPLE: 'ON'
      USE_STD_FORMAT: 'OFF'
      CXX_STANDARD: 11
    - GENERATOR: '"Visual Studio 15 2017 Win64"'
      BUILD_TYPE: Release
      BUILD_SHARED: 'OFF'
      FATAL_ERRORS: 'OFF'
      WCHAR: 'OFF'
      WCHAR_FILES: 'OFF'
      BUILD_EXAMPLE: 'ON'
      USE_STD_FORMAT: 'OFF'
      CXX_STANDARD: 11
    - GENERATOR: '"Visual Studio 15 2017 Win64"'
      BUILD_TYPE: Release
      BUILD_SHARED: 'ON'
      FATAL_ERRORS: 'OFF'
      WCHAR: 'OFF'
      WCHAR_FILES: 'OFF'
      BUILD_EXAMPLE: 'ON'
      USE_STD_FORMAT: 'OFF'
      CXX_STANDARD: 11
    - GENERATOR: '"Visual Studio 15 2017 Win64"'
      BUILD_TYPE: Release
      BUILD_SHARED: 'ON'
      FATAL_ERRORS: 'OFF'
      WCHAR: 'ON'
      WCHAR_FILES: 'ON'
      BUILD_EXAMPLE: 'OFF'
      USE_STD_FORMAT: 'OFF'
      CXX_STANDARD: 11
    - GENERATOR: '"Visual Studio 16 2019" -A x64'
      BUILD_TYPE: Release
      BUILD_SHARED: 'ON'
      FATAL_ERRORS: 'ON'
      WCHAR: 'OFF'
      WCHAR_FILES: 'OFF'
      BUILD_EXAMPLE: 'OFF'
      USE_STD_FORMAT: 'OFF'
      CXX_STANDARD: 17
      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
    - GENERATOR: '"Visual Studio 17 2022" -A x64'
      BUILD_TYPE: Release
      BUILD_SHARED: 'ON'
      FATAL_ERRORS: 'ON'
      WCHAR: 'OFF'
      WCHAR_FILES: 'OFF'
      BUILD_EXAMPLE: 'OFF'
      USE_STD_FORMAT: 'ON'
      CXX_STANDARD: 20
      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
    - GENERATOR: '"Visual Studio 17 2022" -A x64'
      BUILD_TYPE: Release
      BUILD_SHARED: 'ON'
      FATAL_ERRORS: 'ON'
      WCHAR: 'ON'
      WCHAR_FILES: 'ON'
      BUILD_EXAMPLE: 'OFF'
      USE_STD_FORMAT: 'ON'
      CXX_STANDARD: 20
      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
build_script:
  - cmd: >-
      set

      mkdir build

      cd build

      set PATH=%PATH%;C:\Program Files\Git\usr\bin

      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% ..

      cmake --build . --config %BUILD_TYPE%

before_test:
  - set PATH=%PATH%;C:\projects\spdlog\build\_deps\catch2-build\src\%BUILD_TYPE%;C:\projects\spdlog\build\%BUILD_TYPE%
  
test_script:
  - C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe


================================================
FILE: bench/CMakeLists.txt
================================================
# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)

cmake_minimum_required(VERSION 3.11)
project(spdlog_bench CXX)

if(NOT TARGET spdlog)
    # Stand-alone build
    find_package(spdlog CONFIG REQUIRED)
endif()

find_package(Threads REQUIRED)
find_package(benchmark CONFIG)
if(NOT benchmark_FOUND)
    message(STATUS "Using CMake Version ${CMAKE_VERSION}")
    # User can fetch googlebenchmark
    message(STATUS "Downloading GoogleBenchmark")
    include(FetchContent)

    # disable tests
    set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "")
    # Do not build and run googlebenchmark tests
    FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0)
    FetchContent_MakeAvailable(googlebenchmark)
endif()

add_executable(bench bench.cpp)
spdlog_enable_warnings(bench)
target_link_libraries(bench PRIVATE spdlog::spdlog)

add_executable(async_bench async_bench.cpp)
target_link_libraries(async_bench PRIVATE spdlog::spdlog)

add_executable(latency latency.cpp)
target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog)

add_executable(formatter-bench formatter-bench.cpp)
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)


================================================
FILE: bench/async_bench.cpp
================================================
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// bench.cpp : spdlog benchmarks
//
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"

#if defined(SPDLOG_USE_STD_FORMAT)
#include <format>
#elif defined(SPDLOG_FMT_EXTERNAL)
#include <fmt/format.h>
#else
#include "spdlog/fmt/bundled/format.h"
#endif

#include "utils.h"
#include <atomic>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)  // disable fopen warning under msvc
#endif                           // _MSC_VER

int count_lines(const char *filename) {
    int counter = 0;
    auto *infile = fopen(filename, "r");
    int ch;
    while (EOF != (ch = getc(infile))) {
        if ('\n' == ch) counter++;
    }
    fclose(infile);

    return counter;
}

void verify_file(const char *filename, int expected_count) {
    spdlog::info("Verifying {} to contain {} line..", filename, expected_count);
    auto count = count_lines(filename);
    if (count != expected_count) {
        spdlog::error("Test failed. {} has {} lines instead of {}", filename, count,
                      expected_count);
        exit(1);
    }
    spdlog::info("Line count OK ({})\n", count);
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif

int main(int argc, char *argv[]) {
    int howmany = 1000000;
    int queue_size = std::min(howmany + 2, 8192);
    int threads = 10;
    int iters = 3;

    try {
        spdlog::set_pattern("[%^%l%$] %v");
        if (argc == 1) {
            spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]);
            return 0;
        }

        if (argc > 1) howmany = atoi(argv[1]);
        if (argc > 2) threads = atoi(argv[2]);
        if (argc > 3) {
            queue_size = atoi(argv[3]);
            if (queue_size > 500000) {
                spdlog::error("Max queue size allowed: 500,000");
                exit(1);
            }
        }

        if (argc > 4) iters = atoi(argv[4]);

        auto slot_size = sizeof(spdlog::details::async_msg);
        spdlog::info("-------------------------------------------------");
        spdlog::info("Messages     : {:L}", howmany);
        spdlog::info("Threads      : {:L}", threads);
        spdlog::info("Queue        : {:L} slots", queue_size);
        spdlog::info("Queue memory : {:L} x {:L} = {:L} KB ", queue_size, slot_size,
                     (queue_size * slot_size) / 1024);
        spdlog::info("Total iters  : {:L}", iters);
        spdlog::info("-------------------------------------------------");

        const char *filename = "logs/basic_async.log";
        spdlog::info("");
        spdlog::info("*********************************");
        spdlog::info("Queue Overflow Policy: block");
        spdlog::info("*********************************");
        for (int i = 0; i < iters; i++) {
            auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
            auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
            auto logger = std::make_shared<async_logger>(
                "async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block);
            bench_mt(howmany, std::move(logger), threads);
            // verify_file(filename, howmany);
        }

        spdlog::info("");
        spdlog::info("*********************************");
        spdlog::info("Queue Overflow Policy: overrun");
        spdlog::info("*********************************");
        // do same test but discard oldest if queue is full instead of blocking
        filename = "logs/basic_async-overrun.log";
        for (int i = 0; i < iters; i++) {
            auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
            auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
            auto logger =
                std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp),
                                               async_overflow_policy::overrun_oldest);
            bench_mt(howmany, std::move(logger), threads);
        }
        spdlog::shutdown();
    } catch (std::exception &ex) {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
        return 1;
    }
    return 0;
}

void thread_fun(std::shared_ptr<spdlog::logger> logger, int howmany) {
    for (int i = 0; i < howmany; i++) {
        logger->info("Hello logger: msg number {}", i);
    }
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int thread_count) {
    using std::chrono::high_resolution_clock;
    vector<std::thread> threads;
    auto start = high_resolution_clock::now();

    int msgs_per_thread = howmany / thread_count;
    int msgs_per_thread_mod = howmany % thread_count;
    for (int t = 0; t < thread_count; ++t) {
        if (t == 0 && msgs_per_thread_mod)
            threads.push_back(
                std::thread(thread_fun, logger, msgs_per_thread + msgs_per_thread_mod));
        else
            threads.push_back(std::thread(thread_fun, logger, msgs_per_thread));
    }

    for (auto &t : threads) {
        t.join();
    }

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    spdlog::info("Elapsed: {} secs\t {:L}/sec", delta_d, int(howmany / delta_d));
}


================================================
FILE: bench/bench.cpp
================================================
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// bench.cpp : spdlog benchmarks
//
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"

#if defined(SPDLOG_USE_STD_FORMAT)
#include <format>
#elif defined(SPDLOG_FMT_EXTERNAL)
#include <fmt/format.h>
#else
#include "spdlog/fmt/bundled/format.h"
#endif

#include "utils.h"
#include <atomic>
#include <cstdlib>  // EXIT_FAILURE
#include <memory>
#include <string>
#include <thread>

void bench(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_count);

// void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log);
// void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log);

static const size_t file_size = 30 * 1024 * 1024;
static const size_t rotating_files = 5;
static const int max_threads = 1000;

void bench_threaded_logging(size_t threads, int iters) {
    spdlog::info("**************************************************************");
    spdlog::info(spdlog::fmt_lib::format(
        std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters));
    spdlog::info("**************************************************************");

    auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);
    bench_mt(iters, std::move(basic_mt), threads);
    auto basic_mt_tracing =
        spdlog::basic_logger_mt("basic_mt/backtrace-on", "logs/basic_mt.log", true);
    basic_mt_tracing->enable_backtrace(32);
    bench_mt(iters, std::move(basic_mt_tracing), threads);

    spdlog::info("");
    auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size,
                                                  rotating_files);
    bench_mt(iters, std::move(rotating_mt), threads);
    auto rotating_mt_tracing = spdlog::rotating_logger_mt(
        "rotating_mt/backtrace-on", "logs/rotating_mt.log", file_size, rotating_files);
    rotating_mt_tracing->enable_backtrace(32);
    bench_mt(iters, std::move(rotating_mt_tracing), threads);

    spdlog::info("");
    auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
    bench_mt(iters, std::move(daily_mt), threads);
    auto daily_mt_tracing = spdlog::daily_logger_mt("daily_mt/backtrace-on", "logs/daily_mt.log");
    daily_mt_tracing->enable_backtrace(32);
    bench_mt(iters, std::move(daily_mt_tracing), threads);

    spdlog::info("");
    auto empty_logger = std::make_shared<spdlog::logger>("level-off");
    empty_logger->set_level(spdlog::level::off);
    bench(iters, empty_logger);
    auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on");
    empty_logger_tracing->set_level(spdlog::level::off);
    empty_logger_tracing->enable_backtrace(32);
    bench(iters, empty_logger_tracing);
}

void bench_single_threaded(int iters) {
    spdlog::info("**************************************************************");
    spdlog::info(
        spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters));
    spdlog::info("**************************************************************");

    auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true);
    bench(iters, std::move(basic_st));

    auto basic_st_tracing =
        spdlog::basic_logger_st("basic_st/backtrace-on", "logs/basic_st.log", true);
    bench(iters, std::move(basic_st_tracing));

    spdlog::info("");
    auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size,
                                                  rotating_files);
    bench(iters, std::move(rotating_st));
    auto rotating_st_tracing = spdlog::rotating_logger_st(
        "rotating_st/backtrace-on", "logs/rotating_st.log", file_size, rotating_files);
    rotating_st_tracing->enable_backtrace(32);
    bench(iters, std::move(rotating_st_tracing));

    spdlog::info("");
    auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
    bench(iters, std::move(daily_st));
    auto daily_st_tracing = spdlog::daily_logger_st("daily_st/backtrace-on", "logs/daily_st.log");
    daily_st_tracing->enable_backtrace(32);
    bench(iters, std::move(daily_st_tracing));

    spdlog::info("");
    auto empty_logger = std::make_shared<spdlog::logger>("level-off");
    empty_logger->set_level(spdlog::level::off);
    bench(iters, empty_logger);

    auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on");
    empty_logger_tracing->set_level(spdlog::level::off);
    empty_logger_tracing->enable_backtrace(32);
    bench(iters, empty_logger_tracing);
}

int main(int argc, char *argv[]) {
    spdlog::set_automatic_registration(false);
    spdlog::default_logger()->set_pattern("[%^%l%$] %v");
    int iters = 250000;
    size_t threads = 4;
    try {
        if (argc > 1) {
            iters = std::stoi(argv[1]);
        }
        if (argc > 2) {
            threads = std::stoul(argv[2]);
        }

        if (threads > max_threads) {
            throw std::runtime_error(
                spdlog::fmt_lib::format("Number of threads exceeds maximum({})", max_threads));
        }

        bench_single_threaded(iters);
        bench_threaded_logging(1, iters);
        bench_threaded_logging(threads, iters);
    } catch (std::exception &ex) {
        spdlog::error(ex.what());
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

void bench(int howmany, std::shared_ptr<spdlog::logger> log) {
    using std::chrono::duration;
    using std::chrono::duration_cast;
    using std::chrono::high_resolution_clock;

    auto start = high_resolution_clock::now();
    for (auto i = 0; i < howmany; ++i) {
        log->info("Hello logger: msg number {}", i);
    }

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();

    spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"),
                                         "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(),
                                         delta_d, size_t(howmany / delta_d)));
    spdlog::drop(log->name());
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_count) {
    using std::chrono::duration;
    using std::chrono::duration_cast;
    using std::chrono::high_resolution_clock;

    std::vector<std::thread> threads;
    threads.reserve(thread_count);
    auto start = high_resolution_clock::now();
    for (size_t t = 0; t < thread_count; ++t) {
        threads.emplace_back([&]() {
            for (int j = 0; j < howmany / static_cast<int>(thread_count); j++) {
                log->info("Hello logger: msg number {}", j);
            }
        });
    }

    for (auto &t : threads) {
        t.join();
    }

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"),
                                         "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(),
                                         delta_d, size_t(howmany / delta_d)));
    spdlog::drop(log->name());
}

/*
void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log)
{
    using std::chrono::high_resolution_clock;
    using std::chrono::duration;
    using std::chrono::duration_cast;

    auto orig_default = spdlog::default_logger();
    spdlog::set_default_logger(log);
    auto start = high_resolution_clock::now();
    for (auto i = 0; i < howmany; ++i)
    {
        spdlog::info("Hello logger: msg number {}", i);
    }

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    spdlog::drop(log->name());
    spdlog::set_default_logger(std::move(orig_default));
    spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany /
delta_d));
}

void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log)
{
    using std::chrono::high_resolution_clock;
    using std::chrono::duration;
    using std::chrono::duration_cast;

    const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra
metus cursus " "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus
volutpat mi, eu consequat sem " "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam
non dapibus eros. Donec fringilla dui sed " "augue pretium, nec scelerisque est maximus. Nullam
convallis, sem nec blandit maximus, nisi turpis ornare " "nisl, sit amet volutpat neque massa eu
odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis.";

    auto orig_default = spdlog::default_logger();
    spdlog::set_default_logger(log);
    auto start = high_resolution_clock::now();
    for (auto i = 0; i < howmany; ++i)
    {
        spdlog::log(spdlog::level::info, msg);
    }

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    spdlog::drop(log->name());
    spdlog::set_default_logger(std::move(orig_default));
    spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany /
delta_d));
}

*/


================================================
FILE: bench/formatter-bench.cpp
================================================
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

#include "benchmark/benchmark.h"

#include "spdlog/spdlog.h"
#include "spdlog/pattern_formatter.h"

void bench_formatter(benchmark::State &state, std::string pattern) {
    auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern);
    spdlog::memory_buf_t dest;
    std::string logger_name = "logger-name";
    const char *text =
        "Hello. This is some message with length of 80                                   ";

    spdlog::source_loc source_loc{"a/b/c/d/myfile.cpp", 123, "some_func()"};
    spdlog::details::log_msg msg(source_loc, logger_name, spdlog::level::info, text);

    for (auto _ : state) {
        dest.clear();
        formatter->format(msg, dest);
        benchmark::DoNotOptimize(dest);
    }
}

void bench_formatters() {
    // basic patterns(single flag)
    std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%";
    std::vector<std::string> basic_patterns;
    for (auto &flag : all_flags) {
        auto pattern = std::string("%") + flag;
        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);

        //        pattern = std::string("%16") + flag;
        //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
        //
        //        // bench center padding
        //        pattern = std::string("%=16") + flag;
        //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
    }

    // complex patterns
    std::vector<std::string> patterns = {
        "[%D %X] [%l] [%n] %v",
        "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v",
        "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v",
    };
    for (auto &pattern : patterns) {
        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern)
            ->Iterations(2500000);
    }
}

int main(int argc, char *argv[]) {
    spdlog::set_pattern("[%^%l%$] %v");
    if (argc != 2) {
        spdlog::error("Usage: {} <pattern> (or \"all\" to bench all)", argv[0]);
        exit(1);
    }

    std::string pattern = argv[1];
    if (pattern == "all") {
        bench_formatters();
    } else {
        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
    }
    benchmark::Initialize(&argc, argv);
    benchmark::RunSpecifiedBenchmarks();
}


================================================
FILE: bench/latency.cpp
================================================
//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// latency.cpp : spdlog latency benchmarks
//

#include "benchmark/benchmark.h"

#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"

void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) {
    const char *msg =
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
        "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, "
        "eu consequat sem "
        "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec "
        "fringilla dui sed "
        "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, "
        "nisi turpis ornare "
        "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue "
        "nibh turpis duis.";

    for (auto _ : state) {
        logger->info(msg);
    }
}

void bench_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) {
    int i = 0;
    for (auto _ : state) {
        logger->info("Hello logger: msg number {}...............", ++i);
    }
}
void bench_global_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) {
    spdlog::set_default_logger(std::move(logger));
    int i = 0;
    for (auto _ : state) {
        spdlog::info("Hello logger: msg number {}...............", ++i);
    }
}

void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) {
    int i = 0;
    benchmark::DoNotOptimize(i);       // prevent unused warnings
    benchmark::DoNotOptimize(logger);  // prevent unused warnings
    for (auto _ : state) {
        SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++);
    }
}

void bench_disabled_macro_global_logger(benchmark::State &state,
                                        std::shared_ptr<spdlog::logger> logger) {
    spdlog::set_default_logger(std::move(logger));
    int i = 0;
    benchmark::DoNotOptimize(i);       // prevent unused warnings
    benchmark::DoNotOptimize(logger);  // prevent unused warnings
    for (auto _ : state) {
        SPDLOG_DEBUG("Hello logger: msg number {}...............", i++);
    }
}

#ifdef __linux__
void bench_dev_null() {
    auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null");
    benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))
        ->UseRealTime();
    spdlog::drop("/dev/null_st");

    auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null");
    benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))
        ->UseRealTime();
    spdlog::drop("/dev/null_mt");
}
#endif  // __linux__

int main(int argc, char *argv[]) {
    using spdlog::sinks::null_sink_mt;
    using spdlog::sinks::null_sink_st;

    size_t file_size = 30 * 1024 * 1024;
    size_t rotating_files = 5;
    int n_threads = benchmark::CPUInfo::Get().num_cpus;

    auto full_bench = argc > 1 && std::string(argv[1]) == "full";

    // disabled loggers
    auto disabled_logger =
        std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
    disabled_logger->set_level(spdlog::level::off);
    benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger);
    benchmark::RegisterBenchmark("disabled-at-compile-time (global logger)",
                                 bench_disabled_macro_global_logger, disabled_logger);
    benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger);
    benchmark::RegisterBenchmark("disabled-at-runtime (global logger)", bench_global_logger,
                                 disabled_logger);
    // with backtrace of 64
    auto tracing_disabled_logger =
        std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
    tracing_disabled_logger->enable_backtrace(64);
    benchmark::RegisterBenchmark("disabled-at-runtime/backtrace", bench_logger,
                                 tracing_disabled_logger);

    auto null_logger_st =
        std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
    benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string,
                                 std::move(null_logger_st));
    benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st);
    benchmark::RegisterBenchmark("null_sink_st (global logger)", bench_global_logger,
                                 null_logger_st);
    // with backtrace of 64
    auto tracing_null_logger_st =
        std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
    tracing_null_logger_st->enable_backtrace(64);
    benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);

#ifdef __linux__
    bench_dev_null();
#endif  // __linux__

    if (full_bench) {
        // basic_st
        auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true);
        benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime();
        spdlog::drop("basic_st");
        // with backtrace of 64
        auto tracing_basic_st =
            spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true);
        tracing_basic_st->enable_backtrace(64);
        benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger,
                                     std::move(tracing_basic_st))
            ->UseRealTime();
        spdlog::drop("tracing_basic_st");

        // rotating st
        auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log",
                                                      file_size, rotating_files);
        benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))
            ->UseRealTime();
        spdlog::drop("rotating_st");
        // with backtrace of 64
        auto tracing_rotating_st = spdlog::rotating_logger_st(
            "tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size,
            rotating_files);
        benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger,
                                     std::move(tracing_rotating_st))
            ->UseRealTime();
        spdlog::drop("tracing_rotating_st");

        // daily st
        auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log");
        benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime();
        spdlog::drop("daily_st");
        auto tracing_daily_st =
            spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log");
        benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger,
                                     std::move(tracing_daily_st))
            ->UseRealTime();
        spdlog::drop("tracing_daily_st");

        //
        // Multi threaded bench, 10 loggers using same logger concurrently
        //
        auto null_logger_mt =
            std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
        benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)
            ->Threads(n_threads)
            ->UseRealTime();

        // basic_mt
        auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true);
        benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))
            ->Threads(n_threads)
            ->UseRealTime();
        spdlog::drop("basic_mt");

        // rotating mt
        auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log",
                                                      file_size, rotating_files);
        benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))
            ->Threads(n_threads)
            ->UseRealTime();
        spdlog::drop("rotating_mt");

        // daily mt
        auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log");
        benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))
            ->Threads(n_threads)
            ->UseRealTime();
        spdlog::drop("daily_mt");
    }

    // async
    auto queue_size = 1024 * 1024 * 3;
    auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
    auto async_logger = std::make_shared<spdlog::async_logger>(
        "async_logger", std::make_shared<null_sink_mt>(), std::move(tp),
        spdlog::async_overflow_policy::overrun_oldest);
    benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)
        ->Threads(n_threads)
        ->UseRealTime();

    auto async_logger_tracing = std::make_shared<spdlog::async_logger>(
        "async_logger_tracing", std::make_shared<null_sink_mt>(), std::move(tp),
        spdlog::async_overflow_policy::overrun_oldest);
    async_logger_tracing->enable_backtrace(32);
    benchmark::RegisterBenchmark("async_logger/tracing", bench_logger, async_logger_tracing)
        ->Threads(n_threads)
        ->UseRealTime();

    benchmark::Initialize(&argc, argv);
    benchmark::RunSpecifiedBenchmarks();
}


================================================
FILE: bench/utils.h
================================================
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

#pragma once

#include <iomanip>
#include <locale>
#include <sstream>

namespace utils {

template <typename T>
inline std::string format(const T &value) {
    static std::locale loc("");
    std::stringstream ss;
    ss.imbue(loc);
    ss << value;
    return ss.str();
}

template <>
inline std::string format(const double &value) {
    static std::locale loc("");
    std::stringstream ss;
    ss.imbue(loc);
    ss << std::fixed << std::setprecision(1) << value;
    return ss.str();
}

}  // namespace utils


================================================
FILE: cmake/ide.cmake
================================================
# ---------------------------------------------------------------------------------------
# IDE support for headers
# ---------------------------------------------------------------------------------------
set(SPDLOG_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/../include")

file(GLOB SPDLOG_TOP_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/*.h")
file(GLOB SPDLOG_DETAILS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/details/*.h")
file(GLOB SPDLOG_SINKS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/sinks/*.h")
file(GLOB SPDLOG_FMT_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/*.h")
file(GLOB SPDLOG_FMT_BUNDELED_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/bundled/*.h")
set(SPDLOG_ALL_HEADERS ${SPDLOG_TOP_HEADERS} ${SPDLOG_DETAILS_HEADERS} ${SPDLOG_SINKS_HEADERS} ${SPDLOG_FMT_HEADERS}
                       ${SPDLOG_FMT_BUNDELED_HEADERS})

source_group("Header Files\\spdlog" FILES ${SPDLOG_TOP_HEADERS})
source_group("Header Files\\spdlog\\details" FILES ${SPDLOG_DETAILS_HEADERS})
source_group("Header Files\\spdlog\\sinks" FILES ${SPDLOG_SINKS_HEADERS})
source_group("Header Files\\spdlog\\fmt" FILES ${SPDLOG_FMT_HEADERS})
source_group("Header Files\\spdlog\\fmt\\bundled\\" FILES ${SPDLOG_FMT_BUNDELED_HEADERS})


================================================
FILE: cmake/pch.h.in
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

// details/pattern_formatter-inl.h
// fmt/bin_to_hex.h
// fmt/bundled/format-inl.h
#include <cctype>

// details/file_helper-inl.h
// details/os-inl.h
// fmt/bundled/posix.h
// logger-inl.h
// sinks/daily_file_sink.h
// sinks/stdout_sinks.h
#include <cstdio>

// details/os-inl.h
// fmt/bundled/posix.h
#include <cstdlib>

// details/os-inl.h
// details/pattern_formatter-inl.h
// fmt/bundled/format-inl.h
#include <cstring>

// details/os-inl.h
// details/os.h
// details/pattern_formatter-inl.h
// details/pattern_formatter.h
// fmt/bundled/chrono.h
// sinks/daily_file_sink.h
// sinks/rotating_file_sink-inl.h
#include <ctime>

// fmt/bundled/format-inl.h
#include <climits>

// fmt/bundled/format-inl.h
#include <cwchar>

// fmt/bundled/format-inl.h
// fmt/bundled/format.h
#include <cmath>

// fmt/bundled/format-inl.h
#include <cstdarg>

// details/file_helper-inl.h
// fmt/bundled/format.h
// fmt/bundled/posix.h
// sinks/rotating_file_sink-inl.h
#include <cerrno>

// details/circular_q.h
// details/thread_pool-inl.h
// fmt/bundled/format-inl.h
#include <cassert>

// async_logger-inl.h
// cfg/helpers-inl.h
// log_levels.h
// common.h
// details/file_helper-inl.h
// details/log_msg.h
// details/os-inl.h
// details/pattern_formatter-inl.h
// details/pattern_formatter.h
// details/registry-inl.h
// details/registry.h
// details/tcp_client-windows.h
// details/tcp_client.h
// sinks/android_sink.h
// sinks/ansicolor_sink.h
// sinks/basic_file_sink.h
// sinks/daily_file_sink.h
// sinks/dup_filter_sink.h
// sinks/msvc_sink.h
// sinks/ringbuffer_sink.h
// sinks/rotating_file_sink-inl.h
// sinks/rotating_file_sink.h
// sinks/syslog_sink.h
// sinks/tcp_sink.h
// sinks/win_eventlog_sink.h
// sinks/wincolor_sink.h
// spdlog.h:
#include <string>

// cfg/helpers-inl.h
// fmt/bundled/chrono.h
#include <sstream>

// fmt/bundled/ostream.h
// sinks/ostream_sink.h
#include <ostream>

// cfg/log_levels.h
// details/registry-inl.h
// details/registry.h
#include <unordered_map>

// details/circular_q.h
// details/pattern_formatter-inl.h
// details/pattern_formatter.h
// details/thread_pool.h
// fmt/bundled/compile.h
// logger.h
// sinks/dist_sink.h
// sinks/ringbuffer_sink.h
// sinks/win_eventlog_sink.h
#include <vector>

// details/os-inl.h
// details/pattern_formatter-inl.h
// sinks/ansicolor_sink.h
// sinks/syslog_sink.h
// sinks/systemd_sink.h
// sinks/wincolor_sink.h
#include <array>

// details/file_helper-inl.h
// details/file_helper.h
// sinks/rotating_file_sink-inl.h
#include <tuple>

// details/os-inl.h
// fmt/bundled/format.h
// fmt/bundled/printf.h
#include <limits>

// common.h
// details/backtracer.h
// details/null_mutex.h
#include <atomic>

// common.h
// details/backtracer.h
// details/null_mutex.h
#include <locale>

// common.h
#include <initializer_list>

// common.h
#include <exception>

// common.h
// details/fmt_helper.h
// fmt/bundled/ranges.h
#include <type_traits>

// cfg/helpers-inl.h
// details/null_mutex.h
// details/pattern_formatter-inl.h
#include <utility>

// async.h
// async_logger-inl.h
// common.h
// details/pattern_formatter-inl.h
// details/pattern_formatter.h
// details/registry-inl.h
// details/registry.h
// details/thread_pool.h
// fmt/bundled/format.h
// sinks/ansicolor_sink.h
// sinks/base_sink-inl.h
// sinks/dist_sink.h
// sinks/stdout_sinks-inl.h
// sinks/wincolor_sink.h
// spdlog.h
#include <memory>

// async.h
// common.h
// details/backtracer.h
// details/periodic_worker.h
// details/registry-inl.h
// details/registry.h
// details/thread_pool.h
// sinks/tcp_sink.h
// spdlog.h
#include <functional>

// details/mpmc_blocking_q.h
// details/periodic_worker.h
#include <condition_variable>

// details/os-inl.h
// fmt/bundled/format.h
// fmt/bundled/printf.h
// sinks/dist_sink.h
#include <algorithm>

// common.h
// details/file_helper-inl.h
// details/fmt_helper.h
// details/os-inl.h
// details/pattern_formatter-inl.h
// details/pattern_formatter.h
// details/periodic_worker.h
// details/registry-inl.h
// details/registry.h
// details/thread_pool.h
// fmt/bundled/chrono.h
// sinks/android_sink.h
// sinks/daily_file_sink.h
// sinks/dup_filter_sink.h
// sinks/rotating_file_sink-inl.h
// sinks/rotating_file_sink.h
// sinks/tcp_sink.h
// spdlog.h
#include <chrono>

// details/file_helper-inl.h
// details/os-inl.h
// details/pattern_formatter-inl.h
// details/periodic_worker.h
// details/thread_pool.h
// sinks/android_sink.h
#include <thread>

// async.h
// details/backtracer.h
// details/console_globals.h
// details/mpmc_blocking_q.h
// details/pattern_formatter-inl.h
// details/periodic_worker.h
// details/registry.h
// sinks/android_sink.h
// sinks/ansicolor_sink.h
// sinks/basic_file_sink.h
// sinks/daily_file_sink.h
// sinks/dist_sink.h
// sinks/dup_filter_sink.h
// sinks/msvc_sink.h
// sinks/null_sink.h
// sinks/ostream_sink.h
// sinks/ringbuffer_sink.h
// sinks/rotating_file_sink-inl.h
// sinks/rotating_file_sink.h
// sinks/tcp_sink.h
// sinks/win_eventlog_sink.h
// sinks/wincolor_sink.h
//
// color_sinks.cpp
// file_sinks.cpp
// spdlog.cpp
// stdout_sinks.cpp
#include <mutex>

// spdlog
#include <spdlog/common.h>


================================================
FILE: cmake/spdlog.pc.in
================================================
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@PKG_CONFIG_INCLUDEDIR@
libdir=@PKG_CONFIG_LIBDIR@

Name: lib@PROJECT_NAME@
Description: Fast C++ logging library.
URL: https://github.com/gabime/@PROJECT_NAME@
Version: @SPDLOG_VERSION@
CFlags: -I${includedir} @PKG_CONFIG_DEFINES@
Libs: -L${libdir} -lspdlog -pthread
Requires: @PKG_CONFIG_REQUIRES@



================================================
FILE: cmake/spdlogCPack.cmake
================================================
set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators")

set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_BINARY_DIR}" "${PROJECT_NAME}" ALL .)

set(CPACK_PROJECT_URL "https://github.com/gabime/spdlog")
set(CPACK_PACKAGE_VENDOR "Gabi Melman")
set(CPACK_PACKAGE_CONTACT "Gabi Melman <gmelman1@gmail.com>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Fast C++ logging library")
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
if(PROJECT_VERSION_TWEAK)
    set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK})
endif()
set(CPACK_PACKAGE_RELOCATABLE ON CACHE BOOL "Build relocatable package")

set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries")
set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL})
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PROJECT_URL})
set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.")

if(CPACK_PACKAGE_NAME)
    set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
    set(CPACK_DEBIAN_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
else()
    set(CPACK_RPM_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
    set(CPACK_DEBIAN_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
    set(CPACK_RPM_PACKAGE_NAME "${PROJECT_NAME}")
    set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
endif()

if(CPACK_RPM_PACKAGE_RELEASE)
    set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}")
endif()
if(CPACK_DEBIAN_PACKAGE_RELEASE)
    set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}-${CPACK_DEBIAN_PACKAGE_RELEASE}")
endif()

if(CPACK_RPM_PACKAGE_ARCHITECTURE)
    set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
endif()
if(CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
    set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
endif()
set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.rpm")
set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb")

if(NOT CPACK_PACKAGE_RELOCATABLE)
    # Depend on pkgconfig rpm to create the system pkgconfig folder
    set(CPACK_RPM_PACKAGE_REQUIRES pkgconfig)
    set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
        "${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()

include(CPack)


================================================
FILE: cmake/spdlogConfig.cmake.in
================================================
# Copyright(c) 2019 spdlog authors
# Distributed under the MIT License (http://opensource.org/licenses/MIT)

@PACKAGE_INIT@

find_package(Threads REQUIRED)

set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@)
set(SPDLOG_FMT_EXTERNAL_HO @SPDLOG_FMT_EXTERNAL_HO@)
set(config_targets_file @config_targets_file@)

if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
    include(CMakeFindDependencyMacro)
    find_dependency(fmt CONFIG)
endif()


include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}")

check_required_components(spdlog)


================================================
FILE: cmake/utils.cmake
================================================
# Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION
function(spdlog_extract_version)
    file(READ "${CMAKE_CURRENT_LIST_DIR}/include/spdlog/version.h" file_contents)
    string(REGEX MATCH "SPDLOG_VER_MAJOR ([0-9]+)" _ "${file_contents}")
    if(NOT CMAKE_MATCH_COUNT EQUAL 1)
        message(FATAL_ERROR "Could not extract major version number from spdlog/version.h")
    endif()
    set(ver_major ${CMAKE_MATCH_1})

    string(REGEX MATCH "SPDLOG_VER_MINOR ([0-9]+)" _ "${file_contents}")
    if(NOT CMAKE_MATCH_COUNT EQUAL 1)
        message(FATAL_ERROR "Could not extract minor version number from spdlog/version.h")
    endif()

    set(ver_minor ${CMAKE_MATCH_1})
    string(REGEX MATCH "SPDLOG_VER_PATCH ([0-9]+)" _ "${file_contents}")
    if(NOT CMAKE_MATCH_COUNT EQUAL 1)
        message(FATAL_ERROR "Could not extract patch version number from spdlog/version.h")
    endif()
    set(ver_patch ${CMAKE_MATCH_1})

    set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE)
    set(SPDLOG_VERSION_MINOR ${ver_minor} PARENT_SCOPE)
    set(SPDLOG_VERSION_PATCH ${ver_patch} PARENT_SCOPE)
    set(SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE)
endfunction()

# Turn on warnings on the given target
function(spdlog_enable_warnings target_name)
    if(SPDLOG_BUILD_WARNINGS)
        if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
            list(APPEND MSVC_OPTIONS "/W3")
            if(MSVC_VERSION GREATER 1900) # Allow non fatal security warnings for msvc 2015
                list(APPEND MSVC_OPTIONS "/WX")
            endif()
        endif()

        target_compile_options(
            ${target_name}
            PRIVATE $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
                    -Wall
                    -Wextra
                    -Wconversion
                    -pedantic
                    -Werror
                    -Wfatal-errors>
                    $<$<CXX_COMPILER_ID:MSVC>:${MSVC_OPTIONS}>)
    endif()
endfunction()

# Enable address sanitizer (gcc/clang only)
function(spdlog_enable_addr_sanitizer target_name)
    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
        message(FATAL_ERROR "Sanitizer supported only for gcc/clang")
    endif()
    message(STATUS "Address sanitizer enabled")
    target_compile_options(${target_name} PRIVATE -fsanitize=address,undefined)
    target_compile_options(${target_name} PRIVATE -fno-sanitize=signed-integer-overflow)
    target_compile_options(${target_name} PRIVATE -fno-sanitize-recover=all)
    target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
    target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined)
endfunction()

# Enable thread sanitizer (gcc/clang only)
function(spdlog_enable_thread_sanitizer target_name)
    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
        message(FATAL_ERROR "Sanitizer supported only for gcc/clang")
    endif()
    message(STATUS "Thread sanitizer enabled")
    target_compile_options(${target_name} PRIVATE -fsanitize=thread)
    target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
    target_link_libraries(${target_name} PRIVATE -fsanitize=thread)
endfunction()


================================================
FILE: cmake/version.rc.in
================================================
#define APSTUDIO_READONLY_SYMBOLS
#include <windows.h>
#undef APSTUDIO_READONLY_SYMBOLS

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US


VS_VERSION_INFO VERSIONINFO
 FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
 PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x40004L
 FILETYPE 0x2L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "FileDescription", "spdlog dll\0"
            VALUE "FileVersion", "@SPDLOG_VERSION@.0\0"
            VALUE "InternalName", "spdlog.dll\0"
            VALUE "LegalCopyright", "Copyright (C) spdlog\0"
            VALUE "ProductName", "spdlog\0"
            VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END







================================================
FILE: example/CMakeLists.txt
================================================
# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)

cmake_minimum_required(VERSION 3.11)
project(spdlog_examples CXX)

if(NOT TARGET spdlog)
    # Stand-alone build
    find_package(spdlog REQUIRED)
endif()

# ---------------------------------------------------------------------------------------
# Example of using pre-compiled library
# ---------------------------------------------------------------------------------------
add_executable(example example.cpp)
target_link_libraries(example PRIVATE spdlog::spdlog $<$<BOOL:${MINGW}>:ws2_32>)

# ---------------------------------------------------------------------------------------
# Example of using header-only library
# ---------------------------------------------------------------------------------------
if(SPDLOG_BUILD_EXAMPLE_HO)
    add_executable(example_header_only example.cpp)
    target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
endif()


================================================
FILE: example/example.cpp
================================================
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

// spdlog usage example

#include <cstdio>
#include <chrono>

void load_levels_example();
void stdout_logger_example();
void basic_example();
void rotating_example();
void daily_example();
void callback_example();
void async_example();
void binary_example();
void vector_example();
void stopwatch_example();
void trace_example();
void multi_sink_example();
void user_defined_example();
void err_handler_example();
void syslog_example();
void udp_example();
void custom_flags_example();
void file_events_example();
void replace_default_logger_example();
void mdc_example();

#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h"   // support for loading levels from the environment variable
#include "spdlog/fmt/ostr.h"  // support for user defined types

int main(int, char *[]) {
    try {
        // Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
        load_levels_example();

        spdlog::info("Welcome to spdlog version {}.{}.{}  !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR,
                     SPDLOG_VER_PATCH);

        spdlog::warn("Easy padding in numbers like {:08d}", 12);
        spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        spdlog::info("Support for floats {:03.2f}", 1.23456);
        spdlog::info("Positional args are {1} {0}..", "too", "supported");
        spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");

        // Runtime log levels
        spdlog::set_level(spdlog::level::info);  // Set global log level to info
        spdlog::debug("This message should not be displayed!");
        spdlog::set_level(spdlog::level::trace);  // Set specific logger's log level
        spdlog::debug("This message should be displayed..");

        // Customize msg format for all loggers
        spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v");
        spdlog::info("This an info message with custom format");
        spdlog::set_pattern("%+");  // back to default format
        spdlog::set_level(spdlog::level::info);

        // Backtrace support
        // Loggers can store in a ring buffer all messages (including debug/trace) for later
        // inspection. When needed, call dump_backtrace() to see what happened:
        spdlog::enable_backtrace(10);  // create ring buffer with capacity of 10  messages
        for (int i = 0; i < 100; i++) {
            spdlog::debug("Backtrace message {}", i);  // not logged..
        }
        // e.g. if some error happened:
        spdlog::dump_backtrace();  // log them now!

        stdout_logger_example();
        basic_example();
        rotating_example();
        daily_example();
        callback_example();
        async_example();
        binary_example();
        vector_example();
        multi_sink_example();
        user_defined_example();
        err_handler_example();
        trace_example();
        stopwatch_example();
        udp_example();
        custom_flags_example();
        file_events_example();
        replace_default_logger_example();
        mdc_example();

        // Flush all *registered* loggers using a worker thread every 3 seconds.
        // note: registered loggers *must* be thread safe for this to work correctly!
        spdlog::flush_every(std::chrono::seconds(3));

        // Apply some function on all registered loggers
        spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release all spdlog resources, and drop all loggers in the registry.
        // This is optional (only mandatory if using windows + async log).
        spdlog::shutdown();
    }

    // Exceptions will only be thrown upon failed logger or sink construction (not during logging).
    catch (const spdlog::spdlog_ex &ex) {
        std::printf("Log initialization failed: %s\n", ex.what());
        return 1;
    }
}

#include "spdlog/sinks/stdout_color_sinks.h"
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
void stdout_logger_example() {
    // Create color multi threaded logger.
    auto console = spdlog::stdout_color_mt("console");
    // or for stderr:
    // auto console = spdlog::stderr_color_mt("error-logger");
}

#include "spdlog/sinks/basic_file_sink.h"
void basic_example() {
    // Create basic file logger (not rotated).
    auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true);
}

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example() {
    // Create a file rotating logger with 5mb size max and 3 rotated files.
    auto rotating_logger =
        spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}

#include "spdlog/sinks/daily_file_sink.h"
void daily_example() {
    // Create a daily logger - a new file is created every day on 2:30am.
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

#include "spdlog/sinks/callback_sink.h"
void callback_example() {
    // Create the logger
    auto logger = spdlog::callback_logger_mt("custom_callback_logger",
                                             [](const spdlog::details::log_msg & /*msg*/) {
                                                 // do what you need to do with msg
                                             });
}

#include "spdlog/cfg/env.h"
void load_levels_example() {
    // Set the log level to "info" and mylogger to "trace":
    // SPDLOG_LEVEL=info,mylogger=trace && ./example
    spdlog::cfg::load_env_levels();
    // or specify the env variable name:
    // MYAPP_LEVEL=info,mylogger=trace && ./example
    // spdlog::cfg::load_env_levels("MYAPP_LEVEL");
    // or from command line:
    // ./example SPDLOG_LEVEL=info,mylogger=trace
    // #include "spdlog/cfg/argv.h" // for loading levels from argv
    // spdlog::cfg::load_argv_levels(args, argv);
}

#include "spdlog/async.h"
void async_example() {
    // Default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
    auto async_file =
        spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file =
    // spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger",
    // "logs/async_log.txt");

    for (int i = 1; i < 101; ++i) {
        async_file->info("Async message #{}", i);
    }
}

// Log binary data as hex.
// Many types of std::container<char> types can be used.
// Iterator ranges are supported too.
// Format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.

#if !defined SPDLOG_USE_STD_FORMAT || defined(_MSC_VER)
#include "spdlog/fmt/bin_to_hex.h"
void binary_example() {
    std::vector<char> buf;
    for (int i = 0; i < 80; i++) {
        buf.push_back(static_cast<char>(i & 0xff));
    }
    spdlog::info("Binary example: {}", spdlog::to_hex(buf));
    spdlog::info("Another binary example:{:n}",
                 spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
    // logger->info("hexdump style: {:a}", spdlog::to_hex(buf));
    // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));
}
#else
void binary_example() {
    // not supported with std::format yet
}
#endif

// Log a vector of numbers
#ifndef SPDLOG_USE_STD_FORMAT
#include "spdlog/fmt/ranges.h"
void vector_example() {
    std::vector<int> vec = {1, 2, 3};
    spdlog::info("Vector example: {}", vec);
}

#else
void vector_example() {}
#endif

// ! DSPDLOG_USE_STD_FORMAT

// Compile time log levels.
// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
void trace_example() {
    // trace from default logger
    SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
    // debug from default logger
    SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);

    // trace from logger object
    auto logger = spdlog::get("file_logger");
    SPDLOG_LOGGER_TRACE(logger, "another trace message");
}

// stopwatch example
#include "spdlog/stopwatch.h"
#include <thread>
void stopwatch_example() {
    spdlog::stopwatch sw;
    std::this_thread::sleep_for(std::chrono::milliseconds(123));
    spdlog::info("Stopwatch: {} seconds", sw);
}

#include "spdlog/sinks/udp_sink.h"
void udp_example() {
    spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091);
    auto my_logger = spdlog::udp_logger_mt("udplog", cfg);
    my_logger->set_level(spdlog::level::debug);
    my_logger->info("hello world");
}

// A logger with multiple sinks (stdout and file) - each with a different format and log level.
void multi_sink_example() {
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink =
        std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.set_level(spdlog::level::debug);
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}

// User defined types logging
struct my_type {
    int value_ = 0;
    explicit my_type(int value)
        : value_(value) {}
};

#ifndef SPDLOG_USE_STD_FORMAT  // when using fmtlib
template <>
struct fmt::formatter<my_type> : fmt::formatter<std::string> {
    auto format(my_type my, format_context &ctx) const -> decltype(ctx.out()) {
        return fmt::format_to(ctx.out(), "[my_type value={}]", my.value_);
    }
};

#else  // when using std::format
template <>
struct std::formatter<my_type> : std::formatter<std::string> {
    auto format(my_type my, format_context &ctx) const -> decltype(ctx.out()) {
        return std::format_to(ctx.out(), "[my_type value={}]", my.value_);
    }
};
#endif

void user_defined_example() { spdlog::info("user defined type: {}", my_type(14)); }

// Custom error handler. Will be triggered on log failure.
void err_handler_example() {
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) {
        printf("*** Custom log error handler: %s ***\n", msg.c_str());
    });
}

// syslog example (linux/osx/freebsd)
#ifndef _WIN32
#include "spdlog/sinks/syslog_sink.h"
void syslog_example() {
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}
#endif

// Android example.
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"
void android_example() {
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger_mt("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}
#endif

// Log patterns can contain custom flags.
// this will add custom flag '%*' which will be bound to a <my_formatter_flag> instance
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter {
public:
    void format(const spdlog::details::log_msg &,
                const std::tm &,
                spdlog::memory_buf_t &dest) override {
        std::string some_txt = "custom-flag";
        dest.append(some_txt.data(), some_txt.data() + some_txt.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_flags_example() {
    using spdlog::details::make_unique;  // for pre c++14
    auto formatter = make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    // set the new formatter using spdlog::set_formatter(formatter) or
    // logger->set_formatter(formatter) spdlog::set_formatter(std::move(formatter));
}

void file_events_example() {
    // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
    spdlog::file_event_handlers handlers;
    handlers.before_open = [](spdlog::filename_t filename) {
        spdlog::info("Before opening {}", filename);
    };
    handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) {
        spdlog::info("After opening {}", filename);
        fputs("After opening\n", fstream);
    };
    handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) {
        spdlog::info("Before closing {}", filename);
        fputs("Before closing\n", fstream);
    };
    handlers.after_close = [](spdlog::filename_t filename) {
        spdlog::info("After closing {}", filename);
    };
    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/events-sample.txt",
                                                                         true, handlers);
    spdlog::logger my_logger("some_logger", file_sink);
    my_logger.info("Some log line");
}

void replace_default_logger_example() {
    // store the old logger so we don't break other examples.
    auto old_logger = spdlog::default_logger();

    auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/somelog.txt", true);
    spdlog::set_default_logger(std::move(new_logger));
    spdlog::set_level(spdlog::level::info);
    spdlog::debug("This message should not be displayed!");
    spdlog::set_level(spdlog::level::trace);
    spdlog::debug("This message should be displayed..");
    spdlog::set_default_logger(std::move(old_logger));
}

// Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread
// local storage. Each thread maintains its own MDC, which loggers use to append diagnostic
// information to log outputs. Note: it is not supported in asynchronous mode due to its reliance on
// thread-local storage.

#ifndef SPDLOG_NO_TLS
#include "spdlog/mdc.h"
void mdc_example() {
    spdlog::mdc::put("key1", "value1");
    spdlog::mdc::put("key2", "value2");
    // if not using the default format, you can use the %& formatter to print mdc data as well
    spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v");
    spdlog::info("Some log message with context");
}
#else
void mdc_example() {
    // if TLS feature is disabled
}
#endif


================================================
FILE: include/spdlog/async.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along with a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.

#include <spdlog/async_logger.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/thread_pool.h>

#include <functional>
#include <memory>
#include <mutex>

namespace spdlog {

namespace details {
static const size_t default_async_q_size = 8192;
}

// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue
// size of 8192 items and single thread.
template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl {
    template <typename Sink, typename... SinkArgs>
    static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
        auto &registry_inst = details::registry::instance();

        // create global thread pool if not already exists..

        auto &mutex = registry_inst.tp_mutex();
        std::lock_guard<std::recursive_mutex> tp_lock(mutex);
        auto tp = registry_inst.get_tp();
        if (tp == nullptr) {
            tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
            registry_inst.set_tp(tp);
        }

        auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
        auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink),
                                                         std::move(tp), OverflowPolicy);
        registry_inst.initialize_logger(new_logger);
        return new_logger;
    }
};

using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;

template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name,
                                                    SinkArgs &&...sink_args) {
    return async_factory::create<Sink>(std::move(logger_name),
                                       std::forward<SinkArgs>(sink_args)...);
}

template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name,
                                                       SinkArgs &&...sink_args) {
    return async_factory_nonblock::create<Sink>(std::move(logger_name),
                                                std::forward<SinkArgs>(sink_args)...);
}

// set global thread pool.
inline void init_thread_pool(size_t q_size,
                             size_t thread_count,
                             std::function<void()> on_thread_start,
                             std::function<void()> on_thread_stop) {
    auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,
                                                     on_thread_stop);
    details::registry::instance().set_tp(std::move(tp));
}

inline void init_thread_pool(size_t q_size,
                             size_t thread_count,
                             std::function<void()> on_thread_start) {
    init_thread_pool(q_size, thread_count, on_thread_start, [] {});
}

inline void init_thread_pool(size_t q_size, size_t thread_count) {
    init_thread_pool(q_size, thread_count, [] {}, [] {});
}

// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() {
    return details::registry::instance().get_tp();
}
}  // namespace spdlog


================================================
FILE: include/spdlog/async_logger-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/async_logger.h>
#endif

#include <spdlog/details/thread_pool.h>
#include <spdlog/sinks/sink.h>

#include <memory>
#include <string>

SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
                                                 sinks_init_list sinks_list,
                                                 std::weak_ptr<details::thread_pool> tp,
                                                 async_overflow_policy overflow_policy)
    : async_logger(std::move(logger_name),
                   sinks_list.begin(),
                   sinks_list.end(),
                   std::move(tp),
                   overflow_policy) {}

SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
                                                 sink_ptr single_sink,
                                                 std::weak_ptr<details::thread_pool> tp,
                                                 async_overflow_policy overflow_policy)
    : async_logger(
          std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}

// send the log message to the thread pool
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){
    SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
        pool_ptr -> post_log(shared_from_this(), msg, overflow_policy_);
}
else {
    throw_spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(msg.source)
}

// send flush request to the thread pool
SPDLOG_INLINE void spdlog::async_logger::flush_(){
    SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
        pool_ptr -> post_flush(shared_from_this(), overflow_policy_);
}
else {
    throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(source_loc())
}

//
// backend functions - called from the thread pool to do the actual job
//
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &incoming_log_msg) {
    for (auto &sink : sinks_) {
        if (sink->should_log(incoming_log_msg.level)) {
            SPDLOG_TRY { sink->log(incoming_log_msg); }
            SPDLOG_LOGGER_CATCH(incoming_log_msg.source)
        }
    }

    if (should_flush_(incoming_log_msg)) {
        backend_flush_();
    }
}

SPDLOG_INLINE void spdlog::async_logger::backend_flush_() {
    for (auto &sink : sinks_) {
        SPDLOG_TRY { sink->flush(); }
        SPDLOG_LOGGER_CATCH(source_loc())
    }
}

SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
    auto cloned = std::make_shared<spdlog::async_logger>(*this);
    cloned->name_ = std::move(new_name);
    return cloned;
}


================================================
FILE: include/spdlog/async_logger.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

// Fast asynchronous logger.
// Uses pre allocated queue.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
//    1. Checks if its log level is enough to log the message
//    2. Push a new copy of the message to a queue (or block the caller until
//    space is available in the queue)
// Upon destruction, logs all remaining messages in the queue before
// destructing..

#include <spdlog/logger.h>

namespace spdlog {

// Async overflow policy - block by default.
enum class async_overflow_policy {
    block,           // Block until message can be enqueued
    overrun_oldest,  // Discard oldest message in the queue if full when trying to
                     // add new item.
    discard_new      // Discard new message if the queue is full when trying to add new item.
};

namespace details {
class thread_pool;
}

class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>,
                                      public logger {
    friend class details::thread_pool;

public:
    template <typename It>
    async_logger(std::string logger_name,
                 It begin,
                 It end,
                 std::weak_ptr<details::thread_pool> tp,
                 async_overflow_policy overflow_policy = async_overflow_policy::block)
        : logger(std::move(logger_name), begin, end),
          thread_pool_(std::move(tp)),
          overflow_policy_(overflow_policy) {}

    async_logger(std::string logger_name,
                 sinks_init_list sinks_list,
                 std::weak_ptr<details::thread_pool> tp,
                 async_overflow_policy overflow_policy = async_overflow_policy::block);

    async_logger(std::string logger_name,
                 sink_ptr single_sink,
                 std::weak_ptr<details::thread_pool> tp,
                 async_overflow_policy overflow_policy = async_overflow_policy::block);

    std::shared_ptr<logger> clone(std::string new_name) override;

protected:
    void sink_it_(const details::log_msg &msg) override;
    void flush_() override;
    void backend_sink_it_(const details::log_msg &incoming_log_msg);
    void backend_flush_();

private:
    std::weak_ptr<details::thread_pool> thread_pool_;
    async_overflow_policy overflow_policy_;
};
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "async_logger-inl.h"
#endif


================================================
FILE: include/spdlog/cfg/argv.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>

//
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
//
// set all loggers to debug level:
// example.exe "SPDLOG_LEVEL=debug"

// set logger1 to trace level
// example.exe "SPDLOG_LEVEL=logger1=trace"

// turn off all logging except for logger1 and logger2:
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"

namespace spdlog {
namespace cfg {

// search for SPDLOG_LEVEL= in the args and use it to init the levels
inline void load_argv_levels(int argc, const char **argv) {
    const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        if (arg.find(spdlog_level_prefix) == 0) {
            const auto levels_spec = arg.substr(spdlog_level_prefix.size());
            helpers::load_levels(levels_spec);
        }
    }
}

inline void load_argv_levels(int argc, char **argv) {
    load_argv_levels(argc, const_cast<const char **>(argv));
}

}  // namespace cfg
}  // namespace spdlog


================================================
FILE: include/spdlog/cfg/env.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>

//
// Init levels and patterns from env variables SPDLOG_LEVEL
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
// Note - fallback to "info" level on unrecognized levels
//
// Examples:
//
// set global level to debug:
// export SPDLOG_LEVEL=debug
//
// turn off all logging except for logger1:
// export SPDLOG_LEVEL="off,logger1=debug"
//

// turn off all logging except for logger1 and logger2:
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"

namespace spdlog {
namespace cfg {
inline void load_env_levels(const char* var = "SPDLOG_LEVEL") {
    const auto levels_spec = details::os::getenv(var);
    if (!levels_spec.empty()) {
        helpers::load_levels(levels_spec);
    }
}

}  // namespace cfg
}  // namespace spdlog


================================================
FILE: include/spdlog/cfg/helpers-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/cfg/helpers.h>
#endif

#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>

#include <algorithm>
#include <sstream>
#include <string>
#include <utility>

namespace spdlog {
namespace cfg {
namespace helpers {

// inplace convert to lowercase
inline std::string &to_lower_(std::string &str) {
    std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
        return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
    });
    return str;
}

// inplace trim spaces
inline std::string &trim_(std::string &str) {
    const char *spaces = " \n\r\t";
    str.erase(str.find_last_not_of(spaces) + 1);
    str.erase(0, str.find_first_not_of(spaces));
    return str;
}

// return (name,value) trimmed pair from the given "name = value" string.
// return empty string on missing parts
// "key=val" => ("key", "val")
// " key  =  val " => ("key", "val")
// "key=" => ("key", "")
// "val" => ("", "val")

inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str) {
    auto n = str.find(sep);
    std::string k, v;
    if (n == std::string::npos) {
        v = str;
    } else {
        k = str.substr(0, n);
        v = str.substr(n + 1);
    }
    return std::make_pair(trim_(k), trim_(v));
}

// return vector of key/value pairs from a sequence of "K1=V1,K2=V2,.."
// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str) {
    std::string token;
    std::istringstream token_stream(str);
    std::unordered_map<std::string, std::string> rv{};
    while (std::getline(token_stream, token, ',')) {
        if (token.empty()) {
            continue;
        }
        auto kv = extract_kv_('=', token);
        rv[kv.first] = kv.second;
    }
    return rv;
}

SPDLOG_INLINE void load_levels(const std::string &levels_spec) {
    if (levels_spec.empty() || levels_spec.size() >= 32768) {
        return;
    }

    auto key_vals = extract_key_vals_(levels_spec);
    std::unordered_map<std::string, level::level_enum> levels;
    level::level_enum global_level = level::info;
    bool global_level_found = false;

    for (auto &name_level : key_vals) {
        const auto &logger_name = name_level.first;
        const auto &level_name = to_lower_(name_level.second);
        const auto level = level::from_str(level_name);
        // ignore unrecognized level names
        if (level == level::off && level_name != "off") {
            continue;
        }
        if (logger_name.empty())  // no logger name indicates global level
        {
            global_level_found = true;
            global_level = level;
        } else {
            levels[logger_name] = level;
        }
    }

    details::registry::instance().set_levels(std::move(levels),
                                             global_level_found ? &global_level : nullptr);
}

}  // namespace helpers
}  // namespace cfg
}  // namespace spdlog


================================================
FILE: include/spdlog/cfg/helpers.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/common.h>
#include <unordered_map>

namespace spdlog {
namespace cfg {
namespace helpers {
//
// Init levels from given string
//
// Examples:
//
// set global level to debug: "debug"
// turn off all logging except for logger1: "off,logger1=debug"
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
//
SPDLOG_API void load_levels(const std::string &levels_spec);
}  // namespace helpers

}  // namespace cfg
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "helpers-inl.h"
#endif  // SPDLOG_HEADER_ONLY


================================================
FILE: include/spdlog/common-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/common.h>
#endif

#include <algorithm>
#include <iterator>
#include <cctype>

namespace spdlog {
namespace level {

#if __cplusplus >= 201703L
constexpr
#endif
    static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;

static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;

SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
    return level_string_views[l];
}

SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
    return short_level_names[l];
}

SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT {
    auto it = std::find_if(std::begin(level_string_views), std::end(level_string_views),
                           [&name](const string_view_t &level_name) {
                               return level_name.size() == name.size() &&
                                      std::equal(name.begin(), name.end(), level_name.begin(),
                                                 [](char a, char b) {
                                                     return std::tolower(static_cast<unsigned char>(a)) ==
                                                            std::tolower(static_cast<unsigned char>(b));
                                                 });
                           });
    if (it != std::end(level_string_views))
        return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));

    // check also for "warn" and "err" before giving up..
    auto iequals = [](const std::string &a, const std::string &b) {
        return a.size() == b.size() &&
               std::equal(a.begin(), a.end(), b.begin(), [](char ac, char bc) {
                   return std::tolower(static_cast<unsigned char>(ac)) ==
                          std::tolower(static_cast<unsigned char>(bc));
               });
    };

    if (iequals(name, "warn")) {
        return level::warn;
    }
    if (iequals(name, "err")) {
        return level::err;
    }
    return level::off;
}
}  // namespace level

SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
    : msg_(std::move(msg)) {}

SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) {
#ifdef SPDLOG_USE_STD_FORMAT
    msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what();
#else
    memory_buf_t outbuf;
    fmt::format_system_error(outbuf, last_errno, msg.c_str());
    msg_ = fmt::to_string(outbuf);
#endif
}

SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); }

SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) {
    SPDLOG_THROW(spdlog_ex(msg, last_errno));
}

SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); }

}  // namespace spdlog


================================================
FILE: include/spdlog/common.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/details/null_mutex.h>
#include <spdlog/tweakme.h>

#include <atomic>
#include <chrono>
#include <cstdio>
#include <exception>
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <type_traits>

#ifdef SPDLOG_USE_STD_FORMAT
#include <version>
#if __cpp_lib_format >= 202207L
#include <format>
#else
#include <string_view>
#endif
#endif

#ifdef SPDLOG_COMPILED_LIB
#undef SPDLOG_HEADER_ONLY
#if defined(SPDLOG_SHARED_LIB)
#if defined(_WIN32)
#ifdef spdlog_EXPORTS
#define SPDLOG_API __declspec(dllexport)
#else  // !spdlog_EXPORTS
#define SPDLOG_API __declspec(dllimport)
#endif
#else  // !defined(_WIN32)
#define SPDLOG_API __attribute__((visibility("default")))
#endif
#else  // !defined(SPDLOG_SHARED_LIB)
#define SPDLOG_API
#endif
#define SPDLOG_INLINE
#else  // !defined(SPDLOG_COMPILED_LIB)
#define SPDLOG_API
#define SPDLOG_HEADER_ONLY
#define SPDLOG_INLINE inline
#endif  // #ifdef SPDLOG_COMPILED_LIB

#include <spdlog/fmt/fmt.h>

#if !defined(SPDLOG_USE_STD_FORMAT) && \
    FMT_VERSION >= 80000  // backward compatibility with fmt versions older than 8
#define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
#define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string)
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
#include <spdlog/fmt/xchar.h>
#endif
#else
#define SPDLOG_FMT_RUNTIME(format_string) format_string
#define SPDLOG_FMT_STRING(format_string) format_string
#endif

// visual studio up to 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define SPDLOG_NOEXCEPT _NOEXCEPT
#define SPDLOG_CONSTEXPR
#else
#define SPDLOG_NOEXCEPT noexcept
#define SPDLOG_CONSTEXPR constexpr
#endif

// If building with std::format, can just use constexpr, otherwise if building with fmt
// SPDLOG_CONSTEXPR_FUNC needs to be set the same as FMT_CONSTEXPR to avoid situations where
// a constexpr function in spdlog could end up calling a non-constexpr function in fmt
// depending on the compiler
// If fmt determines it can't use constexpr, we should inline the function instead
#ifdef SPDLOG_USE_STD_FORMAT
#define SPDLOG_CONSTEXPR_FUNC constexpr
#else  // Being built with fmt
#if FMT_USE_CONSTEXPR
#define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR
#else
#define SPDLOG_CONSTEXPR_FUNC inline
#endif
#endif

#if defined(__GNUC__) || defined(__clang__)
#define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define SPDLOG_DEPRECATED __declspec(deprecated)
#else
#define SPDLOG_DEPRECATED
#endif

// disable thread local on msvc 2013
#ifndef SPDLOG_NO_TLS
#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
#define SPDLOG_NO_TLS 1
#endif
#endif

#ifndef SPDLOG_FUNCTION
#define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
#endif

#ifdef SPDLOG_NO_EXCEPTIONS
#define SPDLOG_TRY
#define SPDLOG_THROW(ex)                               \
    do {                                               \
        printf("spdlog fatal error: %s\n", ex.what()); \
        std::abort();                                  \
    } while (0)
#define SPDLOG_CATCH_STD
#else
#define SPDLOG_TRY try
#define SPDLOG_THROW(ex) throw(ex)
#define SPDLOG_CATCH_STD             \
    catch (const std::exception &) { \
    }
#endif

namespace spdlog {

class formatter;

namespace sinks {
class sink;
}

#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
using filename_t = std::wstring;
// allow macro expansion to occur in SPDLOG_FILENAME_T
#define SPDLOG_FILENAME_T_INNER(s) L##s
#define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
#else
using filename_t = std::string;
#define SPDLOG_FILENAME_T(s) s
#endif

using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
#ifdef SPDLOG_USE_STD_FORMAT
namespace fmt_lib = std;

using string_view_t = std::string_view;
using memory_buf_t = std::string;

template <typename... Args>
#if __cpp_lib_format >= 202207L
using format_string_t = std::format_string<Args...>;
#else
using format_string_t = std::string_view;
#endif

template <class T, class Char = char>
struct is_convertible_to_basic_format_string
    : std::integral_constant<bool, std::is_convertible<T, std::basic_string_view<Char>>::value> {};

#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
using wstring_view_t = std::wstring_view;
using wmemory_buf_t = std::wstring;

template <typename... Args>
#if __cpp_lib_format >= 202207L
using wformat_string_t = std::wformat_string<Args...>;
#else
using wformat_string_t = std::wstring_view;
#endif
#endif
#define SPDLOG_BUF_TO_STRING(x) x
#else  // use fmt lib instead of std::format
namespace fmt_lib = fmt;

using string_view_t = fmt::basic_string_view<char>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;

template <typename... Args>
using format_string_t = fmt::format_string<Args...>;

template <class T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

template <typename Char>
#if FMT_VERSION >= 90101
using fmt_runtime_string = fmt::runtime_format_string<Char>;
#else
using fmt_runtime_string = fmt::basic_runtime<Char>;
#endif

// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the
// condition from basic_format_string here, in addition, fmt::basic_runtime<Char> is only
// convertible to basic_format_string<Char> but not basic_string_view<Char>
template <class T, class Char = char>
struct is_convertible_to_basic_format_string
    : std::integral_constant<bool,
                             std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
                                 std::is_same<remove_cvref_t<T>, fmt_runtime_string<Char>>::value> {
};

#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
using wstring_view_t = fmt::basic_string_view<wchar_t>;
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;

template <typename... Args>
using wformat_string_t = fmt::wformat_string<Args...>;
#endif
#define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x)
#endif

#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifndef _WIN32
#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
#endif  // _WIN32
#endif  // SPDLOG_WCHAR_TO_UTF8_SUPPORT

template <class T>
struct is_convertible_to_any_format_string
    : std::integral_constant<bool,
                             is_convertible_to_basic_format_string<T, char>::value ||
                                 is_convertible_to_basic_format_string<T, wchar_t>::value> {};

#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int;
#else
using level_t = std::atomic<int>;
#endif

#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6

#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif

// Log level enum
namespace level {
enum level_enum : int {
    trace = SPDLOG_LEVEL_TRACE,
    debug = SPDLOG_LEVEL_DEBUG,
    info = SPDLOG_LEVEL_INFO,
    warn = SPDLOG_LEVEL_WARN,
    err = SPDLOG_LEVEL_ERROR,
    critical = SPDLOG_LEVEL_CRITICAL,
    off = SPDLOG_LEVEL_OFF,
    n_levels
};

#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5)
#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5)
#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4)
#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7)
#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5)
#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8)
#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3)

#if !defined(SPDLOG_LEVEL_NAMES)
#define SPDLOG_LEVEL_NAMES                                                                  \
    {                                                                                       \
        SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO,           \
            SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, SPDLOG_LEVEL_NAME_CRITICAL, \
            SPDLOG_LEVEL_NAME_OFF                                                           \
    }
#endif

#if !defined(SPDLOG_SHORT_LEVEL_NAMES)

#define SPDLOG_SHORT_LEVEL_NAMES \
    { "T", "D", "I", "W", "E", "C", "O" }
#endif

SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;

}  // namespace level

//
// Color mode used by sinks with color support.
//
enum class color_mode { always, automatic, never };

//
// Pattern time - specific time getting to use for pattern_formatter.
// local time by default
//
enum class pattern_time_type {
    local,  // log localtime
    utc     // log utc
};

//
// Log exception
//
class SPDLOG_API spdlog_ex : public std::exception {
public:
    explicit spdlog_ex(std::string msg);
    spdlog_ex(const std::string &msg, int last_errno);
    const char *what() const SPDLOG_NOEXCEPT override;

private:
    std::string msg_;
};

[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);

struct source_loc {
    SPDLOG_CONSTEXPR source_loc() = default;
    SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
        : filename{filename_in},
          line{line_in},
          funcname{funcname_in} {}

    SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT { return line <= 0; }
    const char *filename{nullptr};
    int line{0};
    const char *funcname{nullptr};
};

struct file_event_handlers {
    file_event_handlers()
        : before_open(nullptr),
          after_open(nullptr),
          before_close(nullptr),
          after_close(nullptr) {}

    std::function<void(const filename_t &filename)> before_open;
    std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open;
    std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close;
    std::function<void(const filename_t &filename)> after_close;
};

namespace details {

// make_unique support for pre c++14
#if __cplusplus >= 201402L  // C++14 and beyond
using std::enable_if_t;
using std::make_unique;
#else
template <bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&...args) {
    static_assert(!std::is_array<T>::value, "arrays not supported");
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif

// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
template <typename T, typename U, enable_if_t<!std::is_same<T, U>::value, int> = 0>
constexpr T conditional_static_cast(U value) {
    return static_cast<T>(value);
}

template <typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
constexpr T conditional_static_cast(U value) {
    return value;
}

}  // namespace details
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "common-inl.h"
#endif


================================================
FILE: include/spdlog/details/backtracer-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/backtracer.h>
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE backtracer::backtracer(const backtracer &other) {
    std::lock_guard<std::mutex> lock(other.mutex_);
    enabled_ = other.enabled();
    messages_ = other.messages_;
}

SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT {
    std::lock_guard<std::mutex> lock(other.mutex_);
    enabled_ = other.enabled();
    messages_ = std::move(other.messages_);
}

SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) {
    std::lock_guard<std::mutex> lock(mutex_);
    enabled_ = other.enabled();
    messages_ = std::move(other.messages_);
    return *this;
}

SPDLOG_INLINE void backtracer::enable(size_t size) {
    std::lock_guard<std::mutex> lock{mutex_};
    enabled_.store(true, std::memory_order_relaxed);
    messages_ = circular_q<log_msg_buffer>{size};
}

SPDLOG_INLINE void backtracer::disable() {
    std::lock_guard<std::mutex> lock{mutex_};
    enabled_.store(false, std::memory_order_relaxed);
}

SPDLOG_INLINE bool backtracer::enabled() const { return enabled_.load(std::memory_order_relaxed); }

SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) {
    std::lock_guard<std::mutex> lock{mutex_};
    messages_.push_back(log_msg_buffer{msg});
}

SPDLOG_INLINE bool backtracer::empty() const {
    std::lock_guard<std::mutex> lock{mutex_};
    return messages_.empty();
}

// pop all items in the q and apply the given fun on each of them.
SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun) {
    std::lock_guard<std::mutex> lock{mutex_};
    while (!messages_.empty()) {
        auto &front_msg = messages_.front();
        fun(front_msg);
        messages_.pop_front();
    }
}
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/backtracer.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/details/circular_q.h>
#include <spdlog/details/log_msg_buffer.h>

#include <atomic>
#include <functional>
#include <mutex>

// Store log messages in circular buffer.
// Useful for storing debug data in case of error/warning happens.

namespace spdlog {
namespace details {
class SPDLOG_API backtracer {
    mutable std::mutex mutex_;
    std::atomic<bool> enabled_{false};
    circular_q<log_msg_buffer> messages_;

public:
    backtracer() = default;
    backtracer(const backtracer &other);

    backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
    backtracer &operator=(backtracer other);

    void enable(size_t size);
    void disable();
    bool enabled() const;
    void push_back(const log_msg &msg);
    bool empty() const;

    // pop all items in the q and apply the given fun on each of them.
    void foreach_pop(std::function<void(const details::log_msg &)> fun);
};

}  // namespace details
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "backtracer-inl.h"
#endif


================================================
FILE: include/spdlog/details/circular_q.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

// circular q view of std::vector.
#pragma once

#include <cassert>
#include <vector>

#include "spdlog/common.h"

namespace spdlog {
namespace details {
template <typename T>
class circular_q {
    size_t max_items_ = 0;
    typename std::vector<T>::size_type head_ = 0;
    typename std::vector<T>::size_type tail_ = 0;
    size_t overrun_counter_ = 0;
    std::vector<T> v_;

public:
    using value_type = T;

    // empty ctor - create a disabled queue with no elements allocated at all
    circular_q() = default;

    explicit circular_q(size_t max_items)
        : max_items_(max_items + 1)  // one item is reserved as marker for full q
          ,
          v_(max_items_) {}

    circular_q(const circular_q &) = default;
    circular_q &operator=(const circular_q &) = default;

    // move cannot be default,
    // since we need to reset head_, tail_, etc to zero in the moved object
    circular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); }

    circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT {
        copy_moveable(std::move(other));
        return *this;
    }

    // push back, overrun (oldest) item if no room left
    void push_back(T &&item) {
        if (max_items_ > 0) {
            v_[tail_] = std::move(item);
            tail_ = (tail_ + 1) % max_items_;

            if (tail_ == head_)  // overrun last item if full
            {
                head_ = (head_ + 1) % max_items_;
                ++overrun_counter_;
            }
        }
    }

    // Return reference to the front item.
    // If there are no elements in the container, the behavior is undefined.
    const T &front() const { return v_[head_]; }

    T &front() { return v_[head_]; }

    // Return number of elements actually stored
    size_t size() const {
        if (tail_ >= head_) {
            return tail_ - head_;
        } else {
            return max_items_ - (head_ - tail_);
        }
    }

    // Return const reference to item by index.
    // If index is out of range 0…size()-1, the behavior is undefined.
    const T &at(size_t i) const {
        assert(i < size());
        return v_[(head_ + i) % max_items_];
    }

    // Pop item from front.
    // If there are no elements in the container, the behavior is undefined.
    void pop_front() { head_ = (head_ + 1) % max_items_; }

    bool empty() const { return tail_ == head_; }

    bool full() const {
        // head is ahead of the tail by 1
        if (max_items_ > 0) {
            return ((tail_ + 1) % max_items_) == head_;
        }
        return false;
    }

    size_t overrun_counter() const { return overrun_counter_; }

    void reset_overrun_counter() { overrun_counter_ = 0; }

private:
    // copy from other&& and reset it to disabled state
    void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT {
        max_items_ = other.max_items_;
        head_ = other.head_;
        tail_ = other.tail_;
        overrun_counter_ = other.overrun_counter_;
        v_ = std::move(other.v_);

        // put &&other in disabled, but valid state
        other.max_items_ = 0;
        other.head_ = other.tail_ = 0;
        other.overrun_counter_ = 0;
    }
};
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/console_globals.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <mutex>
#include <spdlog/details/null_mutex.h>

namespace spdlog {
namespace details {

struct console_mutex {
    using mutex_t = std::mutex;
    static mutex_t &mutex() {
        static mutex_t s_mutex;
        return s_mutex;
    }
};

struct console_nullmutex {
    using mutex_t = null_mutex;
    static mutex_t &mutex() {
        static mutex_t s_mutex;
        return s_mutex;
    }
};
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/file_helper-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/file_helper.h>
#endif

#include <spdlog/common.h>
#include <spdlog/details/os.h>

#include <cerrno>
#include <cstdio>
#include <string>
#include <tuple>

namespace spdlog {
namespace details {

SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers)
    : event_handlers_(event_handlers) {}

SPDLOG_INLINE file_helper::~file_helper() { close(); }

SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) {
    close();
    filename_ = fname;

    auto *mode = SPDLOG_FILENAME_T("ab");
    auto *trunc_mode = SPDLOG_FILENAME_T("wb");

    if (event_handlers_.before_open) {
        event_handlers_.before_open(filename_);
    }
    for (int tries = 0; tries < open_tries_; ++tries) {
        // create containing folder if not exists already.
        os::create_dir(os::dir_name(fname));
        if (truncate) {
            // Truncate by opening-and-closing a tmp file in "wb" mode, always
            // opening the actual log-we-write-to in "ab" mode, since that
            // interacts more politely with eternal processes that might
            // rotate/truncate the file underneath us.
            std::FILE *tmp;
            if (os::fopen_s(&tmp, fname, trunc_mode)) {
                continue;
            }
            std::fclose(tmp);
        }
        if (!os::fopen_s(&fd_, fname, mode)) {
            if (event_handlers_.after_open) {
                event_handlers_.after_open(filename_, fd_);
            }
            return;
        }

        details::os::sleep_for_millis(open_interval_);
    }

    throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing",
                    errno);
}

SPDLOG_INLINE void file_helper::reopen(bool truncate) {
    if (filename_.empty()) {
        throw_spdlog_ex("Failed re opening file - was not opened before");
    }
    this->open(filename_, truncate);
}

SPDLOG_INLINE void file_helper::flush() {
    if (std::fflush(fd_) != 0) {
        throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno);
    }
}

SPDLOG_INLINE void file_helper::sync() {
    if (!os::fsync(fd_)) {
        throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno);
    }
}

SPDLOG_INLINE void file_helper::close() {
    if (fd_ != nullptr) {
        if (event_handlers_.before_close) {
            event_handlers_.before_close(filename_, fd_);
        }

        std::fclose(fd_);
        fd_ = nullptr;

        if (event_handlers_.after_close) {
            event_handlers_.after_close(filename_);
        }
    }
}

SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) {
    if (fd_ == nullptr) return;
    size_t msg_size = buf.size();
    auto data = buf.data();

    if (!details::os::fwrite_bytes(data, msg_size, fd_)) {
        throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
    }
}

SPDLOG_INLINE size_t file_helper::size() const {
    if (fd_ == nullptr) {
        throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_));
    }
    return os::filesize(fd_);
}

SPDLOG_INLINE const filename_t &file_helper::filename() const { return filename_; }

//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(
    const filename_t &fname) {
    auto ext_index = fname.rfind('.');

    // no valid extension found - return whole path and empty string as
    // extension
    if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) {
        return std::make_tuple(fname, filename_t());
    }

    // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
    auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
    if (folder_index != filename_t::npos && folder_index >= ext_index - 1) {
        return std::make_tuple(fname, filename_t());
    }

    // finally - return a valid base and extension tuple
    return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
}

}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/file_helper.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/common.h>
#include <tuple>

namespace spdlog {
namespace details {

// Helper class for file sinks.
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors.

class SPDLOG_API file_helper {
public:
    file_helper() = default;
    explicit file_helper(const file_event_handlers &event_handlers);

    file_helper(const file_helper &) = delete;
    file_helper &operator=(const file_helper &) = delete;
    ~file_helper();

    void open(const filename_t &fname, bool truncate = false);
    void reopen(bool truncate);
    void flush();
    void sync();
    void close();
    void write(const memory_buf_t &buf);
    size_t size() const;
    const filename_t &filename() const;

    //
    // return file path and its extension:
    //
    // "mylog.txt" => ("mylog", ".txt")
    // "mylog" => ("mylog", "")
    // "mylog." => ("mylog.", "")
    // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
    //
    // the starting dot in filenames is ignored (hidden files):
    //
    // ".mylog" => (".mylog". "")
    // "my_folder/.mylog" => ("my_folder/.mylog", "")
    // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
    static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);

private:
    const int open_tries_ = 5;
    const unsigned int open_interval_ = 10;
    std::FILE *fd_{nullptr};
    filename_t filename_;
    file_event_handlers event_handlers_;
};
}  // namespace details
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "file_helper-inl.h"
#endif


================================================
FILE: include/spdlog/details/fmt_helper.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once

#include <chrono>
#include <iterator>
#include <spdlog/common.h>
#include <spdlog/fmt/fmt.h>
#include <type_traits>

#ifdef SPDLOG_USE_STD_FORMAT
#include <charconv>
#include <limits>
#endif

// Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog {
namespace details {
namespace fmt_helper {

inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) {
    auto *buf_ptr = view.data();
    dest.append(buf_ptr, buf_ptr + view.size());
}

#ifdef SPDLOG_USE_STD_FORMAT
template <typename T>
inline void append_int(T n, memory_buf_t &dest) {
    // Buffer should be large enough to hold all digits (digits10 + 1) and a sign
    SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits<T>::digits10 + 2;
    char buf[BUF_SIZE];

    auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10);
    if (ec == std::errc()) {
        dest.append(buf, ptr);
    } else {
        throw_spdlog_ex("Failed to format int", static_cast<int>(ec));
    }
}
#else
template <typename T>
inline void append_int(T n, memory_buf_t &dest) {
    fmt::format_int i(n);
    dest.append(i.data(), i.data() + i.size());
}
#endif

template <typename T>
SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) {
    // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912
    unsigned int count = 1;
    for (;;) {
        // Integer division is slow so do it for a group of four digits instead
        // of for every digit. The idea comes from the talk by Alexandrescu
        // "Three Optimization Tips for C++". See speed-test for a comparison.
        if (n < 10) return count;
        if (n < 100) return count + 1;
        if (n < 1000) return count + 2;
        if (n < 10000) return count + 3;
        n /= 10000u;
        count += 4;
    }
}

template <typename T>
inline unsigned int count_digits(T n) {
    using count_type =
        typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
#ifdef SPDLOG_USE_STD_FORMAT
    return count_digits_fallback(static_cast<count_type>(n));
#else
    return static_cast<unsigned int>(fmt::
// fmt 7.0.0 renamed the internal namespace to detail.
// See: https://github.com/fmtlib/fmt/issues/1538
#if FMT_VERSION < 70000
                                         internal
#else
                                         detail
#endif
                                     ::count_digits(static_cast<count_type>(n)));
#endif
}

inline void pad2(int n, memory_buf_t &dest) {
    if (n >= 0 && n < 100)  // 0-99
    {
        dest.push_back(static_cast<char>('0' + n / 10));
        dest.push_back(static_cast<char>('0' + n % 10));
    } else  // unlikely, but just in case, let fmt deal with it
    {
        fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n);
    }
}

template <typename T>
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) {
    static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
    for (auto digits = count_digits(n); digits < width; digits++) {
        dest.push_back('0');
    }
    append_int(n, dest);
}

template <typename T>
inline void pad3(T n, memory_buf_t &dest) {
    static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
    if (n < 1000) {
        dest.push_back(static_cast<char>(n / 100 + '0'));
        n = n % 100;
        dest.push_back(static_cast<char>((n / 10) + '0'));
        dest.push_back(static_cast<char>((n % 10) + '0'));
    } else {
        append_int(n, dest);
    }
}

template <typename T>
inline void pad6(T n, memory_buf_t &dest) {
    pad_uint(n, 6, dest);
}

template <typename T>
inline void pad9(T n, memory_buf_t &dest) {
    pad_uint(n, 9, dest);
}

// return fraction of a second of the given time_point.
// e.g.
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
template <typename ToDuration>
inline ToDuration time_fraction(log_clock::time_point tp) {
    using std::chrono::duration_cast;
    using std::chrono::seconds;
    auto duration = tp.time_since_epoch();
    auto secs = duration_cast<seconds>(duration);
    return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
}

}  // namespace fmt_helper
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/log_msg-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/log_msg.h>
#endif

#include <spdlog/details/os.h>

namespace spdlog {
namespace details {

SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time,
                               spdlog::source_loc loc,
                               string_view_t a_logger_name,
                               spdlog::level::level_enum lvl,
                               spdlog::string_view_t msg)
    : logger_name(a_logger_name),
      level(lvl),
      time(log_time)
#ifndef SPDLOG_NO_THREAD_ID
      ,
      thread_id(os::thread_id())
#endif
      ,
      source(loc),
      payload(msg) {
}

SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc,
                               string_view_t a_logger_name,
                               spdlog::level::level_enum lvl,
                               spdlog::string_view_t msg)
    : log_msg(os::now(), loc, a_logger_name, lvl, msg) {}

SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name,
                               spdlog::level::level_enum lvl,
                               spdlog::string_view_t msg)
    : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {}

}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/log_msg.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/common.h>
#include <string>

namespace spdlog {
namespace details {
struct SPDLOG_API log_msg {
    log_msg() = default;
    log_msg(log_clock::time_point log_time,
            source_loc loc,
            string_view_t logger_name,
            level::level_enum lvl,
            string_view_t msg);
    log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
    log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
    log_msg(const log_msg &other) = default;
    log_msg &operator=(const log_msg &other) = default;

    string_view_t logger_name;
    level::level_enum level{level::off};
    log_clock::time_point time;
    size_t thread_id{0};

    // wrapping the formatted text with color (updated by pattern_formatter).
    mutable size_t color_range_start{0};
    mutable size_t color_range_end{0};

    source_loc source;
    string_view_t payload;
};
}  // namespace details
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "log_msg-inl.h"
#endif


================================================
FILE: include/spdlog/details/log_msg_buffer-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/log_msg_buffer.h>
#endif

namespace spdlog {
namespace details {

SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
    : log_msg{orig_msg} {
    buffer.append(logger_name.begin(), logger_name.end());
    buffer.append(payload.begin(), payload.end());
    update_string_views();
}

SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
    : log_msg{other} {
    buffer.append(logger_name.begin(), logger_name.end());
    buffer.append(payload.begin(), payload.end());
    update_string_views();
}

SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT
    : log_msg{other},
      buffer{std::move(other.buffer)} {
    update_string_views();
}

SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) {
    log_msg::operator=(other);
    buffer.clear();
    buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
    update_string_views();
    return *this;
}

SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT {
    log_msg::operator=(other);
    buffer = std::move(other.buffer);
    update_string_views();
    return *this;
}

SPDLOG_INLINE void log_msg_buffer::update_string_views() {
    logger_name = string_view_t{buffer.data(), logger_name.size()};
    payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
}

}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/log_msg_buffer.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <spdlog/details/log_msg.h>

namespace spdlog {
namespace details {

// Extend log_msg with internal buffer to store its payload.
// This is needed since log_msg holds string_views that points to stack data.

class SPDLOG_API log_msg_buffer : public log_msg {
    memory_buf_t buffer;
    void update_string_views();

public:
    log_msg_buffer() = default;
    explicit log_msg_buffer(const log_msg &orig_msg);
    log_msg_buffer(const log_msg_buffer &other);
    log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
    log_msg_buffer &operator=(const log_msg_buffer &other);
    log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
};

}  // namespace details
}  // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "log_msg_buffer-inl.h"
#endif


================================================
FILE: include/spdlog/details/mpmc_blocking_q.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

// multi producer-multi consumer blocking queue.
// enqueue(..) - will block until room found to put the new message.
// enqueue_nowait(..) - enqueue immediately. overruns oldest message if no 
// room left.
// dequeue_for(..) - will block until the queue is not empty or timeout have
// passed.

#include <spdlog/details/circular_q.h>

#include <atomic>
#include <condition_variable>
#include <mutex>

namespace spdlog {
namespace details {

template <typename T>
class mpmc_blocking_queue {
public:
    using item_type = T;
    explicit mpmc_blocking_queue(size_t max_items)
        : q_(max_items) {}

#ifndef __MINGW32__
    // try to enqueue and block if no room left
    void enqueue(T &&item) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            pop_cv_.wait(lock, [this] { return !this->q_.full(); });
            q_.push_back(std::move(item));
        }
        push_cv_.notify_one();
    }

    // enqueue immediately. overrun oldest message in the queue if no room left.
    void enqueue_nowait(T &&item) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            q_.push_back(std::move(item));
        }
        push_cv_.notify_one();
    }

    void enqueue_if_have_room(T &&item) {
        bool pushed = false;
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            if (!q_.full()) {
                q_.push_back(std::move(item));
                pushed = true;
            }
        }

        if (pushed) {
            push_cv_.notify_one();
        } else {
            ++discard_counter_;
        }
    }

    // dequeue with a timeout.
    // Return true, if succeeded dequeue item, false otherwise
    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) {
                return false;
            }
            popped_item = std::move(q_.front());
            q_.pop_front();
        }
        pop_cv_.notify_one();
        return true;
    }

    // blocking dequeue without a timeout.
    void dequeue(T &popped_item) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            push_cv_.wait(lock, [this] { return !this->q_.empty(); });
            popped_item = std::move(q_.front());
            q_.pop_front();
        }
        pop_cv_.notify_one();
    }

#else
    // apparently mingw deadlocks if the mutex is released before cv.notify_one(),
    // so release the mutex at the very end each function.

    // try to enqueue and block if no room left
    void enqueue(T &&item) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        pop_cv_.wait(lock, [this] { return !this->q_.full(); });
        q_.push_back(std::move(item));
        push_cv_.notify_one();
    }

    // enqueue immediately. overrun oldest message in the queue if no room left.
    void enqueue_nowait(T &&item) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        q_.push_back(std::move(item));
        push_cv_.notify_one();
    }

    void enqueue_if_have_room(T &&item) {
        bool pushed = false;
        std::unique_lock<std::mutex> lock(queue_mutex_);
        if (!q_.full()) {
            q_.push_back(std::move(item));
            pushed = true;
        }

        if (pushed) {
            push_cv_.notify_one();
        } else {
            ++discard_counter_;
        }
    }

    // dequeue with a timeout.
    // Return true, if succeeded dequeue item, false otherwise
    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) {
            return false;
        }
        popped_item = std::move(q_.front());
        q_.pop_front();
        pop_cv_.notify_one();
        return true;
    }

    // blocking dequeue without a timeout.
    void dequeue(T &popped_item) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        push_cv_.wait(lock, [this] { return !this->q_.empty(); });
        popped_item = std::move(q_.front());
        q_.pop_front();
        pop_cv_.notify_one();
    }

#endif

    size_t overrun_counter() {
        std::lock_guard<std::mutex> lock(queue_mutex_);
        return q_.overrun_counter();
    }

    size_t discard_counter() { return discard_counter_.load(std::memory_order_relaxed); }

    size_t size() {
        std::lock_guard<std::mutex> lock(queue_mutex_);
        return q_.size();
    }

    void reset_overrun_counter() {
        std::lock_guard<std::mutex> lock(queue_mutex_);
        q_.reset_overrun_counter();
    }

    void reset_discard_counter() { discard_counter_.store(0, std::memory_order_relaxed); }

private:
    std::mutex queue_mutex_;
    std::condition_variable push_cv_;
    std::condition_variable pop_cv_;
    spdlog::details::circular_q<T> q_;
    std::atomic<size_t> discard_counter_{0};
};
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/null_mutex.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <atomic>
#include <utility>
// null, no cost dummy "mutex" and dummy "atomic" int

namespace spdlog {
namespace details {
struct null_mutex {
    void lock() const {}
    void unlock() const {}
};

struct null_atomic_int {
    int value{0};
    null_atomic_int() = default;

    explicit null_atomic_int(int new_value)
        : value(new_value) {}

    int load(std::memory_order = std::memory_order_relaxed) const { return value; }

    void store(int new_value, std::memory_order = std::memory_order_relaxed) { value = new_value; }

    int exchange(int new_value, std::memory_order = std::memory_order_relaxed) {
        std::swap(new_value, value);
        return new_value;  // return value before the call
    }
};

}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/os-inl.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/os.h>
#endif

#include <spdlog/common.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <thread>

#ifdef _WIN32
#include <spdlog/details/windows_include.h>
#include <io.h>       // for _get_osfhandle, _isatty, _fileno
#include <process.h>  // for _get_pid

#ifdef __MINGW32__
#include <share.h>
#endif

#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
#include <cassert>
#include <limits>
#endif

#include <direct.h>  // for _mkdir/_wmkdir

#else  // unix

#include <fcntl.h>
#include <unistd.h>

#ifdef __linux__
#include <sys/syscall.h>  //Use gettid() syscall under linux to get thread id

#elif defined(_AIX)
#include <pthread.h>  // for pthread_getthrds_np

#elif defined(__DragonFly__) || defined(__FreeBSD__)
#include <pthread_np.h>  // for pthread_getthreadid_np

#elif defined(__NetBSD__)
#include <lwp.h>  // for _lwp_self

#elif defined(__sun)
#include <thread.h>  // for thr_self
#endif

#endif  // unix

#if defined __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifndef __has_feature       // Clang - feature checking macros.
#define __has_feature(x) 0  // Compatibility with non-clang compilers.
#endif

namespace spdlog {
namespace details {
namespace os {

SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT {
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
    timespec ts;
    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
    return std::chrono::time_point<log_clock, typename log_clock::duration>(
        std::chrono::duration_cast<typename log_clock::duration>(
            std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));

#else
    return log_clock::now();
#endif
}
SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT {
#ifdef _WIN32
    std::tm tm;
    ::localtime_s(&tm, &time_tt);
#else
    std::tm tm;
    ::localtime_r(&time_tt, &tm);
#endif
    return tm;
}

SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT {
    std::time_t now_t = ::time(nullptr);
    return localtime(now_t);
}

SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT {
#ifdef _WIN32
    std::tm tm;
    ::gmtime_s(&tm, &time_tt);
#else
    std::tm tm;
    ::gmtime_r(&time_tt, &tm);
#endif
    return tm;
}

SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT {
    std::time_t now_t = ::time(nullptr);
    return gmtime(now_t);
}

// fopen_s on non windows for writing
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
    *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#else
    *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif
#if defined(SPDLOG_PREVENT_CHILD_FD)
    if (*fp != nullptr) {
        auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
        if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) {
            ::fclose(*fp);
            *fp = nullptr;
        }
    }
#endif
#else  // unix
#if defined(SPDLOG_PREVENT_CHILD_FD)
    const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
    const int fd =
        ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
    if (fd == -1) {
        return true;
    }
    *fp = ::fdopen(fd, mode.c_str());
    if (*fp == nullptr) {
        ::close(fd);
    }
#else
    *fp = ::fopen((filename.c_str()), mode.c_str());
#endif
#endif

    return *fp == nullptr;
}

SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
    return ::_wremove(filename.c_str());
#else
    return std::remove(filename.c_str());
#endif
}

SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
    return path_exists(filename) ? remove(filename) : 0;
}

SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
    return ::_wrename(filename1.c_str(), filename2.c_str());
#else
    return std::rename(filename1.c_str(), filename2.c_str());
#endif
}

// Return true if path exists (file or directory)
SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
#ifdef _WIN32
    struct _stat buffer;
#ifdef SPDLOG_WCHAR_FILENAMES
    return (::_wstat(filename.c_str(), &buffer) == 0);
#else
    return (::_stat(filename.c_str(), &buffer) == 0);
#endif
#else  // common linux/unix all have the stat system call
    struct stat buffer;
    return (::stat(filename.c_str(), &buffer) == 0);
#endif
}

#ifdef _MSC_VER
// avoid warning about unreachable statement at the end of filesize()
#pragma warning(push)
#pragma warning(disable : 4702)
#endif

// Return file size according to open FILE* object
SPDLOG_INLINE size_t filesize(FILE *f) {
    if (f == nullptr) {
        throw_spdlog_ex("Failed getting file size. fd is null");
    }
#if defined(_WIN32) && !defined(__CYGWIN__)
    int fd = ::_fileno(f);
#if defined(_WIN64)  // 64 bits
    __int64 ret = ::_filelengthi64(fd);
    if (ret >= 0) {
        return static_cast<size_t>(ret);
    }

#else  // windows 32 bits
    long ret = ::_filelength(fd);
    if (ret >= 0) {
        return static_cast<size_t>(ret);
    }
#endif

#else  // unix
// OpenBSD and AIX doesn't compile with :: before the fileno(..)
#if defined(__OpenBSD__) || defined(_AIX)
    int fd = fileno(f);
#else
    int fd = ::fileno(f);
#endif
// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated)
#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && \
    (defined(__LP64__) || defined(_LP64))
    struct stat64 st;
    if (::fstat64(fd, &st) == 0) {
        return static_cast<size_t>(st.st_size);
    }
#else  // other unix or linux 32 bits or cygwin
    struct stat st;
    if (::fstat(fd, &st) == 0) {
        return static_cast<size_t>(st.st_size);
    }
#endif
#endif
    throw_spdlog_ex("Failed getting file size from fd", errno);
    return 0;  // will not be reached.
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#if !defined(SPDLOG_NO_TZ_OFFSET)
#ifdef _WIN32
// Compare the timestamp as Local (mktime) vs UTC (_mkgmtime) to get the offset.
SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) {
    std::tm local_tm = tm;  // copy since mktime might adjust it (normalize dates, set tm_isdst)
    std::time_t local_time_t = std::mktime(&local_tm);
    if (local_time_t == -1) {
        return 0; // fallback
    }

    std::time_t utc_time_t = _mkgmtime(&local_tm);
    if (utc_time_t == -1) {
        return 0; // fallback
    }
    auto offset_seconds = utc_time_t - local_time_t;
    return static_cast<int>(offset_seconds / 60);
}
#else
// On unix simply use tm_gmtoff
SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) {
    return static_cast<int>(tm.tm_gmtoff / 60);
}
#endif  // _WIN32
#endif  // SPDLOG_NO_TZ_OFFSET

// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT {
#ifdef _WIN32
    return static_cast<size_t>(::GetCurrentThreadId());
#elif defined(__linux__)
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
#define SYS_gettid __NR_gettid
#endif
    return static_cast<size_t>(::syscall(SYS_gettid));
#elif defined(_AIX)
    struct __pthrdsinfo buf;
    int reg_size = 0;
    pthread_t pt = pthread_self();
    int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, &reg_size);
    int tid = (!retval) ? buf.__pi_tid : 0;
    return static_cast<size_t>(tid);
#elif defined(__DragonFly__) || defined(__FreeBSD__)
    return static_cast<size_t>(::pthread_getthreadid_np());
#elif defined(__NetBSD__)
    return static_cast<size_t>(::_lwp_self());
#elif defined(__OpenBSD__)
    return static_cast<size_t>(::getthrid());
#elif defined(__sun)
    return static_cast<size_t>(::thr_self());
#elif __APPLE__
    uint64_t tid;
// There is no pthread_threadid_np prior to Mac OS X 10.6, and it is not supported on any PPC,
// including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
    {
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
        tid = pthread_mach_thread_np(pthread_self());
#elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
        if (&pthread_threadid_np) {
            pthread_threadid_np(nullptr, &tid);
        } else {
            tid = pthread_mach_thread_np(pthread_self());
        }
#else
        pthread_threadid_np(nullptr, &tid);
#endif
    }
#else
    pthread_threadid_np(nullptr, &tid);
#endif
    return static_cast<size_t>(tid);
#else  // Default to standard C++11 (other Unix)
    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif
}

// Return current thread id as size_t (from thread local storage)
SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT {
#if defined(SPDLOG_NO_TLS)
    return _thread_id();
#else  // cache thread id in tls
    static thread_local const size_t tid = _thread_id();
    return tid;
#endif
}

// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT {
#if defined(_WIN32)
    ::Sleep(milliseconds);
#else
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
#endif
}

// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) {
    memory_buf_t buf;
    wstr_to_utf8buf(filename, buf);
    return SPDLOG_BUF_TO_STRING(buf);
}
#else
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { return filename; }
#endif

SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT {
#ifdef _WIN32
    return conditional_static_cast<int>(::GetCurrentProcessId());
#else
    return conditional_static_cast<int>(::getpid());
#endif
}

// Determine if the terminal supports colors
// Based on: https://github.com/agauniyal/rang/
SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT {
#ifdef _WIN32
    return true;
#else

    static const bool result = []() {
        const char *env_colorterm_p = std::getenv("COLORTERM");
        if (env_colorterm_p != nullptr) {
            return true;
        }

        static constexpr std::array<const char *, 16> terms = {
            {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys",
             "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}};

        const char *env_term_p = std::getenv("TERM");
        if (env_term_p == nullptr) {
            return false;
        }

        return std::any_of(terms.begin(), terms.end(), [&](const char *term) {
            return std::strstr(env_term_p, term) != nullptr;
        });
    }();

    return result;
#endif
}

// Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/
SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT {
#ifdef _WIN32
    return ::_isatty(_fileno(file)) != 0;
#else
    return ::isatty(fileno(file)) != 0;
#endif
}

#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
    if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 4 - 1) {
        throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
    }

    int wstr_size = static_cast<int>(wstr.size());
    if (wstr_size == 0) {
        target.resize(0);
        return;
    }

    int result_size = static_cast<int>(target.capacity());
    if ((wstr_size + 1) * 4 > result_size) {
        result_size =
            ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
    }

    if (result_size > 0) {
        target.resize(result_size);
        result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(),
                                            result_size, NULL, NULL);

        if (result_size > 0) {
            target.resize(result_size);
            return;
        }
    }

    throw_spdlog_ex(
        fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}

SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
    if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1) {
        throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
    }

    int str_size = static_cast<int>(str.size());
    if (str_size == 0) {
        target.resize(0);
        return;
    }

    // find the size to allocate for the result buffer
    int result_size = ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, NULL, 0);

    if (result_size > 0) {
        target.resize(result_size);
        result_size =
            ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, target.data(), result_size);
        if (result_size > 0) {
            assert(result_size == static_cast<int>(target.size()));
            return;
        }
    }

    throw_spdlog_ex(
        fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif  // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) &&
        // defined(_WIN32)

// return true on success
static SPDLOG_INLINE bool mkdir_(const filename_t &path) {
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
    return ::_wmkdir(path.c_str()) == 0;
#else
    return ::_mkdir(path.c_str()) == 0;
#endif
#else
    return ::mkdir(path.c_str(), mode_t(0755)) == 0;
#endif
}

// create the given directory - and all directories leading to it
// return true on success or if the directory already exists
SPDLOG_INLINE bool create_dir(const filename_t &path) {
    if (path_exists(path)) {
        return true;
    }

    if (path.empty()) {
        return false;
    }

    size_t search_offset = 0;
    do {
        auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
        // treat the entire path as a folder if no folder separator not found
        if (token_pos == filename_t::npos) {
            token_pos = path.size();
        }

        auto subdir = path.substr(0, token_pos);
#ifdef _WIN32
        // if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\",
        // otherwise path_exists(subdir) returns false (issue #3079)
        const bool is_drive = subdir.length() == 2 && subdir[1] == ':';
        if (is_drive) {
            subdir += '\\';
            token_pos++;
        }
#endif

        if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) {
            return false;  // return error if failed creating dir
        }
        search_offset = token_pos + 1;
    } while (search_offset < path.size());

    return true;
}

// Return directory name from given path or empty string
// "abc/file" => "abc"
// "abc/" => "abc"
// "abc" => ""
// "abc///" => "abc//"
SPDLOG_INLINE filename_t dir_name(const filename_t &path) {
    auto pos = path.find_last_of(folder_seps_filename);
    return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
}

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif  // _MSC_VER
std::string SPDLOG_INLINE getenv(const char *field) {
#if defined(_MSC_VER) && defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_DESKTOP_APP) && \
    (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
    return std::string{};  // not supported under uwp
#else
    char *buf = std::getenv(field);
    return buf ? buf : std::string{};
#endif
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif  // _MSC_VER

// Do fsync by FILE handlerpointer
// Return true on success
SPDLOG_INLINE bool fsync(FILE *fp) {
#ifdef _WIN32
    return FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)))) != 0;
#else
    return ::fsync(fileno(fp)) == 0;
#endif
}

// Do non-locking fwrite if possible by the os or use the regular locking fwrite
// Return true on success.
SPDLOG_INLINE bool fwrite_bytes(const void *ptr, const size_t n_bytes, FILE *fp) {
#if defined(_WIN32) && defined(SPDLOG_FWRITE_UNLOCKED)
    return _fwrite_nolock(ptr, 1, n_bytes, fp) == n_bytes;
#elif defined(SPDLOG_FWRITE_UNLOCKED)
    return ::fwrite_unlocked(ptr, 1, n_bytes, fp) == n_bytes;
#else
    return std::fwrite(ptr, 1, n_bytes, fp) == n_bytes;
#endif
}

}  // namespace os
}  // namespace details
}  // namespace spdlog


================================================
FILE: include/spdlog/details/os.h
================================================
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)

#pragma once

#include <ctime>  // std::time_t
#include <spdlog/common.h>

namespace spdlog {
namespace details {
namespace os {

SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;

SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;

SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT;

SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;

SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT;

// eol definition
#if !defined(SPDLOG_EOL)
#ifdef _WIN32
#define SPDLOG_EOL "\r\n"
#else
#define SPDLOG_EOL "\n"
#endif
#endif

SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;

// folder separator
#if !defined(SPDLOG_FOLDER_SEPS)
#ifdef _WIN32
#define SPDLOG_FOLDER_SEPS "\\/"
#else
#define SPDLOG_FOLDER_SEPS "/"
#endif
#endif

SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS;
SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] =
    SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS);

// fopen_s on non windows for writing
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);

// Remove filename. return 0 on success
SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT;

// Remove file if exists. return 0 on success
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_
Download .txt
gitextract_woroxd9g/

├── .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
├── 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
    ├── test_timezone.cpp
    ├── utils.cpp
    └── utils.h
Download .txt
SYMBOL INDEX (629 symbols across 113 files)

FILE: bench/async_bench.cpp
  function count_lines (line 41) | int count_lines(const char *filename) {
  function verify_file (line 53) | void verify_file(const char *filename, int expected_count) {
  function main (line 68) | int main(int argc, char *argv[]) {
  function thread_fun (line 140) | void thread_fun(std::shared_ptr<spdlog::logger> logger, int howmany) {
  function bench_mt (line 146) | void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int t...

FILE: bench/bench.cpp
  function bench_threaded_logging (line 40) | void bench_threaded_logging(size_t threads, int iters) {
  function bench_single_threaded (line 79) | void bench_single_threaded(int iters) {
  function main (line 119) | int main(int argc, char *argv[]) {
  function bench (line 147) | void bench(int howmany, std::shared_ptr<spdlog::logger> log) {
  function bench_mt (line 166) | void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t t...

FILE: bench/formatter-bench.cpp
  function bench_formatter (line 11) | void bench_formatter(benchmark::State &state, std::string pattern) {
  function bench_formatters (line 28) | void bench_formatters() {
  function main (line 56) | int main(int argc, char *argv[]) {

FILE: bench/latency.cpp
  function bench_c_string (line 19) | void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::log...
  function bench_logger (line 36) | void bench_logger(benchmark::State &state, std::shared_ptr<spdlog::logge...
  function bench_global_logger (line 42) | void bench_global_logger(benchmark::State &state, std::shared_ptr<spdlog...
  function bench_disabled_macro (line 50) | void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlo...
  function bench_disabled_macro_global_logger (line 59) | void bench_disabled_macro_global_logger(benchmark::State &state,
  function bench_dev_null (line 71) | void bench_dev_null() {
  function main (line 84) | int main(int argc, char *argv[]) {

FILE: bench/utils.h
  function namespace (line 12) | namespace utils {

FILE: example/example.cpp
  function main (line 35) | int main(int, char *[]) {
  function stdout_logger_example (line 111) | void stdout_logger_example() {
  function basic_example (line 119) | void basic_example() {
  function rotating_example (line 125) | void rotating_example() {
  function daily_example (line 132) | void daily_example() {
  function callback_example (line 138) | void callback_example() {
  function load_levels_example (line 147) | void load_levels_example() {
  function async_example (line 161) | void async_example() {
  function binary_example (line 187) | void binary_example() {
  function binary_example (line 203) | void binary_example() {
  function vector_example (line 211) | void vector_example() {
  function vector_example (line 217) | void vector_example() {}
  function trace_example (line 224) | void trace_example() {
  function stopwatch_example (line 238) | void stopwatch_example() {
  function udp_example (line 245) | void udp_example() {
  function multi_sink_example (line 253) | void multi_sink_example() {
  type my_type (line 269) | struct my_type {
    method my_type (line 271) | explicit my_type(int value)
  type fmt::formatter<my_type> (line 277) | struct fmt::formatter<my_type> : fmt::formatter<std::string> {
    method format (line 278) | auto format(my_type my, format_context &ctx) const -> decltype(ctx.out...
  type std::formatter<my_type> (line 285) | struct std::formatter<my_type> : std::formatter<std::string> {
    method format (line 286) | auto format(my_type my, format_context &ctx) const -> decltype(ctx.out...
  function user_defined_example (line 292) | void user_defined_example() { spdlog::info("user defined type: {}", my_t...
  function err_handler_example (line 295) | void err_handler_example() {
  function syslog_example (line 305) | void syslog_example() {
  function android_example (line 315) | void android_example() {
  class my_formatter_flag (line 325) | class my_formatter_flag : public spdlog::custom_flag_formatter {
    method format (line 327) | void format(const spdlog::details::log_msg &,
    method clone (line 334) | std::unique_ptr<custom_flag_formatter> clone() const override {
  function custom_flags_example (line 339) | void custom_flags_example() {
  function file_events_example (line 347) | void file_events_example() {
  function replace_default_logger_example (line 370) | void replace_default_logger_example() {
  function mdc_example (line 390) | void mdc_example() {
  function mdc_example (line 398) | void mdc_example() {

FILE: include/spdlog/async.h
  function namespace (line 25) | namespace spdlog {

FILE: include/spdlog/async_logger-inl.h
  function SPDLOG_INLINE (line 16) | SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,

FILE: include/spdlog/async_logger.h
  type class (line 22) | enum class
  function namespace (line 29) | namespace details {

FILE: include/spdlog/cfg/argv.h
  function namespace (line 20) | namespace spdlog {

FILE: include/spdlog/cfg/env.h
  function namespace (line 26) | namespace spdlog {

FILE: include/spdlog/cfg/helpers-inl.h
  function namespace (line 18) | namespace spdlog {

FILE: include/spdlog/cfg/helpers.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/common-inl.h
  function namespace (line 14) | namespace spdlog {
  function SPDLOG_INLINE (line 64) | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
  function SPDLOG_INLINE (line 67) | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errn...
  function SPDLOG_INLINE (line 77) | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { retu...
  function SPDLOG_INLINE (line 79) | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errn...
  function SPDLOG_INLINE (line 83) | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlo...

FILE: include/spdlog/common.h
  function namespace (line 127) | namespace sinks {
  function namespace (line 244) | namespace level {
  type class (line 288) | enum class
  type class (line 294) | enum class
  type source_loc (line 315) | struct source_loc {
  function line (line 324) | int line{0}
  type file_event_handlers (line 328) | struct file_event_handlers {
  function namespace (line 341) | namespace details {

FILE: include/spdlog/details/backtracer-inl.h
  function namespace (line 10) | namespace details {

FILE: include/spdlog/details/backtracer.h
  function namespace (line 16) | namespace spdlog {

FILE: include/spdlog/details/circular_q.h
  function namespace (line 12) | namespace spdlog {

FILE: include/spdlog/details/console_globals.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/details/file_helper-inl.h
  function namespace (line 18) | namespace spdlog {

FILE: include/spdlog/details/file_helper.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/details/fmt_helper.h
  function namespace (line 17) | namespace spdlog {

FILE: include/spdlog/details/log_msg-inl.h
  function namespace (line 12) | namespace spdlog {

FILE: include/spdlog/details/log_msg.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/details/log_msg_buffer-inl.h
  function SPDLOG_INLINE (line 13) | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
  function SPDLOG_INLINE (line 20) | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)

FILE: include/spdlog/details/log_msg_buffer.h
  function namespace (line 8) | namespace spdlog {

FILE: include/spdlog/details/mpmc_blocking_q.h
  function namespace (line 19) | namespace spdlog {

FILE: include/spdlog/details/null_mutex.h
  function namespace (line 10) | namespace spdlog {

FILE: include/spdlog/details/os-inl.h
  function namespace (line 71) | namespace spdlog {

FILE: include/spdlog/details/periodic_worker-inl.h
  function namespace (line 10) | namespace spdlog {

FILE: include/spdlog/details/periodic_worker.h
  function namespace (line 18) | namespace spdlog {

FILE: include/spdlog/details/registry-inl.h
  function namespace (line 30) | namespace spdlog {

FILE: include/spdlog/details/registry.h
  function namespace (line 21) | namespace spdlog {

FILE: include/spdlog/details/synchronous_factory.h
  function namespace (line 8) | namespace spdlog {

FILE: include/spdlog/details/tcp_client-windows.h
  function namespace (line 22) | namespace spdlog {

FILE: include/spdlog/details/tcp_client.h
  function namespace (line 24) | namespace spdlog {

FILE: include/spdlog/details/thread_pool-inl.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/details/thread_pool.h
  type class (line 23) | enum class
  type async_msg (line 27) | struct async_msg
  function explicit (line 66) | explicit async_msg(async_msg_type the_type)
  function class (line 70) | class SPDLOG_API thread_pool {

FILE: include/spdlog/details/udp_client-windows.h
  function namespace (line 24) | namespace spdlog {

FILE: include/spdlog/details/udp_client.h
  function namespace (line 25) | namespace spdlog {

FILE: include/spdlog/fmt/bin_to_hex.h
  function namespace (line 39) | namespace spdlog {

FILE: include/spdlog/fmt/bundled/args.h
  function FMT_BEGIN_NAMESPACE (line 19) | FMT_BEGIN_NAMESPACE
  function class (line 43) | class dynamic_arg_list {
  function FMT_EXPORT (line 74) | FMT_EXPORT template <typename Context> class dynamic_format_arg_store {
  function pop_one (line 121) | auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
  function operator (line 134) | operator basic_format_args<Context>() const {
  function clear (line 199) | void clear() {
  function reserve (line 207) | void reserve(size_t new_cap, size_t new_cap_named) {

FILE: include/spdlog/fmt/bundled/base.h
  function max_of (line 334) | struct monostate {
  function namespace (line 357) | namespace detail {
  function T (line 380) | constexpr auto const_check(T val) -> T {
  function int128_opt (line 407) | inline auto map(int128_opt x) -> int128_opt { return x; }
  function uint128_opt (line 408) | inline auto map(uint128_opt x) -> uint128_opt { return x; }
  function int128_opt (line 413) | enum class int128_opt {}
  function uint128_opt (line 414) | enum class uint128_opt {}
  function monostate (line 416) | inline auto map(int128_opt) -> monostate { return {}; }
  function monostate (line 417) | inline auto map(uint128_opt) -> monostate { return {}; }
  function Int (line 439) | auto to_unsigned(Int value) -> make_unsigned_t<Int> {
  function typename (line 455) | typename T::value_type*> {}
  function FMT_ALWAYS_INLINE (line 469) | constexpr FMT_ALWAYS_INLINE auto narrow(const char* s) -> const char* {
  function namespace (line 483) | namespace adl {
  function FMT_CONSTEXPR20 (line 502) | FMT_CONSTEXPR20 auto get_container(OutputIt it) ->
  function FMT_BEGIN_EXPORT (line 513) | FMT_BEGIN_EXPORT
  function size (line 564) | constexpr auto data() const noexcept -> const Char* { return data_; }
  function operator (line 572) | constexpr auto operator[](size_t pos) const noexcept -> const Char& {
  function FMT_CONSTEXPR (line 576) | FMT_CONSTEXPR void remove_prefix(size_t n) noexcept {
  function FMT_CONSTEXPR (line 581) | FMT_CONSTEXPR auto starts_with(basic_string_view<Char> sv) const noexcept
  function FMT_CONSTEXPR (line 585) | FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool {
  function FMT_CONSTEXPR (line 588) | FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool {
  function FMT_CONSTEXPR (line 592) | FMT_CONSTEXPR auto compare(basic_string_view other) const -> int {
  function presentation_type (line 665) | enum class presentation_type : unsigned char {
  function type (line 1267) | constexpr auto arg_type(int id) const -> type { return types_[id]; }
  function FMT_CONSTEXPR (line 1269) | FMT_CONSTEXPR auto next_arg_id() -> int {
  function FMT_CONSTEXPR (line 1281) | FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
  function FMT_CONSTEXPR (line 1291) | FMT_CONSTEXPR arg_ref(basic_string_view<Char> n) : name(n) {}
  function FMT_CONSTEXPR (line 1344) | FMT_CONSTEXPR inline auto parse_align(char c) -> align {
  function FMT_CONSTEXPR (line 1390) | FMT_CONSTEXPR void on_index(int id) {
  function state (line 1467) | enum class state { start, align, sign, hash, zero, width, precision, loc...
  type compile_string (line 1690) | struct compile_string {}
  function FMT_CONSTEXPR (line 1732) | FMT_CONSTEXPR auto on_arg_id(int id) -> int {
  function FMT_CONSTEXPR (line 1736) | FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
  function FMT_CONSTEXPR (line 1744) | FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) {
  function on_error (line 1766) | void on_error(const char* message) {
  function FMT_CONSTEXPR (line 1796) | FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept {
  function size (line 1811) | auto begin() const noexcept -> const T* { return ptr_; }
  function FMT_CONSTEXPR (line 1821) | FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; }
  function FMT_CONSTEXPR (line 1825) | FMT_CONSTEXPR void clear() { size_ = 0; }
  function FMT_CONSTEXPR (line 1829) | FMT_CONSTEXPR void try_resize(size_t count) {
  function FMT_CONSTEXPR (line 1838) | FMT_CONSTEXPR void try_reserve(size_t new_capacity) {
  function FMT_CONSTEXPR (line 1842) | FMT_CONSTEXPR void push_back(const T& value) {
  function append (line 1854) | void
  function count (line 1883) | struct buffer_traits {
  function FMT_CONSTEXPR (line 1897) | FMT_CONSTEXPR auto limit(size_t size) -> size_t {
  function flush (line 1916) | void flush() {
  function flush (line 1957) | void flush() {
  type custom_tag (line 2169) | struct custom_tag {}
  function FMT_INLINE (line 2201) | constexpr FMT_INLINE value() : no_value() {}
  function FMT_INLINE (line 2255) | FMT_INLINE value(void* x FMT_BUILTIN) : pointer(x) {}
  function FMT_INLINE (line 2256) | FMT_INLINE value(const void* x FMT_BUILTIN) : pointer(x) {}
  function FMT_INLINE (line 2257) | FMT_INLINE value(volatile void* x FMT_BUILTIN)
  function FMT_INLINE (line 2259) | FMT_INLINE value(const volatile void* x FMT_BUILTIN)
  function FMT_INLINE (line 2261) | FMT_INLINE value(nullptr_t) : pointer(nullptr) {}
  type is_output_iterator (line 2336) | struct is_output_iterator
  function named_arg_store (line 2366) | struct named_arg_store {
  function vprint_mojibake (line 2457) | inline void vprint_mojibake(FILE*, string_view, const format_args&, bool...
  function FMT_BEGIN_EXPORT (line 2480) | FMT_BEGIN_EXPORT
  function FMT_CONSTEXPR20 (line 2497) | FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; }
  function custom_ (line 2519) | custom_(custom) {}
  function format (line 2521) | void format(parse_context<char_type>& parse_ctx, Context& ctx) const {
  function FMT_INLINE (line 2544) | FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) {
  function FMT_CONSTEXPR (line 2609) | FMT_CONSTEXPR auto type(int index) const -> detail::type {
  function FMT_CONSTEXPR (line 2646) | FMT_CONSTEXPR auto get(int id) const -> format_arg {
  function class (line 2683) | class context {
  function runtime_format_string (line 2733) | inline auto runtime(string_view s) -> runtime_format_string<> { return {...
  function FMT_ALWAYS_INLINE (line 2754) | FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) {
  function FMT_ALWAYS_INLINE (line 2768) | FMT_ALWAYS_INLINE fstring(const S& s) : str(s) {
  function str (line 2781) | fstring(const S&) : str(S()) {
  function string_view (line 2790) | const string_view&() const { return str; }
  function FMT_ALWAYS_INLINE (line 2824) | constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args)
  type format_to_result (line 2909) | struct format_to_result {

FILE: include/spdlog/fmt/bundled/chrono.h
  function namespace (line 39) | namespace safe_duration_cast {
  type Factor (line 168) | struct Factor
  function min1 (line 198) | constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
  function namespace (line 225) | namespace detail {
  function namespace (line 268) | namespace detail {
  function buffer_ (line 290) | buffer_(buf) {}
  function FMT_NORETURN (line 417) | FMT_NORETURN inline void throw_duration_error() {
  function FMT_BEGIN_EXPORT (line 493) | FMT_BEGIN_EXPORT
  function namespace (line 540) | namespace detail {
  function else (line 997) | else if (precision > 0) {
  function write1 (line 1133) | void write1(int value) {
  function write2 (line 1136) | void write2(int value) {
  function write2 (line 1141) | void write2(int value, pad_type pad) {
  function write_year_extended (line 1153) | void write_year_extended(long long year, pad_type pad) {
  function write_year (line 1169) | void write_year(long long year, pad_type pad) {
  function write_utc_offset (line 1173) | void write_utc_offset(long long offset, numeric_system ns) {
  function FMT_CONSTEXPR (line 1219) | FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
  function on_abbr_weekday (line 1223) | void on_abbr_weekday() {
  function on_full_weekday (line 1229) | void on_full_weekday() {
  function on_dec0_weekday (line 1235) | void on_dec0_weekday(numeric_system ns) {
  function on_dec1_weekday (line 1239) | void on_dec1_weekday(numeric_system ns) {
  function on_abbr_month (line 1248) | void on_abbr_month() {
  function on_full_month (line 1254) | void on_full_month() {
  function on_datetime (line 1261) | void on_datetime(numeric_system ns) {
  function on_loc_date (line 1276) | void on_loc_date(numeric_system ns) {
  function on_loc_time (line 1282) | void on_loc_time(numeric_system ns) {
  function on_us_date (line 1288) | void on_us_date() {
  function on_iso_date (line 1295) | void on_iso_date() {
  function on_utc_offset (line 1312) | void on_utc_offset(numeric_system ns) { format_utc_offset(tm_, ns); }
  function on_tz_name (line 1313) | void on_tz_name() { format_tz_name(tm_); }
  function on_year (line 1315) | void on_year(numeric_system ns, pad_type pad) {
  function on_short_year (line 1320) | void on_short_year(numeric_system ns) {
  function on_offset_year (line 1325) | void on_offset_year() {
  function on_century (line 1330) | void on_century(numeric_system ns) {
  function on_dec_month (line 1348) | void on_dec_month(numeric_system ns, pad_type pad) {
  function on_dec0_week_of_year (line 1354) | void on_dec0_week_of_year(numeric_system ns, pad_type pad) {
  function on_dec1_week_of_year (line 1360) | void on_dec1_week_of_year(numeric_system ns, pad_type pad) {
  function on_iso_week_of_year (line 1371) | void on_iso_week_of_year(numeric_system ns, pad_type pad) {
  function on_iso_week_based_year (line 1377) | void on_iso_week_based_year() {
  function on_iso_week_based_short_year (line 1380) | void on_iso_week_based_short_year() {
  function on_day_of_year (line 1384) | void on_day_of_year(pad_type pad) {
  function on_day_of_month (line 1394) | void on_day_of_month(numeric_system ns, pad_type pad) {
  function on_24_hour (line 1400) | void on_24_hour(numeric_system ns, pad_type pad) {
  function on_12_hour (line 1405) | void on_12_hour(numeric_system ns, pad_type pad) {
  function on_minute (line 1410) | void on_minute(numeric_system ns, pad_type pad) {
  function on_second (line 1416) | void on_second(numeric_system ns, pad_type pad) {
  function on_12_hour_time (line 1437) | void on_12_hour_time() {
  function on_24_hour_time (line 1449) | void on_24_hour_time() {
  function on_iso_time (line 1454) | void on_iso_time() {
  function on_am_pm (line 1460) | void on_am_pm() {
  function on_duration_value (line 1470) | void on_duration_value() {}
  function on_duration_unit (line 1471) | void on_duration_unit() {}
  function chrono_format_checker (line 1474) | struct chrono_format_checker : null_chrono_spec_handler<chrono_format_ch...
  function FMT_CONSTEXPR (line 1494) | FMT_CONSTEXPR void on_duration_unit() {}
  function class (line 1588) | class get_locale {
  function write_sign (line 1684) | void write_sign() {
  function write_nan (line 1702) | void write_nan() { std::copy_n("nan", 3, out); }
  function on_text (line 1713) | void on_text(const Char* begin, const Char* end) {
  function on_abbr_weekday (line 1718) | void on_abbr_weekday() {}
  function on_full_weekday (line 1719) | void on_full_weekday() {}
  function on_dec0_weekday (line 1720) | void on_dec0_weekday(numeric_system) {}
  function on_dec1_weekday (line 1721) | void on_dec1_weekday(numeric_system) {}
  function on_abbr_month (line 1722) | void on_abbr_month() {}
  function on_full_month (line 1723) | void on_full_month() {}
  function on_datetime (line 1724) | void on_datetime(numeric_system) {}
  function on_loc_date (line 1725) | void on_loc_date(numeric_system) {}
  function on_loc_time (line 1726) | void on_loc_time(numeric_system) {}
  function on_us_date (line 1727) | void on_us_date() {}
  function on_iso_date (line 1728) | void on_iso_date() {}
  function on_utc_offset (line 1729) | void on_utc_offset(numeric_system) {}
  function on_tz_name (line 1730) | void on_tz_name() {}
  function on_year (line 1731) | void on_year(numeric_system, pad_type) {}
  function on_short_year (line 1732) | void on_short_year(numeric_system) {}
  function on_offset_year (line 1733) | void on_offset_year() {}
  function on_century (line 1734) | void on_century(numeric_system) {}
  function on_iso_week_based_year (line 1735) | void on_iso_week_based_year() {}
  function on_iso_week_based_short_year (line 1736) | void on_iso_week_based_short_year() {}
  function on_dec_month (line 1737) | void on_dec_month(numeric_system, pad_type) {}
  function on_dec0_week_of_year (line 1738) | void on_dec0_week_of_year(numeric_system, pad_type) {}
  function on_dec1_week_of_year (line 1739) | void on_dec1_week_of_year(numeric_system, pad_type) {}
  function on_iso_week_of_year (line 1740) | void on_iso_week_of_year(numeric_system, pad_type) {}
  function on_day_of_month (line 1741) | void on_day_of_month(numeric_system, pad_type) {}
  function on_day_of_year (line 1743) | void on_day_of_year(pad_type) {
  function on_24_hour (line 1748) | void on_24_hour(numeric_system ns, pad_type pad) {
  function on_12_hour (line 1757) | void on_12_hour(numeric_system ns, pad_type pad) {
  function on_minute (line 1766) | void on_minute(numeric_system ns, pad_type pad) {
  function on_second (line 1775) | void on_second(numeric_system ns, pad_type pad) {
  function on_12_hour_time (line 1799) | void on_12_hour_time() {
  function on_24_hour_time (line 1804) | void on_24_hour_time() {
  function on_iso_time (line 1816) | void on_iso_time() {
  function on_am_pm (line 1823) | void on_am_pm() {
  function on_duration_value (line 1828) | void on_duration_value() {
  function on_duration_unit (line 1834) | void on_duration_unit() { out = format_duration_unit<Char, Period>(out); }
  function class (line 1847) | class weekday {
  function class (line 1858) | class day {
  function class (line 1869) | class month {
  function class (line 1880) | class year {
  function class (line 1890) | class year_month_day {
  function FMT_CONSTEXPR (line 2112) | FMT_CONSTEXPR void set_localized() { specs_.set_localized(); }

FILE: include/spdlog/fmt/bundled/color.h
  function color (line 16) | enum class color : uint32_t {
  function vprint (line 497) | inline void vprint(FILE* f, text_style ts, string_view fmt, format_args ...
  function T (line 629) | auto styled(const T& value, text_style ts)

FILE: include/spdlog/fmt/bundled/compile.h
  function class (line 21) | class compiled_string {}
  function namespace (line 56) | inline namespace literals {
  function FMT_END_EXPORT (line 63) | FMT_END_EXPORT
  function FMT_INLINE (line 472) | FMT_INLINE auto format_to(OutputIt out, const CompiledFormat& cf,
  function FMT_CONSTEXPR_STRING (line 479) | FMT_CONSTEXPR_STRING auto format(const S&, T&&... args)
  function FMT_CONSTEXPR (line 558) | FMT_CONSTEXPR static_format_result(const S& fmt, T&&... args) {

FILE: include/spdlog/fmt/bundled/format-inl.h
  function FMT_FUNC (line 36) | FMT_FUNC void assert_fail(const char* file, int line, const char* messag...
  function namespace (line 45) | namespace detail {
  function namespace (line 51) | namespace detail {
  function namespace (line 71) | namespace detail {
  function noexcept (line 212) | inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int {
  function FMT_INLINE_VARIABLE (line 217) | FMT_INLINE_VARIABLE constexpr struct div_small_pow10_infos_struct {
  function noexcept (line 260) | inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t {
  function noexcept (line 265) | inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t {
  function float (line 273) | struct cache_accessor<float> {
  function noexcept (line 327) | static auto compute_delta(const cache_entry_type& cache, int beta) noexcept
  function carrier_uint (line 344) | static auto compute_left_endpoint_for_shorter_interval_case(
  function carrier_uint (line 351) | static auto compute_right_endpoint_for_shorter_interval_case(
  function carrier_uint (line 358) | static auto compute_round_up_for_shorter_interval_case(
  function double (line 367) | struct cache_accessor<double> {
  function bigint (line 1384) | struct formatter<detail::bigint> {
  function FMT_FUNC (line 1410) | FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
  function FMT_FUNC (line 1425) | FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_c...
  function FMT_FUNC (line 1436) | FMT_FUNC void report_system_error(int error_code,
  function FMT_FUNC (line 1441) | FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string {
  function namespace (line 1449) | namespace detail {
  function operator (line 1493) | operator F*() const { return file_; }
  function unget (line 1504) | void unget(char c) {
  function flush (line 1509) | void flush() { fflush(this->file_); }
  function init_buffer (line 1527) | void init_buffer() {
  function span (line 1541) | auto get_write_buffer() const -> span<char> {
  function advance_write_buffer (line 1546) | void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += s...
  function flush (line 1555) | void flush() { fflush_unlocked(this->file_); }
  function init_buffer (line 1573) | void init_buffer() {
  function advance_write_buffer (line 1592) | void advance_write_buffer(size_t size) {
  function init_buffer (line 1615) | void init_buffer() {}
  function unget (line 1630) | void unget(char c) {
  function grow (line 1668) | static void grow(buffer<char>& base, size_t) {
  function FMT_FUNC (line 1695) | FMT_FUNC auto write_console(int, string_view) -> bool { return false; }
  function FMT_FUNC (line 1701) | FMT_FUNC bool write_console(int fd, string_view text) {
  function FMT_FUNC (line 1710) | FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args...
  function FMT_FUNC (line 1719) | FMT_FUNC void print(std::FILE* f, string_view text) {
  function FMT_FUNC (line 1731) | FMT_FUNC void vprint_buffered(std::FILE* f, string_view fmt, format_args...
  function FMT_FUNC (line 1737) | FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) {
  function FMT_FUNC (line 1744) | FMT_FUNC void vprintln(std::FILE* f, string_view fmt, format_args args) {
  function FMT_FUNC (line 1751) | FMT_FUNC void vprint(string_view fmt, format_args args) {
  function namespace (line 1755) | namespace detail {
  function FMT_FUNC (line 1794) | FMT_FUNC auto is_printable(uint32_t cp) -> bool {

FILE: include/spdlog/fmt/bundled/format.h
  function namespace (line 161) | namespace std {
  function namespace (line 200) | namespace detail {
  function operator (line 354) | auto operator*(const uint128_fallback& lhs, uint32_t rhs)
  function uint128_fallback (line 391) | uint64_t n) noexcept -> uint128_fallback& {
  function To (line 441) | auto bit_cast(const From& from) -> To {
  function FMT_INLINE (line 479) | FMT_INLINE void assume(bool condition) {
  function FMT_CONSTEXPR20 (line 494) | __attribute__((no_sanitize("undefined")))
  function T (line 505) | inline auto reserve(basic_appender<T> it, size_t n)
  function FMT_NOINLINE (line 572) | FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end,
  function FMT_CONSTEXPR (line 594) | FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e)
  function for_each_codepoint (line 636) | void for_each_codepoint(string_view s, F f) {
  function true_type (line 693) | struct is_integral<int128_opt> : std::true_type {}
  function true_type (line 694) | struct is_integral<uint128_t> : std::true_type {}
  type float128 (line 720) | struct float128 {}
  function true_type (line 726) | struct is_floating_point<float128> : std::true_type {}
  function deallocate (line 756) | void deallocate(T* p, size_t) { free(p); }
  function FMT_CONSTEXPR20 (line 805) | FMT_CONSTEXPR20 void deallocate() {
  function FMT_CONSTEXPR20 (line 810) | static FMT_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
  function FMT_CONSTEXPR20 (line 844) | FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
  function FMT_CONSTEXPR (line 907) | FMT_CONSTEXPR void resize(size_t count) { this->try_resize(count); }
  function reserve (line 910) | void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
  function append (line 914) | void append(const ContiguousRange& range) {
  function string (line 922) | auto to_string(const basic_memory_buffer<char, SIZE>& buf)
  function class (line 930) | class writer {
  function class (line 952) | class string_buffer {
  function FMT_END_EXPORT (line 979) | FMT_END_EXPORT
  function namespace (line 985) | namespace detail {
  function Char (line 1003) | constexpr auto compile_string_to_view(basic_string_view<Char> s)
  function char (line 1036) | inline auto digits2(size_t value) -> const char* {
  function Char (line 1048) | auto getsign(sign s) -> Char {
  function FMT_CONSTEXPR (line 1068) | FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int {
  function FMT_CONSTEXPR20 (line 1096) | FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int {
  function FMT_INLINE (line 1123) | FMT_INLINE auto do_count_digits(uint32_t n) -> int {
  function FMT_CONSTEXPR20 (line 1146) | FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int {
  function wchar_t (line 1172) | inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_...
  function Char (line 1178) | auto decimal_point(locale_ref loc) -> Char {
  function wchar_t (line 1181) | inline auto decimal_point(locale_ref loc) -> wchar_t {
  function FMT_API (line 1192) | FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
  function write2digits (line 1206) | void write2digits(Char* out, size_t value) {
  function class (line 1300) | class utf8_to_utf16 {
  function FMT_INLINE (line 1386) | FMT_INLINE auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fall...
  function namespace (line 1414) | namespace dragonbox {
  function float (line 1454) | struct float_info<float> {
  function double (line 1466) | struct float_info<double> {
  function FMT_CONSTEXPR (line 1632) | FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64...
  function FMT_CONSTEXPR (line 1649) | FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp {
  function T (line 1658) | auto convert_float(T value) -> convert_float_result<T> {
  function FMT_NOINLINE (line 1672) | FMT_NOINLINE auto fill(OutputIt it, size_t n,
  function OutputIt (line 1714) | auto write_bytes(OutputIt out, string_view bytes,
  function write (line 1728) | auto write = [=](reserve_iterator<OutputIt> it) {
  type next_state (line 1873) | struct next_state {
  type size_padding (line 2041) | struct size_padding {
  function FMT_INLINE (line 2062) | FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
  function FMT_NOINLINE (line 2126) | FMT_NOINLINE auto write_int_noinline(OutputIt out,
  function FMT_INLINE (line 2137) | FMT_INLINE auto write(basic_appender<Char> out, T value,
  function FMT_INLINE (line 2151) | FMT_INLINE auto write(OutputIt out, T value,
  function OutputIt (line 2159) | auto write(OutputIt out, Char value, const format_specs& specs,
  type bounded_output_iterator (line 2224) | struct bounded_output_iterator {
  function operator (line 2229) | auto operator++() -> bounded_output_iterator& {
  type big_decimal_fp (line 2367) | struct big_decimal_fp {
  function write (line 2589) | auto write = [=](reserve_iterator<OutputIt> it) {
  function FMT_CONSTEXPR (line 2643) | FMT_CONSTEXPR auto signbit(T value) -> bool {
  function class (line 2663) | class bigint {
  function FMT_CONSTEXPR (line 2768) | FMT_CONSTEXPR auto num_bigits() const -> int {
  function FMT_CONSTEXPR20 (line 2829) | FMT_CONSTEXPR20 void assign_pow10(int exp) {
  function FMT_CONSTEXPR20 (line 2846) | FMT_CONSTEXPR20 void square() {
  function FMT_CONSTEXPR (line 2876) | FMT_CONSTEXPR void align(const bigint& other) {
  function FMT_CONSTEXPR (line 2889) | FMT_CONSTEXPR auto divmod_assign(const bigint& divisor) -> int {
  type dragon (line 2904) | enum dragon {
  function format_hexfloat (line 3049) | void format_hexfloat(Float value, format_specs specs,
  function format_hexfloat (line 3129) | void format_hexfloat(Float value, format_specs specs,
  function OutputIt (line 3446) | auto write(OutputIt out, T value, format_specs specs,
  function OutputIt (line 3605) | auto write(OutputIt out, T value, const format_specs& specs = {},
  type dynamic_spec_getter (line 3698) | struct dynamic_spec_getter {
  function handle_dynamic_spec (line 3712) | void handle_dynamic_spec(
  function value (line 3732) | static_named_arg(const T& v) : value(v) {}
  function on_text (line 3764) | void on_text(const Char* begin, const Char* end) {
  function FMT_CONSTEXPR (line 3769) | FMT_CONSTEXPR auto on_arg_id(int id) -> int {
  function FMT_CONSTEXPR (line 3773) | FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
  function FMT_INLINE (line 3780) | FMT_INLINE void on_replacement_field(int id, const Char*) {
  function FMT_NORETURN (line 3804) | FMT_NORETURN void on_error(const char* message) { report_error(message); }
  function generic_context (line 3854) | constexpr auto arg(int id) const -> basic_format_arg<generic_context> {
  function generic_context (line 3857) | auto arg(basic_string_view<Char> name) const
  function advance_to (line 3867) | void advance_to(iterator it) {
  function Char (line 3950) | long, Char> {}
  function Enum (line 3989) | auto underlying(Enum e) noexcept -> underlying_t<Enum> {
  function namespace (line 3993) | namespace enums {
  function format (line 4013) | struct bytes {
  function namespace (line 4143) | inline namespace literals {
  function class (line 4165) | class format_int {
  function FMT_INLINE (line 4347) | FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
  function FMT_CONSTEXPR_STRING (line 4360) | FMT_CONSTEXPR_STRING auto to_string(T value) -> std::string {
  function FMT_CONSTEXPR_STRING (line 4368) | FMT_CONSTEXPR_STRING auto to_string(const T& value)
  function FMT_CONSTEXPR_STRING (line 4375) | FMT_CONSTEXPR_STRING auto to_string(const T& value)

FILE: include/spdlog/fmt/bundled/os.h
  function FMT_API (line 115) | FMT_API const std::error_category& system_category() noexcept;
  function class (line 173) | class buffered_file {
  function descriptor (line 210) | inline auto get() const noexcept -> FILE* { return file_; }
  function pipe (line 312) | struct FMT_API pipe {
  function detail (line 322) | auto getpagesize() -> long;
  function class (line 367) | class ostream : private detail::buffer<char> {

FILE: include/spdlog/fmt/bundled/ostream.h
  function FMT_BEGIN_NAMESPACE (line 33) | FMT_BEGIN_NAMESPACE
  function T (line 112) | auto streamed(const T& value) -> detail::streamed_view<T> {
  function vprint (line 116) | inline void vprint(std::ostream& os, string_view fmt, format_args args) {

FILE: include/spdlog/fmt/bundled/printf.h
  function advance_to (line 41) | void advance_to(basic_appender<Char>) {}
  function basic_printf_context (line 45) | auto arg(int id) const -> basic_format_arg<basic_printf_context> {
  function namespace (line 50) | namespace detail {
  type int_checker (line 78) | struct int_checker
  type printf_precision_handler (line 86) | struct printf_precision_handler {
  type is_zero_int (line 102) | struct is_zero_int {
  function bool (line 116) | struct make_unsigned_or_bool<bool> {
  function arg_ (line 176) | arg_(arg) {}
  function class (line 196) | class printf_width_handler {
  function get_arg (line 401) | auto get_arg = [&](int arg_index) {

FILE: include/spdlog/fmt/bundled/ranges.h
  function namespace (line 33) | namespace detail {
  function FMT_CONSTEXPR (line 142) | static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
  function namespace (line 210) | namespace tuple {
  function FMT_EXPORT (line 281) | FMT_EXPORT
  type is_tuple_formattable (line 288) | struct is_tuple_formattable {
  type is_range (line 345) | struct is_range {
  function namespace (line 350) | namespace detail {
  function FMT_CONSTEXPR (line 408) | FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
  function FMT_CONSTEXPR (line 507) | FMT_CONSTEXPR formatter() {
  function typename (line 730) | const ->

FILE: include/spdlog/fmt/bundled/std.h
  function FMT_BEGIN_NAMESPACE (line 79) | FMT_BEGIN_NAMESPACE

FILE: include/spdlog/fmt/bundled/xchar.h
  function FMT_BEGIN_NAMESPACE (line 23) | FMT_BEGIN_NAMESPACE
  function FMT_ALWAYS_INLINE (line 97) | FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
  function str_ (line 104) | basic_fstring(const S&) : str_(S()) {
  function operator (line 112) | operator basic_string_view<Char>() const { return str_; }
  function wchar_t (line 121) | inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
  function namespace (line 132) | inline namespace literals {
  function vprint (line 290) | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
  function vprint (line 298) | inline void vprint(wstring_view fmt, wformat_args args) {
  function vprint (line 333) | inline void vprint(std::wostream& os, wstring_view fmt, wformat_args arg...
  function wstring (line 350) | auto to_wstring(const T& value) -> std::wstring {

FILE: include/spdlog/formatter.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/fwd.h
  function namespace (line 6) | namespace spdlog {

FILE: include/spdlog/logger-inl.h
  function namespace (line 16) | namespace spdlog {
  function SPDLOG_INLINE (line 109) | SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks() { return sinks_; }
  function SPDLOG_INLINE (line 117) | SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_n...

FILE: include/spdlog/logger.h
  function namespace (line 48) | namespace spdlog {
  function log (line 119) | void log(source_loc loc, level::level_enum lvl, string_view_t msg) {
  function log (line 130) | void log(level::level_enum lvl, string_view_t msg) { log(source_loc{}, l...
  function log (line 177) | void log(log_clock::time_point log_time,
  function log (line 193) | void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) {
  function log (line 206) | void log(level::level_enum lvl, wstring_view_t msg) { log(source_loc{}, ...
  function std (line 281) | const std::string &name() const;

FILE: include/spdlog/mdc.h
  function namespace (line 24) | namespace spdlog {

FILE: include/spdlog/pattern_formatter-inl.h
  function class (line 42) | class scoped_padder {
  function name_formatter (line 104) | name_formatter final : public flag_formatter {
  function level_formatter (line 117) | level_formatter final : public flag_formatter {
  function format (line 136) | void format(const details::log_msg &msg, const std::tm &, memory_buf_t &...
  function to12h (line 149) | static int to12h(const tm &t) { return t.tm_hour > 12 ? t.tm_hour - 12 :...
  function std (line 152) | static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Th...
  function format (line 160) | void format(const details::log_msg &, const std::tm &tm_time, memory_buf...
  function std (line 168) | static std::array<const char *, 7> full_days{
  function format (line 177) | void format(const details::log_msg &, const std::tm &tm_time, memory_buf...
  function format (line 194) | void format(const details::log_msg &, const std::tm &tm_time, memory_buf...
  function std (line 202) | static const std::array<const char *, 12> full_months{{"January", "Febru...
  function SPDLOG_INLINE (line 1014) | SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_ms...
  function handle_flag_ (line 1022) | void pattern_formatter::handle_flag_(char flag, details::padding_info pa...

FILE: include/spdlog/pattern_formatter.h
  function namespace (line 19) | namespace spdlog {
  function class (line 40) | class SPDLOG_API flag_formatter {
  function set_padding_info (line 60) | void set_padding_info(const details::padding_info &padding) {
  function pattern_formatter (line 65) | pattern_formatter final : public formatter {

FILE: include/spdlog/sinks/android_sink.h
  function namespace (line 25) | namespace spdlog {

FILE: include/spdlog/sinks/ansicolor_sink-inl.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/sinks/ansicolor_sink.h
  function namespace (line 14) | namespace spdlog {

FILE: include/spdlog/sinks/base_sink-inl.h
  function SPDLOG_INLINE (line 26) | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_ms...
  function SPDLOG_INLINE (line 32) | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush() {
  function SPDLOG_INLINE (line 38) | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::st...
  function SPDLOG_INLINE (line 44) | SPDLOG_INLINE
  function SPDLOG_INLINE (line 51) | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::s...
  function SPDLOG_INLINE (line 56) | SPDLOG_INLINE

FILE: include/spdlog/sinks/basic_file_sink-inl.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/sinks/basic_file_sink.h
  function namespace (line 14) | namespace spdlog {

FILE: include/spdlog/sinks/callback_sink.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/sinks/daily_file_sink.h
  function namespace (line 23) | namespace spdlog {

FILE: include/spdlog/sinks/dist_sink.h
  function namespace (line 19) | namespace spdlog {

FILE: include/spdlog/sinks/dup_filter_sink.h
  function namespace (line 37) | namespace spdlog {

FILE: include/spdlog/sinks/hourly_file_sink.h
  function namespace (line 21) | namespace spdlog {

FILE: include/spdlog/sinks/kafka_sink.h
  function namespace (line 24) | namespace spdlog {
  function flush_ (line 80) | void flush_() override { producer_->flush(config_.flush_timeout_ms); }

FILE: include/spdlog/sinks/mongo_sink.h
  function namespace (line 26) | namespace spdlog {

FILE: include/spdlog/sinks/msvc_sink.h
  function namespace (line 25) | namespace spdlog {

FILE: include/spdlog/sinks/null_sink.h
  function namespace (line 12) | namespace spdlog {

FILE: include/spdlog/sinks/ostream_sink.h
  function namespace (line 12) | namespace spdlog {

FILE: include/spdlog/sinks/qt_sinks.h
  function namespace (line 27) | namespace spdlog {

FILE: include/spdlog/sinks/ringbuffer_sink.h
  function namespace (line 15) | namespace spdlog {

FILE: include/spdlog/sinks/rotating_file_sink-inl.h
  function namespace (line 22) | namespace spdlog {

FILE: include/spdlog/sinks/rotating_file_sink.h
  function namespace (line 14) | namespace spdlog {

FILE: include/spdlog/sinks/sink.h
  function namespace (line 9) | namespace spdlog {

FILE: include/spdlog/sinks/stdout_color_sinks-inl.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/sinks/stdout_color_sinks.h
  function namespace (line 14) | namespace spdlog {

FILE: include/spdlog/sinks/stdout_sinks-inl.h
  function namespace (line 28) | namespace spdlog {

FILE: include/spdlog/sinks/stdout_sinks.h
  function namespace (line 15) | namespace spdlog {

FILE: include/spdlog/sinks/syslog_sink.h
  function namespace (line 14) | namespace spdlog {

FILE: include/spdlog/sinks/systemd_sink.h
  function namespace (line 17) | namespace spdlog {

FILE: include/spdlog/sinks/tcp_sink.h
  function namespace (line 28) | namespace spdlog {

FILE: include/spdlog/sinks/udp_sink.h
  function namespace (line 23) | namespace spdlog {

FILE: include/spdlog/sinks/win_eventlog_sink.h
  function namespace (line 46) | namespace spdlog {
  function get_event_category (line 155) | struct eventlog {
  function HANDLE (line 194) | HANDLE event_log_handle() {
  function flush_ (line 234) | void flush_() override {}

FILE: include/spdlog/sinks/wincolor_sink-inl.h
  function namespace (line 16) | namespace spdlog {

FILE: include/spdlog/sinks/wincolor_sink.h
  function namespace (line 17) | namespace spdlog {

FILE: include/spdlog/spdlog-inl.h
  function namespace (line 13) | namespace spdlog {

FILE: include/spdlog/spdlog.h
  function namespace (line 23) | namespace spdlog {
  function log (line 192) | void log(source_loc source, level::level_enum lvl, const T &msg) {
  function log (line 197) | void log(level::level_enum lvl, const T &msg) {
  function log (line 203) | void log(source_loc source,
  function log (line 211) | void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&.....
  function trace (line 247) | void trace(const T &msg) {
  function debug (line 252) | void debug(const T &msg) {
  function info (line 257) | void info(const T &msg) {
  function warn (line 262) | void warn(const T &msg) {
  function error (line 267) | void error(const T &msg) {
  function critical (line 272) | void critical(const T &msg) {

FILE: include/spdlog/stopwatch.h
  function namespace (line 29) | namespace spdlog {
  type formatter (line 60) | struct formatter

FILE: src/bundled_fmtlib_format.cpp
  type detail (line 20) | namespace detail {

FILE: src/color_sinks.cpp
  class SPDLOG_API (line 17) | class SPDLOG_API
  class SPDLOG_API (line 18) | class SPDLOG_API
  class SPDLOG_API (line 19) | class SPDLOG_API
  class SPDLOG_API (line 20) | class SPDLOG_API
  class SPDLOG_API (line 21) | class SPDLOG_API
  class SPDLOG_API (line 22) | class SPDLOG_API
  class SPDLOG_API (line 25) | class SPDLOG_API
  class SPDLOG_API (line 26) | class SPDLOG_API
  class SPDLOG_API (line 27) | class SPDLOG_API
  class SPDLOG_API (line 28) | class SPDLOG_API
  class SPDLOG_API (line 29) | class SPDLOG_API
  class SPDLOG_API (line 30) | class SPDLOG_API

FILE: src/file_sinks.cpp
  class SPDLOG_API (line 15) | class SPDLOG_API
  class SPDLOG_API (line 16) | class SPDLOG_API
  class SPDLOG_API (line 19) | class SPDLOG_API
  class SPDLOG_API (line 20) | class SPDLOG_API

FILE: src/spdlog.cpp
  class SPDLOG_API (line 27) | class SPDLOG_API
  class SPDLOG_API (line 28) | class SPDLOG_API

FILE: src/stdout_sinks.cpp
  class SPDLOG_API (line 14) | class SPDLOG_API
  class SPDLOG_API (line 15) | class SPDLOG_API
  class SPDLOG_API (line 16) | class SPDLOG_API
  class SPDLOG_API (line 17) | class SPDLOG_API
  class SPDLOG_API (line 18) | class SPDLOG_API
  class SPDLOG_API (line 19) | class SPDLOG_API

FILE: tests/test_create_dir.cpp
  function try_create_dir (line 10) | bool try_create_dir(const spdlog::filename_t &path, const spdlog::filena...
  function get_full_path (line 93) | std::string get_full_path(const std::string &relative_folder_path) {
  function get_full_path (line 101) | std::wstring get_full_path(const std::wstring &relative_folder_path) {
  function find_non_existing_drive (line 107) | spdlog::filename_t::value_type find_non_existing_drive() {

FILE: tests/test_daily_logger.cpp
  function filename_buf_to_utf8string (line 14) | std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) {
  function filename_buf_to_utf8string (line 20) | std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) {
  type custom_daily_file_name_calculator (line 47) | struct custom_daily_file_name_calculator {
    method calc_filename (line 48) | static spdlog::filename_t calc_filename(const spdlog::filename_t &base...
  function create_msg (line 127) | static spdlog::details::log_msg create_msg(std::chrono::seconds offset) {
  function test_rotate (line 134) | static void test_rotate(int days_to_run, uint16_t max_days, uint16_t exp...

FILE: tests/test_errors.cpp
  class failing_sink (line 12) | class failing_sink : public spdlog::sinks::base_sink<std::mutex> {
    method sink_it_ (line 14) | void sink_it_(const spdlog::details::log_msg &) final {
    method flush_ (line 18) | void flush_() final { throw std::runtime_error("some error happened du...
  type custom_ex (line 20) | struct custom_ex {}

FILE: tests/test_eventlog.cpp
  function test_single_print (line 10) | static void test_single_print(std::function<void(std::string const &)> d...

FILE: tests/test_file_helper.cpp
  function write_with_helper (line 11) | static void write_with_helper(file_helper &helper, size_t howmany) {
  function test_split_ext (line 63) | static void test_split_ext(const spdlog::filename_t::value_type *fname,
  type flags (line 113) | enum class flags { before_open, after_open, before_close, after_close }

FILE: tests/test_fmt_helper.cpp
  function SPDLOG_CONSTEXPR_FUNC (line 6) | SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_...
  function test_pad2 (line 11) | void test_pad2(int n, const char *expected) {
  function test_pad3 (line 18) | void test_pad3(uint32_t n, const char *expected) {
  function test_pad6 (line 25) | void test_pad6(std::size_t n, const char *expected) {
  function test_pad9 (line 32) | void test_pad9(std::size_t n, const char *expected) {

FILE: tests/test_misc.cpp
  function log_info (line 9) | std::string log_info(const T& what, spdlog::level::level_enum logger_lev...
  type auto_closer (line 205) | struct auto_closer {
    method auto_closer (line 207) | explicit auto_closer(FILE* f)
    method auto_closer (line 209) | auto_closer(const auto_closer&) = delete;
    method auto_closer (line 210) | auto_closer& operator=(const auto_closer&) = delete;

FILE: tests/test_mpmc_q.cpp
  function milliseconds (line 6) | static milliseconds millis_from(const test_clock::time_point &tp0) {

FILE: tests/test_pattern_formatter.cpp
  function SPDLOG_CONSTEXPR_FUNC (line 8) | SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_...
  function log_to_str (line 15) | static std::string log_to_str(const std::string &msg, const Args &...arg...
  function log_to_str_with_time (line 30) | static std::string log_to_str_with_time(spdlog::log_clock::time_point lo...
  class custom_test_flag (line 367) | class custom_test_flag : public spdlog::custom_flag_formatter {
    method custom_test_flag (line 369) | explicit custom_test_flag(std::string txt)
    method format (line 372) | void format(const spdlog::details::log_msg &,
    method get_padding_info (line 386) | spdlog::details::padding_info get_padding_info() { return padinfo_; }
    method clone (line 390) | std::unique_ptr<custom_flag_formatter> clone() const override {

FILE: tests/test_sink.h
  function namespace (line 15) | namespace spdlog {

FILE: tests/test_timezone.cpp
  function make_tm (line 9) | std::tm make_tm(int year, int month, int day, int hour, int minute) {
  class ScopedTZ (line 24) | class ScopedTZ {
    method ScopedTZ (line 29) | explicit ScopedTZ(const std::string& tz_name) {

FILE: tests/utils.cpp
  function prepare_logdir (line 10) | void prepare_logdir() {
  function file_contents (line 22) | std::string file_contents(const std::string &filename) {
  function count_lines (line 30) | std::size_t count_lines(const std::string &filename) {
  function require_message_count (line 42) | void require_message_count(const std::string &filename, const std::size_...
  function get_filesize (line 50) | std::size_t get_filesize(const std::string &filename) {
  function ends_with (line 59) | bool ends_with(std::string const &value, std::string const &ending) {
  function count_files (line 68) | std::size_t count_files(const std::string &folder) {
  function count_files (line 88) | std::size_t count_files(const std::string &folder) {
Condensed preview — 175 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,251K chars).
[
  {
    "path": ".clang-format",
    "chars": 429,
    "preview": "---\nLanguage:        Cpp\nBasedOnStyle:  Google\nAccessModifierOffset: -4\nStandard:        c++17\nIndentWidth:     4\nTabWid"
  },
  {
    "path": ".clang-tidy",
    "chars": 1728,
    "preview": "Checks: 'cppcoreguidelines-*,\nperformance-*,\nmodernize-*,\ngoogle-*,\nmisc-*\ncert-*,\nreadability-*,\nclang-analyzer-*,\n-per"
  },
  {
    "path": ".git-blame-ignore-revs",
    "chars": 220,
    "preview": "# clang-format\n1a0bfc7a89f2d58e22605a4dc7e18a9a555b65aa\n95c226e9c92928e20ccdac0d060e7241859e282b\n9d52261185b5f2c454c381d"
  },
  {
    "path": ".gitattributes",
    "chars": 13,
    "preview": "* text=false\n"
  },
  {
    "path": ".github/workflows/coverity_scan.yml",
    "chars": 1712,
    "preview": "name: coverity-linux\n\non: [push, pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  coverity_scan:\n    runs-on: ubunt"
  },
  {
    "path": ".github/workflows/linux.yml",
    "chars": 3631,
    "preview": "name: linux\n\non: [push, pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  # ----------------------------------------"
  },
  {
    "path": ".github/workflows/macos.yml",
    "chars": 1074,
    "preview": "name: macos\n\non: [push, pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: macOS-latest\n    name:"
  },
  {
    "path": ".github/workflows/windows.yml",
    "chars": 2643,
    "preview": "name: windows\n\non: [push, pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: windows-latest\n    s"
  },
  {
    "path": ".gitignore",
    "chars": 1137,
    "preview": "# Auto generated files\r\n[Dd]ebug/\r\n[Rr]elease/\r\nbuild/*\r\n*.slo\r\n*.lo\r\n*.o\r\n*.obj\r\n*.suo\r\n*.tlog\r\n*.ilk\r\n*.log\r\n*.pdb\r\n*."
  },
  {
    "path": "CMakeLists.txt",
    "chars": 18493,
    "preview": "# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\ncmake_minimum"
  },
  {
    "path": "INSTALL",
    "chars": 1010,
    "preview": "Header Only Version\r\n==================================================================\r\nJust copy the files to your bui"
  },
  {
    "path": "LICENSE",
    "chars": 1323,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 - present, Gabi Melman and spdlog contributors.\n\nPermission is hereby granted,"
  },
  {
    "path": "README.md",
    "chars": 19411,
    "preview": "# spdlog\r\n\r\n \r\n[![ci](https://github.com/gabime/spdlog/actions/workflows/linux.yml/badge.svg)](https://github.com/gabime"
  },
  {
    "path": "appveyor.yml",
    "chars": 2769,
    "preview": "version: 1.0.{build}\nimage: Visual Studio 2017\nenvironment:\n  matrix:\n    - GENERATOR: '\"Visual Studio 15 2017 Win64\"'\n "
  },
  {
    "path": "bench/CMakeLists.txt",
    "chars": 1285,
    "preview": "# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\ncmake_minimum"
  },
  {
    "path": "bench/async_bench.cpp",
    "chars": 5721,
    "preview": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n//\n//"
  },
  {
    "path": "bench/bench.cpp",
    "chars": 9516,
    "preview": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n//\n//"
  },
  {
    "path": "bench/formatter-bench.cpp",
    "chars": 2405,
    "preview": "//\n// Copyright(c) 2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#incl"
  },
  {
    "path": "bench/latency.cpp",
    "chars": 9527,
    "preview": "//\n// Copyright(c) 2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n//\n//"
  },
  {
    "path": "bench/utils.h",
    "chars": 628,
    "preview": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "cmake/ide.cmake",
    "chars": 1190,
    "preview": "# ---------------------------------------------------------------------------------------\n# IDE support for headers\n# --"
  },
  {
    "path": "cmake/pch.h.in",
    "chars": 5278,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "cmake/spdlog.pc.in",
    "chars": 364,
    "preview": "prefix=@CMAKE_INSTALL_PREFIX@\nexec_prefix=${prefix}\nincludedir=@PKG_CONFIG_INCLUDEDIR@\nlibdir=@PKG_CONFIG_LIBDIR@\n\nName:"
  },
  {
    "path": "cmake/spdlogCPack.cmake",
    "chars": 2716,
    "preview": "set(CPACK_GENERATOR \"TGZ;ZIP\" CACHE STRING \"Semicolon separated list of generators\")\n\nset(CPACK_INCLUDE_TOPLEVEL_DIRECTO"
  },
  {
    "path": "cmake/spdlogConfig.cmake.in",
    "chars": 550,
    "preview": "# Copyright(c) 2019 spdlog authors\r\n# Distributed under the MIT License (http://opensource.org/licenses/MIT)\r\n\r\n@PACKAGE"
  },
  {
    "path": "cmake/utils.cmake",
    "chars": 3234,
    "preview": "# Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION\nfunction(spdlog_extract_version)\n    fil"
  },
  {
    "path": "cmake/version.rc.in",
    "chars": 977,
    "preview": "#define APSTUDIO_READONLY_SYMBOLS\n#include <windows.h>\n#undef APSTUDIO_READONLY_SYMBOLS\n\nLANGUAGE LANG_ENGLISH, SUBLANG_"
  },
  {
    "path": "example/CMakeLists.txt",
    "chars": 990,
    "preview": "# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\ncmake_minimum"
  },
  {
    "path": "example/example.cpp",
    "chars": 14840,
    "preview": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n\n// spdlo"
  },
  {
    "path": "include/spdlog/async.h",
    "chars": 4012,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/async_logger-inl.h",
    "chars": 2882,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/async_logger.h",
    "chars": 2556,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/cfg/argv.h",
    "chars": 1221,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/cfg/env.h",
    "chars": 1023,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/cfg/helpers-inl.h",
    "chars": 3194,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/cfg/helpers.h",
    "chars": 722,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/common-inl.h",
    "chars": 3039,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/common.h",
    "chars": 11607,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/backtracer-inl.h",
    "chars": 2000,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/backtracer.h",
    "chars": 1161,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/circular_q.h",
    "chars": 3375,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/console_globals.h",
    "chars": 603,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/file_helper-inl.h",
    "chars": 4669,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/file_helper.h",
    "chars": 1754,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/fmt_helper.h",
    "chars": 4443,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/log_msg-inl.h",
    "chars": 1392,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/log_msg.h",
    "chars": 1200,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/log_msg_buffer-inl.h",
    "chars": 1664,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/log_msg_buffer.h",
    "chars": 931,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/mpmc_blocking_q.h",
    "chars": 5280,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/null_mutex.h",
    "chars": 933,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/os-inl.h",
    "chars": 16986,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/os.h",
    "chars": 4050,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/periodic_worker-inl.h",
    "chars": 616,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/periodic_worker.h",
    "chars": 1809,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/registry-inl.h",
    "chars": 8855,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/registry.h",
    "chars": 4460,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/synchronous_factory.h",
    "chars": 751,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/tcp_client-windows.h",
    "chars": 7063,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/tcp_client.h",
    "chars": 6393,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/thread_pool-inl.h",
    "chars": 4270,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/thread_pool.h",
    "chars": 3515,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/udp_client-windows.h",
    "chars": 3122,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/udp_client.h",
    "chars": 2214,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/details/windows_include.h",
    "chars": 180,
    "preview": "#pragma once\n\n#ifndef NOMINMAX\n#define NOMINMAX  // prevent windows redefining min/max\n#endif\n\n#ifndef WIN32_LEAN_AND_ME"
  },
  {
    "path": "include/spdlog/fmt/bin_to_hex.h",
    "chars": 7362,
    "preview": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/bundled/args.h",
    "chars": 7199,
    "preview": "// Formatting library for C++ - dynamic argument lists\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All right"
  },
  {
    "path": "include/spdlog/fmt/bundled/base.h",
    "chars": 105054,
    "preview": "// Formatting library for C++ - the base API for char/UTF-8\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All "
  },
  {
    "path": "include/spdlog/fmt/bundled/chrono.h",
    "chars": 77449,
    "preview": "// Formatting library for C++ - chrono support\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights reserv"
  },
  {
    "path": "include/spdlog/fmt/bundled/color.h",
    "chars": 23913,
    "preview": "// Formatting library for C++ - color support\n//\n// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors\n"
  },
  {
    "path": "include/spdlog/fmt/bundled/compile.h",
    "chars": 20493,
    "preview": "// Formatting library for C++ - experimental format string compilation\n//\n// Copyright (c) 2012 - present, Victor Zverov"
  },
  {
    "path": "include/spdlog/fmt/bundled/core.h",
    "chars": 187,
    "preview": "// This file is only provided for compatibility and may be removed in future\n// versions. Use fmt/base.h if you don't ne"
  },
  {
    "path": "include/spdlog/fmt/bundled/fmt.license.rst",
    "chars": 1431,
    "preview": "Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "include/spdlog/fmt/bundled/format-inl.h",
    "chars": 81008,
    "preview": "// Formatting library for C++ - implementation\n//\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All rights reserved."
  },
  {
    "path": "include/spdlog/fmt/bundled/format.h",
    "chars": 162666,
    "preview": "/*\n  Formatting library for C++\n\n  Copyright (c) 2012 - present, Victor Zverovich\n\n  Permission is hereby granted, free "
  },
  {
    "path": "include/spdlog/fmt/bundled/os.h",
    "chars": 12860,
    "preview": "// Formatting library for C++ - optional OS-specific functionality\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n"
  },
  {
    "path": "include/spdlog/fmt/bundled/ostream.h",
    "chars": 5027,
    "preview": "// Formatting library for C++ - std::ostream support\n//\n// Copyright (c) 2012 - present, Victor Zverovich\n// All rights "
  },
  {
    "path": "include/spdlog/fmt/bundled/printf.h",
    "chars": 19991,
    "preview": "// Formatting library for C++ - legacy printf implementation\n//\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All ri"
  },
  {
    "path": "include/spdlog/fmt/bundled/ranges.h",
    "chars": 28126,
    "preview": "// Formatting library for C++ - range and tuple support\n//\n// Copyright (c) 2012 - present, Victor Zverovich and {fmt} c"
  },
  {
    "path": "include/spdlog/fmt/bundled/std.h",
    "chars": 23532,
    "preview": "// Formatting library for C++ - formatters for standard library types\n//\n// Copyright (c) 2012 - present, Victor Zverovi"
  },
  {
    "path": "include/spdlog/fmt/bundled/xchar.h",
    "chars": 13098,
    "preview": "// Formatting library for C++ - optional wchar_t and exotic character support\n//\n// Copyright (c) 2012 - present, Victor"
  },
  {
    "path": "include/spdlog/fmt/chrono.h",
    "chars": 467,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/compile.h",
    "chars": 475,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/fmt.h",
    "chars": 712,
    "preview": "//\n// Copyright(c) 2016-2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n"
  },
  {
    "path": "include/spdlog/fmt/ostr.h",
    "chars": 470,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/ranges.h",
    "chars": 467,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/std.h",
    "chars": 557,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/fmt/xchar.h",
    "chars": 464,
    "preview": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "include/spdlog/formatter.h",
    "chars": 463,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/fwd.h",
    "chars": 305,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/logger-inl.h",
    "chars": 6675,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/logger.h",
    "chars": 13590,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/mdc.h",
    "chars": 1493,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/pattern_formatter-inl.h",
    "chars": 47187,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/pattern_formatter.h",
    "chars": 3760,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/android_sink.h",
    "chars": 4717,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/ansicolor_sink-inl.h",
    "chars": 5095,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/ansicolor_sink.h",
    "chars": 4031,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/base_sink-inl.h",
    "chars": 1804,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/base_sink.h",
    "chars": 1600,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/basic_file_sink-inl.h",
    "chars": 1387,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/basic_file_sink.h",
    "chars": 2312,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/callback_sink.h",
    "chars": 1705,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/daily_file_sink.h",
    "chars": 9656,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/dist_sink.h",
    "chars": 2384,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/dup_filter_sink.h",
    "chars": 3498,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/hourly_file_sink.h",
    "chars": 7279,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/kafka_sink.h",
    "chars": 4445,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/mongo_sink.h",
    "chars": 4003,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/msvc_sink.h",
    "chars": 1988,
    "preview": "// Copyright(c) 2016 Alexander Dalshov & spdlog contributors.\n// Distributed under the MIT License (http://opensource.or"
  },
  {
    "path": "include/spdlog/sinks/null_sink.h",
    "chars": 1240,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/ostream_sink.h",
    "chars": 1222,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/qt_sinks.h",
    "chars": 12697,
    "preview": "// Copyright(c) 2015-present, Gabi Melman, mguludag and spdlog contributors.\n// Distributed under the MIT License (http:"
  },
  {
    "path": "include/spdlog/sinks/ringbuffer_sink.h",
    "chars": 2196,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/rotating_file_sink-inl.h",
    "chars": 6087,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/rotating_file_sink.h",
    "chars": 3348,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/sink-inl.h",
    "chars": 721,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/sink.h",
    "chars": 889,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/stdout_color_sinks-inl.h",
    "chars": 1431,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/stdout_color_sinks.h",
    "chars": 1780,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/stdout_sinks-inl.h",
    "chars": 4344,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/stdout_sinks.h",
    "chars": 2421,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/syslog_sink.h",
    "chars": 4248,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/systemd_sink.h",
    "chars": 4868,
    "preview": "// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com\n// Distributed under the MIT License (http://opensource.org/licenses/MI"
  },
  {
    "path": "include/spdlog/sinks/tcp_sink.h",
    "chars": 2700,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/udp_sink.h",
    "chars": 1857,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/win_eventlog_sink.h",
    "chars": 8888,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/wincolor_sink-inl.h",
    "chars": 7092,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/sinks/wincolor_sink.h",
    "chars": 2688,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/spdlog-inl.h",
    "chars": 3264,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/spdlog.h",
    "chars": 11872,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/stopwatch.h",
    "chars": 1865,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/tweakme.h",
    "chars": 6610,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "include/spdlog/version.h",
    "chars": 417,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "scripts/ci_setup_clang.sh",
    "chars": 226,
    "preview": "#!/bin/bash\n\nset -ex\n\nVERSION=$1\n\napt-get update\napt-get install -y libc++-${VERSION}-dev libc++abi-${VERSION}-dev\n\nif ["
  },
  {
    "path": "scripts/extract_version.py",
    "chars": 497,
    "preview": "#!/usr/bin/env python3\n\nimport os\nimport re\n\nbase_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))\n"
  },
  {
    "path": "scripts/format.sh",
    "chars": 630,
    "preview": "#!/bin/bash\n\ncd \"$(dirname \"$0\")\"/..\npwd\nfind_sources=\"find include src tests example bench -not ( -path include/spdlog/"
  },
  {
    "path": "src/async.cpp",
    "chars": 394,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "src/bundled_fmtlib_format.cpp",
    "chars": 1417,
    "preview": "// Slightly modified version of fmt lib's format.cc source file.\n// Copyright (c) 2012 - 2016, Victor Zverovich\n// All r"
  },
  {
    "path": "src/cfg.cpp",
    "chars": 275,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "src/color_sinks.cpp",
    "chars": 3137,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "src/file_sinks.cpp",
    "chars": 797,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "src/spdlog.cpp",
    "chars": 1134,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "src/stdout_sinks.cpp",
    "chars": 2014,
    "preview": "// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.\n// Distributed under the MIT License (http://opensource"
  },
  {
    "path": "tests/CMakeLists.txt",
    "chars": 2536,
    "preview": "cmake_minimum_required(VERSION 3.11)\nproject(spdlog_utests CXX)\n\nif(NOT TARGET spdlog)\n    # Stand-alone build\n    find_"
  },
  {
    "path": "tests/includes.h",
    "chars": 1096,
    "preview": "#pragma once\n\n#if defined(__GNUC__) && __GNUC__ == 12\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmayb"
  },
  {
    "path": "tests/main.cpp",
    "chars": 264,
    "preview": "#if defined(__GNUC__) && __GNUC__ == 12\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialize"
  },
  {
    "path": "tests/test_async.cpp",
    "chars": 7489,
    "preview": "#include \"includes.h\"\n#include \"spdlog/async.h\"\n#include \"spdlog/sinks/basic_file_sink.h\"\n#include \"test_sink.h\"\n\n#defin"
  },
  {
    "path": "tests/test_backtrace.cpp",
    "chars": 2915,
    "preview": "#include \"includes.h\"\n#include \"test_sink.h\"\n#include \"spdlog/async.h\"\n\nTEST_CASE(\"bactrace1\", \"[bactrace]\") {\n    using"
  },
  {
    "path": "tests/test_bin_to_hex.cpp",
    "chars": 3826,
    "preview": "#include \"includes.h\"\n#include \"test_sink.h\"\n#include \"spdlog/fmt/bin_to_hex.h\"\n\nTEST_CASE(\"to_hex\", \"[to_hex]\") {\n    s"
  },
  {
    "path": "tests/test_cfg.cpp",
    "chars": 6739,
    "preview": "\n#include \"includes.h\"\n#include \"test_sink.h\"\n\n#include <spdlog/cfg/env.h>\n#include <spdlog/cfg/argv.h>\n\nusing spdlog::c"
  },
  {
    "path": "tests/test_circular_q.cpp",
    "chars": 1035,
    "preview": "#include \"includes.h\"\n#include \"spdlog/details/circular_q.h\"\n\nusing q_type = spdlog::details::circular_q<size_t>;\nTEST_C"
  },
  {
    "path": "tests/test_create_dir.cpp",
    "chars": 6437,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_custom_callbacks.cpp",
    "chars": 1417,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_daily_logger.cpp",
    "chars": 6265,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_dup_filter.cpp",
    "chars": 3068,
    "preview": "#include \"includes.h\"\n#include \"spdlog/sinks/dup_filter_sink.h\"\n#include \"test_sink.h\"\n\nTEST_CASE(\"dup_filter_test1\", \"["
  },
  {
    "path": "tests/test_errors.cpp",
    "chars": 4368,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_eventlog.cpp",
    "chars": 2957,
    "preview": "#if _WIN32\n\n#include \"includes.h\"\n#include \"test_sink.h\"\n\n#include \"spdlog/sinks/win_eventlog_sink.h\"\n\nstatic const LPCS"
  },
  {
    "path": "tests/test_file_helper.cpp",
    "chars": 7263,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_file_logging.cpp",
    "chars": 6518,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_fmt_helper.cpp",
    "chars": 2152,
    "preview": "\n#include \"includes.h\"\n\nusing spdlog::memory_buf_t;\n\nSPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const me"
  },
  {
    "path": "tests/test_macros.cpp",
    "chars": 1839,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_misc.cpp",
    "chars": 9623,
    "preview": "#ifdef _WIN32  // to prevent fopen warning on windows\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include \"includes.h\"\n#inc"
  },
  {
    "path": "tests/test_mpmc_q.cpp",
    "chars": 3294,
    "preview": "#include \"includes.h\"\n\nusing std::chrono::milliseconds;\nusing test_clock = std::chrono::high_resolution_clock;\n\nstatic m"
  },
  {
    "path": "tests/test_pattern_formatter.cpp",
    "chars": 27277,
    "preview": "#include \"includes.h\"\n#include \"test_sink.h\"\n#include <regex>\n#include <chrono>\n\nusing spdlog::memory_buf_t;\n\nSPDLOG_CON"
  },
  {
    "path": "tests/test_registry.cpp",
    "chars": 4878,
    "preview": "#include \"includes.h\"\n\nstatic const char *const tested_logger_name = \"null_logger\";\nstatic const char *const tested_logg"
  },
  {
    "path": "tests/test_ringbuffer.cpp",
    "chars": 2232,
    "preview": "#include \"includes.h\"\n#include \"spdlog/sinks/ringbuffer_sink.h\"\n\nTEST_CASE(\"ringbuffer invalid size\", \"[ringbuffer]\") {\n"
  },
  {
    "path": "tests/test_sink.h",
    "chars": 1971,
    "preview": "//\n// Copyright(c) 2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#prag"
  },
  {
    "path": "tests/test_stdout_api.cpp",
    "chars": 2757,
    "preview": "/*\n * This content is released under the MIT License as specified in\n * https://raw.githubusercontent.com/gabime/spdlog/"
  },
  {
    "path": "tests/test_stopwatch.cpp",
    "chars": 1439,
    "preview": "#include \"includes.h\"\n#include \"test_sink.h\"\n#include \"spdlog/stopwatch.h\"\n\nTEST_CASE(\"stopwatch1\", \"[stopwatch]\") {\n   "
  },
  {
    "path": "tests/test_systemd.cpp",
    "chars": 588,
    "preview": "#include \"includes.h\"\n#include \"spdlog/sinks/systemd_sink.h\"\n\nTEST_CASE(\"systemd\", \"[all]\") {\n    auto systemd_sink = st"
  },
  {
    "path": "tests/test_time_point.cpp",
    "chars": 1449,
    "preview": "#include \"includes.h\"\n#include \"test_sink.h\"\n#include \"spdlog/async.h\"\n\nTEST_CASE(\"time_point1\", \"[time_point log_msg]\")"
  },
  {
    "path": "tests/test_timezone.cpp",
    "chars": 5760,
    "preview": "#ifndef SPDLOG_NO_TZ_OFFSET\n\n#include \"includes.h\"\n#include <ctime>\n#include <cstdlib>\n#include <cstring>\n\n// Helper to "
  },
  {
    "path": "tests/utils.cpp",
    "chars": 2863,
    "preview": "#include \"includes.h\"\n\n#ifdef _WIN32\n#include <windows.h>\n#else\n#include <sys/types.h>\n#include <dirent.h>\n#endif\n\nvoid "
  },
  {
    "path": "tests/utils.h",
    "chars": 451,
    "preview": "#pragma once\n\n#include <cstddef>\n#include <string>\n\nstd::size_t count_files(const std::string &folder);\n\nvoid prepare_lo"
  }
]

About this extraction

This page contains the full source code of the gabime/spdlog GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 175 files (1.1 MB), approximately 324.7k tokens, and a symbol index with 629 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!