summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/db.rs6
-rw-r--r--src/error.rs3
-rw-r--r--src/handlers.rs24
-rw-r--r--src/main.rs17
-rw-r--r--src/models.rs2
5 files changed, 43 insertions, 9 deletions
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<PgPool, sqlx::Error> {
- 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<ListQuery>,
) -> Result<([(HeaderName, &'static str); 2], Vec<u8>), 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<PgPool>,
AppPath(id): AppPath<Uuid>,
) -> Result<Json<MeasurementView>, 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<PgPool>,
AppPath(id): AppPath<Uuid>,
) -> Result<StatusCode, AppError> {
- 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]