Creare log in Rust e Axum con tracing
In questo articolo vediamo come usare tracing per creare dei log dentro la nostra applicazione Axum.
Salveremo i warning e gli error su file ed imposteremo anche una rotazione.
Queste le dipendenze che dobbiamo aggiungere a cargo:
cargo add tracing tracing-subscriber tracing-appender
A questo punto vi posto tutto il mio main.rs, dove c'è anche la funzione init_tracing che si occupa di inizializzare i log:
mod config;
mod controllers;
mod middleware;
mod models;
mod routes;
mod services;
mod state;
use crate::routes::anagrafiche_routes::anagrafiche_routes;
use axum::routing::get;
use axum::{Json, Router};
use config::Config;
use routes::{auth_routes::auth_routes, utenti_routes::utenti_routes};
use sqlx::mysql::MySqlPoolOptions;
use state::AppState;
use std::net::SocketAddr;
use tower_http::cors::CorsLayer;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::Layer;
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
pub struct LogGuards {
_warn: WorkerGuard,
}
pub fn init_tracing() -> LogGuards {
std::fs::create_dir_all("logs").ok();
let warn_appender = RollingFileAppender::new(Rotation::DAILY, "logs", "error.log");
let (warn_writer, guard_warn) = tracing_appender::non_blocking(warn_appender);
let warn_layer = tracing_subscriber::fmt::layer()
.with_writer(warn_writer)
.with_ansi(false)
.with_filter(tracing_subscriber::filter::LevelFilter::WARN);
let console_layer = tracing_subscriber::fmt::layer()
.with_span_events(FmtSpan::CLOSE)
.with_filter(tracing_subscriber::filter::LevelFilter::INFO);
tracing_subscriber::registry()
.with(warn_layer)
.with(console_layer)
.init();
LogGuards {
_warn: guard_warn,
}
}
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let _guards = init_tracing();
tracing::warn!("Attenzione, prova warn");
tracing::error!("Errore di prova");
dotenvy::dotenv().ok();
let config = Config::from_env();
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect(&config.database_url)
.await?;
let state = AppState { pool };
let app = Router::new()
.route("/", get(root))
.merge(utenti_routes())
.merge(auth_routes())
.merge(anagrafiche_routes())
.layer(CorsLayer::permissive())
.with_state(state);
let addr: SocketAddr = config.server_addr.parse()?;
tracing::info!("Server avviato: http://{}", addr);
axum::serve(tokio::net::TcpListener::bind(addr).await?, app).await?;
Ok(())
}
async fn root() -> Json<String> {
let version = env!("CARGO_PKG_VERSION");
Json(format!("App version: {}", version))
}
Vi ho messo degli errori di prova.
Ma volendo potete fare così in altre parti della vostra applicazione:
pub async fn get_by_utente(
State(state): State<AppState>,
user: AuthenticatedUser,
) -> Json<Vec<Anagrafica>> {
let user_id = user.claims.data.id;
match anagrafiche_service::get_by_utente(&state, user_id).await {
Ok(data) => Json(data),
Err(e) => {
error!("Errore in get_by_utente (utente_id={}): {:?}", user_id, e);
Json(vec![])
}
}
}
Enjoy!
rust axum tracing
Commentami!