chore(logs): add explicit http logs

Default is now RUST_LOG=info,http=warn. Effect of each level on the access log:

  ┌────────────────────┬────────────────────────┐
  │   Level on http    │ Status classes emitted │
  ├────────────────────┼────────────────────────┤
  │ info               │ 2xx/3xx + 4xx + 5xx    │
  ├────────────────────┼────────────────────────┤
  │ warn (default)     │ 4xx + 5xx              │
  ├────────────────────┼────────────────────────┤
  │ error              │ 5xx only               │
  ├────────────────────┼────────────────────────┤
  │ off                │ nothing                │
  └────────────────────┴────────────────────────┘

  Target mapping:

  ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────┐
  │                                                       Routes                                                       │     Target      │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ health_routes                                                                                                      │ http::probe     │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ magic_link_router                                                                                                  │ http::web       │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ All /api/auth/* sub-routers (login, register, refresh, public, protected, app_pw, device_public, device_protected) │ http::api::auth │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ setup_router, public_api_routes, protected_api, wopi_api_protected                                                 │ http::api       │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ well_known_router, caldav_protected, carddav_protected, webdav_protected                                           │ http::dav       │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ nc_router                                                                                                          │ http::nextcloud │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ wopi_protocol                                                                                                      │ http::wopi      │
  ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────┤
  │ web_routes (+ ServeDir fallback)                                                                                   │ http::web       │
  └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────┘

  # Default value:

  - **http=warn** if target http not specified
  - **http::web=error** if target http::web not specified

  Common operator overrides:

  # Server-error-only access logs (the new default)
  unset RUST_LOG

  # See login failures and other client errors on auth
  RUST_LOG=info,http=warn,http::api::auth=info

  # which is similar to
  RUST_LOG=info,http::api::auth=info

  # Full access log everywhere (heavy)
  RUST_LOG=info,http=info

  # Silence everything except errors
  RUST_LOG=warn
This commit is contained in:
Edouard Vanbelle
2026-06-08 08:37:16 +02:00
parent 06e4e56ce7
commit 4fc3746754
5 changed files with 438 additions and 78 deletions
+25 -2
View File
@@ -2,10 +2,11 @@ use crate::application::services::batch_operations::BatchOperationService;
use crate::common::di::AppState;
use axum::{
Router,
body::Body,
extract::{DefaultBodyLimit, State},
http::StatusCode,
response::{IntoResponse, Json as AxumJson},
routing::{delete, get, post, put},
response::{IntoResponse, Json as AxumJson, Response},
routing::{any, delete, get, post, put},
};
use serde_json::json;
use std::sync::Arc;
@@ -588,6 +589,19 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
.with_state(app_state.clone());
router = router.nest("/users", users_router);
// Collector for any unknown `/api/*` path. Without this, an
// unmatched API URL falls through Axum's matcher to the
// ServeDir fallback and is logged under `http::web` — wrong
// surface for operator triage. Adding the catch-all here
// anchors the 404 on whichever access-log layer the parent
// mount applies (i.e. `http::api`).
//
// The bare `/api/auth/*`, `/api/wopi/*`, and other more-
// specific nests are registered at higher specificity and
// still win over this catch-all — Axum's matcher prefers
// them on every overlapping request.
router = router.route("/{*rest}", any(api_not_found));
// Compression is applied once, globally, in `main.rs` with a content-type
// aware predicate that skips already-compressed media. Re-applying it here
// would double-wrap `/api`: this inner layer (no predicate) would compress
@@ -595,3 +609,12 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
// So this router only adds tracing; compression is the global layer's job.
router.layer(TraceLayer::new_for_http())
}
/// Catch-all 404 for unknown `/api/*` paths. Pure log-anchoring
/// shim — see the comment in `create_api_routes`.
async fn api_not_found() -> Response {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap()
}