diff --git a/Cargo.lock b/Cargo.lock index 85add31..4939277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -65,7 +65,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -76,7 +76,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -239,6 +239,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + [[package]] name = "cpufeatures" version = "0.2.9" @@ -290,6 +306,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" + [[package]] name = "digest" version = "0.10.7" @@ -329,25 +351,14 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -430,7 +441,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -568,6 +579,7 @@ dependencies = [ "prost", "serde", "serde_json", + "time", "tokio", "tonic 0.9.2", "tower", @@ -715,9 +727,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", "hashbrown 0.14.1", @@ -772,9 +784,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "linked-hash-map" @@ -784,9 +796,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lock_api" @@ -821,9 +833,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -1056,7 +1068,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1077,7 +1089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.1", + "indexmap 2.0.2", ] [[package]] @@ -1097,7 +1109,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1130,9 +1142,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1241,14 +1253,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.8", - "regex-syntax 0.7.5", + "regex-automata 0.4.1", + "regex-syntax 0.8.0", ] [[package]] @@ -1262,13 +1274,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.0", ] [[package]] @@ -1279,15 +1291,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.4", "bytes", @@ -1308,6 +1320,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tower-service", "url", @@ -1346,9 +1359,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "5a74ee2d7c2581cd139b42447d7d9389b889bdaad3a73f1ebb16f2a3237bb19c" dependencies = [ "bitflags 2.4.0", "errno", @@ -1401,7 +1414,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1450,9 +1463,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -1514,9 +1527,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -1529,6 +1542,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.8.0" @@ -1559,7 +1593,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1572,6 +1606,34 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +dependencies = [ + "deranged", + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1589,9 +1651,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -1623,7 +1685,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1805,7 +1867,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1983,7 +2045,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2017,7 +2079,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index dbc88fc..8498abb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ members = [ resolver = "2" [workspace.package] -rust-version = "1.72.0" edition = "2021" authors = [ "Heiko Seeberger " ] license = "Apache-2.0" @@ -27,6 +26,7 @@ opentelemetry-otlp = { version = "0.12", default-features = false, features = prost = { version = "0.11" } serde = { version = "1.0", features = [ "derive" ] } serde_json = { version = "1.0" } +time = { version = "0.3", features = [ "formatting" ] } tokio = { version = "1", features = [ "macros", "rt-multi-thread", "signal" ] } tokio-stream = { version = "0.1", features = [ "fs" ] } tonic = { version = "0.9" } diff --git a/hello-tracing-backend/Dockerfile b/hello-tracing-backend/Dockerfile index 2ae6eb4..d7bb013 100644 --- a/hello-tracing-backend/Dockerfile +++ b/hello-tracing-backend/Dockerfile @@ -1,4 +1,4 @@ -ARG RUST_VERSION=1.72.1 +ARG RUST_VERSION=1.73.0 FROM rust:${RUST_VERSION}-bullseye AS builder RUN apt-get update && \ diff --git a/hello-tracing-backend/src/main.rs b/hello-tracing-backend/src/main.rs index 3cc6dd3..89249bb 100644 --- a/hello-tracing-backend/src/main.rs +++ b/hello-tracing-backend/src/main.rs @@ -2,27 +2,42 @@ mod api; use anyhow::{Context, Result}; use configured::Configured; -use hello_tracing_common::tracing::{init_tracing, TracingConfig}; +use hello_tracing_common::{ + log_error, + tracing::{init_tracing, TracingConfig}, +}; use serde::Deserialize; +use std::panic; use tracing::{error, info}; #[tokio::main] -async fn main() -> Result<()> { - let config = Config::load().context("load configuration")?; - init_tracing(config.tracing.clone()).context("initialize tracing")?; +async fn main() { + // Load configuration first, because needed for tracing initialization. + let config = match Config::load().context("load configuration") { + Ok(config) => config, + Err(error) => { + log_error(error); + return; + } + }; - info!(?config, "starting"); + // If tracing initialization fails, nevertheless emit a structured log event. + if let Err(error) = init_tracing(config.tracing.clone()) { + log_error(error); + return; + } - let result = api::serve(config.api).await; + // Replace the default panic hook with one that uses structured logging at ERROR level. + panic::set_hook(Box::new(|panic| error!(%panic, "process panicked"))); - if let Err(error) = result { + // Run and log any error. + if let Err(error) = run(config).await { error!( error = format!("{error:#}"), backtrace = %error.backtrace(), - "hello-tracing-backend exited with ERROR" + "process exited with ERROR" ); }; - Ok(()) } #[derive(Debug, Deserialize)] @@ -31,3 +46,9 @@ struct Config { api: api::Config, tracing: TracingConfig, } + +async fn run(config: Config) -> Result<()> { + info!(?config, "starting"); + + api::serve(config.api).await +} diff --git a/hello-tracing-common/Cargo.toml b/hello-tracing-common/Cargo.toml index 953fbf3..5c0133b 100644 --- a/hello-tracing-common/Cargo.toml +++ b/hello-tracing-common/Cargo.toml @@ -21,6 +21,7 @@ opentelemetry-otlp = { workspace = true } prost = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +time = { workspace = true } tokio = { workspace = true } tonic = { workspace = true } tower = { workspace = true } diff --git a/hello-tracing-common/src/lib.rs b/hello-tracing-common/src/lib.rs index b9fc993..f539048 100644 --- a/hello-tracing-common/src/lib.rs +++ b/hello-tracing-common/src/lib.rs @@ -1,2 +1,18 @@ +use serde_json::json; +use std::fmt::Display; +use time::{format_description::well_known::Rfc3339, OffsetDateTime}; + pub mod otel; pub mod tracing; + +pub 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()); +} diff --git a/hello-tracing-common/src/tracing.rs b/hello-tracing-common/src/tracing.rs index aca5eb1..cb0d0a3 100644 --- a/hello-tracing-common/src/tracing.rs +++ b/hello-tracing-common/src/tracing.rs @@ -29,7 +29,7 @@ pub fn init_tracing(config: TracingConfig) -> Result<()> { tracing_subscriber::registry() .with(EnvFilter::from_default_env()) - .with(fmt::layer().json()) + .with(fmt::layer().json().flatten_event(true)) .with(otlp_layer(config)?) .try_init() .context("initialize tracing subscriber") diff --git a/hello-tracing-gateway/Dockerfile b/hello-tracing-gateway/Dockerfile index 238a9cb..05286da 100644 --- a/hello-tracing-gateway/Dockerfile +++ b/hello-tracing-gateway/Dockerfile @@ -1,4 +1,4 @@ -ARG RUST_VERSION=1.72.1 +ARG RUST_VERSION=1.73.0 FROM rust:${RUST_VERSION}-bullseye AS builder RUN apt-get update && \ diff --git a/hello-tracing-gateway/proto b/hello-tracing-gateway/proto index 8c61997..b5dc24b 120000 --- a/hello-tracing-gateway/proto +++ b/hello-tracing-gateway/proto @@ -1 +1 @@ -../hello-tracing-backend/proto/ \ No newline at end of file +../hello-tracing-backend/proto \ No newline at end of file diff --git a/hello-tracing-gateway/src/main.rs b/hello-tracing-gateway/src/main.rs index 7ae6b01..d729550 100644 --- a/hello-tracing-gateway/src/main.rs +++ b/hello-tracing-gateway/src/main.rs @@ -4,28 +4,42 @@ mod backend; use crate::backend::Backend; use anyhow::{Context, Result}; use configured::Configured; -use hello_tracing_common::tracing::{init_tracing, TracingConfig}; +use hello_tracing_common::{ + log_error, + tracing::{init_tracing, TracingConfig}, +}; use serde::Deserialize; +use std::panic; use tracing::{error, info}; #[tokio::main] -async fn main() -> Result<()> { - let config = Config::load().context("load configuration")?; - init_tracing(config.tracing.clone()).context("initialize tracing")?; +async fn main() { + // Load configuration first, because needed for tracing initialization. + let config = match Config::load().context("load configuration") { + Ok(config) => config, + Err(error) => { + log_error(error); + return; + } + }; - info!(?config, "starting"); + // If tracing initialization fails, nevertheless emit a structured log event. + if let Err(error) = init_tracing(config.tracing.clone()) { + log_error(error); + return; + } - let backend = Backend::new(config.backend); - let result = api::serve(config.api, backend).await; + // Replace the default panic hook with one that uses structured logging at ERROR level. + panic::set_hook(Box::new(|panic| error!(%panic, "process panicked"))); - if let Err(error) = result { + // Run and log any error. + if let Err(error) = run(config).await { error!( error = format!("{error:#}"), backtrace = %error.backtrace(), - "hello-tracing-gateway exited with ERROR" + "process exited with ERROR" ); }; - Ok(()) } #[derive(Debug, Deserialize)] @@ -35,3 +49,10 @@ struct Config { backend: backend::Config, tracing: TracingConfig, } + +async fn run(config: Config) -> Result<()> { + info!(?config, "starting"); + + let backend = Backend::new(config.backend); + api::serve(config.api, backend).await +}