RepoPilotOpen in app →

gabime/spdlog

Fast C++ logging library.

Healthy

Healthy across the board

weakest axis
Use as dependencyConcerns

non-standard license (Other)

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3w ago
  • 39+ active contributors
  • Distributed ownership (top contributor 47% of recent commits)
Show all 7 evidence items →
  • Other licensed
  • CI configured
  • Tests present
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/gabime/spdlog)](https://repopilot.app/r/gabime/spdlog)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/gabime/spdlog on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: gabime/spdlog

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/gabime/spdlog shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3w ago
  • 39+ active contributors
  • Distributed ownership (top contributor 47% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Non-standard license (Other) — review terms

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live gabime/spdlog repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/gabime/spdlog.

What it runs against: a local clone of gabime/spdlog — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in gabime/spdlog | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch v1.x exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 50 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>gabime/spdlog</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of gabime/spdlog. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/gabime/spdlog.git
#   cd spdlog
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of gabime/spdlog and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "gabime/spdlog(\\.git)?\\b" \\
  && ok "origin remote is gabime/spdlog" \\
  || miss "origin remote is not gabime/spdlog (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify v1.x >/dev/null 2>&1 \\
  && ok "default branch v1.x exists" \\
  || miss "default branch v1.x no longer exists"

# 4. Critical files exist
test -f "include/spdlog/logger.h" \\
  && ok "include/spdlog/logger.h" \\
  || miss "missing critical file: include/spdlog/logger.h"
test -f "include/spdlog/details/registry.h" \\
  && ok "include/spdlog/details/registry.h" \\
  || miss "missing critical file: include/spdlog/details/registry.h"
test -f "include/spdlog/sinks/base_sink.h" \\
  && ok "include/spdlog/sinks/base_sink.h" \\
  || miss "missing critical file: include/spdlog/sinks/base_sink.h"
test -f "include/spdlog/details/thread_pool.h" \\
  && ok "include/spdlog/details/thread_pool.h" \\
  || miss "missing critical file: include/spdlog/details/thread_pool.h"
test -f "include/spdlog/pattern_formatter.h" \\
  && ok "include/spdlog/pattern_formatter.h" \\
  || miss "missing critical file: include/spdlog/pattern_formatter.h"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 50 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~20d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/gabime/spdlog"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

spdlog is a fast, header-only C++11 logging library that uses the {fmt} formatting library to provide high-performance structured logging with minimal overhead. It solves the problem of adding efficient, feature-rich logging to C++ applications without sacrificing performance, supporting both synchronous and asynchronous logging modes with multiple output targets (files, console, syslog, Windows event log). Header-only library with optional compiled mode: core logging logic lives in include/spdlog/ (main headers like spdlog.h, logger.h, async_logger.h), implementation details in include/spdlog/details/ (formatting, file I/O, queuing), sink implementations for various targets, and bench/ contains performance microbenchmarks. cmake/ handles build configuration with precompiled header support.

👥Who it's for

C++ systems programmers and application developers who need production-grade logging with microsecond-scale latency and compile-time or runtime configurability—particularly those building high-throughput services, game engines, or performance-critical applications where logging overhead is measurable.

🌱Maturity & risk

Highly mature and actively maintained: the repo has extensive CI coverage (Linux/macOS/Windows via GitHub Actions + AppVeyor), is available across 10+ package managers (apt, brew, vcpkg, conan, conda), and receives regular commits. Production-ready with strong API stability and widespread adoption in enterprise codebases.

Very low risk: single primary maintainer (gabime) but project is stable with no pending breaking changes visible in CI. Only core dependency is {fmt} library (vendored or external), and the codebase is well-tested across platforms. The main risk is reliance on C++11 compiler features, which may limit use in legacy environments.

Active areas of work

The project is in maintenance mode with focus on stability—recent work includes CMake modernization, CI pipeline enhancements (coverity scan), and cross-platform compatibility fixes. The repo actively patches bugs and integrates upstream {fmt} improvements but is not adding major new features.

🚀Get running

git clone https://github.com/gabime/spdlog.git
cd spdlog && mkdir build && cd build
cmake .. && cmake --build .
ctest  # Run tests

For header-only use, simply copy include/spdlog/ into your project and include spdlog/spdlog.h with a C++11 compiler.

Daily commands: This is a library, not an application. To test: cd build && ctest. To see examples: cd example && cmake .. && cmake --build . && ./example. For benchmarking: cd bench && cmake .. && cmake --build . && ./async_bench.

🗺️Map of the codebase

  • include/spdlog/logger.h — Core logger interface that all logging operations flow through; essential entry point for understanding the public API
  • include/spdlog/details/registry.h — Global registry managing logger lifecycle and creation; critical for understanding how loggers are instantiated and retrieved
  • include/spdlog/sinks/base_sink.h — Abstract base class for all sink implementations; defines the contract every log destination must fulfill
  • include/spdlog/details/thread_pool.h — Async logging implementation using thread pool; handles performance-critical message queuing for async loggers
  • include/spdlog/pattern_formatter.h — Log message formatting engine that applies pattern templates; core path for output customization
  • include/spdlog/details/log_msg.h — Core data structure encapsulating a single log message; foundational for message passing throughout the library
  • include/spdlog/async_logger.h — Async logger implementation separating log calls from formatting/writing; critical for non-blocking logging patterns

🛠️How to make changes

Add a New Sink Type

  1. Create a new sink class in include/spdlog/sinks/ inheriting from base_sink.h template (include/spdlog/sinks/base_sink.h)
  2. Implement sink_it_() method to write the log message to your destination (include/spdlog/sinks/base_sink.h)
  3. Implement flush() method for flushing any buffered output (include/spdlog/sinks/base_sink.h)
  4. Add factory function in include/spdlog/async.h or create a helper header for easy instantiation (include/spdlog/async.h)
  5. Reference example: include/spdlog/sinks/basic_file_sink.h for implementation pattern (include/spdlog/sinks/basic_file_sink.h)

Add Custom Log Formatting

  1. Inherit from formatter.h abstract class or pattern_formatter.h for pattern-based formatting (include/spdlog/formatter.h)
  2. Implement format(const log_msg& msg, memory_buf_t& dest) method (include/spdlog/details/log_msg.h)
  3. Register formatter with logger via set_formatter() call (include/spdlog/logger.h)
  4. Reference pattern_formatter.h for token parsing (e.g., %Y for year, %l for level) (include/spdlog/pattern_formatter.h)

Enable Async Logging for a Logger

  1. Replace synchronous logger creation with async_logger_mt or async_logger_st (include/spdlog/async.h)
  2. Ensure thread_pool is initialized via init_thread_pool(queue_size, thread_count) (include/spdlog/details/thread_pool.h)
  3. Log messages are queued to mpmc_blocking_q.h instead of blocking on I/O (include/spdlog/details/mpmc_blocking_q.h)
  4. Call spdlog::shutdown() at program end to flush async messages and join threads (include/spdlog/async_logger.h)

🔧Why these technologies

  • Header-only template library — Enables zero-overhead abstractions with compile-time specialization; users pay only for features they use
  • MPMC blocking queue (thread_pool.h) — Efficiently decouples async log calls from I/O; multiple producer threads safely enqueue messages without contention
  • fmt library integration (fmt/bundled) — Modern type-safe string formatting with compile-time format checking; avoids printf-style vulnerabilities
  • Sink abstraction pattern — Pluggable output destinations allow users to route logs to files, network, databases, etc. without core changes

⚖️Trade-offs already made

  • Header-only vs. compiled library

    • Why: Header-only provides flexibility and zero-dependency distribution; compiled version reduces compile times at cost of compilation step
    • Consequence: Users choose based on build-time vs. runtime preferences; CMakeLists.txt supports both modes
  • Async logger uses separate thread pool

    • Why: Decouples application thread from I/O; prevents logging from blocking critical paths
    • Consequence: Adds ~100ns enqueue overhead and requires explicit spdlog::shutdown() at exit to flush pending messages
  • Pattern-based formatting (pattern_formatter.h)

    • Why: Simple, human-readable format strings (e.g., %Y-%m-%d) match syslog conventions; easier than format strings
    • Consequence: Slightly more parsing overhead than hardcoded formats; supports common cases but less flexible than C++ iostreams
  • Global registry singleton (registry.h)

    • Why: Simplifies logger retrieval and lifecycle management; users don't manage logger pointers
    • Consequence: Not thread-safe by default for registry mutation; application must serialize logger creation or use registry_mt.h

🚫Non-goals (don't propose these)

  • Real-time guarantees: async logging has unbounded latency if queue fills (MPMC is not lock-free)
  • Built-in log aggregation or centralized logging: sinks write to local destinations only
  • Structured logging with key-value pairs: library focuses on formatted text output (though custom formatters can add structure)
  • Log filtering at library level: filtering is caller's responsibility via if(logger->should_log(level)) checks
  • Cross-platform networking sinks: tcp_client and udp_client are basic implementations without TLS/authentication

🪤Traps & gotchas

Async mode requires manual spdlog::shutdown() on program exit to flush pending messages—omitting this causes silent log loss. The {fmt} library version must match spdlog's expectations (check CMakeLists.txt for FMT_VERSION constraints). On Windows, console sink output requires UTF-8 code page setup. Header-only mode requires C++11; compiled mode can use older standards with reduced features.

🏗️Architecture

💡Concepts to learn

  • Lock-free ring buffer (MPMC queue) — spdlog's async mode uses a lock-free circular queue to avoid mutex contention when moving log messages from application threads to the background logger thread—understanding this is key to why async mode is fast
  • Thread pool with work queue — spdlog's async logger delegates actual I/O work to a configurable thread pool; understanding work queues explains latency vs. throughput tradeoffs
  • Variadic templates & fmt library integration — spdlog uses C++11 variadic templates to forward log arguments to {fmt} at compile-time, enabling zero-cost abstractions and type safety
  • Sink abstraction pattern — spdlog's architecture decouples logging logic from output targets via the sink interface; understanding this pattern helps extend spdlog with custom outputs
  • Memory-mapped file I/O — spdlog's file sinks use platform-specific optimizations (memory mapping on POSIX, buffered writes on Windows); knowledge of this helps optimize for your OS
  • Backtrace ring buffer (circular debug log) — spdlog's backtrace feature stores recent debug messages in a ring buffer that can be dumped on-demand; useful for post-mortem debugging without spamming logs
  • fmtlib/fmt — Core formatting dependency for spdlog; provides the {fmt} syntax that spdlog wraps for structured logging
  • google/glog — Closest alternative C++ logging library with different design philosophy (file-centric, less customizable but simpler API)
  • boost/log — Heavy-weight alternative part of Boost; more features but higher compilation overhead and steeper learning curve
  • Tencent/rapidjson — JSON logging use case: spdlog users building JSON-formatted logs often pair it with rapidjson for message serialization
  • nlohmann/json — Alternative JSON library frequently used with spdlog for structured/JSON logging without external dependencies

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for UDP/TCP client implementations

The repo contains UDP and TCP client implementations (include/spdlog/details/tcp_client.h, udp_client.h, and their Windows variants) but there are no visible test files for network sink functionality. This is critical for a logging library that supports remote logging. Tests should cover connection failures, message delivery, and platform-specific behavior (Windows vs POSIX).

  • [ ] Create tests/test_udp_client.cpp covering connection, send, and error scenarios
  • [ ] Create tests/test_tcp_client.cpp covering connection pooling and disconnection handling
  • [ ] Add platform-specific tests in tests/test_network_windows.cpp for Windows socket behavior
  • [ ] Integrate network tests into CMakeLists.txt test configuration
  • [ ] Add network sink integration tests to verify end-to-end logging flow

Add GitHub Actions workflow for sanitizer builds (ASan/MSan/UBSan)

While the repo has Linux, macOS, and Windows CI workflows (.github/workflows/), there's no dedicated sanitizer workflow to catch memory leaks, undefined behavior, and data races. This is especially important for a high-performance logging library used in production. The existing workflows can be extended or a new sanitizer workflow added.

  • [ ] Create .github/workflows/sanitizers.yml with ASan, MSan, and UBSan builds for Linux
  • [ ] Configure CMake flags (-DSANITIZE_ADDRESS=ON, -DSANITIZE_MEMORY=ON, etc.)
  • [ ] Run existing benchmarks and tests under sanitizers to catch issues
  • [ ] Document sanitizer results in workflow artifacts for debugging
  • [ ] Add suppression files (cmake/sanitizer_suppressions.txt) for known safe patterns if needed

Implement comprehensive integration tests for async logger with thread pool edge cases

The repo has async_logger.h and thread_pool implementations but testing around the async queue (mpmc_blocking_q.h), overflow handling, and shutdown sequences appears minimal. A dedicated test suite should verify thread-safety under high contention, queue overflow behavior, and graceful shutdown with pending messages.

  • [ ] Create tests/test_async_logger_edge_cases.cpp covering queue overflow scenarios
  • [ ] Add stress tests in tests/test_thread_pool_contention.cpp with high message rates and multiple threads
  • [ ] Test graceful shutdown with pending messages using include/spdlog/details/periodic_worker.h patterns
  • [ ] Verify backtracer functionality (include/spdlog/details/backtracer.h) under async conditions
  • [ ] Add tests for the mpmc_blocking_q.h circular queue boundary conditions

🌿Good first issues

  • Add example demonstrating custom sink implementation: create example/custom_sink_example.cpp showing how to extend base_sink<> for a user-defined output target (e.g., network socket, database, memory buffer)
  • Improve async logger documentation: the interaction between async.h convenience functions and manual thread_pool configuration is underdocumented—add inline code examples to include/spdlog/async.h
  • Add performance regression test: create bench/regression_test.cpp that compares latency between versions to catch performance regressions in CI before release

Top contributors

Click to expand

📝Recent commits

Click to expand
  • a297670 — Tcp client auto reconnect (#3595) (nbakovljev)
  • bfde7d3 — Fix socket closure in tcp_client to prevent errors on invalid socket (#3594) (nbakovljev)
  • 52e2454 — docs: fix misleading unit wording in comment (#3596) (Daschi1)
  • cc6fcee — [ci] Fix macOS build: use C++20 for std::format matrix entry (#3589) (gabime)
  • 75e93f4 — Set C++ standard to 20 if not defined (#3583) (loic-lopez)
  • fb12274 — [bench] Update Google benchmark to version 1.8.4 (#3579) (gruenich)
  • 3c61b05 — [ci] Update actions/checkout to latest major relese (#3575) (gruenich)
  • 45b67ee — Add constructor for dup_filter_sink with sinks parameter (#3549) (Niram7777)
  • 1fbc60a — docs: fix SPDLOG_LEVEL env example (#3561) (omerrbbulut)
  • 0f7562a — tests: timezone: Provide DST rules when setting TZ on POSIX systems (#3542) (ziyao233)

🔒Security observations

The spdlog codebase demonstrates generally good security posture as a C++ logging library. Primary concerns are: (1) bundled fmt library requiring manual security updates, (2) custom implementations of circular queue and thread pool requiring thorough security review, and (3) network components requiring validation of TLS/encryption support. No hardcoded secrets, injection vulnerabilities, or critical misconfigurations are evident from the file structure. The header-only nature and focus on logging reduce attack surface. Recommend formal security code review of custom data structures and network components, and transition to external dependency management where feasible.

  • Medium · Bundled Third-Party Formatting Library — include/spdlog/fmt/bundled/. The codebase includes a bundled version of the fmt library (include/spdlog/fmt/bundled/). Bundled dependencies can lead to outdated security patches and maintenance issues. If vulnerabilities are discovered in fmt, updates must be manually applied to this repository rather than relying on package managers. Fix: Consider using fmt as an external dependency managed by CMake/vcpkg rather than bundling it. This allows for easier updates and security patching. If bundling is necessary, maintain a clear version tracking system and establish a process for regular security updates.
  • Low · Potential Buffer Overflow in Circular Queue — include/spdlog/details/circular_q.h. The circular queue implementation (include/spdlog/details/circular_q.h) is a custom data structure commonly prone to off-by-one errors and buffer overflows. Without access to the actual code, custom queue implementations warrant careful review for boundary condition handling. Fix: Conduct thorough code review and fuzzing tests on the circular_q.h implementation. Verify boundary conditions, capacity checks, and index calculations are correct. Consider using standard library containers where possible.
  • Low · Network Components Without Visible Security Validation — include/spdlog/details/tcp_client.h, include/spdlog/details/udp_client.h, include/spdlog/details/tcp_client-windows.h, include/spdlog/details/udp_client-windows.h. The codebase includes TCP and UDP client implementations (tcp_client.h, udp_client.h, and Windows-specific variants). Network-based logging can introduce security risks including MITM attacks and information disclosure if not properly secured. Fix: Verify that network components support TLS/SSL encryption for TCP connections. Ensure UDP connections are only used for trusted networks. Add input validation and length checks for all network data. Document security considerations for network-based logging.
  • Low · Thread Pool Implementation Requires Security Review — include/spdlog/details/thread_pool.h. Custom thread pool implementation (include/spdlog/details/thread_pool.h) manages concurrent access and queue operations. Improper implementation could lead to race conditions, deadlocks, or privilege escalation in multi-threaded environments. Fix: Review thread synchronization primitives for correctness. Ensure proper use of mutexes and condition variables. Conduct thread safety analysis and consider using established thread pool libraries where appropriate. Add logging/monitoring for thread pool health.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · gabime/spdlog — RepoPilot