feat: add tracing
This commit is contained in:
parent
653502c470
commit
93140e7d22
8 changed files with 431 additions and 174 deletions
|
|
@ -1,3 +1,4 @@
|
|||
pub mod configuration;
|
||||
pub mod routes;
|
||||
pub mod startup;
|
||||
pub mod telemetry;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use env_logger::Env;
|
||||
use learn_axum::configuration::get_configuration;
|
||||
use learn_axum::startup;
|
||||
use learn_axum::telemetry::{get_subscriber, init_subscriber};
|
||||
use sqlx::PgPool;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
|
@ -8,7 +8,9 @@ use tokio::net::TcpListener;
|
|||
/// Entry point for the application.
|
||||
/// Log level default can be overridden with the RUST_LOG environment variable.
|
||||
async fn main() {
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
let subscriber = get_subscriber("learn_axum".into(), "info".into(), std::io::stdout);
|
||||
init_subscriber(subscriber);
|
||||
|
||||
let configuration = get_configuration().expect("Failed to read configuration.");
|
||||
let addr = format!("127.0.0.1:{}", configuration.application_port);
|
||||
let listener = TcpListener::bind(addr).await.unwrap(); //.expect("Unable to bind to port");
|
||||
|
|
|
|||
|
|
@ -13,23 +13,36 @@ struct FormData {
|
|||
name: String,
|
||||
}
|
||||
|
||||
async fn subscribe(State(pool): State<PgPool>, Form(form): Form<FormData>) {
|
||||
let request_id = Uuid::new_v4();
|
||||
tracing::info!(
|
||||
"request_id {} - Adding '{}' '{}' as a new subscriber.",
|
||||
request_id,
|
||||
form.email,
|
||||
form.name
|
||||
);
|
||||
tracing::info!(
|
||||
"request_id {} - Saving new subscriber details in the database",
|
||||
request_id
|
||||
);
|
||||
match sqlx::query!(
|
||||
#[tracing::instrument(
|
||||
name = "Adding a new subscriber",
|
||||
skip(form, pool),
|
||||
fields(
|
||||
request_id = %Uuid::new_v4(),
|
||||
subscriber_email = %form.email,
|
||||
subscriber_name = %form.name
|
||||
)
|
||||
)]
|
||||
pub async fn subscribe(State(pool): State<PgPool>, Form(form): Form<FormData>) {
|
||||
match insert_subscriber(&pool, &form).await {
|
||||
Ok(_) => {
|
||||
tracing::info!("Subscriber added to the database");
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::error!("Failed to add subscriber to the database");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Saving new subscriber details in the database",
|
||||
skip(form, pool)
|
||||
)]
|
||||
pub async fn insert_subscriber(pool: &PgPool, form: &FormData) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO subscriptions (id, email, name, subscribed_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
"#,
|
||||
INSERT INTO subscriptions (id, email, name, subscribed_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
"#,
|
||||
Uuid::new_v4(),
|
||||
form.email,
|
||||
form.name,
|
||||
|
|
@ -37,23 +50,13 @@ async fn subscribe(State(pool): State<PgPool>, Form(form): Form<FormData>) {
|
|||
)
|
||||
// We use `get_ref` to get an immutable reference to the `PgConnection`
|
||||
// wrapped by `web::Data`.
|
||||
.execute(&pool)
|
||||
.execute(pool)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
tracing::info!(
|
||||
"request_id {} - New subscriber details have been saved",
|
||||
request_id
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"request_id {} - Failed to execute query: {:?}",
|
||||
request_id,
|
||||
e
|
||||
);
|
||||
}
|
||||
};
|
||||
.map_err(|e| {
|
||||
tracing::error!("Failed to execute query: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn routes_subscriptions(pool: PgPool) -> Router {
|
||||
|
|
|
|||
35
src/telemetry.rs
Normal file
35
src/telemetry.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use tracing::{subscriber::set_global_default, Subscriber};
|
||||
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::fmt::MakeWriter;
|
||||
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
|
||||
|
||||
pub fn get_subscriber<Sink>(
|
||||
name: String,
|
||||
env_filter: String,
|
||||
sink: Sink,
|
||||
) -> impl Subscriber + Sync + Send
|
||||
where
|
||||
// This "weird" syntax is a higher-ranked trait bound (HRTB)
|
||||
// It basically means that Sink implements the `MakeWriter`
|
||||
// trait for all choices of the lifetime parameter `'a`
|
||||
// Check out https://doc.rust-lang.org/nomicon/hrtb.html
|
||||
// for more details.
|
||||
Sink: for<'a> MakeWriter<'a> + Send + Sync + 'static,
|
||||
{
|
||||
let env_filter =
|
||||
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter));
|
||||
let formatting_layer = BunyanFormattingLayer::new(name, sink);
|
||||
Registry::default()
|
||||
.with(env_filter)
|
||||
.with(JsonStorageLayer)
|
||||
.with(formatting_layer)
|
||||
}
|
||||
|
||||
/// Register a subscriber as global default to process span data.
|
||||
///
|
||||
/// It should only be called once!
|
||||
pub fn init_subscriber(subscriber: impl Subscriber + Send + Sync) {
|
||||
LogTracer::init().expect("Failed to set logger");
|
||||
set_global_default(subscriber).expect("Failed to set subscriber");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue