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    sync::*,
7    ErrorHandler, LevelFilter, Record, Result, StringBuf,
8};
9
10/// A sink with a win32 API `OutputDebugStringW` as the target.
11pub struct WinDebugSink {
12    prop: SinkProp,
13}
14
15impl WinDebugSink {
16    /// Gets a builder of `WinDebugSink` with default parameters:
17    ///
18    /// | Parameter       | Default Value               |
19    /// |-----------------|-----------------------------|
20    /// | [level_filter]  | [`LevelFilter::All`]        |
21    /// | [formatter]     | [`FullFormatter`]           |
22    /// | [error_handler] | [`ErrorHandler::default()`] |
23    ///
24    /// [level_filter]: WinDebugSinkBuilder::level_filter
25    /// [formatter]: WinDebugSinkBuilder::formatter
26    /// [`FullFormatter`]: crate::formatter::FullFormatter
27    /// [error_handler]: WinDebugSinkBuilder::error_handler
28    #[must_use]
29    pub fn builder() -> WinDebugSinkBuilder {
30        WinDebugSinkBuilder {
31            prop: SinkProp::default(),
32        }
33    }
34
35    /// Constructs a `WinDebugSink`.
36    #[allow(clippy::new_without_default)]
37    #[deprecated(
38        since = "0.3.0",
39        note = "it may be removed in the future, use `WinDebugSink::builder()` instead"
40    )]
41    #[must_use]
42    pub fn new() -> WinDebugSink {
43        WinDebugSink::builder().build().unwrap()
44    }
45}
46
47impl GetSinkProp for WinDebugSink {
48    fn prop(&self) -> &SinkProp {
49        &self.prop
50    }
51}
52
53impl Sink for WinDebugSink {
54    fn log(&self, record: &Record) -> Result<()> {
55        #[cfg(windows)] // https://github.com/rust-lang/rust/issues/97976
56        use std::os::windows::ffi::OsStrExt;
57
58        let mut string_buf = StringBuf::new();
59        let mut ctx = FormatterContext::new();
60        self.prop
61            .formatter()
62            .format(record, &mut string_buf, &mut ctx)?;
63
64        let wide: Vec<u16> = OsStr::new(&string_buf)
65            .encode_wide()
66            .chain(once(0))
67            .collect();
68        let wide = wide.as_ptr();
69
70        unsafe { winapi::um::debugapi::OutputDebugStringW(wide) }
71
72        Ok(())
73    }
74
75    fn flush(&self) -> Result<()> {
76        Ok(())
77    }
78}
79
80#[allow(missing_docs)]
81pub struct WinDebugSinkBuilder {
82    prop: SinkProp,
83}
84
85impl WinDebugSinkBuilder {
86    // Prop
87    //
88
89    /// Specifies a log level filter.
90    ///
91    /// This parameter is **optional**, and defaults to [`LevelFilter::All`].
92    #[must_use]
93    pub fn level_filter(self, level_filter: LevelFilter) -> Self {
94        self.prop.set_level_filter(level_filter);
95        self
96    }
97
98    /// Specifies a formatter.
99    ///
100    /// This parameter is **optional**, and defaults to [`FullFormatter`].
101    ///
102    /// [`FullFormatter`]: crate::formatter::FullFormatter
103    #[must_use]
104    pub fn formatter<F>(self, formatter: F) -> Self
105    where
106        F: Formatter + 'static,
107    {
108        self.prop.set_formatter(formatter);
109        self
110    }
111
112    /// Specifies an error handler.
113    ///
114    /// This parameter is **optional**, and defaults to
115    /// [`ErrorHandler::default()`].
116    #[must_use]
117    pub fn error_handler<F: Into<ErrorHandler>>(self, handler: F) -> Self {
118        self.prop.set_error_handler(handler);
119        self
120    }
121
122    //
123
124    /// Builds a [`WinDebugSink`].
125    pub fn build(self) -> Result<WinDebugSink> {
126        let sink = WinDebugSink { prop: self.prop };
127        Ok(sink)
128    }
129
130    /// Builds a `Arc<WinDebugSink>`.
131    ///
132    /// This is a shorthand method for `.build().map(Arc::new)`.
133    pub fn build_arc(self) -> Result<Arc<WinDebugSink>> {
134        self.build().map(Arc::new)
135    }
136}