webview_bundle_cli/
logging.rs1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3use tracing::subscriber::Interest;
4use tracing::Metadata;
5use tracing_subscriber::filter::LevelFilter;
6use tracing_subscriber::layer::{Context, Filter, SubscriberExt};
7use tracing_subscriber::util::SubscriberInitExt;
8use tracing_subscriber::{registry, Layer};
9
10pub fn setup_logging(level: LoggingLevel, kind: LoggingKind) {
11 if level == LoggingLevel::None {
12 return;
13 }
14 let format = tracing_subscriber::fmt::layer()
15 .with_level(true)
16 .with_target(false)
17 .with_thread_names(true)
18 .with_file(true)
19 .with_ansi(true);
20 match kind {
21 LoggingKind::Pretty => {
22 let format = format.pretty();
23 registry()
24 .with(format.with_filter(LoggingFilter { level }))
25 .init()
26 }
27 LoggingKind::Compact => {
28 let format = format.compact();
29 registry()
30 .with(format.with_filter(LoggingFilter { level }))
31 .init()
32 }
33 LoggingKind::Json => {
34 let format = format.json().flatten_event(true);
35
36 registry()
37 .with(format.with_filter(LoggingFilter { level }))
38 .init()
39 }
40 };
41}
42
43#[derive(Copy, Debug, Default, Clone, Ord, PartialOrd, Eq, PartialEq)]
44pub enum LoggingLevel {
45 #[default]
47 None,
48 Debug,
49 Info,
50 Warn,
51 Error,
52}
53
54impl LoggingLevel {
55 fn to_filter_level(self) -> Option<LevelFilter> {
56 match self {
57 LoggingLevel::None => None,
58 LoggingLevel::Info => Some(LevelFilter::INFO),
59 LoggingLevel::Warn => Some(LevelFilter::WARN),
60 LoggingLevel::Error => Some(LevelFilter::ERROR),
61 LoggingLevel::Debug => Some(LevelFilter::DEBUG),
62 }
63 }
64}
65
66impl FromStr for LoggingLevel {
67 type Err = String;
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 match s {
70 "none" => Ok(Self::None),
71 "info" => Ok(Self::Info),
72 "warn" => Ok(Self::Warn),
73 "error" => Ok(Self::Error),
74 "debug" => Ok(Self::Debug),
75 _ => Err("Unexpected value".to_string()),
76 }
77 }
78}
79
80impl Display for LoggingLevel {
81 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82 match self {
83 LoggingLevel::None => write!(f, "none"),
84 LoggingLevel::Debug => write!(f, "debug"),
85 LoggingLevel::Info => write!(f, "info"),
86 LoggingLevel::Warn => write!(f, "warn"),
87 LoggingLevel::Error => write!(f, "error"),
88 }
89 }
90}
91
92struct LoggingFilter {
96 level: LoggingLevel,
97}
98
99const SELF_FILTER: LevelFilter = if cfg!(debug_assertions) {
101 LevelFilter::TRACE
102} else {
103 LevelFilter::DEBUG
104};
105
106impl LoggingFilter {
107 fn check_enabled(&self, meta: &Metadata<'_>) -> bool {
108 let filter = if meta.target().starts_with("webview_bundle") {
109 if let Some(level) = self.level.to_filter_level() {
110 level
111 } else {
112 return false;
113 }
114 } else {
115 LevelFilter::INFO
116 };
117 meta.level() <= &filter
118 }
119}
120
121impl<S> Filter<S> for LoggingFilter {
122 fn enabled(&self, meta: &Metadata<'_>, _: &Context<'_, S>) -> bool {
123 self.check_enabled(meta)
124 }
125
126 fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
127 if self.check_enabled(meta) {
128 Interest::always()
129 } else {
130 Interest::never()
131 }
132 }
133
134 fn max_level_hint(&self) -> Option<LevelFilter> {
135 Some(SELF_FILTER)
136 }
137}
138
139#[derive(Copy, Debug, Default, Clone, Eq, PartialEq)]
140pub enum LoggingKind {
141 #[default]
143 Pretty,
144 Compact,
146 Json,
148}
149
150impl Display for LoggingKind {
151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152 match self {
153 LoggingKind::Pretty => write!(f, "pretty"),
154 LoggingKind::Compact => write!(f, "compact"),
155 LoggingKind::Json => write!(f, "json"),
156 }
157 }
158}
159
160impl FromStr for LoggingKind {
161 type Err = String;
162
163 fn from_str(s: &str) -> Result<Self, Self::Err> {
164 match s {
165 "compact" => Ok(Self::Compact),
166 "pretty" => Ok(Self::Pretty),
167 "json" => Ok(Self::Json),
168 _ => Err("Unexpected value".to_string()),
169 }
170 }
171}