Microservice to bring 2FA to self hosted PDSes

eat: add opt-in per-request logging with JSON format support: eriko.eurosky.social #15

merged opened by baileytownsend.dev targeting main from feat/structured-request-logging
Labels

None yet.

Participants 1
AT URI
at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/sh.tangled.repo.pull/3mg4yntcdwl22
+75 -10
Diff #1
+15
Cargo.lock
··· 2812 2812 "tracing-subscriber", 2813 2813 "url", 2814 2814 "urlencoding", 2815 + "valuable", 2815 2816 ] 2816 2817 2817 2818 [[package]] ··· 4457 4458 "tower", 4458 4459 "tower-layer", 4459 4460 "tower-service", 4461 + "tracing", 4460 4462 ] 4461 4463 4462 4464 [[package]] ··· 4533 4535 ] 4534 4536 4535 4537 [[package]] 4538 + name = "tracing-serde" 4539 + version = "0.2.0" 4540 + source = "registry+https://github.com/rust-lang/crates.io-index" 4541 + checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" 4542 + dependencies = [ 4543 + "serde", 4544 + "tracing-core", 4545 + ] 4546 + 4547 + [[package]] 4536 4548 name = "tracing-subscriber" 4537 4549 version = "0.3.22" 4538 4550 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4542 4554 "nu-ansi-term", 4543 4555 "once_cell", 4544 4556 "regex-automata", 4557 + "serde", 4558 + "serde_json", 4545 4559 "sharded-slab", 4546 4560 "smallvec", 4547 4561 "thread_local", 4548 4562 "tracing", 4549 4563 "tracing-core", 4550 4564 "tracing-log", 4565 + "tracing-serde", 4551 4566 ] 4552 4567 4553 4568 [[package]]
+4 -3
Cargo.toml
··· 11 11 dotenvy = "0.15.7" 12 12 serde = { version = "1.0", features = ["derive"] } 13 13 serde_json = "1.0" 14 - tracing = "0.1" 15 - tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } 14 + tracing = { version = "0.1.44" } 15 + tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "serde", ] } 16 16 hyper-util = { version = "0.1.19", features = ["client", "client-legacy"] } 17 - tower-http = { version = "0.6", features = ["cors", "compression-zstd"] } 17 + tower-http = { version = "0.6", features = ["cors", "compression-zstd", "trace"] } 18 18 tower_governor = { version = "0.8.0", features = ["axum", "tracing"] } 19 19 hex = "0.4" 20 20 jwt-compact = { version = "0.8.0", features = ["es256k"] } ··· 40 40 josekit = "0.10.3" 41 41 dashmap = "6.1" 42 42 tower = "0.5" 43 + valuable = "0.1.1"
+56 -7
src/main.rs
··· 31 31 use tower_governor::{ 32 32 GovernorLayer, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor, 33 33 }; 34 + use tower_http::cors::AllowHeaders; 35 + use tower_http::trace::{DefaultOnRequest, HttpMakeClassifier}; 34 36 use tower_http::{ 35 37 compression::CompressionLayer, 36 - cors::{AllowHeaders, Any, CorsLayer}, 38 + cors::{Any, CorsLayer}, 39 + trace::TraceLayer, 37 40 }; 38 - use tracing::log; 41 + use tracing::{Span, log}; 39 42 use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 40 43 41 44 mod auth; ··· 199 202 200 203 #[tokio::main] 201 204 async fn main() -> Result<(), Box<dyn std::error::Error>> { 202 - setup_tracing(); 203 205 let pds_env_location = 204 206 env::var("PDS_ENV_LOCATION").unwrap_or_else(|_| "/pds/pds.env".to_string()); 205 207 ··· 209 211 "Error loading pds.env file (ignore if you loaded your variables in the environment somehow else): {e}" 210 212 ); 211 213 } 214 + // Sets up after the pds.env file is loaded 215 + setup_tracing(); 212 216 213 217 let pds_root = 214 218 env::var("PDS_DATA_DIRECTORY").expect("PDS_DATA_DIRECTORY is not set in your pds.env file"); ··· 385 389 ); 386 390 } 387 391 392 + let request_logging = env::var("GATEKEEPER_REQUEST_LOGGING") 393 + .map(|v| v.eq_ignore_ascii_case("true") || v == "1") 394 + .unwrap_or(false); 395 + 396 + if request_logging { 397 + app = app.layer(request_trace_layer()); 398 + } 399 + 388 400 let app = app 389 401 .layer(CompressionLayer::new()) 390 402 .layer(cors) ··· 416 428 417 429 fn setup_tracing() { 418 430 let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); 419 - tracing_subscriber::registry() 420 - .with(env_filter) 421 - .with(fmt::layer()) 422 - .init(); 431 + let json = env::var("GATEKEEPER_LOG_FORMAT") 432 + .map(|v| v.eq_ignore_ascii_case("json")) 433 + .unwrap_or(false); 434 + 435 + if json { 436 + tracing_subscriber::registry() 437 + .with(env_filter) 438 + .with(fmt::layer().json()) 439 + .init(); 440 + } else { 441 + tracing_subscriber::registry() 442 + .with(env_filter) 443 + .with(fmt::layer()) 444 + .init(); 445 + } 423 446 } 424 447 425 448 async fn shutdown_signal() { ··· 447 470 _ = terminate => {}, 448 471 } 449 472 } 473 + 474 + fn request_trace_layer() -> TraceLayer< 475 + HttpMakeClassifier, 476 + impl Fn(&axum::http::Request<Body>) -> Span + Clone, 477 + DefaultOnRequest, 478 + impl Fn(&axum::http::Response<Body>, Duration, &Span) + Clone, 479 + > { 480 + TraceLayer::new_for_http() 481 + .make_span_with(|req: &axum::http::Request<Body>| { 482 + let headers = req.headers(); 483 + tracing::info_span!("request", 484 + method = %req.method(), 485 + path = %req.uri().path(), 486 + headers = %format!("{:?}", headers), 487 + ) 488 + }) 489 + .on_response( 490 + |resp: &axum::http::Response<Body>, latency: Duration, _span: &tracing::Span| { 491 + tracing::info!( 492 + status = resp.status().as_u16(), 493 + latency_ms = latency.as_millis() as u64, 494 + "response" 495 + ); 496 + }, 497 + ) 498 + }

History

2 rounds 0 comments
sign up or login to add to the discussion
2 commits
expand
feat: add opt-in per-request logging
light changes to logging changes
expand 0 comments
pull request successfully merged
2 commits
expand
feat: add opt-in per-request logging
light changes to logging changes
expand 0 comments