Originally from @eriko.eurosky.social with some changes
+15
Cargo.lock
+15
Cargo.lock
···
2812
"tracing-subscriber",
2813
"url",
2814
"urlencoding",
2815
]
2816
2817
[[package]]
···
4457
"tower",
4458
"tower-layer",
4459
"tower-service",
4460
]
4461
4462
[[package]]
···
4533
]
4534
4535
[[package]]
4536
name = "tracing-subscriber"
4537
version = "0.3.22"
4538
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4542
"nu-ansi-term",
4543
"once_cell",
4544
"regex-automata",
4545
"sharded-slab",
4546
"smallvec",
4547
"thread_local",
4548
"tracing",
4549
"tracing-core",
4550
"tracing-log",
4551
]
4552
4553
[[package]]
···
2812
"tracing-subscriber",
2813
"url",
2814
"urlencoding",
2815
+
"valuable",
2816
]
2817
2818
[[package]]
···
4458
"tower",
4459
"tower-layer",
4460
"tower-service",
4461
+
"tracing",
4462
]
4463
4464
[[package]]
···
4535
]
4536
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]]
4548
name = "tracing-subscriber"
4549
version = "0.3.22"
4550
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4554
"nu-ansi-term",
4555
"once_cell",
4556
"regex-automata",
4557
+
"serde",
4558
+
"serde_json",
4559
"sharded-slab",
4560
"smallvec",
4561
"thread_local",
4562
"tracing",
4563
"tracing-core",
4564
"tracing-log",
4565
+
"tracing-serde",
4566
]
4567
4568
[[package]]
+4
-3
Cargo.toml
+4
-3
Cargo.toml
···
11
dotenvy = "0.15.7"
12
serde = { version = "1.0", features = ["derive"] }
13
serde_json = "1.0"
14
-
tracing = "0.1"
15
-
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
16
hyper-util = { version = "0.1.19", features = ["client", "client-legacy"] }
17
-
tower-http = { version = "0.6", features = ["cors", "compression-zstd"] }
18
tower_governor = { version = "0.8.0", features = ["axum", "tracing"] }
19
hex = "0.4"
20
jwt-compact = { version = "0.8.0", features = ["es256k"] }
···
40
josekit = "0.10.3"
41
dashmap = "6.1"
42
tower = "0.5"
···
11
dotenvy = "0.15.7"
12
serde = { version = "1.0", features = ["derive"] }
13
serde_json = "1.0"
14
+
tracing = { version = "0.1.44" }
15
+
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "serde", ] }
16
hyper-util = { version = "0.1.19", features = ["client", "client-legacy"] }
17
+
tower-http = { version = "0.6", features = ["cors", "compression-zstd", "trace"] }
18
tower_governor = { version = "0.8.0", features = ["axum", "tracing"] }
19
hex = "0.4"
20
jwt-compact = { version = "0.8.0", features = ["es256k"] }
···
40
josekit = "0.10.3"
41
dashmap = "6.1"
42
tower = "0.5"
43
+
valuable = "0.1.1"
+56
-7
src/main.rs
+56
-7
src/main.rs
···
31
use tower_governor::{
32
GovernorLayer, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor,
33
};
34
use tower_http::{
35
compression::CompressionLayer,
36
-
cors::{AllowHeaders, Any, CorsLayer},
37
};
38
-
use tracing::log;
39
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
40
41
mod auth;
···
199
200
#[tokio::main]
201
async fn main() -> Result<(), Box<dyn std::error::Error>> {
202
-
setup_tracing();
203
let pds_env_location =
204
env::var("PDS_ENV_LOCATION").unwrap_or_else(|_| "/pds/pds.env".to_string());
205
···
209
"Error loading pds.env file (ignore if you loaded your variables in the environment somehow else): {e}"
210
);
211
}
212
213
let pds_root =
214
env::var("PDS_DATA_DIRECTORY").expect("PDS_DATA_DIRECTORY is not set in your pds.env file");
···
385
);
386
}
387
388
let app = app
389
.layer(CompressionLayer::new())
390
.layer(cors)
···
416
417
fn setup_tracing() {
418
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();
423
}
424
425
async fn shutdown_signal() {
···
447
_ = terminate => {},
448
}
449
}
···
31
use tower_governor::{
32
GovernorLayer, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor,
33
};
34
+
use tower_http::cors::AllowHeaders;
35
+
use tower_http::trace::{DefaultOnRequest, HttpMakeClassifier};
36
use tower_http::{
37
compression::CompressionLayer,
38
+
cors::{Any, CorsLayer},
39
+
trace::TraceLayer,
40
};
41
+
use tracing::{Span, log};
42
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
43
44
mod auth;
···
202
203
#[tokio::main]
204
async fn main() -> Result<(), Box<dyn std::error::Error>> {
205
let pds_env_location =
206
env::var("PDS_ENV_LOCATION").unwrap_or_else(|_| "/pds/pds.env".to_string());
207
···
211
"Error loading pds.env file (ignore if you loaded your variables in the environment somehow else): {e}"
212
);
213
}
214
+
// Sets up after the pds.env file is loaded
215
+
setup_tracing();
216
217
let pds_root =
218
env::var("PDS_DATA_DIRECTORY").expect("PDS_DATA_DIRECTORY is not set in your pds.env file");
···
389
);
390
}
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
+
400
let app = app
401
.layer(CompressionLayer::new())
402
.layer(cors)
···
428
429
fn setup_tracing() {
430
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
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
+
}
446
}
447
448
async fn shutdown_signal() {
···
470
_ = terminate => {},
471
}
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
baileytownsend.dev
submitted
#1
2 commits
expand
collapse
feat: add opt-in per-request logging
Add GATEKEEPER_REQUEST_LOGGING=true to enable per-request tracing
with method, path, client_ip, status, and latency_ms. Disabled by
default — existing behavior unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
light changes to logging changes
expand 0 comments
pull request successfully merged
baileytownsend.dev
submitted
#0
2 commits
expand
collapse
feat: add opt-in per-request logging
Add GATEKEEPER_REQUEST_LOGGING=true to enable per-request tracing
with method, path, client_ip, status, and latency_ms. Disabled by
default — existing behavior unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
light changes to logging changes