From e45e9fa8b50daa028233fd739fe96a3bdc8ec54b Mon Sep 17 00:00:00 2001 From: batsumaru <> Date: Fri, 16 Oct 2026 16:18:02 +0900 Subject: Add more logging --- src/db.rs | 6 ++++-- src/error.rs | 3 +++ src/handlers.rs | 24 +++++++++++++++++++++++- src/main.rs | 17 ++++++++++++----- src/models.rs | 2 +- 5 files changed, 43 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/db.rs b/src/db.rs index 7e3610b..21c7db4 100644 --- a/src/db.rs +++ b/src/db.rs @@ -4,8 +4,10 @@ use std::env; const DATABASE_URL_FALLBACK: &str = "postgres://health:health@127.0.0.1:5432/health"; pub async fn connect() -> Result { - let database_url = - env::var("DATABASE_URL").unwrap_or_else(|_| DATABASE_URL_FALLBACK.to_string()); + let database_url = env::var("DATABASE_URL").unwrap_or_else(|_| { + tracing::warn!("DATABASE_URL not set, falling back to the default local database"); + DATABASE_URL_FALLBACK.to_string() + }); PgPoolOptions::new() .max_connections(5) .connect(&database_url) diff --git a/src/error.rs b/src/error.rs index d16106a..6bc4fc5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -76,6 +76,9 @@ impl IntoResponse for AppError { AppError::NotFound => (StatusCode::NOT_FOUND, "not found".to_owned()), AppError::Rejection(status, message) => (status, message), }; + if status.is_client_error() { + tracing::debug!(%status, error = %message, "request failed"); + } (status, Json(json!({ "error": message }))).into_response() } } diff --git a/src/handlers.rs b/src/handlers.rs index 7067f3a..9ae87c3 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -29,6 +29,7 @@ pub async fn export_measurements( AppQuery(query): AppQuery, ) -> Result<([(HeaderName, &'static str); 2], Vec), AppError> { let rows = fetch_measurements(&pool, &query).await?; + tracing::info!(count = rows.len(), "exporting measurements"); let mut writer = csv::WriterBuilder::new() .has_headers(false) .from_writer(Vec::new()); @@ -65,6 +66,14 @@ async fn fetch_measurements( { return Err(AppError::BadRequest("from must not be after to")); } + tracing::debug!( + from = ?query.from, + to = ?query.to, + metric_type = ?query.metric_type, + limit = ?limit, + order = ?query.order, + "fetching measurements" + ); // SQL can't bind ASC/DESC as a parameter. The CASE yields measured_at only when // `order` is desc (sorted DESC) and NULL otherwise, so that key ties for every // row and the ASC key decides the order. If this gets slow, use an if/else with a @@ -88,6 +97,7 @@ async fn fetch_measurements( ) .fetch_all(pool) .await?; + tracing::debug!(count = rows.len(), "fetched measurements"); Ok(rows) } @@ -110,6 +120,11 @@ pub async fn create_measurement( ) .fetch_one(&pool) .await?; + tracing::info!( + id = %measurement.id, + metric_type = ?measurement.metric_type, + "created measurement" + ); let location = format!("/measurements/{}", measurement.id); Ok(( StatusCode::CREATED, @@ -122,6 +137,7 @@ pub async fn get_measurement( State(pool): State, AppPath(id): AppPath, ) -> Result, AppError> { + tracing::debug!(%id, "fetching measurement"); let measurement = sqlx::query_as!( MeasurementView, " @@ -160,6 +176,7 @@ pub async fn update_measurement( if result.rows_affected() == 0 { return Err(AppError::NotFound); } + tracing::info!(%id, "updated measurement"); Ok(StatusCode::NO_CONTENT) } @@ -167,9 +184,14 @@ pub async fn delete_measurement( State(pool): State, AppPath(id): AppPath, ) -> Result { - sqlx::query!("DELETE FROM measurement WHERE id = $1", id) + let result = sqlx::query!("DELETE FROM measurement WHERE id = $1", id) .execute(&pool) .await?; + if result.rows_affected() == 0 { + tracing::debug!(%id, "measurement to delete did not exist"); + } else { + tracing::info!(%id, "deleted measurement"); + } Ok(StatusCode::NO_CONTENT) } diff --git a/src/main.rs b/src/main.rs index 4f34c0c..91d56b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use std::env; use axum::{Router, routing::get}; use dotenvy::dotenv; use sqlx::PgPool; +use tracing_subscriber::EnvFilter; use crate::error::AppError; @@ -38,14 +39,20 @@ fn router(pool: PgPool) -> Router { #[tokio::main] async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt::init(); dotenv().ok(); + tracing_subscriber::fmt() + .with_env_filter( + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")), + ) + .init(); let pool = db::connect().await?; + tracing::info!("connected to database"); let app = router(pool); - let listener = tokio::net::TcpListener::bind( - env::var("HEALTH_BIND_ADDRESS").unwrap_or_else(|_| BIND_ADDRESS_FALLBACK.to_string()), - ) - .await?; + let bind_address = env::var("HEALTH_BIND_ADDRESS").unwrap_or_else(|_| { + tracing::info!("HEALTH_BIND_ADDRESS not set, falling back to {BIND_ADDRESS_FALLBACK}"); + BIND_ADDRESS_FALLBACK.to_string() + }); + let listener = tokio::net::TcpListener::bind(bind_address).await?; tracing::info!("listening at {}", listener.local_addr()?); axum::serve(listener, app).await?; Ok(()) diff --git a/src/models.rs b/src/models.rs index 480ef2f..c23dab7 100644 --- a/src/models.rs +++ b/src/models.rs @@ -87,7 +87,7 @@ pub struct MetricUnitPair { pub unit: Unit, } -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Debug)] #[serde(rename_all = "lowercase")] pub enum Order { #[default] -- cgit v1.3