logging_subscriber/
lib.rs

1use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
2
3use console::{Style, StyledObject};
4use lazy_static::lazy_static;
5use tracing_subscriber::filter::LevelFilter;
6
7mod logging_subscriber;
8mod logging_writer;
9mod prelude;
10mod test;
11
12lazy_static! {
13	pub static ref LOGGING_WRITER: Arc<Mutex<LoggingWriter>> = Arc::new(Mutex::new(LoggingWriter::default()));
14}
15
16#[derive(Debug, Clone, Default)]
17pub(crate) struct BlockingWriter {}
18
19#[derive(Debug)]
20#[allow(dead_code)]
21pub struct LoggingWriter {
22	pub(crate) enabled: bool,
23	pub(crate) level: tracing::metadata::LevelFilter,
24
25	default_style: Style,
26
27	date_time_style: Style,
28
29	style_error: Option<Style>,
30	style_warn: Option<Style>,
31	style_debug: Option<Style>,
32	style_trace: Option<Style>,
33	style_info: Option<Style>,
34
35	level_style_error: Style,
36	level_style_warn: Style,
37	level_style_debug: Style,
38	level_style_trace: Style,
39	level_style_info: Style,
40
41	separator: String,
42	timestamp_format: String,
43	format_level: LevelOutput,
44
45	display_line_number: bool,
46	display_level: bool,
47	display_target: bool,
48	display_filename: bool,
49	display_time: bool,
50}
51
52#[derive(Debug, Clone, Copy)]
53#[allow(dead_code)]
54pub enum LevelOutput {
55	Abbreviated,
56	Long,
57	None,
58}
59
60#[derive(Debug, Clone)]
61pub struct LoggingSubscriberLayer;
62
63#[derive(Debug, Clone)]
64pub struct LoggingSubscriberBuilder {
65	pub display_line_number: bool,
66	pub display_level: bool,
67	pub display_time: bool,
68	pub display_target: bool,
69	pub display_filename: bool,
70
71	default_style: Style,
72	date_time_style: Style,
73
74	level_style_error: Style,
75	level_style_warn: Style,
76	level_style_debug: Style,
77	level_style_trace: Style,
78	level_style_info: Style,
79
80	style_error: Option<Style>,
81	style_warn: Option<Style>,
82	style_info: Option<Style>,
83	style_debug: Option<Style>,
84	style_trace: Option<Style>,
85
86	min_level: tracing::metadata::LevelFilter,
87	separator: String,
88	timestamp_format: String,
89	format_level: LevelOutput,
90}
91
92#[derive(Debug, Default, Clone)]
93pub struct AdaptiveStyle {
94	pub(crate) light: console::Style,
95	pub(crate) dark: console::Style,
96}
97
98impl AdaptiveStyle {
99	pub fn new(light: console::Style, dark: console::Style) -> Self {
100		AdaptiveStyle { light, dark }
101	}
102
103	pub fn from(style: console::Style) -> Self {
104		AdaptiveStyle {
105			light: style.clone(),
106			dark: style.clone(),
107		}
108	}
109
110	fn is_dark_background() -> bool {
111		terminal_light::luma().map_or(false, |luma| luma <= 0.5)
112	}
113
114	#[must_use]
115	pub fn paint<D>(&self, val: D) -> StyledObject<D> {
116		if AdaptiveStyle::is_dark_background() {
117			self.dark.apply_to(val)
118		} else {
119			self.dark.apply_to(val)
120		}
121	}
122}
123
124impl From<Style> for AdaptiveStyle {
125	fn from(value: console::Style) -> Self {
126		AdaptiveStyle::from(value)
127	}
128}
129
130impl From<AdaptiveStyle> for console::Style {
131	fn from(value: AdaptiveStyle) -> Self {
132		let dark_theme = terminal_light::luma().map_or(false, |luma| luma <= 0.5);
133		if dark_theme {
134			value.dark
135		} else {
136			value.light
137		}
138	}
139}
140
141#[allow(dead_code)]
142pub fn set_enabled(value: bool) -> Result<(), PoisonError<MutexGuard<'static, LoggingWriter>>> {
143	match LOGGING_WRITER.lock() {
144		Ok(mut item) => {
145			item.enabled = value;
146			Ok(())
147		}
148		Err(err) => Err(err),
149	}
150}
151
152/// Returns true if logging is enabled
153pub fn is_enabled() -> Result<bool, PoisonError<MutexGuard<'static, LoggingWriter>>> {
154	match LOGGING_WRITER.lock() {
155		Ok(item) => Ok(item.enabled),
156		Err(err) => Err(err),
157	}
158}
159
160#[allow(dead_code)]
161pub fn set_level(value: LevelFilter) -> Result<(), PoisonError<MutexGuard<'static, LoggingWriter>>> {
162	match LOGGING_WRITER.lock() {
163		Ok(mut item) => {
164			item.level = value;
165			Ok(())
166		}
167		Err(err) => Err(err),
168	}
169}