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

> Learn to configure spdlog for Windows logging with Event Log and debugger output using win_eventlog_sink_mt and msvc_sink_mt. Integrate spdlog seamlessly into your Windows applications.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-08-06

---

**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`](https://github.com/gabime/spdlog/blob/main/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

```cpp
#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`](https://github.com/gabime/spdlog/blob/main/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

```cpp
#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:

```cpp
#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:

```cpp
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`](https://github.com/gabime/spdlog/blob/main/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`](https://github.com/gabime/spdlog/blob/main/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.