Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: JSON #2

Merged
merged 5 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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"
Expand All @@ -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"]
alloy = ["dep:alloy"]
44 changes: 44 additions & 0 deletions examples/ajj.rs
Original file line number Diff line number Diff line change
@@ -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<dyn std::error::Error>> {
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(())
}
9 changes: 9 additions & 0 deletions src/utils/from_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ impl<const N: usize> FromEnvVar for alloy::primitives::FixedBytes<N> {
}
}

impl FromEnvVar for bool {
type Error = std::str::ParseBoolError;

fn from_env_var(env_var: &str) -> Result<Self, FromEnvErr<Self::Error>> {
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;
Expand Down
47 changes: 38 additions & 9 deletions src/utils/tracing.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand All @@ -8,25 +36,26 @@ 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
///
/// This function will panic if a global subscriber has already been set.
///
/// [`OtelConfig`]: crate::utils::otlp::OtelConfig
pub fn init_tracing() -> Option<OtelGuard> {
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
}
}
Loading