diff --git a/Cargo.toml b/Cargo.toml index 1f302c3b..2fc57b16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "crates/telemetry", "crates/token_manager", "crates/utils", + "crates/metrics", ] default-members = ["crates/api"] @@ -30,6 +31,7 @@ entities = { path = "crates/entities" } error = { path = "crates/error" } id-generator = { path = "crates/id-generator" } intelli-core = { path = "crates/intelli-core" } +metrics = { path = "crates/metrics" } password-hash = { path = "crates/password-hash" } structs = { path = "crates/structs" } telemetry = { path = "crates/telemetry" } @@ -52,6 +54,7 @@ quick_cache = "0.6" prost-build = "0.13" postgres-derive = "0.4" deadpool-postgres = "0.14" +tracing-opentelemetry = "0.24" tokio = { version = "1", features = ["full"] } chrono = { version = "0.4", features = ["serde"] } reqwest = { version = "0.12", features = ["json"] } @@ -65,8 +68,11 @@ ahash = { version = "0.8", features = ["compile-time-rng"] } dashmap = { version = "6", features = ["inline", "raw-api"] } refinery = { version = "0.8", features = ["tokio-postgres"] } postgres-types = { version = "0.2", features = ["with-chrono-0_4"] } +opentelemetry = "0.23" +opentelemetry_sdk = { version = "0.23", features = ["rt-tokio"] } parking_lot = { version = "0.12", features = ["arc_lock", "nightly"] } garde = { version = "0.20", features = ["derive", "email", "email-idna"] } +opentelemetry-otlp = { version = "0.16", features = ["grpc-tonic", "metrics"] } tracing-subscriber = { version = "0.3", features = [ "parking_lot", "env-filter", diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index a168ef74..25d68fe5 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -21,6 +21,7 @@ structs.workspace = true entities.workspace = true telemetry.workspace = true intelli-core.workspace = true +metrics.workspace = true ntex.workspace = true tokio.workspace = true garde.workspace = true @@ -32,5 +33,3 @@ dashmap.workspace = true tokio-stream.workspace = true ntex-cors.workspace = true openssl.workspace = true -tracing-log.workspace = true -tracing-subscriber.workspace = true diff --git a/crates/api/src/config/local_tracing.rs b/crates/api/src/config/local_tracing.rs deleted file mode 100644 index 4ed88638..00000000 --- a/crates/api/src/config/local_tracing.rs +++ /dev/null @@ -1,16 +0,0 @@ -use tracing_log::LogTracer; -use tracing_subscriber::{EnvFilter, FmtSubscriber}; - -pub fn initialize_tracing_subscriber() { - let filter = EnvFilter::new("info,intelli=trace"); - - let subscriber = FmtSubscriber::builder() - .with_ansi(true) - .with_max_level(tracing::Level::TRACE) - .with_env_filter(filter) - .compact() - .finish(); - - LogTracer::init().unwrap(); - tracing::subscriber::set_global_default(subscriber).unwrap(); -} diff --git a/crates/api/src/config/mod.rs b/crates/api/src/config/mod.rs deleted file mode 100644 index de249f24..00000000 --- a/crates/api/src/config/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(crate) use local_tracing::*; - -mod local_tracing; diff --git a/crates/api/src/main.rs b/crates/api/src/main.rs index dff7d1a9..8c0431ef 100644 --- a/crates/api/src/main.rs +++ b/crates/api/src/main.rs @@ -1,13 +1,12 @@ -mod config; mod handlers; mod middlewares; mod routes; mod states; -use config::initialize_tracing_subscriber; use dashmap::DashMap; use db::Database; use dotenvy::{dotenv, var}; +use metrics::initialize_tracing_and_telemetry; use ntex::{http::header, web}; use ntex_cors::Cors; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; @@ -20,7 +19,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; #[tokio::main] async fn main() -> std::io::Result<()> { dotenv().ok(); - initialize_tracing_subscriber(); + initialize_tracing_and_telemetry().expect("Error initializing metrics"); ntex::rt::System::new("intelli-api") .run_local(async { diff --git a/crates/metrics/Cargo.toml b/crates/metrics/Cargo.toml new file mode 100644 index 00000000..c095d603 --- /dev/null +++ b/crates/metrics/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "metrics" +version = "0.1.0" +edition = "2021" + +[lints] +workspace = true + +[lib] +path = "src/metrics.rs" +doctest = false + +[dependencies] +opentelemetry.workspace = true +opentelemetry_sdk.workspace = true +tracing-opentelemetry.workspace = true +opentelemetry-otlp.workspace = true +tracing-subscriber.workspace = true +tracing-log.workspace = true +tracing.workspace = true diff --git a/crates/metrics/src/metrics.rs b/crates/metrics/src/metrics.rs new file mode 100644 index 00000000..01d52981 --- /dev/null +++ b/crates/metrics/src/metrics.rs @@ -0,0 +1,49 @@ +use opentelemetry::global; +use opentelemetry::KeyValue; +use opentelemetry_otlp::WithExportConfig; +use opentelemetry_sdk::{ + runtime::Tokio, + trace::{self, Tracer}, + Resource, +}; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; + +pub fn initialize_tracing_and_telemetry( +) -> Result> { + global::set_text_map_propagator(opentelemetry_sdk::propagation::TraceContextPropagator::new()); + + let tracer = opentelemetry_otlp::new_pipeline() + .tracing() + .with_exporter( + opentelemetry_otlp::new_exporter() + .tonic() + .with_endpoint("http://localhost:4317"), + ) + .with_trace_config( + trace::config().with_resource(Resource::new(vec![KeyValue::new( + "service.name", + "intelli-api", + )])), + ) + .install_batch(Tokio)?; + + let filter = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("info")) + .unwrap(); + + let fmt_layer = fmt::layer().with_ansi(true).compact(); + + let telemetry_layer = tracing_opentelemetry::layer().with_tracer(tracer.clone()); + + let subscriber = Registry::default() + .with(filter) + .with(fmt_layer) + .with(telemetry_layer); + + LogTracer::init()?; + + tracing::subscriber::set_global_default(subscriber)?; + + Ok(tracer) +} diff --git a/crates/telemetry/src/service.rs b/crates/telemetry/src/service.rs index b0232f78..e93e0d4a 100644 --- a/crates/telemetry/src/service.rs +++ b/crates/telemetry/src/service.rs @@ -626,6 +626,6 @@ fn cast(bytes: &[u8]) -> AppResult<&T> { if !mem::size_of::() == bytes.len() { Err(F1ServiceError::CastingError)?; } - + Ok(unsafe { &*(bytes.as_ptr() as *const T) }) }