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 whenIsDebuggerPresent()returns falsefalse: Always callsOutputDebugString, 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_mtimplements Windows Event Log integration usingRegisterEventSourceandReportEvent(source:include/spdlog/sinks/win_eventlog_sink.h)spdlog::sinks::msvc_sink_mtroutes output to debuggers viaOutputDebugStringwith optionalIsDebuggerPresentchecking (source:include/spdlog/sinks/msvc_sink.h)- Both support spdlog's full formatter customization and thread-safety model through
base_sinkinheritance - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →