How to Configure spdlog for Windows-Specific Logging: Event Log and Debugger Output

Use win_eventlog_sink_mt for Windows Event Log integration and msvc_sink_mt for debugger output—both are header-only sinks included in the spdlog library.

The spdlog logging library provides native Windows support through two specialized sinks that integrate directly with Windows diagnostics facilities. Whether you need enterprise-grade event tracking or real-time debugging output during development, these sinks let you redirect logs without platform-specific boilerplate. This guide covers implementation details, configuration options, and working code examples based on the spdlog v1.x source.


Windows Event Log Sink (win_eventlog_sink)

The Event Log sink (include/spdlog/sinks/win_eventlog_sink.h) writes formatted log messages to the Windows Event Log using native WinAPI calls. According to the spdlog source code, this sink registers an event source with RegisterEventSource and dispatches each log record via ReportEvent.

Level Mapping to Windows Event Types

Inside win_eventlog_sink::log, spdlog converts its internal log levels to Windows event types:

spdlog Level Windows Event Type
trace, debug, info EVENTLOG_INFORMATION_TYPE
warn EVENTLOG_WARNING_TYPE
err, critical EVENTLOG_ERROR_TYPE

This mapping ensures that Windows Event Viewer displays logs with appropriate severity icons and filtering.

Basic Event Log Configuration

#include <spdlog/spdlog.h>
#include <spdlog/sinks/win_eventlog_sink.h>

int main()
{
    // "MyApp" appears as the Source name in Event Viewer
    auto eventlog_sink = std::make_shared<spdlog::sinks::win_eventlog_sink_mt>("MyApp");
    
    auto logger = std::make_shared<spdlog::logger>("event_logger", eventlog_sink);
    spdlog::set_default_logger(logger);
    spdlog::set_level(spdlog::level::debug);

    spdlog::info("Service started, build {}", "2.1.0");
    spdlog::error("Database connection failed: code {}", 10061);

    logger->flush();  // Ensure events are written before exit
    return 0;
}

Verification: Open Event Viewer → Windows Logs → Application and filter by source "MyApp" to see your entries.


Debugger Output Sink (msvc_sink / windebug_sink)

The MSVC sink (include/spdlog/sinks/msvc_sink.h) sends log output to the attached debugger using OutputDebugStringA/W. This is invaluable during Visual Studio debugging sessions or when using tools like DebugView from Sysinternals.

Key Constructor Parameter

The msvc_sink constructor accepts check_debugger_present (default: true):

  • true: Silently skips logging when IsDebuggerPresent() returns false
  • false: Always calls OutputDebugString, which has no effect when no debugger is attached

Debugger Sink Implementation

#include <spdlog/spdlog.h>
#include <spdlog/sinks/msvc_sink.h>

int main()
{
    // Skip output if no debugger is attached
    auto debug_sink = std::make_shared<spdlog::sinks::msvc_sink_mt>(/*check_debugger_present=*/true);
    
    // Compact format: colored level + message only
    debug_sink->set_formatter(
        std::make_unique<spdlog::pattern_formatter>("[%^%l%$] %v"));

    auto logger = std::make_shared<spdlog::logger>("debug_logger", debug_sink);
    spdlog::set_default_logger(logger);

    SPDLOG_DEBUG("Processing item {}", 42);  // Visible in VS Output window
    SPDLOG_ERROR("Critical failure at line {}", __LINE__);

    return 0;
}

Output location: Visual Studio Output window (Show output from: Debug), or DebugView when running without VS.


Combining Multiple Sinks for Production Logging

Real-world applications typically need logs in multiple destinations simultaneously. The spdlog::logger constructor accepts a vector of sinks, enabling console, file, Event Log, and debugger output in a single configuration:

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/win_eventlog_sink.h>
#include <spdlog/sinks/msvc_sink.h>

int main()
{
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    auto eventlog_sink = std::make_shared<spdlog::sinks::win_eventlog_sink_mt>("MyService");
    auto debug_sink = std::make_shared<spdlog::sinks::msvc_sink_mt>(true);

    // All three sinks receive every log message
    spdlog::logger logger("multi_sink", {console_sink, eventlog_sink, debug_sink});
    spdlog::set_default_logger(std::make_shared<spdlog::logger>(logger));
    
    spdlog::set_level(spdlog::level::info);
    spdlog::info("User {} logged in from {}", "admin", "192.168.1.100");

    return 0;
}

This pattern leverages base_sink inheritance—all sinks in the collection receive the same formatted message through their shared interface.


Thread-Safety and Performance Considerations

Both Windows sinks follow spdlog's standard naming convention:

  • *_mt: Multi-threaded variant with internal mutex protection (recommended for most use cases)
  • *_st: Single-threaded variant—faster but requires external synchronization

The mutex in *_mt protects the underlying WinAPI calls (ReportEvent, OutputDebugString), which are not inherently thread-safe.


Custom Formatting for Windows Sinks

Both sinks respect spdlog's formatter pattern system. Configure before attaching to logger:

auto formatter = std::make_unique<spdlog::pattern_formatter>(
    "%Y-%m-%d %H:%M:%S.%e | %-8l | %s:%!:%# | %v");

eventlog_sink->set_formatter(std::move(formatter));

The Event Log sink includes this formatted string as the message body; the debugger sink outputs it directly.


Summary

  • spdlog::sinks::win_eventlog_sink_mt implements Windows Event Log integration using RegisterEventSource and ReportEvent (source: include/spdlog/sinks/win_eventlog_sink.h)
  • spdlog::sinks::msvc_sink_mt routes output to debuggers via OutputDebugString with optional IsDebuggerPresent checking (source: include/spdlog/sinks/msvc_sink.h)
  • Both support spdlog's full formatter customization and thread-safety model through base_sink inheritance
  • Multiple sinks can be combined in a single logger for comprehensive Windows logging coverage

Frequently Asked Questions

What header files are required for Windows-specific spdlog sinks?

Include <spdlog/sinks/win_eventlog_sink.h> for Event Log output and <spdlog/sinks/msvc_sink.h> for debugger output. Both headers are distributed with the main spdlog library and require no additional dependencies beyond standard Windows headers.

Does the Event Log sink require administrator privileges?

Creating a new event source for the first time requires elevation, but writing to an existing source does not. Run your application once as Administrator to register the source name, or use the eventcreate utility to pre-register it during installation.

Why don't I see debugger output when running outside Visual Studio?

The msvc_sink defaults to check_debugger_present=true, which suppresses output when no debugger is attached. Pass false to the constructor to force OutputDebugString calls, or use Sysinternals DebugView to capture the output without a full debugger.

Can I use these sinks on non-Windows platforms?

No. Both win_eventlog_sink and msvc_sink contain Windows-specific implementations guarded by #ifdef _WIN32. For cross-platform code, conditionally compile these sinks or use spdlog's compile-time macros to exclude them on other platforms.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →