1#![doc = include_str!("../README.md")]
2
3use std::{
4 fmt::Display,
5 fs::{self, OpenOptions},
6 io::{self, Write},
7 path::Path,
8};
9
10use env_logger::{Builder, Env};
11use jiff::{Timestamp, tz};
12pub use owo_colors::OwoColorize;
13
14#[inline]
15pub fn init(path: Option<&Path>) -> io::Result<()> {
16 let file = path.map(|path| {
17 let _ = fs::remove_file(path);
18 OpenOptions::new()
19 .create(true)
20 .append(true)
21 .open(path)
22 .unwrap()
23 });
24
25 Builder::from_env(Env::default().default_filter_or(
26 "info,bitcoin=off,bitcoincore-rpc=off,fjall=off,lsm_tree=off,rolldown=off,brk_rolldown=off,rmcp=off,brk_rmcp=off,tracing=off",
27 ))
28 .format(move |buf, record| {
29 let date_time = Timestamp::now()
30 .to_zoned(tz::TimeZone::system())
31 .strftime("%Y-%m-%d %H:%M:%S")
32 .to_string();
33 let level = record.level().as_str().to_lowercase();
34 let level = format!("{level:5}");
35 let target = record.target();
36 let dash = "-";
37 let args = record.args();
38
39 if let Some(file) = file.as_ref() {
40 let _ = write(
41 file.try_clone().unwrap(),
42 &date_time,
43 target,
44 &level,
45 dash,
46 args,
47 );
48 }
49
50 let colored_date_time = date_time.bright_black();
51 let colored_level = match level.chars().next().unwrap() {
52 'e' => level.red().to_string(),
53 'w' => level.yellow().to_string(),
54 'i' => level.green().to_string(),
55 'd' => level.blue().to_string(),
56 't' => level.cyan().to_string(),
57 _ => panic!(),
58 };
59 let colored_dash = dash.bright_black();
60
61 write(
62 buf,
63 colored_date_time,
64 target,
65 colored_level,
66 colored_dash,
67 args,
68 )
69 })
70 .init();
71
72 Ok(())
73}
74
75fn write(
76 mut buf: impl Write,
77 date_time: impl Display,
78 _target: impl Display,
79 level: impl Display,
80 dash: impl Display,
81 args: impl Display,
82) -> Result<(), std::io::Error> {
83 writeln!(buf, "{date_time} {dash} {level} {args}")
84 }