cargo_auto/bin_cli_functions_mod.rs
1// bin_cli_functions.rs
2
3//! Functions to work with CLI binary executable projects.
4//!
5//! Binary executables need some standard functions to help to develop them efficiently.
6
7// region: Public API constants
8// ANSI colors for Linux terminal
9// https://github.com/shiena/ansicolor/blob/master/README.md
10/// ANSI color
11#[allow(dead_code)]
12pub const RED: &str = "\x1b[31m";
13/// ANSI color
14#[allow(dead_code)]
15pub const GREEN: &str = "\x1b[32m";
16/// ANSI color
17#[allow(dead_code)]
18pub const YELLOW: &str = "\x1b[33m";
19/// ANSI color
20#[allow(dead_code)]
21pub const BLUE: &str = "\x1b[34m";
22/// ANSI color
23#[allow(dead_code)]
24pub const RESET: &str = "\x1b[0m";
25// endregion: Public API constants
26
27/// Initialize tracing to file tmp/logs/cargo_auto.log
28///
29/// The folder tmp/logs/ is in .gitignore and will not be committed.
30pub fn tracing_init() {
31 // uncomment this line to enable tracing to file
32 // let file_appender = tracing_appender::rolling::daily("tmp/logs", "cargo_auto.log");
33
34 let offset = time::UtcOffset::current_local_offset().expect("should get local offset!");
35 let timer = tracing_subscriber::fmt::time::OffsetTime::new(
36 offset,
37 time::macros::format_description!("[hour]:[minute]:[second].[subsecond digits:6]"),
38 );
39
40 // Filter out logs from: hyper_util, reqwest
41 // A filter consists of one or more comma-separated directives
42 // target[span{field=value}]=level
43 // examples: tokio::net=info
44 // Levels order: ERROR, WARN, INFO, DEBUG, TRACE
45 // ERROR level is always logged.
46 // To add other levels use the RUST_LOG environment variable:
47 // ```bash
48 // export RUST_LOG=cargo_auto=warn
49 // export RUST_LOG=cargo_auto=info
50 // export RUST_LOG=cargo_auto=debug
51 // export RUST_LOG=cargo_auto=trace
52 // ```
53 // Unset the environment variable RUST_LOG:
54 // ```bash
55 // unset RUST_LOG
56 // ```
57 let filter = tracing_subscriber::EnvFilter::from_default_env()
58 .add_directive("hyper_util=error".parse().unwrap_or_else(|e| panic!("{e}")))
59 .add_directive("reqwest=error".parse().unwrap_or_else(|e| panic!("{e}")));
60
61 tracing_subscriber::fmt()
62 .with_file(true)
63 .with_timer(timer)
64 .with_line_number(true)
65 .with_ansi(true)
66 // .with_writer(file_appender)
67 .with_env_filter(filter)
68 .init();
69}
70
71/// The original Rust report of the panic is ugly for the end user
72///
73/// For panics I log the location.
74/// If the message contains "Exiting..." than it is a forced "not-error exit" and the location is not important.
75pub fn panic_set_hook(panic_info: &std::panic::PanicHookInfo) {
76 let mut string_message = "".to_string();
77 if let Some(message) = panic_info.payload().downcast_ref::<String>() {
78 string_message = message.to_owned();
79 }
80 if let Some(message) = panic_info.payload().downcast_ref::<&str>() {
81 string_message.push_str(message);
82 }
83
84 tracing::error!("{string_message}");
85 eprintln!("{string_message}");
86
87 if !string_message.contains("Exiting...") {
88 let file = panic_info.location().unwrap().file();
89 let line = panic_info.location().unwrap().line();
90 let column = panic_info.location().unwrap().column();
91 tracing::error!("{RED}Panic location: {file}:{line}:{column}{RESET}");
92 eprintln!("{RED}Location: {file}:{line}:{column}{RESET}");
93 }
94}