1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#[macro_use]
extern crate shadow_rs;

use pretty_assertions::{assert_eq, assert_ne};
use tap::prelude::*;
use itertools::Itertools;
use eyre::{WrapErr, Result};


pub fn print_version() {
    shadow!(build);
    eprintln!("{} {}", build::PROJECT_NAME, build::PKG_VERSION);
    eprintln!(" > build_time: {}", build::BUILD_TIME_2822);
    eprintln!(" > build_env: {} on {}, channel: {}",
              build::RUST_VERSION, build::BUILD_OS, build::BUILD_RUST_CHANNEL);
    eprintln!(" > branch: {} tag: {} commit: {}", build::BRANCH, build::TAG, build::SHORT_COMMIT);
}


pub static LOGGING_GUARD: once_cell::sync::Lazy<LoggingGuard> = once_cell::sync::Lazy::new(|| {
    setup_logging().unwrap()
});

pub struct LoggingGuard {
    sentry: Option<sentry::ClientInitGuard>,
}

/// Exit the whole process if any child thread panics.
pub fn setup_failfast() {
    use std::panic;
    use std::process;
    let orig_hook = panic::take_hook();
    panic::set_hook(Box::new(move |panic_info| {
        // invoke the default handler and exit the process
        orig_hook(panic_info);
        process::exit(1);
    }));
}

pub fn setup_logging() -> Result<LoggingGuard> {
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::util::SubscriberInitExt;
    use metrics_exporter_prometheus::PrometheusBuilder;
    use std::net::SocketAddr;
    color_eyre::install().wrap_err("Failed to initialize `color_eyre`.")?;
    let mut layers = tracing_subscriber::registry()
        .with(tracing_subscriber::EnvFilter::from_env("LOG_LEVEL"))
        .with(tracing_subscriber::fmt::layer()
              .with_line_number(true)
              .with_file(true)
              .with_thread_ids(true));
    let mut builder = PrometheusBuilder::new();
    if let Ok(url) = std::env::var("PROMETHEUS_PUSH_GATEWAY_URL") {
        builder = builder.with_push_gateway(
            url, std::time::Duration::from_secs(10)
        ).expect("cannot start prometheus push gateway");
    }
    if let Ok(_) = std::env::var("ENABLE_PROMETHEUS_EXPORTER") {
        builder = builder.with_http_listener(SocketAddr::from(([0, 0, 0, 0], 9000)));
    }
    builder.install().wrap_err("Failed to initialize prometheus exporter.")?;
    let guard = LoggingGuard {
        sentry: match std::env::var("SENTRY_URL") {
            Ok(ref url) => {
                let guard = Some(sentry::init(
                    (url.as_str(), sentry::ClientOptions {
                        release: sentry::release_name!(),
                        ..Default::default()
                    })));
                tracing::info!("sentry integration enabled");
                let layers = layers.with(sentry_tracing::layer());
                layers.init();
                guard
            }
            Err(_) => {
                layers.init();
                None
            }
        }
    };
    return Ok(guard);
}