diff --git a/Cargo.lock b/Cargo.lock index c00b3f1..fa67ad4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -69,6 +69,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "arraydeque" version = "0.5.1" @@ -101,7 +107,7 @@ dependencies = [ "futures-util", "handlebars", "http", - "indexmap", + "indexmap 2.7.1", "mime", "multer", "num-traits", @@ -168,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "741110dda927420a28fbc1c310543d3416f789a6ba96859c2c265843a0a96887" dependencies = [ "bytes", - "indexmap", + "indexmap 2.7.1", "serde", "serde_json", ] @@ -258,7 +264,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-tungstenite", - "tower", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -892,6 +898,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + [[package]] name = "h2" version = "0.4.8" @@ -904,7 +916,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -925,6 +937,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.5" @@ -1086,6 +1104,19 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -1289,6 +1320,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -1306,6 +1347,15 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -1605,6 +1655,102 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e87237e2775f74896f9ad219d26a2081751187eb7c9f5c58dde20a23b95d16c" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.11", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d7ab32b827b5b495bd90fa95a6cb65ccc293555dcc3199ae2937d2d237c8ed" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", + "reqwest", + "tracing", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d899720fe06916ccba71c01d04ecd77312734e2de3467fd30d9d580c8ce85656" +dependencies = [ + "futures-core", + "http", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest", + "thiserror 2.0.11", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c40da242381435e18570d5b9d50aca2a4f4f4d8e146231adb4e7768023309b3" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b29a9f89f1a954936d5aa92f19b2feec3c8f3971d3e96206640db7f9706ae3" + +[[package]] +name = "opentelemetry-stdout" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e27d446dabd68610ef0b77d07b102ecde827a4596ea9c01a4d3811e945b286" +dependencies = [ + "chrono", + "futures-util", + "opentelemetry", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afdefb21d1d47394abc1ba6c57363ab141be19e27cc70d0e422b7f303e4d290b" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "opentelemetry", + "percent-encoding", + "rand 0.9.0", + "serde_json", + "thiserror 2.0.11", + "tracing", +] + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -1763,6 +1909,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1835,6 +2001,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.38" @@ -1967,6 +2156,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2", @@ -1993,7 +2183,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tower", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -2041,6 +2231,11 @@ dependencies = [ "dotenv", "hex", "hmac", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry-stdout", + "opentelemetry_sdk", "reqwest", "serde", "serde_json", @@ -2048,9 +2243,11 @@ dependencies = [ "sqlx", "time", "tokio", - "tower", + "tower 0.5.2", "tower-http", "tracing", + "tracing-core", + "tracing-opentelemetry", "tracing-subscriber", ] @@ -2293,6 +2490,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -2387,7 +2593,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.2", "hashlink 0.10.0", - "indexmap", + "indexmap 2.7.1", "log", "memchr", "once_cell", @@ -2796,6 +3002,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", @@ -2896,13 +3103,59 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.5.2" @@ -2989,6 +3242,24 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd8e764bd6f5813fd8bebc3117875190c5b0415be8f7f8059bffb6ecd979c444" +dependencies = [ + "js-sys", + "once_cell", + "opentelemetry", + "opentelemetry_sdk", + "smallvec", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", + "web-time", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -3246,6 +3517,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "whoami" version = "1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 5002d3c..9f70747 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ axum = "0.8.1" chrono = { version = "0.4.38", features = ["clock"] } serde = { version = "1.0.188", features = ["derive"] } sqlx = { version = "0.8.3", features = ["chrono", "postgres", "runtime-tokio"] } -tokio = { version = "1.28.2", features = ["default", "macros", "rt-multi-thread"] } # For async tests +tokio = { version = "1.28.2", features = ["default", "macros", "rt-multi-thread", "signal"] } # For async tests hmac = "0.12.1" sha2 = "0.10.8" hex = "0.4.3" @@ -24,3 +24,10 @@ tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time", "fmt", "std"] } dotenv = "0.15.0" time = { version = "0.3.37", features = ["formatting"] } +opentelemetry = "0.29.1" +opentelemetry_sdk = "0.29.0" +opentelemetry-semantic-conventions = { version = "0.29.0", features = ["semconv_experimental"] } +tracing-core = "0.1.33" +tracing-opentelemetry = "0.30.0" +opentelemetry-otlp = { version = "0.29.0", features = ["grpc-tonic"] } +opentelemetry-stdout = "0.29.0" diff --git a/src/daily_task/mod.rs b/src/daily_task/mod.rs index d342f87..7a64c30 100644 --- a/src/daily_task/mod.rs +++ b/src/daily_task/mod.rs @@ -7,6 +7,7 @@ use tracing::{debug, error, info}; use crate::models::member::Member; +#[tracing::instrument] pub async fn run_daily_task_at_midnight(pool: Arc) { loop { let now = chrono::Utc::now().with_timezone(&Kolkata); @@ -37,6 +38,7 @@ pub async fn run_daily_task_at_midnight(pool: Arc) { /// This function does a number of things, including: /// * Insert new attendance records everyday for [`presense`](https://www.github.com/amfoss/presense) to update them later in the day. /// * Update the AttendanceSummary table +#[tracing::instrument] async fn execute_daily_task(pool: Arc) { // Members is queried outside of each function to avoid repetition let members = sqlx::query_as::<_, Member>("SELECT * FROM Member") @@ -50,6 +52,7 @@ async fn execute_daily_task(pool: Arc) { }; } +#[tracing::instrument] async fn update_attendance(members: Vec, pool: &PgPool) { #[allow(deprecated)] let today = chrono::Utc::now() @@ -92,6 +95,7 @@ async fn update_attendance(members: Vec, pool: &PgPool) { } } +#[tracing::instrument] async fn update_attendance_summary(member_id: i32, pool: &PgPool) { debug!("Updating summary for member #{}", member_id); #[allow(deprecated)] @@ -129,6 +133,7 @@ async fn update_attendance_summary(member_id: i32, pool: &PgPool) { } } +#[tracing::instrument] async fn update_days_attended(member_id: i32, today: NaiveDate, pool: &PgPool) { // Convert year and month into i32 cause SQLx cannot encode u32 into database types let month: i32 = (today.month0() + 1) as i32; diff --git a/src/graphql/mutations/attendance_mutations.rs b/src/graphql/mutations/attendance_mutations.rs index 75bb471..d4cd4fa 100644 --- a/src/graphql/mutations/attendance_mutations.rs +++ b/src/graphql/mutations/attendance_mutations.rs @@ -11,11 +11,12 @@ use crate::models::attendance::{Attendance, MarkAttendanceInput}; type HmacSha256 = Hmac; -#[derive(Default)] +#[derive(Default, Debug)] pub struct AttendanceMutations; #[Object] impl AttendanceMutations { + #[tracing::instrument(skip(ctx))] #[graphql(name = "markAttendance")] async fn mark_attendance( &self, diff --git a/src/graphql/queries/attendance_queries.rs b/src/graphql/queries/attendance_queries.rs index 2050051..e139db3 100644 --- a/src/graphql/queries/attendance_queries.rs +++ b/src/graphql/queries/attendance_queries.rs @@ -5,14 +5,17 @@ use async_graphql::{Context, Object, Result}; use chrono::NaiveDate; use sqlx::PgPool; -#[derive(Default)] +#[derive(Default, Debug)] pub struct AttendanceQueries; #[Object] impl AttendanceQueries { + #[tracing::instrument(skip(ctx))] async fn attendance(&self, ctx: &Context<'_>, member_id: i32) -> Result> { let pool = ctx.data::>().expect("Pool must be in context."); + tracing::info!("Fetching attendance for member ID: {}", member_id); + Ok( sqlx::query_as::<_, Attendance>("SELECT * FROM Attendance WHERE member_id = $1") .bind(member_id) diff --git a/src/graphql/queries/member_queries.rs b/src/graphql/queries/member_queries.rs index dfb7f68..1ae3e1e 100644 --- a/src/graphql/queries/member_queries.rs +++ b/src/graphql/queries/member_queries.rs @@ -9,11 +9,12 @@ use crate::models::{ status_update_streak::StatusUpdateStreakInfo, }; -#[derive(Default)] +#[derive(Default, Debug)] pub struct MemberQueries; #[Object] impl MemberQueries { + #[tracing::instrument(skip(ctx))] pub async fn members( &self, ctx: &Context<'_>, @@ -45,9 +46,12 @@ impl MemberQueries { #[ComplexObject] impl Member { + #[tracing::instrument(skip(ctx))] async fn attendance(&self, ctx: &Context<'_>) -> Vec { let pool = ctx.data::>().expect("Pool must be in context."); + tracing::info!("Fetching attendance for member ID: {}", self.member_id); + sqlx::query_as::<_, AttendanceInfo>( "SELECT date, is_present, time_in, time_out FROM Attendance WHERE member_id = $1", ) diff --git a/src/main.rs b/src/main.rs index 0536d54..02b0c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,18 @@ use tower_http::cors::CorsLayer; use tracing::info; use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; +use opentelemetry::{global, trace::TracerProvider as _, KeyValue}; +use opentelemetry_sdk::{ + metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, + trace::{RandomIdGenerator, Sampler, SdkTracerProvider}, + Resource, +}; +use opentelemetry_semantic_conventions::{ + attribute::{DEPLOYMENT_ENVIRONMENT_NAME, SERVICE_NAME, SERVICE_VERSION}, + SCHEMA_URL, +}; +use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; + use daily_task::run_daily_task_at_midnight; use graphql::{Mutation, Query}; use routes::setup_router; @@ -37,10 +49,27 @@ impl Config { } } +struct OtelGuard { + tracer_provider: SdkTracerProvider, + meter_provider: SdkMeterProvider, +} + +impl Drop for OtelGuard { + fn drop(&mut self) { + if let Err(err) = self.tracer_provider.shutdown() { + eprintln!("{err:?}"); + } + if let Err(err) = self.meter_provider.shutdown() { + eprintln!("{err:?}"); + } + } +} + #[tokio::main] +#[tracing::instrument] async fn main() { let config = Config::from_env(); - setup_tracing(&config.env); + let guard = setup_tracing(&config.env); let pool = setup_database(&config.database_url).await; let schema = build_graphql_schema(pool.clone(), config.secret_key); @@ -56,10 +85,81 @@ async fn main() { let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", config.port)) .await .unwrap(); - axum::serve(listener, router).await.unwrap(); + + axum::serve(listener, router) + .with_graceful_shutdown(shutdown_signal()) + .await + .unwrap(); + + drop(guard); +} + +#[tracing::instrument] +async fn shutdown_signal() { + tokio::signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + + tracing::info!("Shutdown signal received. Flushing telemetry..."); } -fn setup_tracing(env: &str) { +fn resource() -> Resource { + Resource::builder() + .with_attributes(vec![ + KeyValue::new(SERVICE_NAME, env!("CARGO_PKG_NAME")), + KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")), + KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"), + ]) + .with_schema_url(Vec::new(), SCHEMA_URL) + .build() +} + +fn init_meter_provider() -> SdkMeterProvider { + let exporter = opentelemetry_otlp::MetricExporter::builder() + .with_tonic() + .with_temporality(opentelemetry_sdk::metrics::Temporality::default()) + .build() + .unwrap(); + + let reader = PeriodicReader::builder(exporter) + .with_interval(std::time::Duration::from_secs(30)) + .build(); + + let stdout_reader = + PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build(); + + let meter_provider = MeterProviderBuilder::default() + .with_resource(resource()) + .with_reader(reader) + .with_reader(stdout_reader) + .build(); + + global::set_meter_provider(meter_provider.clone()); + + meter_provider +} + +fn init_tracer_provider() -> SdkTracerProvider { + let exporter = opentelemetry_otlp::SpanExporter::builder() + .with_tonic() + .build() + .unwrap(); + + SdkTracerProvider::builder() + .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased( + 1.0, + )))) + .with_id_generator(RandomIdGenerator::default()) + .with_resource(resource()) + .with_batch_exporter(exporter) + .build() +} + +fn setup_tracing(env: &str) -> OtelGuard { + let tracer_provider = init_tracer_provider(); + let meter_provider = init_meter_provider(); + let tracer = tracer_provider.tracer("tracing-otel-subscriber"); + let kolkata_offset = UtcOffset::from_hms(5, 30, 0).expect("Hardcoded offset must be correct"); let timer = fmt::time::OffsetTime::new( kolkata_offset, @@ -75,6 +175,8 @@ fn setup_tracing(env: &str) { .with_ansi(false) // ANSI encodings are unreadable in the raw file. .with_writer(std::fs::File::create("root.log").unwrap()), ) + .with(MetricsLayer::new(meter_provider.clone())) + .with(OpenTelemetryLayer::new(tracer)) .with(EnvFilter::new("info")) .init(); info!("Running in production mode.") @@ -93,10 +195,17 @@ fn setup_tracing(env: &str) { .with_ansi(false) .with_writer(std::fs::File::create("root.log").unwrap()), ) + .with(MetricsLayer::new(meter_provider.clone())) + .with(OpenTelemetryLayer::new(tracer)) .with(EnvFilter::new("trace")) .init(); info!("Running in development mode."); } + + OtelGuard { + tracer_provider, + meter_provider, + } } async fn setup_database(database_url: &str) -> Arc { diff --git a/src/models/attendance.rs b/src/models/attendance.rs index 9efc9dc..0a16a74 100644 --- a/src/models/attendance.rs +++ b/src/models/attendance.rs @@ -39,7 +39,7 @@ pub struct AttendanceSummaryInfo { pub days_attended: i32, } -#[derive(InputObject)] +#[derive(InputObject, Debug)] pub struct MarkAttendanceInput { pub member_id: i32, pub date: NaiveDate, diff --git a/src/models/member.rs b/src/models/member.rs index 89a2715..d0d4027 100644 --- a/src/models/member.rs +++ b/src/models/member.rs @@ -4,6 +4,7 @@ use sqlx::FromRow; #[derive(Enum, Copy, Clone, Eq, PartialEq, sqlx::Type)] #[sqlx(type_name = "sex_type")] +#[derive(Debug)] pub enum Sex { M, F, @@ -12,6 +13,7 @@ pub enum Sex { #[derive(SimpleObject, FromRow)] #[graphql(complex)] +#[derive(Debug)] pub struct Member { pub member_id: i32, pub roll_no: String, diff --git a/src/routes.rs b/src/routes.rs index f6c6db2..dd9dcff 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -9,6 +9,7 @@ use tower_http::cors::CorsLayer; use crate::graphql::{Mutation, Query}; +#[tracing::instrument(skip(schema, cors))] pub fn setup_router( schema: Schema, cors: CorsLayer,