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}