finished logging chapter
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
use config::Config;
|
||||
use secrecy::{ExposeSecret, Secret};
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct Settings {
|
||||
@ -9,25 +10,25 @@ pub struct Settings {
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct DatabaseSettings {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub password: Secret<String>,
|
||||
pub port: u16,
|
||||
pub host: String,
|
||||
pub database_name: String,
|
||||
}
|
||||
|
||||
impl DatabaseSettings {
|
||||
pub fn connection_string(&self) -> String {
|
||||
format!(
|
||||
pub fn connection_string(&self) -> Secret<String> {
|
||||
Secret::new(format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
self.username, self.password, self.host, self.port, self.database_name
|
||||
)
|
||||
self.username, self.password.expose_secret(), self.host, self.port, self.database_name
|
||||
))
|
||||
}
|
||||
|
||||
pub fn connection_string_without_db(&self) -> String {
|
||||
format!(
|
||||
pub fn connection_string_without_db(&self) -> Secret<String> {
|
||||
Secret::new(format!(
|
||||
"postgres://{}:{}@{}:{}",
|
||||
self.username, self.password, self.host, self.port
|
||||
)
|
||||
self.username, self.password.expose_secret(), self.host, self.port
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod configuration;
|
||||
pub mod routes;
|
||||
pub mod startup;
|
||||
pub mod telemetry;
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
use std::net::TcpListener;
|
||||
use secrecy::ExposeSecret;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use zero2prod::configuration::get_configuration;
|
||||
use zero2prod::startup::run;
|
||||
use zero2prod::telemetry::{get_subscriber, init_subscriber};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let subscriber = get_subscriber("zero2prod".into(), "info".into(), std::io::stdout);
|
||||
init_subscriber(subscriber);
|
||||
|
||||
let config = get_configuration().expect("Failed to read configuration");
|
||||
let connection_pool = PgPoolOptions::new()
|
||||
.max_connections(10).connect(&config.database.connection_string()).await.expect("Failed to connect to Postgres.");
|
||||
.max_connections(10).connect(config.database.connection_string().expose_secret()).await.expect("Failed to connect to Postgres.");
|
||||
|
||||
let address = format!("127.0.0.1:{}", config.application_port);
|
||||
let listener = TcpListener::bind(address).expect("Failed to bind random port");
|
||||
|
||||
@ -10,8 +10,28 @@ pub struct FormData {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Adding a new subscriber",
|
||||
skip(form, connection_pool),
|
||||
fields(
|
||||
subscriber_email = %form.email,
|
||||
subscriber_name = %form.name
|
||||
)
|
||||
)]
|
||||
pub async fn subscribe(form: web::Form<FormData>, connection_pool: web::Data<Pool<Postgres>>) -> HttpResponse {
|
||||
match query!(
|
||||
match insert_subscriber(&form, &connection_pool).await
|
||||
{
|
||||
Ok(_) => HttpResponse::Ok().finish(),
|
||||
Err(_) => HttpResponse::InternalServerError().finish(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Saving new subscriber details in the database",
|
||||
skip(form, connection_pool)
|
||||
)]
|
||||
async fn insert_subscriber(form: &FormData, connection_pool: &Pool<Postgres>) -> Result<(), sqlx::Error> {
|
||||
query!(
|
||||
r#"
|
||||
INSERT INTO subscriptions (id, email, name, subscribed_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
@ -21,12 +41,11 @@ pub async fn subscribe(form: web::Form<FormData>, connection_pool: web::Data<Poo
|
||||
form.name,
|
||||
Utc::now()
|
||||
)
|
||||
.execute(connection_pool.get_ref())
|
||||
.await {
|
||||
Ok(_) => HttpResponse::Ok().finish(),
|
||||
Err(e) => {
|
||||
println!("Failed to execute query: {:?}", e);
|
||||
HttpResponse::InternalServerError().finish()
|
||||
}
|
||||
}
|
||||
.execute(connection_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Failed to execute query: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use actix_web::dev::Server;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tracing_actix_web::TracingLogger;
|
||||
use std::net::TcpListener;
|
||||
|
||||
use crate::routes::{health_check, subscribe};
|
||||
@ -9,6 +10,7 @@ pub fn run(listener: TcpListener, connection_pool: Pool<Postgres>) -> Result<Ser
|
||||
let connection_pool = web::Data::new(connection_pool);
|
||||
let server = HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(TracingLogger::default())
|
||||
.route("/health_check", web::get().to(health_check))
|
||||
.route("/subscriptions", web::post().to(subscribe))
|
||||
.app_data(connection_pool.clone())
|
||||
|
||||
20
src/telemetry.rs
Normal file
20
src/telemetry.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// use std::io::Sink;
|
||||
// use tokio::io::Sink;
|
||||
|
||||
use tracing::dispatcher::set_global_default;
|
||||
use tracing::Subscriber;
|
||||
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{fmt::MakeWriter, prelude::*, registry::Registry, EnvFilter};
|
||||
|
||||
pub fn get_subscriber<Sink>(name: String, env_filter: String, sink: Sink) -> impl Subscriber + Send + Sync
|
||||
where Sink: for <'a> MakeWriter<'a> + Send + Sync + 'static {
|
||||
let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new(env_filter));
|
||||
let formatting_layer = BunyanFormattingLayer::new(name, sink);
|
||||
Registry::default().with(env_filter).with(JsonStorageLayer).with(formatting_layer)
|
||||
}
|
||||
|
||||
pub fn init_subscriber(subscriber: impl Subscriber + Send + Sync) {
|
||||
LogTracer::init().expect("Failed to set logger.");
|
||||
set_global_default(subscriber.into()).expect("Failed to set subscriber.");
|
||||
}
|
||||
Reference in New Issue
Block a user