Skip to main content

sketching/
lib.rs

1#![deny(warnings)]
2#![warn(unused_extern_crates)]
3#![allow(non_snake_case)]
4use std::fmt::Display;
5use std::str::FromStr;
6
7use num_enum::{IntoPrimitive, TryFromPrimitive};
8use serde::Deserialize;
9use tracing_forest::printer::TestCapturePrinter;
10use tracing_forest::tag::NoTag;
11use tracing_forest::util::*;
12use tracing_forest::Tag;
13use tracing_subscriber::filter::Directive;
14use tracing_subscriber::prelude::*;
15
16pub mod macros;
17pub mod pipeline;
18
19pub use {tracing, tracing_forest, tracing_subscriber};
20
21#[derive(Clone, Copy, Eq, PartialEq, Debug)]
22pub enum LoggerType {
23    TracingForest,
24    OpenTelemetry,
25}
26
27impl LoggerType {
28    pub fn status_code_field(self) -> &'static str {
29        match self {
30            LoggerType::TracingForest => "status_code",
31            LoggerType::OpenTelemetry => "http.response.status_code",
32        }
33    }
34}
35
36/// Start up the logging for test mode.
37pub fn test_init() {
38    let filter = EnvFilter::builder()
39        // Skipping trace on tests by default saves a *TON* of ram.
40        .with_default_directive(LevelFilter::INFO.into())
41        .from_env_lossy()
42        // escargot builds cargo packages while we integration test and is SUPER noisy.
43        .add_directive(
44            "escargot=ERROR"
45                .parse()
46                .expect("failed to generate log filter"),
47        )
48        // hyper's very noisy in debug mode with connectivity-related things that we only need in extreme cases.
49        .add_directive("hyper=INFO".parse().expect("failed to generate log filter"));
50
51    // start the logging!
52    let _ = tracing_subscriber::Registry::default()
53        .with(ForestLayer::new(TestCapturePrinter::new(), NoTag).with_filter(filter))
54        .try_init();
55}
56
57/// This is for tagging events. Currently not wired in.
58pub fn event_tagger(_event: &Event) -> Option<Tag> {
59    None
60}
61
62#[derive(Debug, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
63#[repr(u64)]
64pub enum EventTag {
65    AdminDebug,
66    AdminError,
67    AdminWarn,
68    AdminInfo,
69    RequestError,
70    RequestWarn,
71    RequestInfo,
72    RequestTrace,
73    SecurityCritical,
74    SecurityDebug,
75    SecurityInfo,
76    SecurityAccess,
77    SecurityError,
78    FilterError,
79    FilterWarn,
80    FilterInfo,
81    FilterTrace,
82    PerfTrace,
83}
84
85impl EventTag {
86    pub fn pretty(self) -> &'static str {
87        match self {
88            EventTag::AdminDebug => "admin.debug",
89            EventTag::AdminError => "admin.error",
90            EventTag::AdminWarn => "admin.warn",
91            EventTag::AdminInfo => "admin.info",
92            EventTag::RequestError => "request.error",
93            EventTag::RequestWarn => "request.warn",
94            EventTag::RequestInfo => "request.info",
95            EventTag::RequestTrace => "request.trace",
96            EventTag::SecurityCritical => "security.critical",
97            EventTag::SecurityDebug => "security.debug",
98            EventTag::SecurityInfo => "security.info",
99            EventTag::SecurityAccess => "security.access",
100            EventTag::SecurityError => "security.error",
101            EventTag::FilterError => "filter.error",
102            EventTag::FilterWarn => "filter.warn",
103            EventTag::FilterInfo => "filter.info",
104            EventTag::FilterTrace => "filter.trace",
105            EventTag::PerfTrace => "perf.trace",
106        }
107    }
108
109    pub fn emoji(self) -> &'static str {
110        use EventTag::*;
111        match self {
112            AdminDebug | SecurityDebug => "🐛",
113            AdminError | FilterError | RequestError | SecurityError => "🚨",
114            AdminWarn | FilterWarn | RequestWarn => "âš ī¸",
115            AdminInfo | FilterInfo | RequestInfo | SecurityInfo => "â„šī¸",
116            RequestTrace | FilterTrace | PerfTrace => "📍",
117            SecurityCritical => "🔐",
118            SecurityAccess => "🔓",
119        }
120    }
121}
122
123#[derive(Clone, Copy, Deserialize, Debug, Default)]
124pub enum LogLevel {
125    #[default]
126    #[serde(rename = "info")]
127    Info,
128    #[serde(rename = "debug")]
129    Debug,
130    #[serde(rename = "trace")]
131    Trace,
132}
133
134impl FromStr for LogLevel {
135    type Err = &'static str;
136
137    fn from_str(s: &str) -> Result<Self, Self::Err> {
138        match s.to_ascii_lowercase().as_str() {
139            "info" => Ok(LogLevel::Info),
140            "debug" => Ok(LogLevel::Debug),
141            "trace" => Ok(LogLevel::Trace),
142            _ => Err("Must be one of info, debug, trace"),
143        }
144    }
145}
146
147impl Display for LogLevel {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        f.write_str(match self {
150            LogLevel::Info => "info",
151            LogLevel::Debug => "debug",
152            LogLevel::Trace => "trace",
153        })
154    }
155}
156
157impl From<LogLevel> for Directive {
158    fn from(value: LogLevel) -> Self {
159        match value {
160            LogLevel::Info => Directive::from(Level::INFO),
161            LogLevel::Debug => Directive::from(Level::DEBUG),
162            LogLevel::Trace => Directive::from(Level::TRACE),
163        }
164    }
165}