spdlog/sink/
win_debug_sink.rs

1use std::{ffi::OsStr, iter::once};
2
3use crate::{
4    formatter::FormatterContext,
5    sink::{helper, Sink},
6    Record, Result, StringBuf,
7};
8
9/// A sink with a win32 API `OutputDebugStringW` as the target.
10pub struct WinDebugSink {
11    common_impl: helper::CommonImpl,
12}
13
14impl WinDebugSink {
15    /// Gets a builder of `WinDebugSink` with default parameters:
16    ///
17    /// | Parameter       | Default Value           |
18    /// |-----------------|-------------------------|
19    /// | [level_filter]  | `All`                   |
20    /// | [formatter]     | `FullFormatter`         |
21    /// | [error_handler] | [default error handler] |
22    ///
23    /// [level_filter]: WinDebugSinkBuilder::level_filter
24    /// [formatter]: WinDebugSinkBuilder::formatter
25    /// [error_handler]: WinDebugSinkBuilder::error_handler
26    /// [default error handler]: error/index.html#default-error-handler
27    #[must_use]
28    pub fn builder() -> WinDebugSinkBuilder {
29        WinDebugSinkBuilder {
30            common_builder_impl: helper::CommonBuilderImpl::new(),
31        }
32    }
33
34    /// Constructs a `WinDebugSink`.
35    #[allow(clippy::new_without_default)]
36    #[deprecated(
37        since = "0.3.0",
38        note = "it may be removed in the future, use `WinDebugSink::builder()` instead"
39    )]
40    #[must_use]
41    pub fn new() -> WinDebugSink {
42        WinDebugSink::builder().build().unwrap()
43    }
44}
45
46impl Sink for WinDebugSink {
47    fn log(&self, record: &Record) -> Result<()> {
48        #[cfg(windows)] // https://github.com/rust-lang/rust/issues/97976
49        use std::os::windows::ffi::OsStrExt;
50
51        let mut string_buf = StringBuf::new();
52        let mut ctx = FormatterContext::new();
53        self.common_impl
54            .formatter
55            .read()
56            .format(record, &mut string_buf, &mut ctx)?;
57
58        let wide: Vec<u16> = OsStr::new(&string_buf)
59            .encode_wide()
60            .chain(once(0))
61            .collect();
62        let wide = wide.as_ptr();
63
64        unsafe { winapi::um::debugapi::OutputDebugStringW(wide) }
65
66        Ok(())
67    }
68
69    fn flush(&self) -> Result<()> {
70        Ok(())
71    }
72
73    helper::common_impl!(@Sink: common_impl);
74}
75
76#[allow(missing_docs)]
77pub struct WinDebugSinkBuilder {
78    common_builder_impl: helper::CommonBuilderImpl,
79}
80
81impl WinDebugSinkBuilder {
82    helper::common_impl!(@SinkBuilder: common_builder_impl);
83
84    /// Builds a [`WinDebugSink`].
85    pub fn build(self) -> Result<WinDebugSink> {
86        let sink = WinDebugSink {
87            common_impl: helper::CommonImpl::from_builder(self.common_builder_impl),
88        };
89        Ok(sink)
90    }
91}