difftreelog
feat extract otel autoconfig from pusher
in: trunk
6 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -673,6 +673,15 @@
]
[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1000,6 +1009,16 @@
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
+name = "flate2"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
name = "fleet"
version = "0.2.0"
dependencies = [
@@ -1025,6 +1044,8 @@
"nixlike",
"nom 8.0.0",
"openssh",
+ "opentelemetry",
+ "opentelemetry_sdk",
"owo-colors",
"peg",
"regex",
@@ -1038,6 +1059,7 @@
"tokio-util",
"tracing",
"tracing-indicatif",
+ "tracing-opentelemetry",
"tracing-subscriber",
]
@@ -1168,6 +1190,15 @@
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1492,6 +1523,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
dependencies = [
+ "base64 0.22.1",
"bytes",
"futures-channel",
"futures-core",
@@ -1499,7 +1531,9 @@
"http",
"http-body",
"hyper",
+ "ipnet",
"libc",
+ "percent-encoding",
"pin-project-lite",
"socket2 0.6.0",
"tokio",
@@ -1598,6 +1632,113 @@
]
[[package]]
+name = "icu_collections"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+
+[[package]]
+name = "icu_properties"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "potential_utf",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+
+[[package]]
+name = "icu_provider"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1684,6 +1825,22 @@
checksum = "4b3f7cef34251886990511df1c61443aa928499d598a9473929ab5a90a527304"
[[package]]
+name = "ipnet"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+
+[[package]]
+name = "iri-string"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
name = "is-terminal"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1799,6 +1956,12 @@
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
+[[package]]
name = "litrs"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2050,6 +2213,93 @@
]
[[package]]
+name = "opentelemetry"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "js-sys",
+ "pin-project-lite",
+ "thiserror 2.0.16",
+ "tracing",
+]
+
+[[package]]
+name = "opentelemetry-exporter-env"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "opentelemetry-otlp",
+ "thiserror 2.0.16",
+]
+
+[[package]]
+name = "opentelemetry-http"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "http",
+ "opentelemetry",
+ "reqwest",
+]
+
+[[package]]
+name = "opentelemetry-otlp"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b"
+dependencies = [
+ "http",
+ "opentelemetry",
+ "opentelemetry-http",
+ "opentelemetry-proto",
+ "opentelemetry_sdk",
+ "prost",
+ "reqwest",
+ "serde_json",
+ "thiserror 2.0.16",
+ "tokio",
+ "tonic 0.13.1",
+ "tracing",
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc"
+dependencies = [
+ "base64 0.22.1",
+ "hex",
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "prost",
+ "serde",
+ "tonic 0.13.1",
+]
+
+[[package]]
+name = "opentelemetry_sdk"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b"
+dependencies = [
+ "futures-channel",
+ "futures-executor",
+ "futures-util",
+ "opentelemetry",
+ "percent-encoding",
+ "rand 0.9.2",
+ "serde_json",
+ "thiserror 2.0.16",
+]
+
+[[package]]
name = "owo-colors"
version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2251,6 +2501,15 @@
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
+name = "potential_utf"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2484,6 +2743,40 @@
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
[[package]]
+name = "reqwest"
+version = "0.12.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tower 0.5.2",
+ "tower-http 0.6.6",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
name = "ring"
version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2817,6 +3110,18 @@
]
[[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 = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2937,6 +3242,12 @@
]
[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2983,8 +3294,22 @@
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "tabled"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3103,9 +3428,9 @@
"tokio",
"tokio-stream",
"tokio-util",
- "tonic",
+ "tonic 0.12.3",
"tonic-build",
- "tower-http",
+ "tower-http 0.5.2",
"tracing",
"tracing-subscriber",
]
@@ -3306,6 +3631,33 @@
]
[[package]]
+name = "tonic"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9"
+dependencies = [
+ "async-trait",
+ "base64 0.22.1",
+ "bytes",
+ "flate2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-timeout",
+ "hyper-util",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "tokio",
+ "tokio-stream",
+ "tower 0.5.2",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
name = "tonic-build"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3347,10 +3699,15 @@
dependencies = [
"futures-core",
"futures-util",
+ "indexmap 2.11.0",
"pin-project-lite",
+ "slab",
"sync_wrapper",
+ "tokio",
+ "tokio-util",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
@@ -3371,6 +3728,24 @@
]
[[package]]
+name = "tower-http"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower 0.5.2",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3438,6 +3813,24 @@
]
[[package]]
+name = "tracing-opentelemetry"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c"
+dependencies = [
+ "js-sys",
+ "once_cell",
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "smallvec",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-subscriber",
+ "web-time",
+]
+
+[[package]]
name = "tracing-serde"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3567,6 +3960,24 @@
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
+name = "url"
+version = "2.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3691,6 +4102,19 @@
]
[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3723,6 +4147,16 @@
]
[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3997,6 +4431,12 @@
checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
[[package]]
+name = "writeable"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[package]]
name = "wsl"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4024,6 +4464,30 @@
]
[[package]]
+name = "yoke"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "z85"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4054,8 +4518,23 @@
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4076,10 +4555,34 @@
]
[[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
name = "zerovec"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
dependencies = [
+ "yoke",
"zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
cmds/fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -46,6 +46,9 @@
indicatif = { version = "0.18", optional = true }
nom = "8.0.0"
tracing-indicatif = { version = "0.3", optional = true }
+tracing-opentelemetry = "0.31.0"
+opentelemetry = "0.30.0"
+opentelemetry_sdk = "0.30.0"
[features]
default = []
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -4,7 +4,7 @@
// pub(crate) mod command;
pub(crate) mod extra_args;
-use std::{ffi::OsString, process::ExitCode};
+use std::{env, ffi::OsString, process::ExitCode};
use anyhow::{Result, bail};
use clap::{CommandFactory, Parser};
@@ -27,7 +27,7 @@
use tracing::{Instrument, error, info, info_span};
#[cfg(feature = "indicatif")]
use tracing_indicatif::IndicatifLayer;
-use tracing_subscriber::{fmt::format::Format, prelude::*, EnvFilter};
+use tracing_subscriber::{EnvFilter, fmt::format::Format, prelude::*};
#[derive(Parser)]
struct Prefetch {}
@@ -170,6 +170,9 @@
let sub = sub.with_writer(indicatif_layer.get_stderr_writer());
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);
crates/opentelemetry-exporter-env/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/crates/opentelemetry-exporter-env/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "opentelemetry-exporter-env"
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+clap = { workspace = true, optional = true }
+opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "gzip-tonic", "http-json"], optional = true }
+thiserror.workspace = true
+
+[features]
+default = ["clap", "otlp"]
+clap = ["dep:clap"]
+otlp = ["dep:opentelemetry-otlp"]
crates/opentelemetry-exporter-env/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/opentelemetry-exporter-env/src/lib.rs
@@ -0,0 +1,264 @@
+use std::collections::HashMap;
+use std::convert::Infallible;
+use std::env::{self, VarError};
+use std::ffi::OsString;
+use std::num::ParseIntError;
+use std::str::FromStr;
+use std::time::Duration;
+
+use clap::Parser;
+#[cfg(feature = "otlp")]
+use opentelemetry_otlp::tonic_types::metadata::MetadataMap;
+#[cfg(feature = "otlp")]
+use opentelemetry_otlp::{
+ ExporterBuildError, LogExporter, MetricExporter, SpanExporter, WithExportConfig,
+ WithHttpConfig, WithTonicConfig,
+};
+
+#[cfg(feature = "otlp")]
+mod otlp;
+
+pub enum Error {
+ InvalidUtf8 {
+ env: &'static str,
+ value: OsString,
+ },
+ EnvParseError {
+ env: &'static str,
+ value: String,
+ error: &'static str,
+ },
+ EnvParseIntError {
+ env: &'static str,
+ value: String,
+ error: ParseIntError,
+ },
+}
+impl From<(&'static str, &'static str, String)> for Error {
+ fn from((env, error, value): (&'static str, &'static str, String)) -> Self {
+ Self::EnvParseError { env, value, error }
+ }
+}
+impl From<(&'static str, ParseIntError, String)> for Error {
+ fn from((env, error, value): (&'static str, ParseIntError, String)) -> Self {
+ Self::EnvParseIntError { env, value, error }
+ }
+}
+impl From<(&'static str, Infallible, String)> for Error {
+ fn from(_v: (&'static str, Infallible, String)) -> Self {
+ unreachable!()
+ }
+}
+
+fn load_env<T>(env: &'static str) -> Result<Option<T>, Error>
+where
+ T: FromStr,
+ Error: From<(&'static str, <T as FromStr>::Err, String)>,
+{
+ match env::var(env) {
+ Ok(v) => Ok(Some(T::from_str(&v).map_err(|err| (env, err, v))?)),
+ Err(VarError::NotPresent) => Ok(None),
+ Err(VarError::NotUnicode(value)) => Err(Error::InvalidUtf8 { env, value }),
+ }
+}
+
+macro_rules! impl_settings {
+ (
+ #[name($env_prefix:literal, $long_prefix:literal)]
+ struct $id:ident {
+ $(
+ $(#[doc = $doc:literal])*
+ #[name($env:literal, $long:literal)]
+ $(#[arg($($tt:tt)*)])?
+ $name:ident: $ty:ty,
+ )*
+ }) => {
+ #[derive(Parser)]
+ pub struct $id {
+ $(
+ $(#[doc = $doc])*
+ #[arg(long = concat!("otel-exporter-otlp-", $long_prefix, $long), env = concat!("OTEL_EXPORTER_OTLP_", $env_prefix, $env), $($($tt)*)?)]
+ pub $name: Option<$ty>,
+ )*
+ }
+ impl $id {
+ pub fn from_env() -> Result<Self, Error> {
+ Ok(Self {
+ $(
+ $name: load_env(concat!("OTEL_EXPORTER_OTLP_", $env_prefix, $env))?,
+ )*
+ })
+ }
+ }
+ }
+}
+macro_rules! impl_enum {
+ (enum $id:ident {
+ $(
+ #[name = $value:literal]
+ $var:ident,
+ )*
+ }) => {
+ #[derive(Clone, Copy)]
+ #[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
+ pub enum $id {
+ $(
+ #[cfg_attr(feature = "clap", value(name = $value))]
+ $var,
+ )*
+ }
+ impl FromStr for $id {
+ type Err = &'static str;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ $(
+ $value => Self::$var,
+ )*
+ _ => return Err("unsupported value, supported are")
+ })
+ }
+ }
+ };
+}
+
+impl_enum! {
+ enum Compression {
+ #[name = "gzip"]
+ Gzip,
+ #[name = "zstd"]
+ Zstd,
+ }
+}
+#[cfg(feature = "otlp")]
+impl From<Compression> for opentelemetry_otlp::Compression {
+ fn from(value: Compression) -> Self {
+ match value {
+ Compression::Gzip => opentelemetry_otlp::Compression::Gzip,
+ Compression::Zstd => opentelemetry_otlp::Compression::Zstd,
+ }
+ }
+}
+
+impl_enum! {
+ enum OtlpProtocol {
+ #[name = "grpc"]
+ Grpc,
+ #[name = "http/protobuf"]
+ HttpProtobuf,
+ #[name = "http/json"]
+ HttpJson,
+ }
+}
+#[cfg(feature = "otlp")]
+impl From<OtlpProtocol> for opentelemetry_otlp::Protocol {
+ fn from(value: OtlpProtocol) -> Self {
+ match value {
+ OtlpProtocol::Grpc => opentelemetry_otlp::Protocol::Grpc,
+ OtlpProtocol::HttpProtobuf => opentelemetry_otlp::Protocol::HttpBinary,
+ OtlpProtocol::HttpJson => opentelemetry_otlp::Protocol::HttpJson,
+ }
+ }
+}
+
+impl_settings! {
+ #[name("", "")]
+ struct OtlpBaseSettings {
+ /// Specifies the OTLP transport compression to be used for all telemetry data.
+ #[name("COMPRESSION", "compression")]
+ #[arg(value_enum)]
+ compression: Compression,
+ /// A base endpoint URL for any signal type, with an optionally-specified port number. Helpful for when you’re sending more than one signal to the same endpoint and want one environment variable to control the endpoint.
+ #[name("ENDPOINT", "endpoint")]
+ endpoint: String,
+ /// A list of headers to apply to all outgoing data (traces, metrics, and logs).
+ #[name("HEADERS", "headers")]
+ headers: String,
+ /// Specifies the OTLP transport protocol to be used for all telemetry data.
+ #[name("PROTOCOL", "protocol")]
+ #[arg(value_enum)]
+ protocol: OtlpProtocol,
+ /// The timeout value for all outgoing data (traces, metrics, and logs) in milliseconds.
+ #[name("TIMEOUT", "timeout")]
+ timeout: u64,
+ }
+}
+impl_settings! {
+ #[name("LOGS_", "logs-")]
+ struct OtlpLogsSettings {
+ /// Specifies the OTLP transport compression to be used for log data.
+ #[name("COMPRESSION", "compression")]
+ #[arg(value_enum)]
+ compression: Compression,
+ /// Endpoint URL for log data only, with an optionally-specified port number. Typically ends with `v1/logs` when using OTLP/HTTP.
+ #[name("ENDPOINT", "endpoint")]
+ endpoint: String,
+ /// A list of headers to apply to all outgoing logs.
+ #[name("HEADERS", "headers")]
+ headers: String,
+ /// Specifies the OTLP transport protocol to be used for log data.
+ #[name("PROTOCOL", "protocol")]
+ #[arg(value_enum)]
+ protocol: OtlpProtocol,
+ /// The timeout value for all outgoing logs in milliseconds.
+ #[name("TIMEOUT", "timeout")]
+ timeout: u64,
+ }
+}
+impl_settings! {
+ #[name("METRICS_", "metrics-")]
+ struct OtlpMetricsSettings {
+ /// Specifies the OTLP transport compression to be used for metrics data.
+ #[name("COMPRESSION", "compression")]
+ #[arg(value_enum)]
+ compression: Compression,
+ /// Endpoint URL for metric data only, with an optionally-specified port number. Typically ends with `v1/metrics` when using OTLP/HTTP.
+ #[name("ENDPOINT", "endpoint")]
+ endpoint: String,
+ /// A list of headers to apply to all outgoing metrics.
+ #[name("HEADERS", "headers")]
+ headers: String,
+ /// Specifies the OTLP transport protocol to be used for metrics data.
+ #[name("PROTOCOL", "protocol")]
+ #[arg(value_enum)]
+ protocol: OtlpProtocol,
+ /// The timeout value for all outgoing metrics in milliseconds.
+ #[name("TIMEOUT", "timeout")]
+ timeout: u64,
+ }
+}
+
+impl_settings! {
+ #[name("TRACES_", "traces-")]
+ struct OtlpTracesSettings {
+ /// Specifies the OTLP transport compression to be used for trace data.
+ #[name("COMPRESSION", "compression")]
+ #[arg(value_enum)]
+ compression: Compression,
+ /// Endpoint URL for trace data only, with an optionally-specified port number. Typically ends with `v1/traces` when using OTLP/HTTP.
+ #[name("ENDPOINT", "endpoint")]
+ endpoint: String,
+ /// A list of headers to apply to all outgoing traces.
+ #[name("HEADERS", "headers")]
+ headers: String,
+ /// Specifies the OTLP transport protocol to be used for trace data.
+ #[name("PROTOCOL", "protocol")]
+ #[arg(value_enum)]
+ protocol: OtlpProtocol,
+ /// The timeout value for all outgoing traces in milliseconds.
+ #[name("TIMEOUT", "timeout")]
+ timeout: u64,
+ }
+}
+
+#[derive(thiserror::Error, Debug)]
+enum ProviderError {
+ #[error("protocol is not set")]
+ UnsetProtocol,
+ #[error("endpoint is not set")]
+ EndpointUnset,
+ #[cfg(feature = "otlp")]
+ #[error("failed to build exporter: {0}")]
+ Exporter(#[from] ExporterBuildError),
+}
+type ProviderResult<T, E = ProviderError> = Result<T, E>;
crates/opentelemetry-exporter-env/src/otlp.rsdiffbeforeafterboth1use std::collections::HashMap;2use std::time::Duration;34use opentelemetry_otlp::tonic_types::metadata::MetadataMap;5use opentelemetry_otlp::{6 LogExporter, MetricExporter, SpanExporter, WithExportConfig as _, WithHttpConfig as _,7 WithTonicConfig as _,8};910use crate::{11 OtlpBaseSettings, OtlpLogsSettings, OtlpMetricsSettings, OtlpProtocol, ProviderError,12 ProviderResult,13};1415fn parse_headers<'a>(16 headers: &'a str,17) -> std::iter::Map<std::str::Split<'a, char>, impl FnMut(&'a str) -> (&'a str, &'a str)> {18 headers.split(',').map(|header| {19 let mut parts = header.splitn(2, '=');20 let key = parts.next().unwrap();21 let value = parts.next().unwrap_or("");22 (key, value)23 })24}2526fn parse_headers_metadata_map(headers: Option<&str>) -> MetadataMap {27 headers28 .map(|headers| {29 MetadataMap::from_headers(30 parse_headers(headers)31 .map(|(key, value)| (key.parse().unwrap(), value.parse().unwrap()))32 .collect(),33 )34 })35 .unwrap_or_default()36}37fn parse_headers_hashmap(headers: Option<&str>) -> HashMap<String, String> {38 headers39 .map(|headers| {40 parse_headers(headers)41 .map(|(key, value)| (key.into(), value.into()))42 .collect()43 })44 .unwrap_or_default()45}4647fn logger_exporter(base: &OtlpBaseSettings, log: &OtlpLogsSettings) -> ProviderResult<LogExporter> {48 let endpoint = log49 .endpoint50 .clone()51 .or_else(|| Some(format!("{}/v1/logs", base.endpoint.as_ref()?)))52 .ok_or(ProviderError::EndpointUnset)?;53 let headers = log.headers.as_deref().or(base.headers.as_deref());54 let timeout = Duration::from_millis(log.timeout.or(base.timeout).unwrap_or(10000));5556 let protocol = log57 .protocol58 .or(base.protocol)59 .ok_or(ProviderError::UnsetProtocol)?;6061 match protocol {62 OtlpProtocol::Grpc => {63 let mut builder = LogExporter::builder()64 .with_tonic()65 .with_endpoint(endpoint)66 .with_metadata(parse_headers_metadata_map(headers))67 .with_protocol(protocol.into())68 .with_timeout(timeout);69 let compression = log.compression.or(base.compression);70 if let Some(compression) = compression {71 builder = builder.with_compression(compression.into());72 }7374 Ok(builder.build()?)75 }76 OtlpProtocol::HttpProtobuf | OtlpProtocol::HttpJson => {77 let builder = LogExporter::builder()78 .with_http()79 .with_endpoint(endpoint)80 .with_headers(parse_headers_hashmap(headers))81 .with_protocol(protocol.into())82 .with_timeout(timeout);8384 Ok(builder.build()?)85 }86 }87}88fn metric_exporter(89 base: &OtlpBaseSettings,90 metric: &OtlpMetricsSettings,91) -> ProviderResult<MetricExporter> {92 let endpoint = metric93 .endpoint94 .clone()95 .or_else(|| Some(format!("{}/v1/metrics", base.endpoint.as_ref()?)))96 .ok_or(ProviderError::EndpointUnset)?;97 let headers = metric.headers.as_deref().or(base.headers.as_deref());98 let timeout = Duration::from_millis(metric.timeout.or(base.timeout).unwrap_or(10000));99100 let protocol = metric101 .protocol102 .or(base.protocol)103 .ok_or(ProviderError::UnsetProtocol)?;104105 match protocol {106 OtlpProtocol::Grpc => {107 let mut builder = MetricExporter::builder()108 .with_tonic()109 .with_endpoint(endpoint)110 .with_metadata(parse_headers_metadata_map(headers))111 .with_protocol(protocol.into())112 .with_timeout(timeout);113 let compression = metric.compression.or(base.compression);114 if let Some(compression) = compression {115 builder = builder.with_compression(compression.into());116 }117118 Ok(builder.build()?)119 }120 OtlpProtocol::HttpProtobuf | OtlpProtocol::HttpJson => {121 let builder = MetricExporter::builder()122 .with_http()123 .with_endpoint(endpoint)124 .with_headers(parse_headers_hashmap(headers))125 .with_protocol(protocol.into())126 .with_timeout(timeout);127128 Ok(builder.build()?)129 }130 }131}132fn span_exporter(133 base: &OtlpBaseSettings,134 trace: &OtlpMetricsSettings,135) -> ProviderResult<SpanExporter> {136 let endpoint = trace137 .endpoint138 .clone()139 .or_else(|| Some(format!("{}/v1/traces", base.endpoint.as_ref()?)))140 .ok_or(ProviderError::EndpointUnset)?;141 let headers = trace.headers.as_deref().or(base.headers.as_deref());142 let timeout = Duration::from_millis(trace.timeout.or(base.timeout).unwrap_or(10000));143144 let protocol = trace145 .protocol146 .or(base.protocol)147 .ok_or(ProviderError::UnsetProtocol)?;148149 match protocol {150 OtlpProtocol::Grpc => {151 let mut builder = SpanExporter::builder()152 .with_tonic()153 .with_endpoint(endpoint)154 .with_metadata(parse_headers_metadata_map(headers))155 .with_protocol(protocol.into())156 .with_timeout(timeout);157 let compression = trace.compression.or(base.compression);158 if let Some(compression) = compression {159 builder = builder.with_compression(compression.into());160 }161162 Ok(builder.build()?)163 }164 OtlpProtocol::HttpProtobuf | OtlpProtocol::HttpJson => {165 let builder = SpanExporter::builder()166 .with_http()167 .with_endpoint(endpoint)168 .with_headers(parse_headers_hashmap(headers))169 .with_protocol(protocol.into())170 .with_timeout(timeout);171172 Ok(builder.build()?)173 }174 }175}