diff --git a/Cargo.toml b/Cargo.toml index 52e0018..9c45b1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "init4-bin-base" description = "Internal utilities for binaries produced by the init4 team" keywords = ["init4", "bin", "base"] -version = "0.1.1" +version = "0.1.2" edition = "2021" rust-version = "1.81" authors = ["init4", "James Prestwich"] @@ -16,7 +16,7 @@ repository = "https://github.com/init4tech/bin-base" # Tracing tracing = "0.1.40" tracing-core = "0.1.33" -tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] } +tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry"] } # OTLP opentelemetry_sdk = "0.28.0" @@ -35,10 +35,12 @@ thiserror = "2.0.11" alloy = { version = "0.11.1", optional = true, default-features = false, features = ["std"] } [dev-dependencies] +ajj = "0.3.1" +axum = "0.8.1" serial_test = "3.2.0" signal-hook = "0.3.17" tokio = { version = "1.43.0", features = ["macros"] } [features] default = ["alloy"] -alloy = ["dep:alloy"] \ No newline at end of file +alloy = ["dep:alloy"] diff --git a/examples/ajj.rs b/examples/ajj.rs new file mode 100644 index 0000000..0ee032e --- /dev/null +++ b/examples/ajj.rs @@ -0,0 +1,44 @@ +//! This example allows you to play with ajj instrumentation. +//! +//! ## Observing traces +//! +//! We recommend the following: +//! - set `RUST_LOG=info` (or `trace` for more detail) to see log lines +//! - use [otel-desktop-viewer](https://github.com/CtrlSpice/otel-desktop-viewer) +//! +//! ## Running this example +//! +//! ```no_compile +//! export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318" +//! export OTEL_TRACES_EXPORTER="otlp" +//! export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" +//! export RUST_LOG=info +//! cargo run --example ajj +//! ``` +//! +//! ```no_compile +//! curl -X POST \ +//! -H 'Content-Type: application/json' \ +//! -d '{"jsonrpc":"2.0","id":"id","method":"helloWorld"}' \ +//! http://localhost:8080/rpc +//! ``` +use ajj::Router; +use init4_bin_base::init4; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let _guard = init4(); + + let router = Router::<()>::new() + .route("helloWorld", || async { + tracing::info!("serving hello world"); + Ok::<_, ()>("Hello, world!") + }) + .into_axum("/rpc"); + + let listener = tokio::net::TcpListener::bind("localhost:8080") + .await + .unwrap(); + axum::serve(listener, router).await.unwrap(); + Ok(()) +} diff --git a/src/utils/from_env.rs b/src/utils/from_env.rs index 8e30ebe..7815a19 100644 --- a/src/utils/from_env.rs +++ b/src/utils/from_env.rs @@ -179,6 +179,15 @@ impl FromEnvVar for alloy::primitives::FixedBytes { } } +impl FromEnvVar for bool { + type Error = std::str::ParseBoolError; + + fn from_env_var(env_var: &str) -> Result> { + let s: String = std::env::var(env_var).map_err(|e| FromEnvErr::env_err(env_var, e))?; + Ok(!s.is_empty()) + } +} + #[cfg(test)] mod test { use std::time::Duration; diff --git a/src/utils/tracing.rs b/src/utils/tracing.rs index 095988b..57b204b 100644 --- a/src/utils/tracing.rs +++ b/src/utils/tracing.rs @@ -1,5 +1,33 @@ -use crate::utils::otlp::{OtelConfig, OtelGuard}; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; +use crate::utils::{ + from_env::FromEnvVar, + otlp::{OtelConfig, OtelGuard}, +}; +use tracing_subscriber::{filter::EnvFilter, layer::SubscriberExt, util::SubscriberInitExt, Layer}; + +const TRACING_LOG_JSON: &str = "TRACING_LOG_JSON"; + +/// Install a format layer based on the `TRACING_LOG_JSON` environment +/// variable, and then install the registr +/// +macro_rules! install_fmt { + (json @ $registry:ident, $filter:ident) => {{ + let fmt = tracing_subscriber::fmt::layer().json().with_filter($filter); + $registry.with(fmt).init(); + }}; + (log @ $registry:ident, $filter:ident) => {{ + let fmt = tracing_subscriber::fmt::layer().with_filter($filter); + $registry.with(fmt).init(); + }}; + ($registry:ident) => {{ + let json = bool::from_env_var(TRACING_LOG_JSON).unwrap_or(false); + let filter = EnvFilter::from_default_env(); + if json { + install_fmt!(json @ $registry, filter); + } else { + install_fmt!(log @ $registry, filter); + } + }}; +} /// Init tracing, returning an optional guard for the OTEL provider. /// @@ -8,7 +36,10 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; /// environment variables are set, it will initialize the OTEL provider /// with the specified configuration, as well as the `fmt` layer. /// -/// See [`OtelConfig`] documentation for env var information. +/// ## Env Reads +/// +/// - `TRACING_LOG_JSON` - If set, will enable JSON logging. +/// - As [`OtelConfig`] documentation for env var information. /// /// ## Panics /// @@ -16,17 +47,15 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer}; /// /// [`OtelConfig`]: crate::utils::otlp::OtelConfig pub fn init_tracing() -> Option { - let registry = tracing_subscriber::registry().with( - tracing_subscriber::fmt::layer() - .with_filter(tracing_subscriber::filter::EnvFilter::from_default_env()), - ); + let registry = tracing_subscriber::registry(); if let Some(cfg) = OtelConfig::load() { let guard = cfg.provider(); - registry.with(guard.layer()).init(); + let registry = registry.with(guard.layer()); + install_fmt!(registry); Some(guard) } else { - registry.init(); + install_fmt!(registry); None } }