mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
packages/ak-common/tracing: init (#21263)
This commit is contained in:
committed by
GitHub
parent
db5a154230
commit
6792c2afeb
950
Cargo.lock
generated
950
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
@@ -27,9 +27,11 @@ config-rs = { package = "config", version = "= 0.15.22", default-features = fals
|
||||
"json",
|
||||
"yaml",
|
||||
] }
|
||||
console-subscriber = "= 0.5.0"
|
||||
dotenvy = "= 0.15.7"
|
||||
eyre = "= 0.6.12"
|
||||
glob = "= 0.3.3"
|
||||
json-subscriber = "= 0.2.8"
|
||||
nix = { version = "= 0.31.2", features = ["signal"] }
|
||||
notify = "= 8.2.0"
|
||||
pin-project-lite = "= 0.2.17"
|
||||
@@ -50,6 +52,16 @@ reqwest-middleware = { version = "= 0.5.1", features = [
|
||||
"rustls",
|
||||
] }
|
||||
rustls = { version = "= 0.23.37", features = ["fips"] }
|
||||
sentry = { version = "= 0.47.0", default-features = false, features = [
|
||||
"backtrace",
|
||||
"contexts",
|
||||
"debug-images",
|
||||
"panic",
|
||||
"rustls",
|
||||
"reqwest",
|
||||
"tower",
|
||||
"tracing",
|
||||
] }
|
||||
serde = { version = "= 1.0.228", features = ["derive"] }
|
||||
serde_json = "= 1.0.149"
|
||||
serde_repr = "= 0.1.20"
|
||||
@@ -57,10 +69,18 @@ serde_with = { version = "= 3.18.0", default-features = false, features = [
|
||||
"base64",
|
||||
] }
|
||||
tempfile = "= 3.27.0"
|
||||
time = { version = "= 0.3.47", features = ["macros"] }
|
||||
thiserror = "= 2.0.18"
|
||||
tokio = { version = "= 1.51.0", features = ["full", "tracing"] }
|
||||
tokio-util = { version = "= 0.7.18", features = ["full"] }
|
||||
tracing = "= 0.1.44"
|
||||
tracing-error = "= 0.2.1"
|
||||
tracing-subscriber = { version = "= 0.3.23", features = [
|
||||
"env-filter",
|
||||
"json",
|
||||
"local-time",
|
||||
"tracing-log",
|
||||
] }
|
||||
url = "= 2.5.8"
|
||||
uuid = { version = "= 1.23.0", features = ["serde", "v4"] }
|
||||
|
||||
|
||||
@@ -14,16 +14,22 @@ arc-swap.workspace = true
|
||||
aws-lc-rs.workspace = true
|
||||
axum-server.workspace = true
|
||||
config-rs.workspace = true
|
||||
console-subscriber.workspace = true
|
||||
eyre.workspace = true
|
||||
glob.workspace = true
|
||||
json-subscriber.workspace = true
|
||||
notify.workspace = true
|
||||
pin-project-lite.workspace = true
|
||||
rustls.workspace = true
|
||||
sentry.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
time.workspace = true
|
||||
tokio-util.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing-error.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ pub use arbiter::{Arbiter, Event, Tasks};
|
||||
pub mod config;
|
||||
pub mod tls;
|
||||
pub mod tokio;
|
||||
pub mod tracing;
|
||||
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
|
||||
216
packages/ak-common/src/tracing.rs
Normal file
216
packages/ak-common/src/tracing.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
use eyre::Result;
|
||||
use time::macros::format_description;
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_subscriber::{
|
||||
filter::EnvFilter,
|
||||
fmt::{self, time::LocalTime},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::config;
|
||||
|
||||
/// Install a tracing subscriber for watching tracing events.
|
||||
///
|
||||
/// If debug mode, will also install a console subscriber, which can be connected to with
|
||||
/// `tokio-console`.
|
||||
///
|
||||
/// This method depends on the [`config`] and [`sentry`] being initialized. For logging before that
|
||||
/// happens, see [`install_crude`].
|
||||
pub fn install() -> Result<()> {
|
||||
let config = config::get();
|
||||
|
||||
let time_format =
|
||||
format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]");
|
||||
|
||||
let mut filter_layer = EnvFilter::builder()
|
||||
.with_default_directive(config.log_level.parse()?)
|
||||
.parse(&config.log_level)?;
|
||||
for (k, v) in &config.log.rust_log {
|
||||
filter_layer = filter_layer.add_directive(format!("{k}={v}").parse()?);
|
||||
}
|
||||
|
||||
if config.debug {
|
||||
let console_layer = console_subscriber::ConsoleLayer::builder()
|
||||
.server_addr(config.listen.debug_tokio)
|
||||
.spawn();
|
||||
tracing_subscriber::registry()
|
||||
.with(ErrorLayer::default())
|
||||
.with(console_layer)
|
||||
.with(
|
||||
fmt::layer()
|
||||
.compact()
|
||||
.event_format(
|
||||
fmt::format()
|
||||
.with_timer(LocalTime::new(time_format))
|
||||
.with_thread_ids(true)
|
||||
.with_thread_names(true)
|
||||
.with_source_location(true)
|
||||
.compact(),
|
||||
)
|
||||
.with_writer(std::io::stderr)
|
||||
.with_filter(filter_layer),
|
||||
)
|
||||
.with(::sentry::integrations::tracing::layer())
|
||||
.init();
|
||||
} else {
|
||||
tracing_subscriber::registry()
|
||||
.with(ErrorLayer::default())
|
||||
.with(json::layer().with_filter(filter_layer))
|
||||
.with(::sentry::integrations::tracing::layer())
|
||||
.init();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Install a very basic tracing subscriber until a fully-featured one can be installed.
|
||||
#[must_use]
|
||||
pub fn install_crude() -> tracing::dispatcher::DefaultGuard {
|
||||
let filter_layer = EnvFilter::builder()
|
||||
.parse("trace,console_subscriber=info,runtime=info,tokio=info,tungstenite=info")
|
||||
.expect("infallible");
|
||||
let subscriber = tracing_subscriber::registry()
|
||||
.with(ErrorLayer::default())
|
||||
.with(filter_layer)
|
||||
.with(json::layer());
|
||||
tracing::dispatcher::set_default(&subscriber.into())
|
||||
}
|
||||
|
||||
/// Utilities for JSON logging
|
||||
mod json {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use time::macros::format_description;
|
||||
use tracing::Subscriber;
|
||||
use tracing_subscriber::{fmt::time::LocalTime, layer::Layer, registry::LookupSpan};
|
||||
|
||||
/// Create a custom layer for JSON formatting, with:
|
||||
///
|
||||
/// - local time
|
||||
/// - "message" key renamed to "event"
|
||||
/// - span data
|
||||
/// - current process id
|
||||
/// - thread information
|
||||
pub(super) fn layer<S>() -> impl Layer<S>
|
||||
where
|
||||
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
|
||||
{
|
||||
let time_format = format_description!(
|
||||
"[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]"
|
||||
);
|
||||
|
||||
let mut json_layer = json_subscriber::fmt::layer()
|
||||
.with_timer(LocalTime::new(time_format))
|
||||
.with_file(true)
|
||||
.with_line_number(true)
|
||||
.flatten_event(true)
|
||||
.flatten_current_span_on_top_level(true);
|
||||
|
||||
let inner_layer = json_layer.inner_layer_mut();
|
||||
inner_layer.with_thread_ids("thread_id");
|
||||
inner_layer.with_thread_names("thread_name");
|
||||
inner_layer.add_dynamic_field("pid", |_, _| {
|
||||
Some(serde_json::Value::Number(serde_json::Number::from(
|
||||
std::process::id(),
|
||||
)))
|
||||
});
|
||||
inner_layer.with_flattened_event_with_renames(
|
||||
move |name, map| match map.get(name) {
|
||||
Some(name) => name.as_str(),
|
||||
None => name,
|
||||
},
|
||||
HashMap::from([("message".to_owned(), "event".to_owned())]),
|
||||
);
|
||||
|
||||
json_layer
|
||||
}
|
||||
}
|
||||
|
||||
/// Utilities for Sentry
|
||||
pub mod sentry {
|
||||
use std::str::FromStr as _;
|
||||
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{VERSION, authentik_user_agent, config};
|
||||
|
||||
/// Install the sentry client. This must happen before [`super::install`] is called.
|
||||
pub fn install() -> sentry::ClientInitGuard {
|
||||
trace!("setting up sentry");
|
||||
let config = config::get();
|
||||
sentry::init(sentry::ClientOptions {
|
||||
dsn: config.error_reporting.sentry_dsn.clone().map(|dsn| {
|
||||
sentry::types::Dsn::from_str(&dsn).expect("Failed to create sentry DSN")
|
||||
}),
|
||||
release: Some(format!("authentik@{VERSION}").into()),
|
||||
environment: Some(config.error_reporting.environment.clone().into()),
|
||||
attach_stacktrace: true,
|
||||
send_default_pii: config.error_reporting.send_pii,
|
||||
sample_rate: config.error_reporting.sample_rate,
|
||||
traces_sample_rate: if config.debug {
|
||||
1.0
|
||||
} else {
|
||||
config.error_reporting.sample_rate
|
||||
},
|
||||
user_agent: authentik_user_agent().into(),
|
||||
..sentry::ClientOptions::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tracing::{error, trace};
|
||||
|
||||
#[test]
|
||||
fn crude() {
|
||||
let _ = super::install_crude();
|
||||
trace!("test");
|
||||
error!("test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
crate::config::init().expect("failed to init config");
|
||||
super::install().expect("failed to install tracing");
|
||||
trace!("test");
|
||||
error!("test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both() {
|
||||
let tracing_crude = super::install_crude();
|
||||
trace!("test");
|
||||
error!("test");
|
||||
crate::config::init().expect("failed to init config");
|
||||
super::install().expect("failed to install tracing");
|
||||
trace!("test");
|
||||
error!("test");
|
||||
drop(tracing_crude);
|
||||
trace!("test");
|
||||
error!("test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sentry_install() {
|
||||
crate::config::init().expect("failed to init config");
|
||||
let _ = super::sentry::install();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all() {
|
||||
let tracing_crude = super::install_crude();
|
||||
trace!("test");
|
||||
error!("test");
|
||||
crate::config::init().expect("failed to init config");
|
||||
let _sentry = super::sentry::install();
|
||||
trace!("test");
|
||||
error!("test");
|
||||
super::install().expect("failed to install tracing");
|
||||
trace!("test");
|
||||
error!("test");
|
||||
drop(tracing_crude);
|
||||
trace!("test");
|
||||
error!("test");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user