spdlog/sink/
win_debug_sink.rs

1use std::{ffi::OsStr, iter::once};
2
3use crate::{
4    formatter::{Formatter, FormatterContext},
5    sink::{GetSinkProp, Sink, SinkProp},
6    ErrorHandler, LevelFilter, Record, Result, StringBuf,
7};
8
9/// A sink with a win32 API `OutputDebugStringW` as the target.
10pub struct WinDebugSink {
11    prop: SinkProp,
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] | [`ErrorHandler::default()`] |
22    ///
23    /// [level_filter]: WinDebugSinkBuilder::level_filter
24    /// [formatter]: WinDebugSinkBuilder::formatter
25    /// [error_handler]: WinDebugSinkBuilder::error_handler
26    /// [`ErrorHandler::default()`]: crate::error::ErrorHandler::default()
27    #[must_use]
28    pub fn builder() -> WinDebugSinkBuilder {
29        WinDebugSinkBuilder {
30            prop: SinkProp::default(),
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 GetSinkProp for WinDebugSink {
47    fn prop(&self) -> &SinkProp {
48        &self.prop
49    }
50}
51
52impl Sink for WinDebugSink {
53    fn log(&self, record: &Record) -> Result<()> {
54        #[cfg(windows)] // https://github.com/rust-lang/rust/issues/97976
55        use std::os::windows::ffi::OsStrExt;
56
57        let mut string_buf = StringBuf::new();
58        let mut ctx = FormatterContext::new();
59        self.prop
60            .formatter()
61            .format(record, &mut string_buf, &mut ctx)?;
62
63        let wide: Vec<u16> = OsStr::new(&string_buf)
64            .encode_wide()
65            .chain(once(0))
66            .collect();
67        let wide = wide.as_ptr();
68
69        unsafe { winapi::um::debugapi::OutputDebugStringW(wide) }
70
71        Ok(())
72    }
73
74    fn flush(&self) -> Result<()> {
75        Ok(())
76    }
77}
78
79#[allow(missing_docs)]
80pub struct WinDebugSinkBuilder {
81    prop: SinkProp,
82}
83
84impl WinDebugSinkBuilder {
85    // Prop
86    //
87
88    /// Specifies a log level filter.
89    ///
90    /// This parameter is **optional**.
91    #[must_use]
92    pub fn level_filter(self, level_filter: LevelFilter) -> Self {
93        self.prop.set_level_filter(level_filter);
94        self
95    }
96
97    /// Specifies a formatter.
98    ///
99    /// This parameter is **optional**.
100    #[must_use]
101    pub fn formatter<F>(self, formatter: F) -> Self
102    where
103        F: Formatter + 'static,
104    {
105        self.prop.set_formatter(formatter);
106        self
107    }
108
109    /// Specifies an error handler.
110    ///
111    /// This parameter is **optional**.
112    #[must_use]
113    pub fn error_handler<F: Into<ErrorHandler>>(self, handler: F) -> Self {
114        self.prop.set_error_handler(handler);
115        self
116    }
117
118    //
119
120    /// Builds a [`WinDebugSink`].
121    pub fn build(self) -> Result<WinDebugSink> {
122        let sink = WinDebugSink { prop: self.prop };
123        Ok(sink)
124    }
125}