From 2d1238eaee34bb46a955811a3741f8bd58ee5415 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 13:51:55 +0900 Subject: [PATCH 01/16] feat: add datadog exporter crate --- scheduler/Cargo.lock | 113 ++++++++++++++++++++++++++++++++++++++----- scheduler/Cargo.toml | 1 + 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/scheduler/Cargo.lock b/scheduler/Cargo.lock index 6784668f..4436994f 100644 --- a/scheduler/Cargo.lock +++ b/scheduler/Cargo.lock @@ -1612,9 +1612,10 @@ dependencies = [ "nettu_scheduler_infra", "nettu_scheduler_sdk", "openssl-probe", - "opentelemetry", + "opentelemetry 0.23.0", + "opentelemetry-datadog", "opentelemetry-otlp", - "opentelemetry_sdk", + "opentelemetry_sdk 0.23.0", "tokio", "tracing", "tracing-bunyan-formatter", @@ -1886,6 +1887,44 @@ dependencies = [ "thiserror", ] +[[package]] +name = "opentelemetry" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c365a63eec4f55b7efeceb724f1336f26a9cf3427b70e59e2cd2a5b947fba96" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", +] + +[[package]] +name = "opentelemetry-datadog" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55061f0b4acd624ce67434c4a6d6d1b5c341d62564bf80094bdaef884f1bf5b" +dependencies = [ + "ahash", + "futures-core", + "http 1.1.0", + "indexmap 2.2.6", + "itertools 0.11.0", + "itoa", + "once_cell", + "opentelemetry 0.24.0", + "opentelemetry-http 0.13.0", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk 0.24.1", + "reqwest 0.12.4", + "rmp", + "ryu", + "thiserror", + "url", +] + [[package]] name = "opentelemetry-http" version = "0.12.0" @@ -1895,10 +1934,23 @@ dependencies = [ "async-trait", "bytes", "http 0.2.12", - "opentelemetry", + "opentelemetry 0.23.0", "reqwest 0.11.27", ] +[[package]] +name = "opentelemetry-http" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad31e9de44ee3538fb9d64fe3376c1362f406162434609e79aea2a41a0af78ab" +dependencies = [ + "async-trait", + "bytes", + "http 1.1.0", + "opentelemetry 0.24.0", + "reqwest 0.12.4", +] + [[package]] name = "opentelemetry-otlp" version = "0.16.0" @@ -1908,10 +1960,10 @@ dependencies = [ "async-trait", "futures-core", "http 0.2.12", - "opentelemetry", - "opentelemetry-http", + "opentelemetry 0.23.0", + "opentelemetry-http 0.12.0", "opentelemetry-proto", - "opentelemetry_sdk", + "opentelemetry_sdk 0.23.0", "prost", "reqwest 0.11.27", "thiserror", @@ -1925,12 +1977,18 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "984806e6cf27f2b49282e2a05e288f30594f3dbc74eb7a6e99422bc48ed78162" dependencies = [ - "opentelemetry", - "opentelemetry_sdk", + "opentelemetry 0.23.0", + "opentelemetry_sdk 0.23.0", "prost", "tonic", ] +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cefe0543875379e47eb5f1e68ff83f45cc41366a92dfd0d073d513bf68e9a05" + [[package]] name = "opentelemetry_sdk" version = "0.23.0" @@ -1944,7 +2002,7 @@ dependencies = [ "glob", "lazy_static", "once_cell", - "opentelemetry", + "opentelemetry 0.23.0", "ordered-float", "percent-encoding", "rand", @@ -1953,6 +2011,25 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "opentelemetry_sdk" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692eac490ec80f24a17828d49b40b60f5aeaccdfe6a503f939713afd22bc28df" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "once_cell", + "opentelemetry 0.24.0", + "percent-encoding", + "rand", + "serde_json", + "thiserror", +] + [[package]] name = "ordered-float" version = "4.2.1" @@ -2365,6 +2442,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.5", @@ -2428,6 +2506,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + [[package]] name = "rrule" version = "0.12.0" @@ -3373,7 +3462,7 @@ checksum = "4ee9e39a66d9b615644893ffc1704d2a89b5b315b7fd0228ad3182ca9a306b19" dependencies = [ "actix-web", "mutually_exclusive_features", - "opentelemetry", + "opentelemetry 0.23.0", "pin-project", "tracing", "tracing-opentelemetry", @@ -3459,8 +3548,8 @@ checksum = "f68803492bf28ab40aeccaecc7021096bd256baf7ca77c3d425d89b35a7be4e4" dependencies = [ "js-sys", "once_cell", - "opentelemetry", - "opentelemetry_sdk", + "opentelemetry 0.23.0", + "opentelemetry_sdk 0.23.0", "smallvec", "tracing", "tracing-core", diff --git a/scheduler/Cargo.toml b/scheduler/Cargo.toml index 20ef6240..b7931baf 100644 --- a/scheduler/Cargo.toml +++ b/scheduler/Cargo.toml @@ -44,6 +44,7 @@ opentelemetry-otlp = { version = "=0.16.0", features = [ "http-proto", "tls", ] } +opentelemetry-datadog = { version = "0.12.0", features = ["reqwest-client"] } tracing-bunyan-formatter = "0.3" openssl-probe = "0.1.2" From 85af51c3a11e6b1601d86924f0d6fb370b825680 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 15:28:03 +0900 Subject: [PATCH 02/16] fix: add datadog telemetry --- scheduler/Cargo.lock | 133 ++++++---------------------------- scheduler/Cargo.toml | 4 +- scheduler/src/telemetry.rs | 144 ++++++++++++++++++++++++++++--------- 3 files changed, 136 insertions(+), 145 deletions(-) diff --git a/scheduler/Cargo.lock b/scheduler/Cargo.lock index 4436994f..ffa85609 100644 --- a/scheduler/Cargo.lock +++ b/scheduler/Cargo.lock @@ -971,16 +971,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "gethostname" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -1612,13 +1602,12 @@ dependencies = [ "nettu_scheduler_infra", "nettu_scheduler_sdk", "openssl-probe", - "opentelemetry 0.23.0", + "opentelemetry", "opentelemetry-datadog", "opentelemetry-otlp", - "opentelemetry_sdk 0.23.0", + "opentelemetry_sdk", "tokio", "tracing", - "tracing-bunyan-formatter", "tracing-opentelemetry", "tracing-subscriber", ] @@ -1887,38 +1876,24 @@ dependencies = [ "thiserror", ] -[[package]] -name = "opentelemetry" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c365a63eec4f55b7efeceb724f1336f26a9cf3427b70e59e2cd2a5b947fba96" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror", -] - [[package]] name = "opentelemetry-datadog" -version = "0.12.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55061f0b4acd624ce67434c4a6d6d1b5c341d62564bf80094bdaef884f1bf5b" +checksum = "c22ae4b7a629f09b09307530e4dda7c37c37631c3d2ce27ce29d1402f57a0265" dependencies = [ "ahash", "futures-core", - "http 1.1.0", + "http 0.2.12", "indexmap 2.2.6", "itertools 0.11.0", "itoa", "once_cell", - "opentelemetry 0.24.0", - "opentelemetry-http 0.13.0", + "opentelemetry", + "opentelemetry-http", "opentelemetry-semantic-conventions", - "opentelemetry_sdk 0.24.1", - "reqwest 0.12.4", + "opentelemetry_sdk", + "reqwest 0.11.27", "rmp", "ryu", "thiserror", @@ -1934,23 +1909,10 @@ dependencies = [ "async-trait", "bytes", "http 0.2.12", - "opentelemetry 0.23.0", + "opentelemetry", "reqwest 0.11.27", ] -[[package]] -name = "opentelemetry-http" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad31e9de44ee3538fb9d64fe3376c1362f406162434609e79aea2a41a0af78ab" -dependencies = [ - "async-trait", - "bytes", - "http 1.1.0", - "opentelemetry 0.24.0", - "reqwest 0.12.4", -] - [[package]] name = "opentelemetry-otlp" version = "0.16.0" @@ -1960,10 +1922,10 @@ dependencies = [ "async-trait", "futures-core", "http 0.2.12", - "opentelemetry 0.23.0", - "opentelemetry-http 0.12.0", + "opentelemetry", + "opentelemetry-http", "opentelemetry-proto", - "opentelemetry_sdk 0.23.0", + "opentelemetry_sdk", "prost", "reqwest 0.11.27", "thiserror", @@ -1977,17 +1939,17 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "984806e6cf27f2b49282e2a05e288f30594f3dbc74eb7a6e99422bc48ed78162" dependencies = [ - "opentelemetry 0.23.0", - "opentelemetry_sdk 0.23.0", + "opentelemetry", + "opentelemetry_sdk", "prost", "tonic", ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.16.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cefe0543875379e47eb5f1e68ff83f45cc41366a92dfd0d073d513bf68e9a05" +checksum = "1869fb4bb9b35c5ba8a1e40c9b128a7b4c010d07091e864a29da19e4fe2ca4d7" [[package]] name = "opentelemetry_sdk" @@ -2002,7 +1964,7 @@ dependencies = [ "glob", "lazy_static", "once_cell", - "opentelemetry 0.23.0", + "opentelemetry", "ordered-float", "percent-encoding", "rand", @@ -2011,25 +1973,6 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "opentelemetry_sdk" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692eac490ec80f24a17828d49b40b60f5aeaccdfe6a503f939713afd22bc28df" -dependencies = [ - "async-trait", - "futures-channel", - "futures-executor", - "futures-util", - "glob", - "once_cell", - "opentelemetry 0.24.0", - "percent-encoding", - "rand", - "serde_json", - "thiserror", -] - [[package]] name = "ordered-float" version = "4.2.1" @@ -2442,7 +2385,6 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", - "futures-channel", "futures-core", "futures-util", "h2 0.4.5", @@ -3462,7 +3404,7 @@ checksum = "4ee9e39a66d9b615644893ffc1704d2a89b5b315b7fd0228ad3182ca9a306b19" dependencies = [ "actix-web", "mutually_exclusive_features", - "opentelemetry 0.23.0", + "opentelemetry", "pin-project", "tracing", "tracing-opentelemetry", @@ -3480,24 +3422,6 @@ dependencies = [ "syn 2.0.68", ] -[[package]] -name = "tracing-bunyan-formatter" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" -dependencies = [ - "ahash", - "gethostname", - "log", - "serde", - "serde_json", - "time", - "tracing", - "tracing-core", - "tracing-log 0.1.2", - "tracing-subscriber", -] - [[package]] name = "tracing-core" version = "0.1.32" @@ -3518,17 +3442,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-log" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -3548,12 +3461,12 @@ checksum = "f68803492bf28ab40aeccaecc7021096bd256baf7ca77c3d425d89b35a7be4e4" dependencies = [ "js-sys", "once_cell", - "opentelemetry 0.23.0", - "opentelemetry_sdk 0.23.0", + "opentelemetry", + "opentelemetry_sdk", "smallvec", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", "web-time", ] @@ -3585,7 +3498,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-serde", ] diff --git a/scheduler/Cargo.toml b/scheduler/Cargo.toml index b7931baf..62bd46d4 100644 --- a/scheduler/Cargo.toml +++ b/scheduler/Cargo.toml @@ -44,8 +44,7 @@ opentelemetry-otlp = { version = "=0.16.0", features = [ "http-proto", "tls", ] } -opentelemetry-datadog = { version = "0.12.0", features = ["reqwest-client"] } -tracing-bunyan-formatter = "0.3" +opentelemetry-datadog = { version = "0.11.0", features = ["reqwest-client"] } openssl-probe = "0.1.2" chrono = "0.4.19" @@ -54,7 +53,6 @@ chrono-tz = "0.8.1" [dev-dependencies] nettu_scheduler_sdk = { path = "./clients/rust" } - [workspace.lints.rust] unsafe_code = "forbid" diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 53ee9bf9..4bb3d47d 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -1,7 +1,11 @@ use opentelemetry::global::{self, set_error_handler}; -use opentelemetry_sdk::propagation::TraceContextPropagator; +use opentelemetry_datadog::{new_pipeline, ApiVersion}; +use opentelemetry_otlp::WithExportConfig; +use opentelemetry_sdk::{ + propagation::TraceContextPropagator, + trace::{self, RandomIdGenerator, Sampler, Tracer}, +}; use tracing::warn; -use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; /// Register a subscriber as global default to process span data. @@ -30,40 +34,39 @@ pub fn init_subscriber() { // Set the global propagator to trace context propagator global::set_text_map_propagator(TraceContextPropagator::new()); - // First, create a OTLP exporter builder. Configure it as you need. - let otlp_exporter = opentelemetry_otlp::new_exporter() - .http() - .with_protocol(opentelemetry_otlp::Protocol::HttpJson); + // Get the tracer - if no endpoint is provided, tracing will be disabled + let tracer = get_tracer(service_name, service_version, service_env); - // Then pass it into pipeline builder - let tracer = opentelemetry_otlp::new_pipeline() - .tracing() - .with_trace_config(opentelemetry_sdk::trace::config().with_resource( - opentelemetry_sdk::Resource::new(vec![ - opentelemetry::KeyValue::new("service.name", service_name.clone()), - opentelemetry::KeyValue::new("service.version", service_version), - opentelemetry::KeyValue::new("deployment.environment", service_env), - ]), - )) - .with_exporter(otlp_exporter) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .unwrap(); - - let telemetry_layer = tracing_opentelemetry::layer().with_tracer(tracer); - - // Create a `tracing` layer to emit spans as structured logs to stdout - let formatting_layer = BunyanFormattingLayer::new(service_name, std::io::stdout); + // Create a telemetry layer if a tracer is available + let telemetry_layer = + tracer.map(|tracer| tracing_opentelemetry::layer().with_tracer(tracer)); // Combine layers into a single subscriber - let subscriber = Registry::default() - .with(env_filter) - .with(telemetry_layer) - .with(JsonStorageLayer) - .with(formatting_layer); + if telemetry_layer.is_some() { + let subscriber = Registry::default() + .with(env_filter) + .with(telemetry_layer.unwrap()) + .with( + tracing_subscriber::fmt::layer() + .json() + .with_current_span(false), + ); - // Set the global subscriber - tracing::subscriber::set_global_default(subscriber) - .expect("Unable to set global subscriber"); + // Set the global subscriber + tracing::subscriber::set_global_default(subscriber) + .expect("Unable to set global subscriber"); + } else { + // If no tracer is available, do not include telemetry layer + let subscriber = Registry::default().with(env_filter).with( + tracing_subscriber::fmt::layer() + .json() + .with_current_span(false), + ); + + // Set the global subscriber + tracing::subscriber::set_global_default(subscriber) + .expect("Unable to set global subscriber"); + } // Set a global error handler to log the tracing internal errors to the console set_error_handler(|e| { @@ -72,3 +75,80 @@ pub fn init_subscriber() { .expect("Failed to set global error handler"); } } + +/// Get the tracer +fn get_tracer( + service_name: String, + service_version: String, + service_env: String, +) -> Option { + let otlp_endpoint = std::env::var("OTLP_TRACING_ENDPOINT"); + let datadog_endpoint = std::env::var("DATADOG_TRACING_ENDPOINT"); + + if let Ok(datadog_endpoint) = datadog_endpoint { + Some(get_tracer_datadog( + datadog_endpoint, + service_name, + service_version, + service_env, + )) + } else if let Ok(otlp_endpoint) = otlp_endpoint { + Some(get_tracer_otlp( + otlp_endpoint, + service_name, + service_version, + service_env, + )) + } else { + warn!("No tracing endpoints provided (DATADOG_TRACING_ENDPOINT or OTLP_TRACING_ENDPOINT), tracing will be disabled"); + None + } +} + +/// Get the tracer based on the tracing endpoint +fn get_tracer_datadog( + datadog_endpoint: String, + service_name: String, + service_version: String, + service_env: String, +) -> Tracer { + new_pipeline() + .with_service_name(service_name) + .with_version(service_version) + .with_env(service_env) + .with_api_version(ApiVersion::Version05) + .with_agent_endpoint(datadog_endpoint) + .with_trace_config( + trace::Config::default() + .with_sampler(Sampler::AlwaysOn) + .with_id_generator(RandomIdGenerator::default()), + ) + .install_batch(opentelemetry_sdk::runtime::Tokio) + .unwrap() +} + +fn get_tracer_otlp( + otlp_endpoint: String, + service_name: String, + service_version: String, + service_env: String, +) -> Tracer { + let otlp_exporter = opentelemetry_otlp::new_exporter() + .http() + .with_protocol(opentelemetry_otlp::Protocol::HttpJson) + .with_endpoint(otlp_endpoint); + + // Then pass it into pipeline builder + opentelemetry_otlp::new_pipeline() + .tracing() + .with_trace_config(opentelemetry_sdk::trace::config().with_resource( + opentelemetry_sdk::Resource::new(vec![ + opentelemetry::KeyValue::new("service.name", service_name.clone()), + opentelemetry::KeyValue::new("service.version", service_version), + opentelemetry::KeyValue::new("deployment.environment", service_env), + ]), + )) + .with_exporter(otlp_exporter) + .install_batch(opentelemetry_sdk::runtime::Tokio) + .unwrap() +} From b70e6310a6d8dc1bdd7b1d39be446c0ef77b31a9 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 15:36:05 +0900 Subject: [PATCH 03/16] fix: add comments + add sampler for OTLP --- scheduler/src/telemetry.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 4bb3d47d..406ac390 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -106,6 +106,7 @@ fn get_tracer( } /// Get the tracer based on the tracing endpoint +/// This is for the (unofficial) Datadog exporter fn get_tracer_datadog( datadog_endpoint: String, service_name: String, @@ -120,13 +121,15 @@ fn get_tracer_datadog( .with_agent_endpoint(datadog_endpoint) .with_trace_config( trace::Config::default() - .with_sampler(Sampler::AlwaysOn) + .with_sampler(Sampler::AlwaysOn) // Leave the decision to DD agent .with_id_generator(RandomIdGenerator::default()), ) .install_batch(opentelemetry_sdk::runtime::Tokio) .unwrap() } +/// Get the tracer based on the OTLP endpoint +/// This is for the OpenTelemetry Protocol (OTLP) exporter fn get_tracer_otlp( otlp_endpoint: String, service_name: String, @@ -138,16 +141,29 @@ fn get_tracer_otlp( .with_protocol(opentelemetry_otlp::Protocol::HttpJson) .with_endpoint(otlp_endpoint); + // Get the sample ratio from the env var, default to 0.1 + let ratio_to_sample = std::env::var("TRACING_SAMPLE_RATIO") + .unwrap_or_else(|_| "0.1".to_string()) + .parse::() + .unwrap_or(0.1); + + // Create sampler based on + // (1) parent => so if parent exists always sample + // (2) if no parent, then the trace id ratio + let sampler = Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(ratio_to_sample))); + // Then pass it into pipeline builder opentelemetry_otlp::new_pipeline() .tracing() - .with_trace_config(opentelemetry_sdk::trace::config().with_resource( - opentelemetry_sdk::Resource::new(vec![ - opentelemetry::KeyValue::new("service.name", service_name.clone()), - opentelemetry::KeyValue::new("service.version", service_version), - opentelemetry::KeyValue::new("deployment.environment", service_env), - ]), - )) + .with_trace_config( + opentelemetry_sdk::trace::config() + .with_resource(opentelemetry_sdk::Resource::new(vec![ + opentelemetry::KeyValue::new("service.name", service_name.clone()), + opentelemetry::KeyValue::new("service.version", service_version), + opentelemetry::KeyValue::new("deployment.environment", service_env), + ])) + .with_sampler(sampler), + ) .with_exporter(otlp_exporter) .install_batch(opentelemetry_sdk::runtime::Tokio) .unwrap() From 0e7763cfddc25e2fc2487ac2e39c06fe8fb64fa2 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 16:15:06 +0900 Subject: [PATCH 04/16] ci: build docker image (temporarily) --- .github/workflows/server-test.yml | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index e62d4dc7..4f7f7c79 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -89,3 +89,63 @@ jobs: run: | cd scheduler cargo nextest run --workspace + + docker-release: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + services: + postgres: + image: postgres:13 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: nettuscheduler + ports: + - 5432:5432 + env: + DATABASE_URL: postgresql://postgres:postgres@localhost/nettuscheduler + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set version env + run: | + # v1.0.0 --> 1.0.0 + VERSION=${GITHUB_REF#refs/*/} + echo "VERSION=${VERSION:1}" >> $GITHUB_ENV + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + scheduler/target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Run migrations + run: | + cd scheduler + cargo install sqlx-cli --no-default-features --features postgres || true + (cd crates/infra && sqlx migrate run) + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: ./scheduler + push: true + file: "./scheduler/debian.Dockerfile" + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test From 6edff997cbe23e47fc6435bce17fac020d75ff43 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 16:15:34 +0900 Subject: [PATCH 05/16] ci: add missing env vars --- .github/workflows/server-test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index 4f7f7c79..e75783ce 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -1,5 +1,9 @@ name: Server test +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + on: pull_request: push: From b44d988319bb2fbd4fd61add4b0abc5a51700837 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 16:49:07 +0900 Subject: [PATCH 06/16] refactor: also use parent and ratio Samplers for DD --- scheduler/src/main.rs | 2 +- scheduler/src/telemetry.rs | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/scheduler/src/main.rs b/scheduler/src/main.rs index 2be49bf1..a05192cd 100644 --- a/scheduler/src/main.rs +++ b/scheduler/src/main.rs @@ -9,7 +9,7 @@ async fn main() -> std::io::Result<()> { // Initialize the environment variables for SSL certificates openssl_probe::init_ssl_cert_env_vars(); - // Initialize the subscriber for logging + // Initialize the subscriber for logging & tracing init_subscriber(); let context = setup_context().await; diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 406ac390..31e8bcd4 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -121,7 +121,7 @@ fn get_tracer_datadog( .with_agent_endpoint(datadog_endpoint) .with_trace_config( trace::Config::default() - .with_sampler(Sampler::AlwaysOn) // Leave the decision to DD agent + .with_sampler(get_sampler()) .with_id_generator(RandomIdGenerator::default()), ) .install_batch(opentelemetry_sdk::runtime::Tokio) @@ -141,17 +141,6 @@ fn get_tracer_otlp( .with_protocol(opentelemetry_otlp::Protocol::HttpJson) .with_endpoint(otlp_endpoint); - // Get the sample ratio from the env var, default to 0.1 - let ratio_to_sample = std::env::var("TRACING_SAMPLE_RATIO") - .unwrap_or_else(|_| "0.1".to_string()) - .parse::() - .unwrap_or(0.1); - - // Create sampler based on - // (1) parent => so if parent exists always sample - // (2) if no parent, then the trace id ratio - let sampler = Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(ratio_to_sample))); - // Then pass it into pipeline builder opentelemetry_otlp::new_pipeline() .tracing() @@ -162,9 +151,25 @@ fn get_tracer_otlp( opentelemetry::KeyValue::new("service.version", service_version), opentelemetry::KeyValue::new("deployment.environment", service_env), ])) - .with_sampler(sampler), + .with_sampler(get_sampler()), ) .with_exporter(otlp_exporter) .install_batch(opentelemetry_sdk::runtime::Tokio) .unwrap() } + +/// Get the sampler to be used +/// This is a parent-based sampler, so if a parent exists, always sample +/// If there is no parent, then this is based on the TRACING_SAMPLE_RATIO env var, defaults to 0.1 +fn get_sampler() -> Sampler { + // Get the sample ratio from the env var, default to 0.1 + let ratio_to_sample = std::env::var("TRACING_SAMPLE_RATIO") + .unwrap_or_else(|_| "0.1".to_string()) + .parse::() + .unwrap_or(0.1); + + // Create sampler based on + // (1) parent => so if parent exists always sample + // (2) if no parent, then the trace id ratio + Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(ratio_to_sample))) +} From 4e36fdfa8bef95868c9ae050cd3c1415a1465a35 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 16:59:51 +0900 Subject: [PATCH 07/16] feat: add instrument on repositories functions --- scheduler/crates/infra/src/repos/account/postgres.rs | 9 ++++++++- .../infra/src/repos/account_integrations/postgres.rs | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/scheduler/crates/infra/src/repos/account/postgres.rs b/scheduler/crates/infra/src/repos/account/postgres.rs index 5eeb829f..3d07f437 100644 --- a/scheduler/crates/infra/src/repos/account/postgres.rs +++ b/scheduler/crates/infra/src/repos/account/postgres.rs @@ -5,10 +5,11 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::IAccountRepo; +#[derive(Debug)] pub struct PostgresAccountRepo { pool: PgPool, } @@ -40,6 +41,7 @@ impl From for Account { #[async_trait::async_trait] impl IAccountRepo for PostgresAccountRepo { + #[instrument] async fn insert(&self, account: &Account) -> anyhow::Result<()> { sqlx::query!( r#" @@ -63,6 +65,7 @@ impl IAccountRepo for PostgresAccountRepo { Ok(()) } + #[instrument] async fn save(&self, account: &Account) -> anyhow::Result<()> { sqlx::query!( r#" @@ -89,6 +92,7 @@ impl IAccountRepo for PostgresAccountRepo { Ok(()) } + #[instrument] async fn find(&self, account_id: &ID) -> Option { let res: Option = sqlx::query_as!( AccountRaw, @@ -111,6 +115,7 @@ impl IAccountRepo for PostgresAccountRepo { res.map(|account| account.into()) } + #[instrument] async fn find_many(&self, accounts_ids: &[ID]) -> anyhow::Result> { let ids = accounts_ids .iter() @@ -137,6 +142,7 @@ impl IAccountRepo for PostgresAccountRepo { Ok(accounts_raw.into_iter().map(|acc| acc.into()).collect()) } + #[instrument] async fn delete(&self, account_id: &ID) -> Option { let res: Option = sqlx::query_as!( AccountRaw, @@ -160,6 +166,7 @@ impl IAccountRepo for PostgresAccountRepo { res.map(|acc| acc.into()) } + #[instrument] async fn find_by_apikey(&self, api_key: &str) -> Option { let res: Option = sqlx::query_as!( AccountRaw, diff --git a/scheduler/crates/infra/src/repos/account_integrations/postgres.rs b/scheduler/crates/infra/src/repos/account_integrations/postgres.rs index 934113a6..8defa7d3 100644 --- a/scheduler/crates/infra/src/repos/account_integrations/postgres.rs +++ b/scheduler/crates/infra/src/repos/account_integrations/postgres.rs @@ -1,9 +1,10 @@ use nettu_scheduler_domain::{AccountIntegration, IntegrationProvider, ID}; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IAccountIntegrationRepo; +#[derive(Debug)] pub struct PostgresAccountIntegrationRepo { pool: PgPool, } @@ -37,6 +38,7 @@ impl From for AccountIntegration { #[async_trait::async_trait] impl IAccountIntegrationRepo for PostgresAccountIntegrationRepo { + #[instrument] async fn insert(&self, integration: &AccountIntegration) -> anyhow::Result<()> { let provider: String = integration.provider.clone().into(); sqlx::query!( @@ -62,6 +64,7 @@ impl IAccountIntegrationRepo for PostgresAccountIntegrationRepo { Ok(()) } + #[instrument] async fn find(&self, account_id: &ID) -> anyhow::Result> { let integrations: Vec = sqlx::query_as!( AccountIntegrationRaw, @@ -83,6 +86,7 @@ impl IAccountIntegrationRepo for PostgresAccountIntegrationRepo { Ok(integrations.into_iter().map(|i| i.into()).collect()) } + #[instrument] async fn delete(&self, account_id: &ID, provider: IntegrationProvider) -> anyhow::Result<()> { let provider: String = provider.into(); match sqlx::query!( From 2bceb9f2e261ca996653d0ff38a0ccc98d9b3e26 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 17:27:09 +0900 Subject: [PATCH 08/16] feat(infra): add instrument --- .../crates/infra/src/repos/calendar/postgres.rs | 10 +++++++++- .../infra/src/repos/calendar_synced/postgres.rs | 6 +++++- .../src/repos/event/calendar_event/postgres.rs | 15 ++++++++++++++- .../event_reminders_expansion_jobs/postgres.rs | 5 ++++- .../src/repos/event/event_synced/postgres.rs | 5 ++++- .../infra/src/repos/event/reminder/postgres.rs | 7 ++++++- .../infra/src/repos/reservation/postgres.rs | 6 +++++- .../crates/infra/src/repos/schedule/postgres.rs | 10 +++++++++- .../crates/infra/src/repos/service/postgres.rs | 9 ++++++++- .../infra/src/repos/service_user/postgres.rs | 8 +++++++- .../repos/service_user_busy_calendars/postgres.rs | 10 +++++++++- scheduler/crates/infra/src/repos/user/postgres.rs | 10 +++++++++- .../infra/src/repos/user_integrations/postgres.rs | 7 ++++++- 13 files changed, 95 insertions(+), 13 deletions(-) diff --git a/scheduler/crates/infra/src/repos/calendar/postgres.rs b/scheduler/crates/infra/src/repos/calendar/postgres.rs index 0979320c..e1b995d6 100644 --- a/scheduler/crates/infra/src/repos/calendar/postgres.rs +++ b/scheduler/crates/infra/src/repos/calendar/postgres.rs @@ -5,11 +5,12 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::ICalendarRepo; use crate::repos::shared::query_structs::MetadataFindQuery; +#[derive(Debug)] pub struct PostgresCalendarRepo { pool: PgPool, } @@ -43,6 +44,7 @@ impl From for Calendar { #[async_trait::async_trait] impl ICalendarRepo for PostgresCalendarRepo { + #[instrument] async fn insert(&self, calendar: &Calendar) -> anyhow::Result<()> { sqlx::query!( r#" @@ -67,6 +69,7 @@ impl ICalendarRepo for PostgresCalendarRepo { Ok(()) } + #[instrument] async fn save(&self, calendar: &Calendar) -> anyhow::Result<()> { sqlx::query!( r#" @@ -91,6 +94,7 @@ impl ICalendarRepo for PostgresCalendarRepo { Ok(()) } + #[instrument] async fn find(&self, calendar_id: &ID) -> Option { let res: Option = sqlx::query_as!( CalendarRaw, @@ -116,6 +120,7 @@ impl ICalendarRepo for PostgresCalendarRepo { res.map(|cal| cal.into()) } + #[instrument] async fn find_multiple(&self, calendar_ids: Vec<&ID>) -> Vec { let calendar_ids: Vec = calendar_ids .into_iter() @@ -145,6 +150,7 @@ impl ICalendarRepo for PostgresCalendarRepo { calendars.into_iter().map(|c| c.into()).collect() } + #[instrument] async fn find_by_user(&self, user_id: &ID) -> Vec { let calendars: Vec = sqlx::query_as!( CalendarRaw, @@ -170,6 +176,7 @@ impl ICalendarRepo for PostgresCalendarRepo { calendars.into_iter().map(|c| c.into()).collect() } + #[instrument] async fn delete(&self, calendar_id: &ID) -> anyhow::Result<()> { sqlx::query!( r#" @@ -191,6 +198,7 @@ impl ICalendarRepo for PostgresCalendarRepo { }) } + #[instrument] async fn find_by_metadata(&self, query: MetadataFindQuery) -> Vec { let calendars: Vec = sqlx::query_as!( CalendarRaw, diff --git a/scheduler/crates/infra/src/repos/calendar_synced/postgres.rs b/scheduler/crates/infra/src/repos/calendar_synced/postgres.rs index 9f3e5f66..9804dc4b 100644 --- a/scheduler/crates/infra/src/repos/calendar_synced/postgres.rs +++ b/scheduler/crates/infra/src/repos/calendar_synced/postgres.rs @@ -1,9 +1,10 @@ use nettu_scheduler_domain::{SyncedCalendar, ID}; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::ICalendarSyncedRepo; +#[derive(Debug)] pub struct PostgresCalendarSyncedRepo { pool: PgPool, } @@ -35,6 +36,7 @@ impl From for SyncedCalendar { #[async_trait::async_trait] impl ICalendarSyncedRepo for PostgresCalendarSyncedRepo { + #[instrument] async fn insert(&self, c: &SyncedCalendar) -> anyhow::Result<()> { let provider: String = c.provider.clone().into(); sqlx::query!( @@ -65,6 +67,7 @@ impl ICalendarSyncedRepo for PostgresCalendarSyncedRepo { Ok(()) } + #[instrument] async fn delete(&self, c: &SyncedCalendar) -> anyhow::Result<()> { let provider: String = c.provider.clone().into(); let rows = sqlx::query!( @@ -97,6 +100,7 @@ impl ICalendarSyncedRepo for PostgresCalendarSyncedRepo { } } + #[instrument] async fn find_by_calendar(&self, calendar_id: &ID) -> anyhow::Result> { let synced_calendars: Vec = sqlx::query_as!( SyncedCalendarRaw, diff --git a/scheduler/crates/infra/src/repos/event/calendar_event/postgres.rs b/scheduler/crates/infra/src/repos/event/calendar_event/postgres.rs index 1810ff9e..badb78eb 100644 --- a/scheduler/crates/infra/src/repos/event/calendar_event/postgres.rs +++ b/scheduler/crates/infra/src/repos/event/calendar_event/postgres.rs @@ -6,11 +6,12 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::{IEventRepo, MostRecentCreatedServiceEvents}; use crate::repos::shared::query_structs::MetadataFindQuery; +#[derive(Debug)] pub struct PostgresEventRepo { pool: PgPool, } @@ -88,6 +89,7 @@ impl From for CalendarEvent { #[async_trait::async_trait] impl IEventRepo for PostgresEventRepo { + #[instrument] async fn insert(&self, e: &CalendarEvent) -> anyhow::Result<()> { sqlx::query!( r#" @@ -135,6 +137,7 @@ impl IEventRepo for PostgresEventRepo { Ok(()) } + #[instrument] async fn save(&self, e: &CalendarEvent) -> anyhow::Result<()> { sqlx::query!( r#" @@ -178,6 +181,7 @@ impl IEventRepo for PostgresEventRepo { Ok(()) } + #[instrument] async fn find(&self, event_id: &ID) -> Option { let res: Option = sqlx::query_as!( EventRaw, @@ -206,6 +210,7 @@ impl IEventRepo for PostgresEventRepo { res.map(|e| e.into()) } + #[instrument] async fn find_many(&self, event_ids: &[ID]) -> anyhow::Result> { let ids = event_ids.iter().map(|id| *id.as_ref()).collect::>(); let events: Vec = sqlx::query_as( @@ -231,6 +236,7 @@ impl IEventRepo for PostgresEventRepo { Ok(events.into_iter().map(|e| e.into()).collect()) } + #[instrument] async fn find_by_calendar( &self, calendar_id: &ID, @@ -288,6 +294,7 @@ impl IEventRepo for PostgresEventRepo { Ok(events.into_iter().map(|e| e.into()).collect()) } + #[instrument] async fn find_by_calendars( &self, calendar_ids: Vec, @@ -325,6 +332,7 @@ impl IEventRepo for PostgresEventRepo { Ok(events.into_iter().map(|e| e.into()).collect()) } + #[instrument] async fn find_most_recently_created_service_events( &self, service_id: &ID, @@ -362,6 +370,7 @@ impl IEventRepo for PostgresEventRepo { events.into_iter().map(|e| e.into()).collect() } + #[instrument] async fn find_by_service( &self, service_id: &ID, @@ -407,6 +416,7 @@ impl IEventRepo for PostgresEventRepo { events.into_iter().map(|e| e.into()).collect() } + #[instrument] async fn find_user_service_events( &self, user_id: &ID, @@ -452,6 +462,7 @@ impl IEventRepo for PostgresEventRepo { events.into_iter().map(|e| e.into()).collect() } + #[instrument] async fn delete(&self, event_id: &ID) -> anyhow::Result<()> { let res = sqlx::query!( r#" @@ -478,6 +489,7 @@ impl IEventRepo for PostgresEventRepo { } } + #[instrument] async fn delete_by_service(&self, service_id: &ID) -> anyhow::Result<()> { sqlx::query!( r#" @@ -498,6 +510,7 @@ impl IEventRepo for PostgresEventRepo { Ok(()) } + #[instrument] async fn find_by_metadata(&self, query: MetadataFindQuery) -> Vec { let events: Vec = sqlx::query_as!( EventRaw, diff --git a/scheduler/crates/infra/src/repos/event/event_reminders_expansion_jobs/postgres.rs b/scheduler/crates/infra/src/repos/event/event_reminders_expansion_jobs/postgres.rs index dca7c636..48a073e5 100644 --- a/scheduler/crates/infra/src/repos/event/event_reminders_expansion_jobs/postgres.rs +++ b/scheduler/crates/infra/src/repos/event/event_reminders_expansion_jobs/postgres.rs @@ -1,10 +1,11 @@ use chrono::{DateTime, Utc}; use nettu_scheduler_domain::EventRemindersExpansionJob; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IEventRemindersGenerationJobsRepo; +#[derive(Debug)] pub struct PostgresEventReminderGenerationJobsRepo { pool: PgPool, } @@ -34,6 +35,7 @@ impl From for EventRemindersExpansionJob { #[async_trait::async_trait] impl IEventRemindersGenerationJobsRepo for PostgresEventReminderGenerationJobsRepo { + #[instrument] async fn bulk_insert(&self, jobs: &[EventRemindersExpansionJob]) -> anyhow::Result<()> { for job in jobs { sqlx::query!( @@ -59,6 +61,7 @@ impl IEventRemindersGenerationJobsRepo for PostgresEventReminderGenerationJobsRe Ok(()) } + #[instrument] async fn delete_all_before(&self, before: DateTime) -> Vec { sqlx::query_as!( JobRaw, diff --git a/scheduler/crates/infra/src/repos/event/event_synced/postgres.rs b/scheduler/crates/infra/src/repos/event/event_synced/postgres.rs index 26e1ec85..992549e8 100644 --- a/scheduler/crates/infra/src/repos/event/event_synced/postgres.rs +++ b/scheduler/crates/infra/src/repos/event/event_synced/postgres.rs @@ -1,9 +1,10 @@ use nettu_scheduler_domain::{SyncedCalendarEvent, ID}; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IEventSyncedRepo; +#[derive(Debug)] pub struct PostgresEventSyncedRepo { pool: PgPool, } @@ -39,6 +40,7 @@ impl From for SyncedCalendarEvent { #[async_trait::async_trait] impl IEventSyncedRepo for PostgresEventSyncedRepo { + #[instrument] async fn insert(&self, e: &SyncedCalendarEvent) -> anyhow::Result<()> { let provider: String = e.provider.clone().into(); sqlx::query!( @@ -71,6 +73,7 @@ impl IEventSyncedRepo for PostgresEventSyncedRepo { Ok(()) } + #[instrument] async fn find_by_event(&self, event_id: &ID) -> anyhow::Result> { let synced_events: Vec = sqlx::query_as!( SyncedEventRaw, diff --git a/scheduler/crates/infra/src/repos/event/reminder/postgres.rs b/scheduler/crates/infra/src/repos/event/reminder/postgres.rs index dcf53aab..a6ea3750 100644 --- a/scheduler/crates/infra/src/repos/event/reminder/postgres.rs +++ b/scheduler/crates/infra/src/repos/event/reminder/postgres.rs @@ -1,10 +1,11 @@ use chrono::{DateTime, Utc}; use nettu_scheduler_domain::{Reminder, ID}; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IReminderRepo; +#[derive(Debug)] pub struct PostgresReminderRepo { pool: PgPool, } @@ -45,6 +46,7 @@ impl From for Reminder { #[async_trait::async_trait] impl IReminderRepo for PostgresReminderRepo { + #[instrument] async fn bulk_insert(&self, reminders: &[Reminder]) -> anyhow::Result<()> { for reminder in reminders { sqlx::query!( @@ -72,6 +74,7 @@ impl IReminderRepo for PostgresReminderRepo { Ok(()) } + #[instrument] async fn init_version(&self, event_id: &ID) -> anyhow::Result { let r_version = sqlx::query_as!( ReminderVersionRaw, @@ -97,6 +100,7 @@ impl IReminderRepo for PostgresReminderRepo { Ok(r_version.version) } + #[instrument] async fn inc_version(&self, event_id: &ID) -> anyhow::Result { let r_version = sqlx::query_as!( ReminderVersionRaw, @@ -126,6 +130,7 @@ impl IReminderRepo for PostgresReminderRepo { Ok(r_version.version) } + #[instrument] async fn delete_all_before(&self, before: DateTime) -> Vec { sqlx::query_as!( ReminderRaw, diff --git a/scheduler/crates/infra/src/repos/reservation/postgres.rs b/scheduler/crates/infra/src/repos/reservation/postgres.rs index 350e1c0e..b6ca77e9 100644 --- a/scheduler/crates/infra/src/repos/reservation/postgres.rs +++ b/scheduler/crates/infra/src/repos/reservation/postgres.rs @@ -1,10 +1,11 @@ use chrono::{DateTime, Utc}; use nettu_scheduler_domain::ID; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IReservationRepo; +#[derive(Debug)] pub struct PostgresReservationRepo { pool: PgPool, } @@ -25,6 +26,7 @@ struct ReservationRaw { #[async_trait::async_trait] impl IReservationRepo for PostgresReservationRepo { + #[instrument] async fn increment(&self, service_id: &ID, timestamp: DateTime) -> anyhow::Result<()> { sqlx::query!( r#" @@ -48,6 +50,7 @@ impl IReservationRepo for PostgresReservationRepo { Ok(()) } + #[instrument] async fn decrement(&self, service_id: &ID, timestamp: DateTime) -> anyhow::Result<()> { sqlx::query_as!( ReservationRaw, @@ -71,6 +74,7 @@ impl IReservationRepo for PostgresReservationRepo { Ok(()) } + #[instrument] async fn count(&self, service_id: &ID, timestamp: DateTime) -> anyhow::Result { let reservation: Option = sqlx::query_as!( ReservationRaw, diff --git a/scheduler/crates/infra/src/repos/schedule/postgres.rs b/scheduler/crates/infra/src/repos/schedule/postgres.rs index 6a1dd37d..948d3afe 100644 --- a/scheduler/crates/infra/src/repos/schedule/postgres.rs +++ b/scheduler/crates/infra/src/repos/schedule/postgres.rs @@ -5,11 +5,12 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::IScheduleRepo; use crate::repos::shared::query_structs::MetadataFindQuery; +#[derive(Debug)] pub struct PostgresScheduleRepo { pool: PgPool, } @@ -45,6 +46,7 @@ impl From for Schedule { #[async_trait::async_trait] impl IScheduleRepo for PostgresScheduleRepo { + #[instrument] async fn insert(&self, schedule: &Schedule) -> anyhow::Result<()> { sqlx::query!( r#" @@ -70,6 +72,7 @@ impl IScheduleRepo for PostgresScheduleRepo { Ok(()) } + #[instrument] async fn save(&self, schedule: &Schedule) -> anyhow::Result<()> { sqlx::query!( r#" @@ -96,6 +99,7 @@ impl IScheduleRepo for PostgresScheduleRepo { Ok(()) } + #[instrument] async fn find(&self, schedule_id: &ID) -> Option { let res: Option = sqlx::query_as!( ScheduleRaw, @@ -121,6 +125,7 @@ impl IScheduleRepo for PostgresScheduleRepo { res.map(|schedule| schedule.into()) } + #[instrument] async fn find_many(&self, schedule_ids: &[ID]) -> Vec { let ids = schedule_ids .iter() @@ -149,6 +154,7 @@ impl IScheduleRepo for PostgresScheduleRepo { schedule_raw.into_iter().map(|e| e.into()).collect() } + #[instrument] async fn find_by_user(&self, user_id: &ID) -> Vec { let schedules: Vec = sqlx::query_as!( ScheduleRaw, @@ -174,6 +180,7 @@ impl IScheduleRepo for PostgresScheduleRepo { schedules.into_iter().map(|s| s.into()).collect() } + #[instrument] async fn delete(&self, schedule_id: &ID) -> anyhow::Result<()> { match sqlx::query!( r#" @@ -204,6 +211,7 @@ impl IScheduleRepo for PostgresScheduleRepo { } } + #[instrument] async fn find_by_metadata(&self, query: MetadataFindQuery) -> Vec { let schedules: Vec = sqlx::query_as!( ScheduleRaw, diff --git a/scheduler/crates/infra/src/repos/service/postgres.rs b/scheduler/crates/infra/src/repos/service/postgres.rs index 886c6ceb..b983472d 100644 --- a/scheduler/crates/infra/src/repos/service/postgres.rs +++ b/scheduler/crates/infra/src/repos/service/postgres.rs @@ -5,11 +5,12 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::IServiceRepo; use crate::repos::{service_user::ServiceUserRaw, shared::query_structs::MetadataFindQuery}; +#[derive(Debug)] pub struct PostgresServiceRepo { pool: PgPool, } @@ -66,6 +67,7 @@ impl From for ServiceWithUsers { #[async_trait::async_trait] impl IServiceRepo for PostgresServiceRepo { + #[instrument] async fn insert(&self, service: &Service) -> anyhow::Result<()> { sqlx::query!( r#" @@ -90,6 +92,7 @@ impl IServiceRepo for PostgresServiceRepo { Ok(()) } + #[instrument] async fn save(&self, service: &Service) -> anyhow::Result<()> { sqlx::query!( r#" @@ -115,6 +118,7 @@ impl IServiceRepo for PostgresServiceRepo { Ok(()) } + #[instrument] async fn find(&self, service_id: &ID) -> Option { let res: Option = sqlx::query_as!( ServiceRaw, @@ -138,6 +142,7 @@ impl IServiceRepo for PostgresServiceRepo { res.map(|service| service.into()) } + #[instrument] async fn find_with_users(&self, service_id: &ID) -> Option { let res: Option = sqlx::query_as( r#" @@ -163,6 +168,7 @@ impl IServiceRepo for PostgresServiceRepo { res.map(|service| service.into()) } + #[instrument] async fn delete(&self, service_id: &ID) -> anyhow::Result<()> { sqlx::query!( r#" @@ -183,6 +189,7 @@ impl IServiceRepo for PostgresServiceRepo { }) } + #[instrument] async fn find_by_metadata(&self, query: MetadataFindQuery) -> Vec { let services: Vec = sqlx::query_as!( ServiceRaw, diff --git a/scheduler/crates/infra/src/repos/service_user/postgres.rs b/scheduler/crates/infra/src/repos/service_user/postgres.rs index 0c01dad9..eaa99ebc 100644 --- a/scheduler/crates/infra/src/repos/service_user/postgres.rs +++ b/scheduler/crates/infra/src/repos/service_user/postgres.rs @@ -1,10 +1,11 @@ use nettu_scheduler_domain::{ServiceResource, TimePlan, ID}; use serde::Deserialize; use sqlx::{types::Uuid, FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::IServiceUserRepo; +#[derive(Debug)] pub struct PostgresServiceUserRepo { pool: PgPool, } @@ -51,6 +52,7 @@ impl From for ServiceResource { #[async_trait::async_trait] impl IServiceUserRepo for PostgresServiceUserRepo { + #[instrument] async fn insert(&self, user: &ServiceResource) -> anyhow::Result<()> { let (available_calendar_id, available_schedule_id) = match &user.availability { TimePlan::Calendar(id) => (Some(id.as_ref()), None), @@ -85,6 +87,7 @@ impl IServiceUserRepo for PostgresServiceUserRepo { Ok(()) } + #[instrument] async fn save(&self, user: &ServiceResource) -> anyhow::Result<()> { let (available_calendar_id, available_schedule_id) = match &user.availability { TimePlan::Calendar(id) => (Some(id.as_ref()), None), @@ -125,6 +128,7 @@ impl IServiceUserRepo for PostgresServiceUserRepo { Ok(()) } + #[instrument] async fn find(&self, service_id: &ID, user_id: &ID) -> Option { // https://github.com/launchbadge/sqlx/issues/367 let res: Option = sqlx::query_as( @@ -153,6 +157,7 @@ impl IServiceUserRepo for PostgresServiceUserRepo { res.map(|s_user| s_user.into()) } + #[instrument] async fn find_by_user(&self, user_id: &ID) -> Vec { // https://github.com/launchbadge/sqlx/issues/367 let service_users: Vec = sqlx::query_as( @@ -178,6 +183,7 @@ impl IServiceUserRepo for PostgresServiceUserRepo { service_users.into_iter().map(|u| u.into()).collect() } + #[instrument] async fn delete(&self, service_id: &ID, user_id: &ID) -> anyhow::Result<()> { sqlx::query!( r#" diff --git a/scheduler/crates/infra/src/repos/service_user_busy_calendars/postgres.rs b/scheduler/crates/infra/src/repos/service_user_busy_calendars/postgres.rs index f203cc15..fbc2878b 100644 --- a/scheduler/crates/infra/src/repos/service_user_busy_calendars/postgres.rs +++ b/scheduler/crates/infra/src/repos/service_user_busy_calendars/postgres.rs @@ -1,9 +1,10 @@ use nettu_scheduler_domain::{BusyCalendar, ID}; use sqlx::{FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use super::{BusyCalendarIdentifier, ExternalBusyCalendarIdentifier, IServiceUserBusyCalendarRepo}; +#[derive(Debug)] pub struct PostgresServiceUseBusyCalendarRepo { pool: PgPool, } @@ -33,6 +34,7 @@ impl From for BusyCalendar { #[async_trait::async_trait] impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { + #[instrument] async fn exists(&self, input: BusyCalendarIdentifier) -> anyhow::Result { let res = sqlx::query!( r#" @@ -58,6 +60,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(res.rows_affected() == 1) } + #[instrument] async fn exists_ext(&self, input: ExternalBusyCalendarIdentifier) -> anyhow::Result { let res = sqlx::query!( r#" @@ -83,6 +86,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(res.rows_affected() == 1) } + #[instrument] async fn insert(&self, input: BusyCalendarIdentifier) -> anyhow::Result<()> { sqlx::query!( r#" @@ -106,6 +110,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(()) } + #[instrument] async fn insert_ext(&self, input: ExternalBusyCalendarIdentifier) -> anyhow::Result<()> { let provider: String = input.provider.clone().into(); sqlx::query!( @@ -131,6 +136,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(()) } + #[instrument] async fn delete(&self, input: BusyCalendarIdentifier) -> anyhow::Result<()> { sqlx::query!( r#" @@ -156,6 +162,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(()) } + #[instrument] async fn delete_ext(&self, input: ExternalBusyCalendarIdentifier) -> anyhow::Result<()> { let provider: String = input.provider.clone().into(); sqlx::query!( @@ -184,6 +191,7 @@ impl IServiceUserBusyCalendarRepo for PostgresServiceUseBusyCalendarRepo { Ok(()) } + #[instrument] async fn find(&self, service_id: &ID, user_id: &ID) -> anyhow::Result> { let busy_calendars: Vec = sqlx::query_as( r#" diff --git a/scheduler/crates/infra/src/repos/user/postgres.rs b/scheduler/crates/infra/src/repos/user/postgres.rs index 40f48901..a5da5fe5 100644 --- a/scheduler/crates/infra/src/repos/user/postgres.rs +++ b/scheduler/crates/infra/src/repos/user/postgres.rs @@ -5,11 +5,12 @@ use sqlx::{ FromRow, PgPool, }; -use tracing::error; +use tracing::{error, instrument}; use super::IUserRepo; use crate::repos::shared::query_structs::MetadataFindQuery; +#[derive(Debug)] pub struct PostgresUserRepo { pool: PgPool, } @@ -39,6 +40,7 @@ impl From for User { #[async_trait::async_trait] impl IUserRepo for PostgresUserRepo { + #[instrument] async fn insert(&self, user: &User) -> anyhow::Result<()> { sqlx::query!( r#" @@ -62,6 +64,7 @@ impl IUserRepo for PostgresUserRepo { Ok(()) } + #[instrument] async fn save(&self, user: &User) -> anyhow::Result<()> { sqlx::query!( r#" @@ -86,6 +89,7 @@ impl IUserRepo for PostgresUserRepo { Ok(()) } + #[instrument] async fn delete(&self, user_id: &ID) -> Option { let res = sqlx::query_as!( UserRaw, @@ -110,6 +114,7 @@ impl IUserRepo for PostgresUserRepo { res.map(|user| user.into()) } + #[instrument] async fn find(&self, user_id: &ID) -> Option { let res = sqlx::query_as!( UserRaw, @@ -133,6 +138,7 @@ impl IUserRepo for PostgresUserRepo { res.map(|user| user.into()) } + #[instrument] async fn find_many(&self, user_ids: &[ID]) -> Vec { let user_ids = user_ids.iter().map(|id| *id.as_ref()).collect::>(); @@ -158,6 +164,7 @@ impl IUserRepo for PostgresUserRepo { users.into_iter().map(|u| u.into()).collect() } + #[instrument] async fn find_by_account_id(&self, user_id: &ID, account_id: &ID) -> Option { let res = sqlx::query_as!( UserRaw, @@ -183,6 +190,7 @@ impl IUserRepo for PostgresUserRepo { res.map(|user| user.into()) } + #[instrument] async fn find_by_metadata(&self, query: MetadataFindQuery) -> Vec { let users: Vec = sqlx::query_as!( UserRaw, diff --git a/scheduler/crates/infra/src/repos/user_integrations/postgres.rs b/scheduler/crates/infra/src/repos/user_integrations/postgres.rs index bdbf77fa..63dfdd9e 100644 --- a/scheduler/crates/infra/src/repos/user_integrations/postgres.rs +++ b/scheduler/crates/infra/src/repos/user_integrations/postgres.rs @@ -1,11 +1,12 @@ use nettu_scheduler_domain::{IntegrationProvider, UserIntegration, ID}; use serde::Deserialize; use sqlx::{FromRow, PgPool}; -use tracing::error; +use tracing::{error, instrument}; use uuid::Uuid; use super::IUserIntegrationRepo; +#[derive(Debug)] pub struct PostgresUserIntegrationRepo { pool: PgPool, } @@ -41,6 +42,7 @@ impl From for UserIntegration { #[async_trait::async_trait] impl IUserIntegrationRepo for PostgresUserIntegrationRepo { + #[instrument] async fn insert(&self, integration: &UserIntegration) -> anyhow::Result<()> { let provider: String = integration.provider.clone().into(); sqlx::query!( @@ -67,6 +69,7 @@ impl IUserIntegrationRepo for PostgresUserIntegrationRepo { Ok(()) } + #[instrument] async fn save(&self, integration: &UserIntegration) -> anyhow::Result<()> { let provider: String = integration.provider.clone().into(); sqlx::query!( @@ -97,6 +100,7 @@ impl IUserIntegrationRepo for PostgresUserIntegrationRepo { Ok(()) } + #[instrument] async fn find(&self, user_id: &ID) -> anyhow::Result> { let integrations = sqlx::query_as!( UserIntegrationRaw, @@ -118,6 +122,7 @@ impl IUserIntegrationRepo for PostgresUserIntegrationRepo { Ok(integrations.into_iter().map(|i| i.into()).collect()) } + #[instrument] async fn delete(&self, user_id: &ID, provider: IntegrationProvider) -> anyhow::Result<()> { let provider: String = provider.into(); match sqlx::query!( From a8cf2d2451581d73c6fbb2d869801fc298342aca Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 17:27:58 +0900 Subject: [PATCH 09/16] ci: test another image --- .github/workflows/server-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index e75783ce..306b5fc9 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -152,4 +152,4 @@ jobs: push: true file: "./scheduler/debian.Dockerfile" tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test2 From 8085aa79b892f2f8e807d5566df9ba60539f260a Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 17:31:44 +0900 Subject: [PATCH 10/16] fix: move json higher --- scheduler/src/telemetry.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 31e8bcd4..c1404f8a 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -45,12 +45,8 @@ pub fn init_subscriber() { if telemetry_layer.is_some() { let subscriber = Registry::default() .with(env_filter) - .with(telemetry_layer.unwrap()) - .with( - tracing_subscriber::fmt::layer() - .json() - .with_current_span(false), - ); + .with(tracing_subscriber::fmt::layer().json()) + .with(telemetry_layer.unwrap()); // Set the global subscriber tracing::subscriber::set_global_default(subscriber) From 2662e15520f8c1df049f466919a2153704270d4e Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 19:15:17 +0900 Subject: [PATCH 11/16] feat: log all requests --- scheduler/crates/api/src/http_logger.rs | 48 ++++++++++++++++++++++++- scheduler/crates/api/src/lib.rs | 8 ++++- scheduler/src/telemetry.rs | 6 +++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/scheduler/crates/api/src/http_logger.rs b/scheduler/crates/api/src/http_logger.rs index 8efabc68..72577aa0 100644 --- a/scheduler/crates/api/src/http_logger.rs +++ b/scheduler/crates/api/src/http_logger.rs @@ -16,10 +16,56 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { } else { Level::INFO }; - tracing_actix_web::root_span!(level = level, request) + let span = tracing_actix_web::root_span!(level = level, request); + + span } fn on_request_end(span: Span, outcome: &Result, Error>) { + // Log the outcome of the request + if let Ok(response) = outcome { + let status_code = response.status().as_u16(); + let method = response.request().method().to_string(); + let path = response.request().path().to_string(); + let response_time = span.metadata().unwrap().name(); // Or use custom timing logic if needed + + // Log with custom fields in JSON format + let message = format!("{} {} => {}", method, path, status_code); + + if status_code >= 500 { + tracing::error!( + method = method, + path = path, + status_code = status_code, + response_time = response_time, + message, + ); + } else if status_code >= 400 { + tracing::warn!( + method = method, + path = path, + status_code = status_code, + response_time = response_time, + message, + ); + } else { + tracing::info!( + method = method, + path = path, + status_code = status_code, + response_time = response_time, + message, + ); + }; + } else if let Err(err) = outcome { + // Fallback in case we can't retrieve the request from the span + tracing::error!( + status_code = 500, + error = %err, + "HTTP request resulted in an error, but request details are missing" + ); + } + DefaultRootSpanBuilder::on_request_end(span, outcome); } } diff --git a/scheduler/crates/api/src/lib.rs b/scheduler/crates/api/src/lib.rs index 98df15c7..aa046fee 100644 --- a/scheduler/crates/api/src/lib.rs +++ b/scheduler/crates/api/src/lib.rs @@ -13,7 +13,13 @@ mod user; use std::net::TcpListener; use actix_cors::Cors; -use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer}; +use actix_web::{ + dev::Server, + middleware::{self}, + web::{self, Data}, + App, + HttpServer, +}; use http_logger::NitteiTracingRootSpanBuilder; use job_schedulers::{start_reminder_generation_job_scheduler, start_send_reminders_job}; use nettu_scheduler_domain::{ diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index c1404f8a..70ae0fac 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -45,7 +45,11 @@ pub fn init_subscriber() { if telemetry_layer.is_some() { let subscriber = Registry::default() .with(env_filter) - .with(tracing_subscriber::fmt::layer().json()) + .with( + tracing_subscriber::fmt::layer() + .json() + .with_current_span(false), + ) .with(telemetry_layer.unwrap()); // Set the global subscriber From cb15302eab8a91fbafb47a2d44b9a8191142b130 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Mon, 2 Sep 2024 19:15:35 +0900 Subject: [PATCH 12/16] ci: update docker image tag --- .github/workflows/server-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index 306b5fc9..3fc36559 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -152,4 +152,4 @@ jobs: push: true file: "./scheduler/debian.Dockerfile" tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test2 + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test3 From 23729a15b5d51906200aa877f17017b3886408ba Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Tue, 3 Sep 2024 10:24:18 +0900 Subject: [PATCH 13/16] fix(logger): avoid unwrapping on None --- scheduler/crates/api/src/http_logger.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scheduler/crates/api/src/http_logger.rs b/scheduler/crates/api/src/http_logger.rs index 72577aa0..dc2ec659 100644 --- a/scheduler/crates/api/src/http_logger.rs +++ b/scheduler/crates/api/src/http_logger.rs @@ -16,9 +16,7 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { } else { Level::INFO }; - let span = tracing_actix_web::root_span!(level = level, request); - - span + tracing_actix_web::root_span!(level = level, request) } fn on_request_end(span: Span, outcome: &Result, Error>) { @@ -27,7 +25,6 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { let status_code = response.status().as_u16(); let method = response.request().method().to_string(); let path = response.request().path().to_string(); - let response_time = span.metadata().unwrap().name(); // Or use custom timing logic if needed // Log with custom fields in JSON format let message = format!("{} {} => {}", method, path, status_code); @@ -37,7 +34,6 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { method = method, path = path, status_code = status_code, - response_time = response_time, message, ); } else if status_code >= 400 { @@ -45,7 +41,6 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { method = method, path = path, status_code = status_code, - response_time = response_time, message, ); } else { @@ -53,7 +48,6 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { method = method, path = path, status_code = status_code, - response_time = response_time, message, ); }; From e4083156a5de9c9ee8477c1bfeafceecc54b0fe0 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Tue, 3 Sep 2024 10:49:14 +0900 Subject: [PATCH 14/16] fix: avoid logging healthcheck --- scheduler/crates/api/src/http_logger.rs | 83 ++++++++++++++----------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/scheduler/crates/api/src/http_logger.rs b/scheduler/crates/api/src/http_logger.rs index dc2ec659..7663df21 100644 --- a/scheduler/crates/api/src/http_logger.rs +++ b/scheduler/crates/api/src/http_logger.rs @@ -21,45 +21,56 @@ impl RootSpanBuilder for NitteiTracingRootSpanBuilder { fn on_request_end(span: Span, outcome: &Result, Error>) { // Log the outcome of the request - if let Ok(response) = outcome { - let status_code = response.status().as_u16(); - let method = response.request().method().to_string(); - let path = response.request().path().to_string(); + log_request(outcome); - // Log with custom fields in JSON format - let message = format!("{} {} => {}", method, path, status_code); + DefaultRootSpanBuilder::on_request_end(span, outcome); + } +} - if status_code >= 500 { - tracing::error!( - method = method, - path = path, - status_code = status_code, - message, - ); - } else if status_code >= 400 { - tracing::warn!( - method = method, - path = path, - status_code = status_code, - message, - ); - } else { - tracing::info!( - method = method, - path = path, - status_code = status_code, - message, - ); - }; - } else if let Err(err) = outcome { - // Fallback in case we can't retrieve the request from the span - tracing::error!( - status_code = 500, - error = %err, - "HTTP request resulted in an error, but request details are missing" - ); +/// Log the outcome of the request +fn log_request(outcome: &Result, Error>) { + // Log the outcome of the request + if let Ok(response) = outcome { + let status_code = response.status().as_u16(); + let method = response.request().method().to_string(); + let path = response.request().path().to_string(); + + // Ignore healthcheck endpoint + if path == "/api/v1/healthcheck" { + return; } - DefaultRootSpanBuilder::on_request_end(span, outcome); + // Log with custom fields in JSON format + let message = format!("{} {} => {}", method, path, status_code); + + if status_code >= 500 { + tracing::error!( + method = method, + path = path, + status_code = status_code, + message, + ); + } else if status_code >= 400 { + tracing::warn!( + method = method, + path = path, + status_code = status_code, + message, + ); + } else { + tracing::info!( + method = method, + path = path, + status_code = status_code, + message, + ); + }; + } else if let Err(err) = outcome { + // Fallback in case we can't retrieve the request from the span + tracing::error!( + status_code = 500, + error = %err, + "HTTP request resulted in an error, but request details are missing" + ); } } From ca0d2d876e4f93c4112988d331fca49894e8f518 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Tue, 3 Sep 2024 10:59:29 +0900 Subject: [PATCH 15/16] ci: push new image tag --- .github/workflows/server-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index 3fc36559..4c22717c 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -152,4 +152,4 @@ jobs: push: true file: "./scheduler/debian.Dockerfile" tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test3 + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test4 From 88e830c7e4bcaecfb8b36c8a654a527d99339174 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Tue, 3 Sep 2024 14:32:36 +0900 Subject: [PATCH 16/16] ci: revert --- .github/workflows/server-test.yml | 64 ------------------------------- 1 file changed, 64 deletions(-) diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index 4c22717c..e62d4dc7 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -1,9 +1,5 @@ name: Server test -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - on: pull_request: push: @@ -93,63 +89,3 @@ jobs: run: | cd scheduler cargo nextest run --workspace - - docker-release: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - services: - postgres: - image: postgres:13 - env: - POSTGRES_PASSWORD: postgres - POSTGRES_DB: nettuscheduler - ports: - - 5432:5432 - env: - DATABASE_URL: postgresql://postgres:postgres@localhost/nettuscheduler - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set version env - run: | - # v1.0.0 --> 1.0.0 - VERSION=${GITHUB_REF#refs/*/} - echo "VERSION=${VERSION:1}" >> $GITHUB_ENV - - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - scheduler/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Run migrations - run: | - cd scheduler - cargo install sqlx-cli --no-default-features --features postgres || true - (cd crates/infra && sqlx migrate run) - - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: ./scheduler - push: true - file: "./scheduler/debian.Dockerfile" - tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:tracing_test4