diff --git a/justfile b/justfile index 668f0d0..9e0cf1c 100644 --- a/justfile +++ b/justfile @@ -33,6 +33,9 @@ test-unit: # run integration tests test-integration: install-crd cargo test -- --ignored +# run telemetry tests +test-telemetry: + OPENTELEMETRY_ENDPOINT_URL=https://0.0.0.0:55680 cargo test --lib --all-features -- get_trace_id_returns_valid_traces --ignored # compile for musl (for docker image) compile features="": diff --git a/src/main.rs b/src/main.rs index 00743de..dd64f5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ #![allow(unused_imports, unused_variables)] use actix_web::{get, middleware, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder}; -pub use controller::{self, Result, State}; +pub use controller::{self, telemetry, Result, State}; use prometheus::{Encoder, TextEncoder}; -use tracing::{debug, error, info, trace, warn}; -use tracing_subscriber::{prelude::*, EnvFilter, Registry}; #[get("/metrics")] async fn metrics(c: Data, _req: HttpRequest) -> impl Responder { @@ -27,22 +25,7 @@ async fn index(c: Data, _req: HttpRequest) -> impl Responder { #[tokio::main] async fn main() -> Result<()> { - // Setup tracing layers - #[cfg(feature = "telemetry")] - let telemetry = tracing_opentelemetry::layer().with_tracer(controller::telemetry::init_tracer().await); - let logger = tracing_subscriber::fmt::layer(); - let env_filter = EnvFilter::try_from_default_env() - .or_else(|_| EnvFilter::try_new("info")) - .unwrap(); - - // Decide on layers - #[cfg(feature = "telemetry")] - let collector = Registry::default().with(telemetry).with(logger).with(env_filter); - #[cfg(not(feature = "telemetry"))] - let collector = Registry::default().with(logger).with(env_filter); - - // Initialize tracing - tracing::subscriber::set_global_default(collector).unwrap(); + telemetry::init().await; // Initiatilize Kubernetes controller state let state = State::default(); diff --git a/src/telemetry.rs b/src/telemetry.rs index b8e32b6..f100588 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -1,4 +1,5 @@ use opentelemetry::trace::TraceId; +use tracing_subscriber::{prelude::*, EnvFilter, Registry}; /// Fetch an opentelemetry::trace::TraceId as hex through the full tracing stack pub fn get_trace_id() -> TraceId { @@ -13,7 +14,7 @@ pub fn get_trace_id() -> TraceId { } #[cfg(feature = "telemetry")] -pub async fn init_tracer() -> opentelemetry::sdk::trace::Tracer { +async fn init_tracer() -> opentelemetry::sdk::trace::Tracer { let otlp_endpoint = std::env::var("OPENTELEMETRY_ENDPOINT_URL").expect("Need a otel tracing collector configured"); @@ -35,3 +36,41 @@ pub async fn init_tracer() -> opentelemetry::sdk::trace::Tracer { .install_batch(opentelemetry::runtime::Tokio) .unwrap() } + +/// Initialize tracing +pub async fn init() { + // Setup tracing layers + #[cfg(feature = "telemetry")] + let telemetry = tracing_opentelemetry::layer().with_tracer(init_tracer().await); + let logger = tracing_subscriber::fmt::layer(); + let env_filter = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("info")) + .unwrap(); + + // Decide on layers + #[cfg(feature = "telemetry")] + let collector = Registry::default().with(telemetry).with(logger).with(env_filter); + #[cfg(not(feature = "telemetry"))] + let collector = Registry::default().with(logger).with(env_filter); + + // Initialize tracing + tracing::subscriber::set_global_default(collector).unwrap(); +} + +#[cfg(test)] +mod test { + // This test only works when telemetry is initialized fully + // and requires OPENTELEMETRY_ENDPOINT_URL pointing to a valid server + #[cfg(feature = "telemetry")] + #[tokio::test] + #[ignore = "requires a trace exporter"] + async fn get_trace_id_returns_valid_traces() { + use super::*; + super::init().await; + #[tracing::instrument(name = "test_span")] // need to be in an instrumented fn + fn test_trace_id() -> TraceId { + get_trace_id() + } + assert_ne!(test_trace_id(), TraceId::INVALID, "valid trace"); + } +}