From 0a0da875f333f2fe483bb842cefc9c434c76242b Mon Sep 17 00:00:00 2001
From: Eduardo Trujillo <ed@chromabits.com>
Date: Sun, 5 Feb 2023 15:57:37 -0800
Subject: [PATCH] feat: Add tracing support

---
 Cargo.lock            | 192 ++++++++++++++++++++++++++++++------------
 Cargo.toml            |   5 +-
 src/cli.rs            |  70 ++++++++++-----
 src/config.rs         |   2 +-
 src/rundir.rs         |   2 +-
 src/thread/monitor.rs |   2 +-
 6 files changed, 193 insertions(+), 80 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 6773bdd..5e1be21 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,15 +2,6 @@
 # It is not intended for manual editing.
 version = 3
 
-[[package]]
-name = "aho-corasick"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
-dependencies = [
- "memchr",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -68,11 +59,12 @@ dependencies = [
  "clap",
  "figment",
  "lazy_static",
- "log",
- "pretty_env_logger",
  "serde",
  "thiserror",
  "toml",
+ "tracing",
+ "tracing-log",
+ "tracing-subscriber",
  "xdg",
 ]
 
@@ -96,19 +88,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "env_logger"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
-dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
-]
-
 [[package]]
 name = "figment"
 version = "0.10.0"
@@ -150,15 +129,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "humantime"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
-dependencies = [
- "quick-error",
-]
-
 [[package]]
 name = "indexmap"
 version = "1.6.1"
@@ -208,12 +178,37 @@ dependencies = [
  "cfg-if 0.1.10",
 ]
 
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata",
+]
+
 [[package]]
 name = "memchr"
 version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
 [[package]]
 name = "os_str_bytes"
 version = "6.0.0"
@@ -223,6 +218,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
 [[package]]
 name = "pear"
 version = "0.2.0"
@@ -247,14 +248,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "pretty_env_logger"
-version = "0.4.0"
+name = "pin-project-lite"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
-dependencies = [
- "env_logger",
- "log",
-]
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 
 [[package]]
 name = "proc-macro2"
@@ -278,12 +275,6 @@ dependencies = [
  "yansi",
 ]
 
-[[package]]
-name = "quick-error"
-version = "1.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-
 [[package]]
 name = "quote"
 version = "1.0.10"
@@ -315,21 +306,27 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.4.2"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 dependencies = [
- "aho-corasick",
- "memchr",
  "regex-syntax",
- "thread_local",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.21"
+version = "0.6.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
 
 [[package]]
 name = "ryu"
@@ -366,6 +363,21 @@ dependencies = [
  "yaml-rust",
 ]
 
+[[package]]
+name = "sharded-slab"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
 [[package]]
 name = "strsim"
 version = "0.10.0"
@@ -420,11 +432,11 @@ dependencies = [
 
 [[package]]
 name = "thread_local"
-version = "1.0.1"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
 dependencies = [
- "lazy_static",
+ "once_cell",
 ]
 
 [[package]]
@@ -436,6 +448,68 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "tracing"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
+dependencies = [
+ "cfg-if 1.0.0",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
+dependencies = [
+ "lazy_static",
+ "log",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
 [[package]]
 name = "uncased"
 version = "0.9.3"
@@ -451,6 +525,12 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
 [[package]]
 name = "version_check"
 version = "0.9.2"
diff --git a/Cargo.toml b/Cargo.toml
index e082d00..cc42702 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,14 +6,15 @@ edition = "2018"
 
 [dependencies]
 serde = "1.0"
-log = "0.4"
 toml = "0.5"
 thiserror = "1.0"
 clap = "3.1"
-pretty_env_logger = "0.4"
 figment = { version = "0.10", features = ["toml", "env"] }
 lazy_static = { version = "1.4", optional = true }
 xdg = { version = "2.4", optional = true }
+tracing-subscriber = {version = "0.3", features=["env-filter"]}
+tracing = "0.1"
+tracing-log = "0.1"
 
 [features]
 default = ["config-yaml", "config-json", "thread", "xdg"]
diff --git a/src/cli.rs b/src/cli.rs
index b9bd316..0b660cf 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,13 +1,16 @@
 use std::path::PathBuf;
 
 use clap::{IntoApp, Parser};
-use log::LevelFilter;
 use serde::{de::DeserializeOwned, Serialize};
 use thiserror::Error;
+use tracing::metadata::LevelFilter;
+use tracing_log::{LogTracer, log_tracer::SetLoggerError};
+use tracing_subscriber::EnvFilter;
 
 use crate::config::{self, ConfigFileFormat};
 
 // Exit codes as defined in sysexits.h.
+pub const INTERNAL_ERROR_EXIT_CODE: i32 = 70;
 pub const CONFIGURATION_ERROR_EXIT_CODE: i32 = 78;
 
 #[derive(Error, Debug)]
@@ -16,6 +19,10 @@ pub enum CliError {
     ArgParse(#[from] clap::Error),
     #[error(transparent)]
     Config(#[from] config::ConfigError),
+    #[error(transparent)]
+    SetLogger(#[from] SetLoggerError),
+    #[error(transparent)]
+    InitLogger(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
 }
 
 pub trait AppOpts: Parser {
@@ -24,15 +31,18 @@ pub trait AppOpts: Parser {
 
         match &result {
             Ok(result) => {
+                //LogTracer::init()?;
+
                 try_init_pretty_logger(
                     result.get_log_environment_variable_name(),
                     result.get_log_level_filter(),
-                )
-                .unwrap();
+                )?;
             }
             Err(_) => {
                 // Initialize the logger with defaults.
-                pretty_env_logger::init();
+                //LogTracer::init()?;
+    
+                tracing_subscriber::fmt::init();
             }
         }
 
@@ -44,10 +54,20 @@ pub trait AppOpts: Parser {
             Ok(args) => args,
             Err(CliError::ArgParse(err)) => err.exit(),
             Err(CliError::Config(err)) => {
-                log::error!("{}", err);
+                tracing::error!("{}", err);
 
                 safe_exit(CONFIGURATION_ERROR_EXIT_CODE);
-            }
+            },
+            Err(CliError::SetLogger(err)) => {
+                eprintln!("{}", err);
+
+                safe_exit(INTERNAL_ERROR_EXIT_CODE);
+            },
+            Err(CliError::InitLogger(err)) => {
+                eprintln!("{}", err);
+
+                safe_exit(INTERNAL_ERROR_EXIT_CODE);
+            },
         }
     }
 
@@ -81,10 +101,20 @@ pub trait ConfigurableAppOpts<C: DeserializeOwned + Default + Serialize>: AppOpt
             Ok(args_and_config) => args_and_config,
             Err(CliError::ArgParse(err)) => err.exit(),
             Err(CliError::Config(err)) => {
-                log::error!("{}", err);
+                tracing::error!("{}", err);
 
                 safe_exit(CONFIGURATION_ERROR_EXIT_CODE);
-            }
+            },
+            Err(CliError::SetLogger(err)) => {
+                eprintln!("{}", err);
+
+                safe_exit(INTERNAL_ERROR_EXIT_CODE);
+            },
+            Err(CliError::InitLogger(err)) => {
+                eprintln!("{}", err);
+
+                safe_exit(INTERNAL_ERROR_EXIT_CODE);
+            },
         }
     }
 
@@ -98,18 +128,20 @@ pub trait ConfigurableAppOpts<C: DeserializeOwned + Default + Serialize>: AppOpt
 fn try_init_pretty_logger(
     environment_variable_name: Option<&str>,
     level_filter_override: Option<LevelFilter>,
-) -> Result<(), log::SetLoggerError> {
-    let mut builder = pretty_env_logger::formatted_builder();
+) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
+    let mut builder = tracing_subscriber::fmt();
 
     if let Some(level_filter_override) = level_filter_override {
-        builder.filter(None, level_filter_override);
+        builder = builder.with_max_level(level_filter_override);
     }
 
-    if let Ok(s) = ::std::env::var(environment_variable_name.unwrap_or("RUST_LOG")) {
-        builder.parse_filters(&s);
-    }
+    let filter = if let Some(environment_variable_name) = environment_variable_name {
+        EnvFilter::from_env(environment_variable_name)
+    } else {
+        EnvFilter::from_default_env()
+    };
 
-    builder.try_init()
+    builder.with_env_filter(filter).try_init()
 }
 
 /// Converts a integer verbosity value into a `LevelFilter`.
@@ -126,11 +158,11 @@ fn try_init_pretty_logger(
 ///
 /// assert_eq!(get_log_level_filter_from_verbosity(15), None);
 /// ```
-pub fn get_log_level_filter_from_verbosity(verbosity: u8) -> Option<log::LevelFilter> {
+pub fn get_log_level_filter_from_verbosity(verbosity: u8) -> Option<LevelFilter> {
     match verbosity {
-        3 => Some(log::LevelFilter::Trace),
-        2 => Some(log::LevelFilter::Debug),
-        1 => Some(log::LevelFilter::Info),
+        3 => Some(LevelFilter::TRACE),
+        2 => Some(LevelFilter::DEBUG),
+        1 => Some(LevelFilter::INFO),
         _ => None,
     }
 }
diff --git a/src/config.rs b/src/config.rs
index 88198cc..4bf6533 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -11,9 +11,9 @@ use figment::{
     providers::{Env, Format, Serialized, Toml},
     Figment, Profile,
 };
-use log::{debug, info};
 use serde::{de::DeserializeOwned, Serialize};
 use thiserror::Error;
+use tracing::{debug, info};
 #[cfg(feature = "xdg")]
 use xdg;
 
diff --git a/src/rundir.rs b/src/rundir.rs
index 35179da..738075e 100644
--- a/src/rundir.rs
+++ b/src/rundir.rs
@@ -1,6 +1,6 @@
-use log::{error, info, warn};
 use std::path::{Path, PathBuf};
 use thiserror::Error;
+use tracing::{error, info, warn};
 
 #[derive(Error, Debug)]
 pub enum RunDirError {
diff --git a/src/thread/monitor.rs b/src/thread/monitor.rs
index c2cf0d6..19e2fa3 100644
--- a/src/thread/monitor.rs
+++ b/src/thread/monitor.rs
@@ -91,7 +91,7 @@ impl ThreadMonitor {
                         None => {}
                     }
                 }
-                Err(_) => log::error!("Unable to update map of panicked threads."),
+                Err(_) => tracing::error!("Unable to update map of panicked threads."),
             }
 
             hook(panic_info)
-- 
GitLab