From b97cde80c7cf5d359b3f1f9aff6043e8aac0864f Mon Sep 17 00:00:00 2001 From: Garry O'Donnell Date: Mon, 25 Mar 2024 19:15:09 +0000 Subject: [PATCH] Propagate OpenTelemetry spans --- Cargo.lock | 52 ++++++++++++++++++++++++++++++++++++++++---- sessions/Cargo.toml | 6 +++-- sessions/src/main.rs | 22 +++++++++++-------- sessions/src/opa.rs | 19 +++++++++++----- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a7f8b1..6a0a850 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,6 +413,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-tracing-opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6672eee77fec7036fe83cf2111e25c4f9ef06b35b50d656d8d8127c2347e3b4a" +dependencies = [ + "axum 0.7.4", + "futures-core", + "futures-util", + "http 1.1.0", + "opentelemetry", + "pin-project-lite", + "tower", + "tracing", + "tracing-opentelemetry", + "tracing-opentelemetry-instrumentation-sdk", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -1415,9 +1433,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" -version = "0.11.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -1709,6 +1727,18 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "opentelemetry-http" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbfa5308166ca861434f0b0913569579b8e587430a3d6bcd7fd671921ec145a" +dependencies = [ + "async-trait", + "bytes", + "http 0.2.12", + "opentelemetry", +] + [[package]] name = "opentelemetry-otlp" version = "0.15.0" @@ -2055,7 +2085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.52", @@ -2570,19 +2600,21 @@ dependencies = [ [[package]] name = "sessions" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "async-graphql", "async-graphql-axum", "axum 0.7.4", "axum-extra", + "axum-tracing-opentelemetry", "built", "chrono", "clap", "dotenvy", "models", "opentelemetry", + "opentelemetry-http", "opentelemetry-otlp", "opentelemetry-semantic-conventions", "opentelemetry_sdk", @@ -3391,6 +3423,18 @@ dependencies = [ "web-time", ] +[[package]] +name = "tracing-opentelemetry-instrumentation-sdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36785b61526c60c97c5aaa3e588d07099e1fb7b51dc96ff1508d4abe80389b36" +dependencies = [ + "http 1.1.0", + "opentelemetry", + "tracing", + "tracing-opentelemetry", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" diff --git a/sessions/Cargo.toml b/sessions/Cargo.toml index bf1a62a..baec658 100644 --- a/sessions/Cargo.toml +++ b/sessions/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "sessions" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] -anyhow = "1.0.81" +anyhow = { version = "1.0.81" } async-graphql = { version = "7.0.3", default-features = false, features = [ "chrono", "graphiql", @@ -13,11 +13,13 @@ async-graphql = { version = "7.0.3", default-features = false, features = [ async-graphql-axum = { version = "7.0.3" } axum = { version = "0.7.4" } axum-extra = { version = "0.9.2", features = ["typed-header"] } +axum-tracing-opentelemetry = "0.18.0" chrono = { version = "0.4.35" } clap = { version = "4.5.3", features = ["derive", "env"] } dotenvy = { version = "0.15.7" } models = { path = "../models" } opentelemetry = { version = "0.22.0", features = ["metrics"] } +opentelemetry-http = { version = "0.11.0" } opentelemetry-otlp = { version = "0.15.0", features = ["metrics", "tokio"] } opentelemetry-semantic-conventions = { version = "0.14.0" } opentelemetry_sdk = { version = "0.22.1", features = ["rt-tokio"] } diff --git a/sessions/src/main.rs b/sessions/src/main.rs index 4a234c6..bce7c73 100644 --- a/sessions/src/main.rs +++ b/sessions/src/main.rs @@ -17,8 +17,9 @@ use crate::{ opa::OpaClient, route_handlers::GraphQLHandler, }; -use async_graphql::{extensions::Tracing, http::GraphiQLSource, SDLExportOptions}; +use async_graphql::{http::GraphiQLSource, SDLExportOptions}; use axum::{response::Html, routing::get, Router}; +use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer}; use clap::Parser; use opentelemetry_otlp::WithExportConfig; use sea_orm::{ConnectOptions, Database, DatabaseConnection, DbErr, TransactionError}; @@ -84,7 +85,7 @@ async fn main() { let database = setup_database(args.database_url).await.unwrap(); let opa_client = OpaClient::new(args.opa_url); let schema = root_schema_builder() - .extension(Tracing) + .extension(async_graphql::extensions::Tracing) .data(database) .data(opa_client) .finish(); @@ -117,13 +118,16 @@ fn setup_router(schema: RootSchema) -> Router { #[allow(clippy::missing_docs_in_private_items)] const GRAPHQL_ENDPOINT: &str = "/"; - Router::new().route( - GRAPHQL_ENDPOINT, - get(Html( - GraphiQLSource::build().endpoint(GRAPHQL_ENDPOINT).finish(), - )) - .post(GraphQLHandler::new(schema)), - ) + Router::new() + .route( + GRAPHQL_ENDPOINT, + get(Html( + GraphiQLSource::build().endpoint(GRAPHQL_ENDPOINT).finish(), + )) + .post(GraphQLHandler::new(schema)), + ) + .layer(OtelInResponseLayer) + .layer(OtelAxumLayer::default()) } /// Serves the endpoints on the specified port forever diff --git a/sessions/src/opa.rs b/sessions/src/opa.rs index c05d30f..c7dc373 100644 --- a/sessions/src/opa.rs +++ b/sessions/src/opa.rs @@ -1,5 +1,6 @@ use axum_extra::headers::{authorization::Bearer, Authorization}; use serde::{Deserialize, Serialize}; +use tracing::instrument; use url::Url; /// Parametrers required by OPA to make the policy decision @@ -50,14 +51,22 @@ impl OpaClient { } /// Queries OPA with the [`OpaInput`] and returns the [`Decision`] + #[instrument(skip(input))] async fn query(&self, input: OpaInput

) -> Result { - self.client + let mut request = self + .client .post(self.endpoint.clone()) .json(&input) - .send() - .await? - .json() - .await + .build()?; + + opentelemetry::global::get_text_map_propagator(|propagator| { + propagator.inject_context( + &opentelemetry::Context::current(), + &mut opentelemetry_http::HeaderInjector(request.headers_mut()), + ) + }); + + self.client.execute(request).await?.json().await } /// Queries OPA with the [`OpaInput`] and returns a [`Result`]