diff --git a/Cargo.lock b/Cargo.lock index 365e1ff..d0b2f5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1095,6 +1095,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5feffc321035ad94088a7e5333abb4d84a8726e54a802e736ce9dd7237e85b" +dependencies = [ + "log", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "opentelemetry-http" version = "0.27.0" @@ -1149,6 +1163,23 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc1b6902ff63b32ef6c489e8048c5e253e2e4a803ea3ea7e783914536eb15c52" +[[package]] +name = "opentelemetry-stdout" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8a298402aa5c260be90d10dc54b5a7d4e1025c354848f8e2c976d761351049" +dependencies = [ + "async-trait", + "chrono", + "futures-util", + "opentelemetry", + "opentelemetry_sdk", + "ordered-float", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "opentelemetry_sdk" version = "0.27.0" @@ -1171,6 +1202,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "ordered-float" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65ee1f9701bf938026630b455d5315f490640234259037edb259798b3bcf85e" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -1226,9 +1266,12 @@ dependencies = [ "clap", "dropshot", "http", + "once_cell", "opentelemetry", + "opentelemetry-appender-tracing", "opentelemetry-otlp", "opentelemetry-semantic-conventions", + "opentelemetry-stdout", "opentelemetry_sdk", "schemars", "serde", @@ -1237,6 +1280,7 @@ dependencies = [ "tokio", "tracing", "tracing-chrome", + "tracing-core", "tracing-opentelemetry", "tracing-slog", "tracing-subscriber", @@ -2094,9 +2138,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", diff --git a/controller/Cargo.toml b/controller/Cargo.toml index 7762979..f268acb 100644 --- a/controller/Cargo.toml +++ b/controller/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "patagia-controller" +description = "Patagia controller server" version = "0.1.0" edition = "2021" license = "MPL-2.0" @@ -23,6 +24,10 @@ opentelemetry_sdk = { version = "0.27.0", features = ["rt-tokio"] } opentelemetry-otlp = { version = "0.27.0", features = ["http-proto", "hyper-client", "opentelemetry-http", "trace"] } opentelemetry = "0.27.0" opentelemetry-semantic-conventions = "0.27.0" +tracing-core = "0.1.33" +opentelemetry-appender-tracing = { version = "0.27.0", features = ["log", "experimental_metadata_attributes"] } +opentelemetry-stdout = "0.27.0" +once_cell = "1.20.2" [[bin]] name = "patagia-controller" diff --git a/controller/src/main.rs b/controller/src/bin/patagia-controller.rs similarity index 56% rename from controller/src/main.rs rename to controller/src/bin/patagia-controller.rs index a3d7216..0c4719b 100644 --- a/controller/src/main.rs +++ b/controller/src/bin/patagia-controller.rs @@ -4,27 +4,17 @@ use dropshot::{ endpoint, ApiDescription, ConfigDropshot, HttpError, HttpResponseOk, RequestContext, ServerBuilder, }; -use opentelemetry::{trace::TracerProvider as _, KeyValue}; -use opentelemetry_otlp::WithExportConfig; -use opentelemetry_sdk::{ - trace::{RandomIdGenerator, Sampler}, - Resource, -}; -use opentelemetry_semantic_conventions::{ - attribute::{SERVICE_NAME, SERVICE_VERSION}, - SCHEMA_URL, -}; use schemars::JsonSchema; use serde::Serialize; use slog::Drain; -use tracing_opentelemetry::OpenTelemetryLayer; use tracing_slog::TracingSlogDrain; -use tracing_subscriber::prelude::*; use std::net::SocketAddr; use std::str::FromStr; use std::sync::Arc; +use patagia_controller::instrumentation; + #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Cli {} @@ -66,44 +56,16 @@ async fn api_version( #[tokio::main] async fn main() -> Result<()> { let _args = Cli::parse(); - let fmt_layer = tracing_subscriber::fmt::layer(); - - let otlp_exporter = opentelemetry_otlp::SpanExporter::builder() - .with_tonic() - .with_endpoint("https://localhost:4317") - .build() - .map_err(|e| anyhow!("Error creating OTLP exporter: {:?}", e))?; - - let resource = Resource::from_schema_url( - [ - KeyValue::new(SERVICE_NAME, env!("CARGO_PKG_NAME")), - KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")), - ], - SCHEMA_URL, - ); - - let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder() - .with_config( - opentelemetry_sdk::trace::Config::default() - .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( - 1.0, - )))) - .with_id_generator(RandomIdGenerator::default()) - .with_resource(resource), - ) - .with_batch_exporter(otlp_exporter, opentelemetry_sdk::runtime::Tokio) - .build(); - - let tracer = tracer_provider.tracer("patagia-controller"); - - tracing_subscriber::registry() - .with(tracing_subscriber::EnvFilter::from_default_env()) - .with(fmt_layer) - .with(OpenTelemetryLayer::new(tracer)) - .init(); + let _tracing = instrumentation::init_tracing_subscriber()?; tracing::info!("Patagia Controller"); + tracing::debug!("Starting server"); + + tracing::error!(name: "my-event-name", target: "my-system", event_id = 20, user_name = "otel", user_email = "otel@opentelemetry.io", message = "This is an example message"); + + foo().await; + let mut api = ApiDescription::new(); api.register(api_version).unwrap(); @@ -126,3 +88,15 @@ async fn main() -> Result<()> { .await .map_err(|e| anyhow!(e)) } + +#[tracing::instrument] +async fn foo() { + tracing::info!( + monotonic_counter.foo = 1_u64, + key_1 = "bar", + key_2 = 10, + "handle foo", + ); + + tracing::info!(histogram.baz = 10, "histogram example",); +} diff --git a/controller/src/instrumentation.rs b/controller/src/instrumentation.rs new file mode 100644 index 0000000..eadba53 --- /dev/null +++ b/controller/src/instrumentation.rs @@ -0,0 +1,126 @@ +use anyhow::{anyhow, Result}; +use once_cell::sync::Lazy; +use opentelemetry::{trace::TracerProvider as _, KeyValue}; +use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; +use opentelemetry_sdk::{ + logs::LoggerProvider, + metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, + runtime, + trace::{RandomIdGenerator, Sampler, TracerProvider}, + Resource, +}; +use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; + +static RESOURCE: Lazy = Lazy::new(|| { + Resource::new(vec![ + KeyValue::new( + opentelemetry_semantic_conventions::resource::SERVICE_NAME, + env!("CARGO_PKG_NAME"), + ), + KeyValue::new( + opentelemetry_semantic_conventions::resource::SERVICE_VERSION, + env!("CARGO_PKG_VERSION"), + ), + ]) +}); + +// Construct LoggingProdiver for LoggingLayer +fn init_logging_provider() -> Result { + let exporter = opentelemetry_otlp::LogExporter::builder() + .with_tonic() + .build()?; + let logging_provider: LoggerProvider = LoggerProvider::builder() + .with_resource(RESOURCE.clone()) + .with_batch_exporter(exporter, runtime::Tokio) + .build(); + Ok(logging_provider) +} + +// Construct MeterProvider for MetricsLayer +fn init_meter_provider() -> Result { + let exporter = opentelemetry_otlp::MetricExporter::builder() + .with_tonic() + .with_temporality(opentelemetry_sdk::metrics::Temporality::default()) + .build() + .map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?; + + let meter_provider = MeterProviderBuilder::default() + .with_resource(RESOURCE.clone()) + .with_reader( + PeriodicReader::builder(exporter, runtime::Tokio) + .with_interval(std::time::Duration::from_secs(10)) + .build(), + ) + .build(); + + opentelemetry::global::set_meter_provider(meter_provider.clone()); + + Ok(meter_provider) +} + +// Construct TracerProvider for OpenTelemetryLayer +fn init_tracer_provider() -> Result { + let exporter = opentelemetry_otlp::SpanExporter::builder() + .with_tonic() + .build() + .map_err(|e| anyhow!("Error creating OTLP span exporter: {:?}", e))?; + + let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder() + .with_config( + opentelemetry_sdk::trace::Config::default() + .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( + 1.0, + )))) + .with_id_generator(RandomIdGenerator::default()) + .with_resource(RESOURCE.clone()), + ) + .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio) + .build(); + + Ok(tracer_provider) +} + +// Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing +pub fn init_tracing_subscriber() -> Result { + let logging_provider = init_logging_provider()?; + let meter_provider = init_meter_provider()?; + let tracer_provider = init_tracer_provider()?; + + let tracer = tracer_provider.tracer("tracing-otel-subscriber"); + + tracing_subscriber::registry() + .with(tracing_subscriber::EnvFilter::from_default_env()) + .with(tracing_subscriber::fmt::layer()) + .with(MetricsLayer::new(meter_provider.clone())) + .with(OpenTelemetryLayer::new(tracer)) + .with(OpenTelemetryTracingBridge::new(&logging_provider)) + .init(); + + Ok(OtelGuard { + logging_provider, + meter_provider, + tracer_provider, + }) +} + +pub struct OtelGuard { + logging_provider: LoggerProvider, + meter_provider: SdkMeterProvider, + tracer_provider: TracerProvider, +} + +impl Drop for OtelGuard { + fn drop(&mut self) { + if let Err(err) = self.tracer_provider.shutdown() { + eprintln!("{err:?}"); + } + if let Err(err) = self.logging_provider.shutdown() { + eprintln!("{err:?}"); + } + if let Err(err) = self.meter_provider.shutdown() { + eprintln!("{err:?}"); + } + } +} diff --git a/controller/src/lib.rs b/controller/src/lib.rs new file mode 100644 index 0000000..9b48f64 --- /dev/null +++ b/controller/src/lib.rs @@ -0,0 +1 @@ +pub mod instrumentation; diff --git a/justfile b/justfile index b5d44be..ce7b418 100644 --- a/justfile +++ b/justfile @@ -5,7 +5,7 @@ default: @just --choose # Run controller -run-controller $RUST_LOG="debug": +run-controller $RUST_LOG="debug,h2=info,hyper_util=info,tower=info": cargo run --package patagia-controller # Run controller local development