1use parse_display::{Display, FromStr};
2use serde_hkx_features::error::Result;
3use std::fs::File;
4use std::path::Path;
5use tracing::Level;
6
7#[derive(Debug, clap::ValueEnum, Clone, Copy, Default, PartialEq, Eq, Display, FromStr)]
9pub enum LogLevel {
10 #[display("trace")]
11 Trace,
12 #[display("debug")]
13 Debug,
14 #[display("info")]
15 Info,
16 #[display("warn")]
17 Warn,
18 #[default]
19 #[display("error")]
20 Error,
21}
22
23impl From<LogLevel> for Level {
24 #[inline]
25 fn from(value: LogLevel) -> Self {
26 match value {
27 LogLevel::Trace => Self::TRACE,
28 LogLevel::Debug => Self::DEBUG,
29 LogLevel::Info => Self::INFO,
30 LogLevel::Warn => Self::WARN,
31 LogLevel::Error => Self::ERROR,
32 }
33 }
34}
35
36pub(crate) fn init<P, L>(log_path: Option<P>, filter: L, with_stdout: bool) -> Result<()>
44where
45 P: AsRef<Path>,
46 L: Into<Level>,
47{
48 use tracing_subscriber::{fmt, layer::SubscriberExt};
49
50 if let Some(log_parent) = log_path.as_ref().and_then(|p| p.as_ref().parent()) {
51 std::fs::create_dir_all(log_parent)?;
52 }
53
54 let subscriber_builder = fmt::Subscriber::builder()
55 .compact()
56 .with_file(true)
57 .with_line_number(true)
58 .with_max_level(filter.into())
59 .with_target(false);
60
61 if with_stdout {
62 if let Some(log_path) = log_path {
63 let log_file = File::create(log_path.as_ref())?;
64
65 let log_file_config = fmt::Layer::default()
66 .compact()
67 .with_ansi(false)
68 .with_file(true)
69 .with_line_number(true)
70 .with_target(false)
71 .with_writer(log_file);
72 tracing::subscriber::set_global_default(
73 subscriber_builder.pretty().finish().with(log_file_config),
74 )?;
75 } else {
76 tracing::subscriber::set_global_default(
77 subscriber_builder
78 .pretty()
79 .with_ansi(true)
80 .with_line_number(true)
81 .with_target(false)
82 .finish(),
83 )?;
84 }
85 } else if let Some(log_path) = log_path {
86 let log_file = File::create(log_path.as_ref())?;
87 subscriber_builder
88 .with_writer(log_file)
89 .with_ansi(false)
90 .init();
91 }
92
93 Ok(())
94}