--- a/Cargo.lock +++ b/Cargo.lock @@ -642,6 +642,16 @@ ] [[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -974,6 +984,8 @@ "nom 8.0.0", "openssh", "opentelemetry", + "opentelemetry-appender-tracing", + "opentelemetry-exporter-env", "opentelemetry_sdk", "peg", "regex", @@ -1239,8 +1251,10 @@ checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1250,9 +1264,11 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 5.3.0", "wasip2", + "wasm-bindgen", ] [[package]] @@ -1450,6 +1466,23 @@ ] [[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] name = "hyper-timeout" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1905,6 +1938,12 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] name = "matchers" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2123,6 +2162,12 @@ ] [[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] name = "opentelemetry" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2137,6 +2182,18 @@ ] [[package]] +name = "opentelemetry-appender-tracing" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] name = "opentelemetry-exporter-env" version = "0.1.0" dependencies = [ @@ -2551,6 +2608,61 @@ ] [[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2 0.5.10", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.5.10", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2729,16 +2841,22 @@ "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-rustls", "tower 0.5.3", "tower-http 0.6.8", "tower-service", @@ -2898,6 +3016,18 @@ ] [[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] name = "rustls-pemfile" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2912,6 +3042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ + "web-time", "zeroize", ] @@ -2957,6 +3088,15 @@ ] [[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2989,6 +3129,29 @@ ] [[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] name = "self_cell" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3455,6 +3618,21 @@ ] [[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] name = "tokio" version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ fleet-shared = { path = "./crates/fleet-shared" } nix-eval = { path = "./crates/nix-eval" } nixlike = { path = "./crates/nixlike" } +opentelemetry-exporter-env = { path = "./crates/opentelemetry-exporter-env" } abort-on-drop = "0.2" age = { version = "0.11", features = ["plugin", "ssh"] } @@ -40,8 +41,9 @@ nix = { version = "0.31.2", features = ["fs", "user"] } nom = "8.0.0" opentelemetry = "0.31.0" -opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "gzip-tonic", "http-json"] } +opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "gzip-tonic", "http-json", "reqwest-rustls"] } opentelemetry_sdk = "0.31.0" +opentelemetry-appender-tracing = "0.31.1" openssh = "0.11.5" peg = "0.8.5" pkg-config = "0.3.30" --- a/cmds/fleet/Cargo.toml +++ b/cmds/fleet/Cargo.toml @@ -48,6 +48,8 @@ thiserror.workspace = true tracing-indicatif = { workspace = true, optional = true } tracing-opentelemetry.workspace = true +opentelemetry-exporter-env.workspace = true +opentelemetry-appender-tracing.workspace = true [features] default = ["indicatif"] --- a/cmds/fleet/src/main.rs +++ b/cmds/fleet/src/main.rs @@ -25,6 +25,12 @@ use nix_eval::{ gc_register_my_thread, gc_unregister_my_thread, init_libraries, init_tokio_for_nix, }; +use opentelemetry::trace::TracerProvider; +use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; +use opentelemetry_exporter_env::{ + OtlpBaseSettings, OtlpLogsSettings, OtlpTracesSettings, ResolvedOtlpSettings, +}; +use opentelemetry_sdk::{logs::SdkLoggerProvider, trace::SdkTracerProvider}; use tracing::{Instrument, error, info, info_span}; #[cfg(feature = "indicatif")] use tracing_indicatif::IndicatifLayer; @@ -96,6 +102,14 @@ fleet_opts: FleetOpts, #[clap(subcommand)] command: Opts, + #[clap(long, next_help_heading = "Telemetry", env = "OTEL_FLEET")] + otel: bool, + #[clap(flatten)] + otlp_base: OtlpBaseSettings, + #[clap(flatten)] + otel_logs: OtlpLogsSettings, + #[clap(flatten)] + otel_traces: OtlpTracesSettings, } async fn run_command(config: &Config, opts: FleetOpts, command: Opts) -> Result<()> { @@ -115,7 +129,7 @@ Ok(()) } -fn setup_logging() { +fn setup_logging(opts: &RootOpts) -> Result<()> { #[cfg(feature = "indicatif")] let indicatif_layer = { use std::time::Duration; @@ -173,12 +187,35 @@ sub.with_filter(filter) // .without, }); - if env::var_os("FLEET_OTEL").is_some() {} - - // #[cfg(feature = "indicatif")] #[cfg(feature = "indicatif")] let reg = reg.with(indicatif_layer); - reg.init(); + + if opts.otel { + let traces = ResolvedOtlpSettings::traces(&opts.otlp_base, &opts.otel_traces)?; + let span_exporter = traces.span_exporter()?; + let logs = ResolvedOtlpSettings::logs(&opts.otlp_base, &opts.otel_logs)?; + let log_exporter = logs.log_exporter()?; + + let span_provider = SdkTracerProvider::builder() + .with_batch_exporter(span_exporter) + .build(); + let log_provider = SdkLoggerProvider::builder() + .with_batch_exporter(log_exporter) + .build(); + + let logger = OpenTelemetryTracingBridge::new(&log_provider); + let tracer = span_provider.tracer("fleet"); + + let reg = reg + .with(tracing_opentelemetry::layer().with_tracer(tracer)) + .with(logger); + + reg.init(); + } else { + reg.init(); + }; + + Ok(()) } fn main() -> ExitCode { @@ -188,7 +225,10 @@ return ExitCode::SUCCESS; } - setup_logging(); + if let Err(e) = setup_logging(&opts) { + eprintln!("{e:#}"); + return ExitCode::FAILURE; + } init_libraries(); --- a/crates/fleet-base/src/opts.rs +++ b/crates/fleet-base/src/opts.rs @@ -96,7 +96,7 @@ #[clap(long, default_value = env!("NIX_SYSTEM"))] pub local_system: String, - /// By default fleet continues on single derivation build failure + /// By default fleet continues on single derivation build failure; /// this flag makes command fail immediately /// /// Opposite of Nix's --keep-going --- a/crates/opentelemetry-exporter-env/src/lib.rs +++ b/crates/opentelemetry-exporter-env/src/lib.rs @@ -196,7 +196,12 @@ pub struct $id { $( $(#[doc = $doc])* - #[cfg_attr(feature = "clap", arg(long = concat!("otel-exporter-otlp-", $long_prefix, $long), env = concat!("OTEL_EXPORTER_OTLP_", $env_prefix, $env) $(, $($tt)*)?))] + #[cfg_attr(feature = "clap", arg( + long = concat!("otel-exporter-otlp-", $long_prefix, $long), + id = concat!("otel-exporter-otlp-", $long_prefix, $long), + env = concat!("OTEL_EXPORTER_OTLP_", $env_prefix, $env) + $(, $($tt)*)?) + )] pub $name: Option<$ty>, )* }