diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index c09882d..8d2c2cf 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -1,9 +1,9 @@ name: Rust Build, Test, Lint on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: call-rust-base-ci: @@ -12,8 +12,6 @@ jobs: with: rust-channel: 'nightly' require-lockfile: true - requires-private-deps: true + requires-private-deps: false feature-sets: '[""]' - secrets: - SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} diff --git a/Cargo.lock b/Cargo.lock index 13000db..cf25928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,29 +38,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ajj" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a844f49f8d1ad6bbbf2e6dd731e3bdf109e4d9540106c4bca336d0f850af08cb" -dependencies = [ - "axum", - "bytes", - "futures-util", - "interprocess", - "mime", - "pin-project", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tower", - "tracing", -] - [[package]] name = "alloy" version = "0.12.6" @@ -563,63 +540,6 @@ dependencies = [ "fs_extra", ] -[[package]] -name = "axum" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" -dependencies = [ - "axum-core", - "base64", - "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1", - "sync_wrapper", - "tokio", - "tokio-tungstenite", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -988,12 +908,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - [[package]] name = "der" version = "0.7.10" @@ -1098,12 +1012,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "doctest-file" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" - [[package]] name = "dunce" version = "1.0.5" @@ -1803,21 +1711,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "interprocess" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d" -dependencies = [ - "doctest-file", - "futures-core", - "libc", - "recvmsg", - "tokio", - "widestring", - "windows-sys 0.52.0", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1997,12 +1890,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - [[package]] name = "memchr" version = "2.7.4" @@ -2056,12 +1943,6 @@ dependencies = [ "sketches-ddsketch", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2336,26 +2217,6 @@ dependencies = [ "ucd-trie", ] -[[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 2.0.101", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2632,12 +2493,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "recvmsg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" - [[package]] name = "redox_syscall" version = "0.5.11" @@ -2776,11 +2631,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rust-tracing" -version = "0.1.3" +version = "0.1.4" dependencies = [ - "ajj", "alloy", - "axum", "init4-from-env-derive", "metrics", "metrics-exporter-prometheus", @@ -3060,28 +2913,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_with" version = "3.12.0" @@ -3137,17 +2968,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.10.9" @@ -3487,33 +3307,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots", -] - [[package]] name = "tokio-util" version = "0.7.15" @@ -3523,8 +3316,6 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "futures-util", - "hashbrown 0.15.3", "pin-project-lite", "tokio", ] @@ -3559,7 +3350,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -3598,7 +3388,6 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3700,25 +3489,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.1", - "rustls", - "rustls-pki-types", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "typenum" version = "1.18.0" @@ -3778,12 +3548,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -3932,15 +3696,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "which" version = "4.4.2" @@ -3953,12 +3708,6 @@ dependencies = [ "rustix 0.38.44", ] -[[package]] -name = "widestring" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 3ca72c1..825a2d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-tracing" -version = "0.1.3" +version = "0.1.4" edition = "2024" [dependencies] @@ -30,8 +30,6 @@ alloy = { version = "0.12.6", optional = true, default-features = false, feature serde = { version = "1", features = ["derive"] } [dev-dependencies] -ajj = "0.3.1" -axum = "0.8.1" serial_test = "3.2.0" signal-hook = "0.3.17" tokio = { version = "1.43.0", features = ["macros"] } diff --git a/examples/build-helper.rs b/examples/build-helper.rs index 291398e..60a1810 100644 --- a/examples/build-helper.rs +++ b/examples/build-helper.rs @@ -5,9 +5,9 @@ use std::sync::{ }; fn main() { - let term: Arc = Default::default(); + let term = Arc::::default(); let _ = signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&term)); - trace(); + let _guard = trace(); } diff --git a/examples/otlp-export.rs b/examples/otlp-export.rs index cd43aa4..121e752 100644 --- a/examples/otlp-export.rs +++ b/examples/otlp-export.rs @@ -24,7 +24,7 @@ use std::sync::{ #[tokio::main] async fn main() -> Result<(), std::io::Error> { - let term: Arc = Default::default(); + let term = Arc::::default(); signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&term))?; signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&term))?; diff --git a/src/lib.rs b/src/lib.rs index 7de6d2c..78694d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ pub mod deps { /// /// [`init_tracing`]: utils::tracing::init_tracing /// [`init_metrics`]: utils::metrics::init_metrics +#[must_use] pub fn trace() -> Option { let guard = utils::tracing::init_tracing(); utils::metrics::init_metrics(); @@ -113,6 +114,7 @@ pub fn trace_with_journald() -> Option { /// /// [`init_tracing`]: utils::tracing::init_tracing /// [`init_metrics`]: utils::metrics::init_metrics +#[must_use] pub fn trace_only() -> Option { utils::tracing::init_tracing() } diff --git a/src/utils/from_env.rs b/src/utils/from_env.rs index 1069aa2..ea51c19 100644 --- a/src/utils/from_env.rs +++ b/src/utils/from_env.rs @@ -164,6 +164,7 @@ pub enum FromEnvErr { impl FromEnvErr { /// Convert the error into another error type. + #[must_use] pub fn infallible_into(self) -> FromEnvErr { match self { Self::EnvError(s, e) => FromEnvErr::EnvError(s, e), @@ -198,11 +199,13 @@ impl FromEnvErr { } /// Missing env var. + #[must_use] pub fn env_err(var: &str, e: VarError) -> Self { Self::EnvError(var.to_string(), e) } /// Empty env var. + #[must_use] pub fn empty(var: &str) -> Self { Self::Empty(var.to_string()) } @@ -215,6 +218,10 @@ impl FromEnvErr { /// Convenience function for parsing a value from the environment, if present /// and non-empty. +/// +/// # Errors +/// +/// Returns an error if the variable is missing, empty, or cannot be parsed. pub fn parse_env_if_present(env_var: &str) -> Result> { let s = std::env::var(env_var).map_err(|e| FromEnvErr::env_err(env_var, e))?; @@ -290,6 +297,10 @@ pub trait FromEnv: core::fmt::Debug + Sized + 'static { /// This will check all environment variables in the inventory, and return /// a list of those that are non-optional and missing. This is useful for /// reporting missing environment variables. + /// + /// # Errors + /// + /// Returns the required environment variables that are missing. fn check_inventory() -> Result<(), Vec<&'static EnvItemInfo>> { let mut missing = Vec::new(); for var in Self::inventory() { @@ -305,6 +316,10 @@ pub trait FromEnv: core::fmt::Debug + Sized + 'static { } /// Load from the environment. + /// + /// # Errors + /// + /// Returns an error if a required value is missing, empty, or invalid. fn from_env() -> Result>; } @@ -325,7 +340,7 @@ where fn from_env() -> Result> { match T::from_env() { Ok(v) => Ok(Some(v)), - Err(FromEnvErr::Empty(_)) | Err(FromEnvErr::EnvError(_, _)) => Ok(None), + Err(FromEnvErr::Empty(_) | FromEnvErr::EnvError(_, _)) => Ok(None), Err(e) => Err(e), } } @@ -455,6 +470,10 @@ pub trait FromEnvVar: core::fmt::Debug + Sized + 'static { type Error: core::error::Error; /// Load the primitive from the environment at the given variable. + /// + /// # Errors + /// + /// Returns an error if the variable is missing, empty, or invalid. fn from_env_var(env_var: &str) -> Result>; /// Load the primitive from the environment at the given variable. If the @@ -462,10 +481,14 @@ pub trait FromEnvVar: core::fmt::Debug + Sized + 'static { /// /// This function will return an error if the environment variable is set /// but cannot be parsed. + /// + /// # Errors + /// + /// Returns an error if the variable is present but invalid. fn from_env_var_or(env_var: &str, default: Self) -> Result> { match Self::from_env_var(env_var) { Ok(v) => Ok(v), - Err(FromEnvErr::Empty(_)) | Err(FromEnvErr::EnvError(_, _)) => Ok(default), + Err(FromEnvErr::Empty(_) | FromEnvErr::EnvError(_, _)) => Ok(default), Err(e) => Err(e), } } @@ -476,13 +499,17 @@ pub trait FromEnvVar: core::fmt::Debug + Sized + 'static { /// /// This function will return an error if the environment variable is set /// but cannot be parsed. + /// + /// # Errors + /// + /// Returns an error if the variable is present but invalid. fn from_env_var_or_else( env_var: &str, default: impl FnOnce() -> Self, ) -> Result> { match Self::from_env_var(env_var) { Ok(v) => Ok(v), - Err(FromEnvErr::Empty(_)) | Err(FromEnvErr::EnvError(_, _)) => Ok(default()), + Err(FromEnvErr::Empty(_) | FromEnvErr::EnvError(_, _)) => Ok(default()), Err(e) => Err(e), } } @@ -493,6 +520,10 @@ pub trait FromEnvVar: core::fmt::Debug + Sized + 'static { /// /// This function will return an error if the environment variable is set /// but cannot be parsed. + /// + /// # Errors + /// + /// Returns an error if the variable is present but invalid. fn from_env_var_or_default(env_var: &str) -> Result> where Self: Default, @@ -653,53 +684,53 @@ mod test { unsafe { std::env::set_var(env, val.to_string()) }; } - fn load_expect_err(env: &str, err: FromEnvErr) + fn load_expect_err(env: &str, err: &FromEnvErr) where T: FromEnvVar, T::Error: PartialEq, { let res = T::from_env_var(env).unwrap_err(); - assert_eq!(res, err); + assert_eq!(&res, err); } - fn test(env: &str, val: T) + fn test(env: &str, val: &T) where T: ToString + FromEnvVar + PartialEq + std::fmt::Debug, { - set(env, &val); + set(env, val); let res = T::from_env_var(env).unwrap(); - assert_eq!(res, val); + assert_eq!(&res, val); } - fn test_expect_err(env: &str, value: U, err: FromEnvErr) + fn test_expect_err(env: &str, value: &U, err: &FromEnvErr) where T: FromEnvVar, U: ToString, T::Error: PartialEq, { - set(env, &value); + set(env, value); load_expect_err::(env, err); } #[test] fn test_primitives() { - test("U8", 42u8); - test("U16", 42u16); - test("U32", 42u32); - test("U64", 42u64); - test("U128", 42u128); - test("Usize", 42usize); - test("I8", 42i8); - test("I8-NEG", -42i16); - test("I16", 42i16); - test("I32", 42i32); - test("I64", 42i64); - test("I128", 42i128); - test("Isize", 42isize); - test("String", "hello".to_string()); - test("Url", url::Url::parse("http://example.com").unwrap()); - test("Level", tracing::Level::INFO); + test("U8", &42u8); + test("U16", &42u16); + test("U32", &42u32); + test("U64", &42u64); + test("U128", &42u128); + test("Usize", &42usize); + test("I8", &42i8); + test("I8-NEG", &-42i16); + test("I16", &42i16); + test("I32", &42i32); + test("I64", &42i64); + test("I128", &42i128); + test("Isize", &42isize); + test("String", &"hello".to_string()); + test("Url", &url::Url::parse("http://example.com").unwrap()); + test("Level", &tracing::Level::INFO); } #[test] @@ -717,10 +748,10 @@ mod test { fn test_a_few_errors() { test_expect_err::( "U8_", - 30000u16, - FromEnvErr::parse_error("30000".parse::().unwrap_err()), + &30000u16, + &FromEnvErr::parse_error("30000".parse::().unwrap_err()), ); - test_expect_err::("U8_", "", FromEnvErr::empty("U8_")); + test_expect_err::("U8_", &"", &FromEnvErr::empty("U8_")); } } diff --git a/src/utils/otlp.rs b/src/utils/otlp.rs index 1b23a53..57b1f74 100644 --- a/src/utils/otlp.rs +++ b/src/utils/otlp.rs @@ -55,6 +55,7 @@ impl OtelGuard { } /// Create a filtered tracing layer. + #[must_use] pub fn layer(&self) -> impl Layer where S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>, @@ -98,13 +99,13 @@ impl core::error::Error for OtlpParseError {} /// - `OTEL_EXPORTER_OTLP_ENDPOINT` - optional. The endpoint to send traces to, /// should be some valid URL. If not specified, then [`OtelConfig::load`] /// will return [`None`]. -/// - OTEL_LEVEL - optional. Specifies the minimum [`tracing::Level`] to +/// - `OTEL_LEVEL` - optional. Specifies the minimum [`tracing::Level`] to /// export. Defaults to [`tracing::Level::DEBUG`]. -/// - OTEL_TIMEOUT - optional. Specifies the timeout for the exporter in +/// - `OTEL_TIMEOUT` - optional. Specifies the timeout for the exporter in /// **milliseconds**. Defaults to 1000ms, which is equivalent to 1 second. -/// - OTEL_ENVIRONMENT_NAME - optional. Value for the `deployment.environment. +/// - `OTEL_ENVIRONMENT_NAME` - optional. Value for the `deployment.environment. /// name` resource key according to the OTEL conventions. -/// - OTEL_SERVICE_NAME - optional. Value for the `service.name` resource key +/// - `OTEL_SERVICE_NAME` - optional. Value for the `service.name` resource key /// according to the OTEL conventions. Overrides the `CARGO_PKG_NAME` if set. #[derive(Debug, Clone)] #[non_exhaustive] @@ -198,6 +199,7 @@ impl OtelConfig { /// - `OTEL_SERVICE_NAME` - optional. Value for the `service.name` resource key. /// If set, this will override the default service name taken from /// `CARGO_PKG_NAME`. + #[must_use] pub fn load() -> Option { Self::from_env().ok() } @@ -221,6 +223,11 @@ impl OtelConfig { /// Instantiate a new Otel provider, and start relevant tasks. Return a /// guard that will shut down the provider when dropped. + /// + /// # Panics + /// + /// Panics if the OTLP HTTP exporter cannot be built. + #[must_use] pub fn provider(&self) -> OtelGuard { let exporter = opentelemetry_otlp::SpanExporter::builder() .with_http() @@ -274,7 +281,7 @@ mod test { assert_eq!(cfg.timeout, std::time::Duration::from_millis(1000)); assert_eq!(cfg.environment, "unknown"); assert!(cfg.service_name_override.is_none()); - }) + }); } #[test] @@ -288,7 +295,7 @@ mod test { let cfg = OtelConfig::load().unwrap(); assert_eq!(cfg.level, tracing::Level::WARN); - }) + }); } #[test] @@ -302,7 +309,7 @@ mod test { let cfg = OtelConfig::load().unwrap(); assert_eq!(cfg.timeout, std::time::Duration::from_millis(500)); - }) + }); } #[test] @@ -315,7 +322,10 @@ mod test { } let cfg = OtelConfig::load().unwrap(); - assert_eq!(cfg.service_name_override, Some("my-test-service".to_string())); + assert_eq!( + cfg.service_name_override, + Some("my-test-service".to_string()) + ); let resource = cfg.resource(); let service_name_attr = resource @@ -323,7 +333,7 @@ mod test { .find(|(k, _)| k.as_str() == SERVICE_NAME) .unwrap(); assert_eq!(service_name_attr.1.as_str(), "my-test-service"); - }) + }); } #[test] @@ -334,6 +344,6 @@ mod test { let cfg = OtelConfig::load(); assert!(cfg.is_none()); - }) + }); } } diff --git a/src/utils/tracing.rs b/src/utils/tracing.rs index 39260ec..3ef2614 100644 --- a/src/utils/tracing.rs +++ b/src/utils/tracing.rs @@ -53,6 +53,7 @@ macro_rules! install_fmt { /// This function will panic if a global subscriber has already been set. /// /// [`OtelConfig`]: crate::utils::otlp::OtelConfig +#[must_use] pub fn init_tracing() -> Option { let registry = tracing_subscriber::registry();