feat(observability): suppress successful health logs
This commit is contained in:
@@ -12,7 +12,7 @@ use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||
use axum::{
|
||||
Json, Router,
|
||||
extract::{DefaultBodyLimit, MatchedPath},
|
||||
http::{HeaderName, HeaderValue, Request},
|
||||
http::{HeaderName, HeaderValue, Request, StatusCode},
|
||||
response::Response,
|
||||
routing::get,
|
||||
};
|
||||
@@ -55,6 +55,29 @@ impl From<&Config> for LogContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_log_http_request_started(path: &str) -> bool {
|
||||
path != "/health"
|
||||
}
|
||||
|
||||
fn should_log_http_response(is_health_check: bool, status: StatusCode) -> bool {
|
||||
!is_health_check || !status.is_success()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct HealthCheckResponse;
|
||||
|
||||
async fn mark_health_check_response(
|
||||
request: axum::extract::Request,
|
||||
next: axum::middleware::Next,
|
||||
) -> Response {
|
||||
let is_health_check = request.uri().path() == "/health";
|
||||
let mut response = next.run(request).await;
|
||||
if is_health_check {
|
||||
response.extensions_mut().insert(HealthCheckResponse);
|
||||
}
|
||||
response
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
dotenvy::dotenv().ok();
|
||||
@@ -161,6 +184,9 @@ fn build_app(
|
||||
make_http_request_span(request, &request_span_context)
|
||||
})
|
||||
.on_request(move |request: &Request<_>, span: &Span| {
|
||||
if !should_log_http_request_started(request.uri().path()) {
|
||||
return;
|
||||
}
|
||||
tracing::info!(
|
||||
parent: span,
|
||||
service = "api",
|
||||
@@ -174,6 +200,11 @@ fn build_app(
|
||||
})
|
||||
.on_response(move |response: &Response, latency: Duration, span: &Span| {
|
||||
let status = response.status();
|
||||
let is_health_check =
|
||||
response.extensions().get::<HealthCheckResponse>().is_some();
|
||||
if !should_log_http_response(is_health_check, status) {
|
||||
return;
|
||||
}
|
||||
let latency_ms = u64::try_from(latency.as_millis()).unwrap_or(u64::MAX);
|
||||
let request_id = response
|
||||
.headers()
|
||||
@@ -226,6 +257,7 @@ fn build_app(
|
||||
},
|
||||
),
|
||||
)
|
||||
.layer(axum::middleware::from_fn(mark_health_check_response))
|
||||
.layer(PropagateRequestIdLayer::x_request_id()),
|
||||
))
|
||||
}
|
||||
@@ -304,11 +336,17 @@ async fn shutdown_signal(log_context: LogContext) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use axum::{body::Body, http::Request};
|
||||
use axum::{
|
||||
body::Body,
|
||||
http::{Request, StatusCode},
|
||||
};
|
||||
use tower::ServiceExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{AppState, LogContext, build_app};
|
||||
use super::{
|
||||
AppState, HealthCheckResponse, LogContext, build_app, should_log_http_request_started,
|
||||
should_log_http_response,
|
||||
};
|
||||
use crate::{
|
||||
auth::AuthService, config::AuthConfig, speech::SpeechService, summary::SummaryService,
|
||||
};
|
||||
@@ -336,6 +374,41 @@ mod tests {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successful_health_request_is_not_logged() {
|
||||
assert!(!should_log_http_request_started("/health"));
|
||||
assert!(!should_log_http_response(true, StatusCode::OK));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_health_request_is_logged() {
|
||||
assert!(should_log_http_response(
|
||||
true,
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordinary_successful_request_is_logged() {
|
||||
assert!(should_log_http_request_started("/api/v1/profiles"));
|
||||
assert!(should_log_http_response(false, StatusCode::OK));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn health_response_is_marked_for_log_filtering() {
|
||||
let response = app()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/health")
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(response.extensions().get::<HealthCheckResponse>().is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn health_generates_a_uuid_request_id() {
|
||||
let response = app()
|
||||
|
||||
Reference in New Issue
Block a user