Skip to content

Commit

Permalink
fix: service does not log errors to the console
Browse files Browse the repository at this point in the history
fix #2
  • Loading branch information
emmysteven committed Aug 24, 2024
1 parent cdfcb0b commit 79151bb
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 57 deletions.
51 changes: 6 additions & 45 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,12 @@ use mailpass::run_server;
use anyhow::{Context, Result};
use configured::Configured;
use serde::Deserialize;
use serde_json::json;
use std::{fmt::Display, panic};
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
use tracing::error;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

#[tokio::main]
async fn main() {
// If tracing initialization fails, nevertheless emit a structured log event.
let result = init_tracing();
if let Err(ref error) = result {
log_error(error);
return;
};

// Replace the default panic hook with one that uses structured logging at ERROR level.
panic::set_hook(Box::new(|panic| error!(%panic, "process panicked")));

// Run and log any error.
if let Err(ref error) = run().await {
error!(
error = format!("{error:#}"),
backtrace = %error.backtrace(),
"process exited with ERROR"
);
if let Err(e) = run().await {
eprintln!("Application error: {:?}", e);
std::process::exit(1);
}
}

Expand All @@ -37,30 +18,10 @@ struct Config {
run_server: mailpass::Config,
}

fn init_tracing() -> Result<()> {
tracing_subscriber::registry()
.with(EnvFilter::from_default_env())
.with(fmt::layer().json().flatten_event(true))
.try_init()
.context("initialize tracing subscriber")
}

fn log_error(error: &impl Display) {
let now = OffsetDateTime::now_utc().format(&Rfc3339).unwrap();
let error = serde_json::to_string(&json!({
"timestamp": now,
"level": "ERROR",
"message": "process exited with ERROR",
"error": format!("{error:#}")
}));
// Not using `eprintln!`, because `tracing_subscriber::fmt` uses stdout by default.
println!("{}", error.unwrap());
}

async fn run() -> Result<()> {
let config = Config::load().context("load configuration")?;

// info!(?config, "starting");

run_server(config.run_server).await
run_server(config.run_server)
.await
.context("Failed to run server")
}
31 changes: 19 additions & 12 deletions backend/src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
use axum::{
body::Body,
http::{Request, StatusCode},
http::StatusCode,
routing::{get, post},
Json, Router,
};
use serde_json::json;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;
use tracing::{field, info_span, Span};
use tower_http::cors::{Any, CorsLayer};
use tower_http::trace::{self, TraceLayer};
use tracing::Level;

use crate::services::email_validator::validate_email;

pub fn setup_routes() -> Router {
tracing_subscriber::fmt()
.with_target(false)
.compact()
.init();

Router::new()
.route("/", get(home))
.route("/email", post(validate_email))
.route("/health", get(health))
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http().make_span_with(make_span)))
.route("/error", get(error))
.layer(
TraceLayer::new_for_http()
.make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO))
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
)
}

async fn home() -> Json<serde_json::Value> {
Expand All @@ -26,12 +35,10 @@ async fn home() -> Json<serde_json::Value> {
Json(response)
}

async fn health() -> StatusCode {
StatusCode::NO_CONTENT
async fn health() -> Result<&'static str, StatusCode> {
Ok("Service is up and running")
}

fn make_span(request: &Request<Body>) -> Span {
let headers = request.headers();
let path = request.uri().path();
info_span!("incoming request", path, ?headers, trace_id = field::Empty)
async fn error() -> Result<&'static str, StatusCode> {
Err(StatusCode::SERVICE_UNAVAILABLE)
}

0 comments on commit 79151bb

Please sign in to comment.