1use std::borrow::Cow;
2use std::fmt::Display;
3
4use owo_colors::Style as OwoStyle;
5use tracing::Level;
6use tracing::Metadata;
7
8use crate::ShouldColor;
9
10#[cfg(doc)]
11use crate::HumanLayer;
12
13pub trait ProvideStyle {
15 fn for_metadata(&self, metadata: &'static Metadata<'static>) -> Cow<'_, Style>;
20}
21
22#[derive(Debug)]
24pub struct LayerStyles {
25 pub trace: Style,
27 pub debug: Style,
29 pub info: Style,
31 pub warn: Style,
33 pub error: Style,
35}
36
37impl LayerStyles {
38 pub fn new() -> Self {
40 let base = Style {
41 initial_indent_text: "".into(),
42 subsequent_indent_text: " ".into(),
43 initial_indent: OwoStyle::new(),
44 message: OwoStyle::new(),
45 field_name: OwoStyle::new().bold(),
46 field_value: OwoStyle::new(),
47 span_name: OwoStyle::new(),
48 span_in: OwoStyle::new().dimmed(),
49 };
50
51 Self {
52 trace: Style {
53 initial_indent_text: "TRACE ".into(),
54 initial_indent: base.initial_indent.purple(),
55 message: base.message.dimmed(),
56 field_name: base.field_name.dimmed(),
57 field_value: base.field_value.dimmed(),
58 span_name: base.span_name.dimmed(),
59 ..base.clone()
60 },
61
62 debug: Style {
63 initial_indent_text: "DEBUG ".into(),
64 initial_indent: base.initial_indent.blue(),
65 message: base.message.dimmed(),
66 field_name: base.field_name.dimmed(),
67 field_value: base.field_value.dimmed(),
68 span_name: base.span_name.dimmed(),
69 ..base.clone()
70 },
71
72 info: Style {
73 initial_indent_text: "• ".into(),
74 initial_indent: base.initial_indent.green(),
75 ..base.clone()
76 },
77
78 warn: Style {
79 initial_indent_text: "⚠ ".into(),
80 initial_indent: base.initial_indent.yellow(),
81 message: base.message.yellow(),
82 ..base.clone()
83 },
84
85 error: Style {
86 initial_indent_text: "⚠ ".into(),
87 initial_indent: base.initial_indent.red(),
88 message: base.message.red(),
89 ..base
90 },
91 }
92 }
93
94 pub(crate) fn for_level(&self, level: Level) -> Cow<'_, Style> {
96 Cow::Borrowed(match level {
97 Level::TRACE => &self.trace,
98 Level::DEBUG => &self.debug,
99 Level::INFO => &self.info,
100 Level::WARN => &self.warn,
101 Level::ERROR => &self.error,
102 })
103 }
104}
105
106impl Default for LayerStyles {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112impl ProvideStyle for LayerStyles {
113 fn for_metadata(&self, metadata: &'static Metadata<'static>) -> Cow<'_, Style> {
114 self.for_level(*metadata.level())
115 }
116}
117
118#[derive(Debug, Clone)]
124pub struct Style {
125 pub(crate) initial_indent_text: Cow<'static, str>,
126 pub(crate) subsequent_indent_text: Cow<'static, str>,
127 pub(crate) initial_indent: OwoStyle,
128 pub(crate) message: OwoStyle,
129 pub(crate) field_name: OwoStyle,
130 pub(crate) field_value: OwoStyle,
131 pub(crate) span_name: OwoStyle,
132 pub(crate) span_in: OwoStyle,
133}
134
135impl Style {
136 pub(crate) fn style_field<'a>(
137 &'a self,
138 color: ShouldColor,
139 name: &'a str,
140 value: &'a str,
141 ) -> StyledField<'a> {
142 StyledField {
143 color,
144 name,
145 name_style: self.field_name,
146 value,
147 value_style: self.field_value,
148 }
149 }
150
151 pub fn with_initial_indent_text(mut self, initial_indent_text: Cow<'static, str>) -> Self {
153 self.initial_indent_text = initial_indent_text;
154 self
155 }
156
157 pub fn with_subsequent_indent_text(
159 mut self,
160 subsequent_indent_text: Cow<'static, str>,
161 ) -> Self {
162 self.subsequent_indent_text = subsequent_indent_text;
163 self
164 }
165
166 pub fn with_initial_indent(mut self, initial_indent: OwoStyle) -> Self {
168 self.initial_indent = initial_indent;
169 self
170 }
171
172 pub fn with_message(mut self, message: OwoStyle) -> Self {
174 self.message = message;
175 self
176 }
177
178 pub fn with_field_name(mut self, field_name: OwoStyle) -> Self {
180 self.field_name = field_name;
181 self
182 }
183
184 pub fn with_field_value(mut self, field_value: OwoStyle) -> Self {
186 self.field_value = field_value;
187 self
188 }
189
190 pub fn with_span_name(mut self, span_name: OwoStyle) -> Self {
192 self.span_name = span_name;
193 self
194 }
195
196 pub fn with_span_in(mut self, span_in: OwoStyle) -> Self {
200 self.span_in = span_in;
201 self
202 }
203}
204
205pub(crate) trait IntoConditionalColor: Display {
206 fn colored(&self, color: ShouldColor, style: OwoStyle) -> ConditionalColor<&Self> {
207 ConditionalColor {
208 inner: self,
209 style,
210 color,
211 }
212 }
213}
214
215impl<T> IntoConditionalColor for T where T: Display {}
216
217pub(crate) struct ConditionalColor<T> {
219 color: ShouldColor,
220 style: OwoStyle,
221 inner: T,
222}
223
224impl<T> Display for ConditionalColor<T>
225where
226 T: Display,
227{
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 match self.color {
230 ShouldColor::Always => self.style.style(&self.inner).fmt(f),
231 ShouldColor::Never => self.inner.fmt(f),
232 }
233 }
234}
235
236pub(crate) struct StyledField<'a> {
237 color: ShouldColor,
238 name: &'a str,
239 name_style: OwoStyle,
240 value: &'a str,
241 value_style: OwoStyle,
242}
243
244impl Display for StyledField<'_> {
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246 write!(f, "{}", self.name.colored(self.color, self.name_style))?;
247 write!(f, "{}", '='.colored(self.color, self.value_style))?;
248 write!(f, "{}", self.value.colored(self.color, self.value_style))?;
249 Ok(())
250 }
251}