diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 37517a6ae..0e270c408 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -41,6 +41,15 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +[[package]] +name = "arc-swap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -470,6 +479,7 @@ dependencies = [ "chrono", "cookie", "datadog-fips", + "datadog-opentelemetry", "datadog-protos", "ddsketch-agent", "dogstatsd", @@ -488,12 +498,12 @@ dependencies = [ "indexmap", "itertools 0.14.0", "lazy_static", - "libdd-common", - "libdd-trace-normalization", + "libdd-common 1.1.0", + "libdd-trace-normalization 1.0.0", "libdd-trace-obfuscation", - "libdd-trace-protobuf", - "libdd-trace-stats", - "libdd-trace-utils", + "libdd-trace-protobuf 1.0.0", + "libdd-trace-stats 1.0.0", + "libdd-trace-utils 1.0.0", "libddwaf", "log", "mime", @@ -501,7 +511,7 @@ dependencies = [ "multipart", "nix 0.26.4", "opentelemetry-proto", - "opentelemetry-semantic-conventions", + "opentelemetry-semantic-conventions 0.30.0", "ordered_hash_map", "proptest", "prost 0.13.5", @@ -568,6 +578,15 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "cadence" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7aff0c323415907f37007d645d7499c378df47efb3e33ffc1f397fa4e549b2e" +dependencies = [ + "crossbeam-channel", +] + [[package]] name = "cc" version = "1.2.55" @@ -704,6 +723,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -737,6 +765,39 @@ dependencies = [ "tracing", ] +[[package]] +name = "datadog-opentelemetry" +version = "0.3.0" +source = "git+https://github.com/DataDog/dd-trace-rs?rev=f51cefc4ad24bec81b38fb2f36b1ed93f21ae913#f51cefc4ad24bec81b38fb2f36b1ed93f21ae913" +dependencies = [ + "anyhow", + "arc-swap", + "base64 0.21.7", + "foldhash 0.1.5", + "hashbrown 0.15.5", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "libdd-common 2.0.0", + "libdd-data-pipeline", + "libdd-telemetry", + "libdd-tinybytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libdd-trace-utils 2.0.0", + "lru", + "opentelemetry 0.31.0", + "opentelemetry-semantic-conventions 0.31.0", + "opentelemetry_sdk 0.31.0", + "rand 0.8.5", + "rustc_version_runtime", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "uuid", +] + [[package]] name = "datadog-protos" version = "0.1.0" @@ -1005,6 +1066,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1154,11 +1221,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -1213,7 +1293,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1221,6 +1301,11 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "headers" @@ -1578,6 +1663,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -1607,6 +1698,8 @@ checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -1730,6 +1823,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "levenshtein" version = "1.0.5" @@ -1776,6 +1875,67 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "libdd-common" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91116127343b77b5dbed498fc97ac76c9332ad2e4564931a41740f33bddc406d" +dependencies = [ + "anyhow", + "bytes", + "cc", + "const_format", + "futures", + "futures-core", + "futures-util", + "hex", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "libc", + "nix 0.29.0", + "pin-project", + "regex", + "serde", + "static_assertions", + "thiserror 1.0.69", + "tokio", + "tower-service", + "windows-sys 0.52.0", +] + +[[package]] +name = "libdd-data-pipeline" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f256e1f90403a6ef9aafb130f303902068ef30b2aa55940a5a13ac23f34b04" +dependencies = [ + "anyhow", + "arc-swap", + "bytes", + "either", + "http 1.4.0", + "http-body-util", + "libdd-common 2.0.0", + "libdd-ddsketch 1.0.1", + "libdd-dogstatsd-client", + "libdd-telemetry", + "libdd-tinybytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libdd-trace-protobuf 1.1.0", + "libdd-trace-stats 1.0.1", + "libdd-trace-utils 2.0.0", + "rmp-serde", + "serde", + "serde_json", + "sha2", + "tokio", + "tokio-util", + "tracing", + "uuid", +] + [[package]] name = "libdd-ddsketch" version = "1.0.0" @@ -1784,6 +1944,63 @@ dependencies = [ "prost 0.14.3", ] +[[package]] +name = "libdd-ddsketch" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b31b2435e2e8eaba0e35a96df3e1407b68f8ef76055383ceb2ba5a09e5a1bb5" +dependencies = [ + "prost 0.14.3", +] + +[[package]] +name = "libdd-dogstatsd-client" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a457381568835e7c3646f3f2d44ff4f3ebcda44d87332e2fdaeb20e6a8365dcd" +dependencies = [ + "anyhow", + "cadence", + "http 1.4.0", + "libdd-common 2.0.0", + "serde", + "tracing", +] + +[[package]] +name = "libdd-telemetry" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e7bb67a865fe7e8a16aacc7bc43a805fb3b907c713e0b212e7a7abe6e0735cb" +dependencies = [ + "anyhow", + "base64 0.22.1", + "futures", + "hashbrown 0.15.5", + "http 1.4.0", + "http-body-util", + "libc", + "libdd-common 2.0.0", + "libdd-ddsketch 1.0.1", + "serde", + "serde_json", + "sys-info", + "tokio", + "tokio-util", + "tracing", + "uuid", + "winver", +] + +[[package]] +name = "libdd-tinybytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47838e12ae2665250b4cdba4e3119230b79e3c522bb9f48dd0c87346f5a8f44" +dependencies = [ + "serde", +] + [[package]] name = "libdd-tinybytes" version = "1.1.0" @@ -1798,7 +2015,17 @@ version = "1.0.0" source = "git+https://github.com/DataDog/libdatadog?rev=c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09#c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" dependencies = [ "anyhow", - "libdd-trace-protobuf", + "libdd-trace-protobuf 1.0.0", +] + +[[package]] +name = "libdd-trace-normalization" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a098586884453469488d903b1c85a6ffad1c85fc79e741cf69ca4472084b15" +dependencies = [ + "anyhow", + "libdd-trace-protobuf 1.1.0", ] [[package]] @@ -1807,9 +2034,9 @@ version = "1.0.0" source = "git+https://github.com/DataDog/libdatadog?rev=c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09#c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" dependencies = [ "anyhow", - "libdd-common", - "libdd-trace-protobuf", - "libdd-trace-utils", + "libdd-common 1.1.0", + "libdd-trace-protobuf 1.0.0", + "libdd-trace-utils 1.0.0", "log", "percent-encoding", "regex", @@ -1828,15 +2055,38 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "libdd-trace-protobuf" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9f34f3070d59a381e6ca81e262c035312253ab135bd8ed15e41fa77af054c7" +dependencies = [ + "prost 0.14.3", + "serde", + "serde_bytes", +] + [[package]] name = "libdd-trace-stats" version = "1.0.0" source = "git+https://github.com/DataDog/libdatadog?rev=c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09#c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" dependencies = [ "hashbrown 0.15.5", - "libdd-ddsketch", - "libdd-trace-protobuf", - "libdd-trace-utils", + "libdd-ddsketch 1.0.0", + "libdd-trace-protobuf 1.0.0", + "libdd-trace-utils 1.0.0", +] + +[[package]] +name = "libdd-trace-stats" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d8ac98adf5831a15463df3d73eaac16d7ee1b11ee4dfead37adcb03771f4de" +dependencies = [ + "hashbrown 0.15.5", + "libdd-ddsketch 1.0.1", + "libdd-trace-protobuf 1.1.0", + "libdd-trace-utils 2.0.0", ] [[package]] @@ -1852,10 +2102,10 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "indexmap", - "libdd-common", - "libdd-tinybytes", - "libdd-trace-normalization", - "libdd-trace-protobuf", + "libdd-common 1.1.0", + "libdd-tinybytes 1.1.0 (git+https://github.com/DataDog/libdatadog?rev=c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09)", + "libdd-trace-normalization 1.0.0", + "libdd-trace-protobuf 1.0.0", "prost 0.14.3", "rand 0.8.5", "rmp", @@ -1868,6 +2118,34 @@ dependencies = [ "zstd", ] +[[package]] +name = "libdd-trace-utils" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140338dedc3a76ef8ffc0a0549a94819daab38e8a714604ec88c8289eab01519" +dependencies = [ + "anyhow", + "bytes", + "futures", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "indexmap", + "libdd-common 2.0.0", + "libdd-tinybytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libdd-trace-normalization 1.0.1", + "libdd-trace-protobuf 1.1.0", + "prost 0.14.3", + "rand 0.8.5", + "rmp", + "rmp-serde", + "rmpv", + "serde", + "serde_json", + "tokio", + "tracing", +] + [[package]] name = "libddwaf" version = "1.28.1" @@ -1949,6 +2227,15 @@ dependencies = [ "value-bag", ] +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2129,6 +2416,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", +] + [[package]] name = "opentelemetry-proto" version = "0.30.0" @@ -2137,8 +2437,8 @@ checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" dependencies = [ "base64 0.22.1", "hex", - "opentelemetry", - "opentelemetry_sdk", + "opentelemetry 0.30.0", + "opentelemetry_sdk 0.30.0", "prost 0.13.5", "serde", "tonic", @@ -2150,6 +2450,12 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2" +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" + [[package]] name = "opentelemetry_sdk" version = "0.30.0" @@ -2159,13 +2465,28 @@ dependencies = [ "futures-channel", "futures-executor", "futures-util", - "opentelemetry", + "opentelemetry 0.30.0", "percent-encoding", "rand 0.9.2", "serde_json", "thiserror 2.0.18", ] +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry 0.31.0", + "percent-encoding", + "rand 0.9.2", + "thiserror 2.0.18", +] + [[package]] name = "ordered-float" version = "2.10.1" @@ -2633,6 +2954,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -2849,6 +3176,25 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -3025,6 +3371,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -3352,6 +3704,16 @@ dependencies = [ "syn 2.0.115", ] +[[package]] +name = "sys-info" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "tar" version = "0.4.44" @@ -3839,6 +4201,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -3897,7 +4270,16 @@ version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", ] [[package]] @@ -3959,6 +4341,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.85" @@ -4040,6 +4456,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -4082,6 +4507,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -4115,6 +4555,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -4127,6 +4573,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -4139,6 +4591,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -4163,6 +4621,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -4175,6 +4639,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -4187,6 +4657,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -4199,6 +4675,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -4211,12 +4693,109 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winver" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0e7162b9e282fd75a0a832cce93994bdb21208d848a418cd05a5fdd9b9ab33" +dependencies = [ + "windows", +] + [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.115", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.115", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" version = "0.6.2" diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 8b3f0f94a..2ca88b877 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -76,6 +76,7 @@ libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "c812 libdd-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" } libdd-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" } libdd-trace-stats = { git = "https://github.com/DataDog/libdatadog", rev = "c8121f422d2c8d219f8d421ff3cdb1fcbe9e8b09" } +datadog-opentelemetry = { git = "https://github.com/DataDog/dd-trace-rs", rev = "f51cefc4ad24bec81b38fb2f36b1ed93f21ae913", default-features = false } dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "28f796bf767fff56caf08153ade5cd80c8e8f705", default-features = false } datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "28f796bf767fff56caf08153ade5cd80c8e8f705", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } diff --git a/bottlecap/LICENSE-3rdparty.csv b/bottlecap/LICENSE-3rdparty.csv index 9c6ff4580..447684078 100644 --- a/bottlecap/LICENSE-3rdparty.csv +++ b/bottlecap/LICENSE-3rdparty.csv @@ -4,6 +4,7 @@ ahash,https://github.com/tkaitchuck/ahash,MIT OR Apache-2.0,Tom Kaitchuck allocator-api2,https://github.com/zakarumych/allocator-api2,MIT OR Apache-2.0,Zakarum anyhow,https://github.com/dtolnay/anyhow,MIT OR Apache-2.0,David Tolnay +arc-swap,https://github.com/vorner/arc-swap,MIT OR Apache-2.0,Michal 'vorner' Vaner async-trait,https://github.com/dtolnay/async-trait,MIT OR Apache-2.0,David Tolnay atomic,https://github.com/Amanieu/atomic-rs,Apache-2.0 OR MIT,Amanieu d'Antras atomic-waker,https://github.com/smol-rs/atomic-waker,Apache-2.0 OR MIT,"Stjepan Glavina , Contributors to futures-rs" @@ -11,6 +12,7 @@ aws-lc-rs,https://github.com/aws/aws-lc-rs,ISC AND (Apache-2.0 OR ISC),AWS-LibCr aws-lc-sys,https://github.com/aws/aws-lc-rs,ISC AND (Apache-2.0 OR ISC) AND OpenSSL,AWS-LC axum,https://github.com/tokio-rs/axum,MIT,The axum Authors axum-core,https://github.com/tokio-rs/axum,MIT,The axum-core Authors +base64,https://github.com/marshallpierce/rust-base64,MIT OR Apache-2.0,"Alice Maz , Marshall Pierce " base64,https://github.com/marshallpierce/rust-base64,MIT OR Apache-2.0,Marshall Pierce bitflags,https://github.com/bitflags/bitflags,MIT OR Apache-2.0,The Rust Project Developers block-buffer,https://github.com/RustCrypto/utils,MIT OR Apache-2.0,RustCrypto Developers @@ -19,6 +21,7 @@ bumpalo,https://github.com/fitzgen/bumpalo,MIT OR Apache-2.0,Nick Fitzgerald byteorder,https://github.com/BurntSushi/byteorder,Unlicense OR MIT,Andrew Gallant bytes,https://github.com/tokio-rs/bytes,MIT,"Carl Lerche , Sean McArthur " +cadence,https://github.com/56quarters/cadence,Apache-2.0 OR MIT,Nick Pillitteri cc,https://github.com/rust-lang/cc-rs,MIT OR Apache-2.0,Alex Crichton cfg-if,https://github.com/rust-lang/cfg-if,MIT OR Apache-2.0,Alex Crichton chrono,https://github.com/chronotope/chrono,MIT OR Apache-2.0,The chrono Authors @@ -29,8 +32,11 @@ core-foundation,https://github.com/servo/core-foundation-rs,MIT OR Apache-2.0,Th core-foundation-sys,https://github.com/servo/core-foundation-rs,MIT OR Apache-2.0,The Servo Project Developers cpufeatures,https://github.com/RustCrypto/utils,MIT OR Apache-2.0,RustCrypto Developers crc32fast,https://github.com/srijs/rust-crc32fast,MIT OR Apache-2.0,"Sam Rijs , Alex Crichton " +crossbeam-channel,https://github.com/crossbeam-rs/crossbeam,MIT OR Apache-2.0,The crossbeam-channel Authors +crossbeam-utils,https://github.com/crossbeam-rs/crossbeam,MIT OR Apache-2.0,The crossbeam-utils Authors crypto-common,https://github.com/RustCrypto/traits,MIT OR Apache-2.0,RustCrypto Developers datadog-fips,https://github.com/DataDog/serverless-components,Apache-2.0,The datadog-fips Authors +datadog-opentelemetry,https://github.com/DataDog/dd-trace-rs/tree/main/datadog-opentelemetry,Apache-2.0,Datadog Inc. datadog-protos,https://github.com/DataDog/saluki,Apache-2.0,The datadog-protos Authors ddsketch-agent,https://github.com/DataDog/saluki,Apache-2.0,The ddsketch-agent Authors deranged,https://github.com/jhpratt/deranged,MIT OR Apache-2.0,Jacob Pratt @@ -65,6 +71,7 @@ h2,https://github.com/hyperium/h2,MIT,"Carl Lerche , Sean McA hashbrown,https://github.com/rust-lang/hashbrown,MIT OR Apache-2.0,Amanieu d'Antras headers,https://github.com/hyperium/headers,MIT,Sean McArthur headers-core,https://github.com/hyperium/headers,MIT,Sean McArthur +heck,https://github.com/withoutboats/heck,MIT OR Apache-2.0,The heck Authors hex,https://github.com/KokaKiwi/rust-hex,MIT OR Apache-2.0,KokaKiwi hmac,https://github.com/RustCrypto/MACs,MIT OR Apache-2.0,RustCrypto Developers http,https://github.com/hyperium/http,MIT OR Apache-2.0,"Alex Crichton , Carl Lerche , Sean McArthur " @@ -84,6 +91,7 @@ icu_normalizer_data,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X P icu_properties,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers icu_properties_data,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers icu_provider,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers +id-arena,https://github.com/fitzgen/id-arena,MIT OR Apache-2.0,"Nick Fitzgerald , Aleksey Kladov " idna,https://github.com/servo/rust-url,MIT OR Apache-2.0,The rust-url developers idna_adapter,https://github.com/hsivonen/idna_adapter,Apache-2.0 OR MIT,The rust-url developers indexmap,https://github.com/indexmap-rs/indexmap,Apache-2.0 OR MIT,The indexmap Authors @@ -95,9 +103,13 @@ itoa,https://github.com/dtolnay/itoa,MIT OR Apache-2.0,David Tolnay js-sys,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys,MIT OR Apache-2.0,The wasm-bindgen Developers lazy_static,https://github.com/rust-lang-nursery/lazy-static.rs,MIT OR Apache-2.0,Marvin Löbel +leb128fmt,https://github.com/bluk/leb128fmt,MIT OR Apache-2.0,Bryant Luk libc,https://github.com/rust-lang/libc,MIT OR Apache-2.0,The Rust Project Developers libdd-common,https://github.com/DataDog/libdatadog/tree/main/datadog-common,Apache-2.0,The libdd-common Authors +libdd-data-pipeline,https://github.com/DataDog/libdatadog/tree/main/libdd-data-pipeline,Apache-2.0,The libdd-data-pipeline Authors libdd-ddsketch,https://github.com/DataDog/libdatadog/tree/main/libdd-ddsketch,Apache-2.0,The libdd-ddsketch Authors +libdd-dogstatsd-client,https://github.com/DataDog/libdatadog/tree/main/libdd-dogstatsd-client,Apache-2.0,The libdd-dogstatsd-client Authors +libdd-telemetry,https://github.com/DataDog/libdatadog/tree/main/libdd-telemetry,Apache-2.0,The libdd-telemetry Authors libdd-tinybytes,https://github.com/DataDog/libdatadog/tree/main/libdd-tinybytes,Apache-2.0,The libdd-tinybytes Authors libdd-trace-normalization,https://github.com/DataDog/libdatadog/tree/main/libdd-trace-normalization,Apache-2.0,David Lee libdd-trace-obfuscation,https://github.com/DataDog/libdatadog/tree/main/libdd-trace-obfuscation,Apache-2.0,Datadog Inc. @@ -110,6 +122,7 @@ linux-raw-sys,https://github.com/sunfishcode/linux-raw-sys,Apache-2.0 WITH LLVM- litemap,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers lock_api,https://github.com/Amanieu/parking_lot,MIT OR Apache-2.0,Amanieu d'Antras log,https://github.com/rust-lang/log,MIT OR Apache-2.0,The Rust Project Developers +lru,https://github.com/jeromefroe/lru-rs,MIT,Jerome Froelich lru-slab,https://github.com/Ralith/lru-slab,MIT OR Apache-2.0 OR Zlib,Benjamin Saunders matchers,https://github.com/hawkw/matchers,MIT,Eliza Weisman matchit,https://github.com/ibraheemdev/matchit,MIT AND BSD-3-Clause,Ibraheem Ahmed @@ -142,6 +155,7 @@ pin-utils,https://github.com/rust-lang-nursery/pin-utils,MIT OR Apache-2.0,Josef potential_utf,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers powerfmt,https://github.com/jhpratt/powerfmt,MIT OR Apache-2.0,Jacob Pratt ppv-lite86,https://github.com/cryptocorrosion/cryptocorrosion,MIT OR Apache-2.0,The CryptoCorrosion Contributors +prettyplease,https://github.com/dtolnay/prettyplease,MIT OR Apache-2.0,David Tolnay proc-macro2,https://github.com/dtolnay/proc-macro2,MIT OR Apache-2.0,"David Tolnay , Alex Crichton " proc-macro2-diagnostics,https://github.com/SergioBenitez/proc-macro2-diagnostics,MIT OR Apache-2.0,Sergio Benitez prost,https://github.com/tokio-rs/prost,Apache-2.0,"Dan Burkert , Lucio Franco , Casper Meijn , Tokio Contributors " @@ -168,18 +182,22 @@ rmp,https://github.com/3Hren/msgpack-rust,MIT,"Evgeny Safronov rmpv,https://github.com/3Hren/msgpack-rust,MIT,Evgeny Safronov rustc-hash,https://github.com/rust-lang/rustc-hash,Apache-2.0 OR MIT,The Rust Project Developers +rustc_version,https://github.com/djc/rustc-version-rs,MIT OR Apache-2.0,The rustc_version Authors +rustc_version_runtime,https://github.com/seppo0010/rustc-version-runtime-rs,MIT,Sebastian Waisbrot rustix,https://github.com/bytecodealliance/rustix,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,"Dan Gohman , Jakub Konka " rustls,https://github.com/rustls/rustls,Apache-2.0 OR ISC OR MIT,The rustls Authors rustls-native-certs,https://github.com/rustls/rustls-native-certs,Apache-2.0 OR ISC OR MIT,The rustls-native-certs Authors rustls-pemfile,https://github.com/rustls/pemfile,Apache-2.0 OR ISC OR MIT,The rustls-pemfile Authors rustls-pki-types,https://github.com/rustls/pki-types,MIT OR Apache-2.0,The rustls-pki-types Authors rustls-webpki,https://github.com/rustls/webpki,ISC,The rustls-webpki Authors +rustversion,https://github.com/dtolnay/rustversion,MIT OR Apache-2.0,David Tolnay ryu,https://github.com/dtolnay/ryu,Apache-2.0 OR BSL-1.0,David Tolnay safemem,https://github.com/abonander/safemem,MIT OR Apache-2.0,Austin Bonander schannel,https://github.com/steffengy/schannel-rs,MIT,"Steven Fackler , Steffen Butzer " scopeguard,https://github.com/bluss/scopeguard,MIT OR Apache-2.0,bluss security-framework,https://github.com/kornelski/rust-security-framework,MIT OR Apache-2.0,"Steven Fackler , Kornel " security-framework-sys,https://github.com/kornelski/rust-security-framework,MIT OR Apache-2.0,"Steven Fackler , Kornel " +semver,https://github.com/dtolnay/semver,MIT OR Apache-2.0,David Tolnay serde,https://github.com/serde-rs/serde,MIT OR Apache-2.0,"Erick Tryzelaar , David Tolnay " serde-aux,https://github.com/iddm/serde-aux,MIT,Victor Polevoy serde-value,https://github.com/arcnmx/serde-value,MIT,arcnmx @@ -206,6 +224,7 @@ subtle,https://github.com/dalek-cryptography/subtle,BSD-3-Clause,"Isis Lovecruft syn,https://github.com/dtolnay/syn,MIT OR Apache-2.0,David Tolnay sync_wrapper,https://github.com/Actyx/sync_wrapper,Apache-2.0,Actyx AG synstructure,https://github.com/mystor/synstructure,MIT,Nika Layzell +sys-info,https://github.com/FillZpp/sys-info-rs,MIT,Siyu Wang tempfile,https://github.com/Stebalien/tempfile,MIT OR Apache-2.0,"Steven Allen , The Rust Project Developers, Ashley Mannix , Jason White " thiserror,https://github.com/dtolnay/thiserror,MIT OR Apache-2.0,David Tolnay thiserror-impl,https://github.com/dtolnay/thiserror,MIT OR Apache-2.0,David Tolnay @@ -246,19 +265,25 @@ untrusted,https://github.com/briansmith/untrusted,ISC,Brian Smith utf8_iter,https://github.com/hsivonen/utf8_iter,Apache-2.0 OR MIT,Henri Sivonen +uuid,https://github.com/uuid-rs/uuid,Apache-2.0 OR MIT,"Ashley Mannix, Dylan DPC, Hunar Roop Kahlon" valuable,https://github.com/tokio-rs/valuable,MIT,The valuable Authors value-bag,https://github.com/sval-rs/value-bag,Apache-2.0 OR MIT,Ashley Mannix want,https://github.com/seanmonstar/want,MIT,Sean McArthur wasi,https://github.com/bytecodealliance/wasi,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,The Cranelift Project Developers wasip2,https://github.com/bytecodealliance/wasi-rs,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,The wasip2 Authors +wasip3,https://github.com/bytecodealliance/wasi-rs,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,The wasip3 Authors wasm-bindgen,https://github.com/wasm-bindgen/wasm-bindgen,MIT OR Apache-2.0,The wasm-bindgen Developers wasm-bindgen-futures,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/futures,MIT OR Apache-2.0,The wasm-bindgen Developers wasm-bindgen-macro,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro,MIT OR Apache-2.0,The wasm-bindgen Developers wasm-bindgen-macro-support,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support,MIT OR Apache-2.0,The wasm-bindgen Developers wasm-bindgen-shared,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared,MIT OR Apache-2.0,The wasm-bindgen Developers +wasm-encoder,https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Nick Fitzgerald +wasm-metadata,https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,The wasm-metadata Authors +wasmparser,https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Yury Delendik web-sys,https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/web-sys,MIT OR Apache-2.0,The wasm-bindgen Developers web-time,https://github.com/daxpedda/web-time,MIT OR Apache-2.0,The web-time Authors webpki-roots,https://github.com/rustls/webpki-roots,CDLA-Permissive-2.0,The webpki-roots Authors +windows,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Microsoft windows-link,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,The windows-link Authors windows-sys,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Microsoft windows-sys,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,The windows-sys Authors @@ -280,7 +305,13 @@ windows_x86_64_gnullvm,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0 windows_x86_64_gnullvm,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,The windows_x86_64_gnullvm Authors windows_x86_64_msvc,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,Microsoft windows_x86_64_msvc,https://github.com/microsoft/windows-rs,MIT OR Apache-2.0,The windows_x86_64_msvc Authors +winver,https://github.com/rhysd/winver,MIT,rhysd wit-bindgen,https://github.com/bytecodealliance/wit-bindgen,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Alex Crichton +wit-bindgen-core,https://github.com/bytecodealliance/wit-bindgen,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Alex Crichton +wit-bindgen-rust,https://github.com/bytecodealliance/wit-bindgen,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Alex Crichton +wit-bindgen-rust-macro,https://github.com/bytecodealliance/wit-bindgen,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Alex Crichton +wit-component,https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Peter Huene +wit-parser,https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser,Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT,Alex Crichton writeable,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers yansi,https://github.com/SergioBenitez/yansi,MIT OR Apache-2.0,Sergio Benitez yoke,https://github.com/unicode-org/icu4x,Unicode-3.0,Manish Goregaokar diff --git a/bottlecap/src/config/env.rs b/bottlecap/src/config/env.rs index f48d2c8d2..4c056d32b 100644 --- a/bottlecap/src/config/env.rs +++ b/bottlecap/src/config/env.rs @@ -24,10 +24,11 @@ use crate::{ }, processing_rule::{ProcessingRule, deserialize_processing_rules}, service_mapping::deserialize_service_mapping, - trace_propagation_style::{TracePropagationStyle, deserialize_trace_propagation_style}, + trace_propagation_style::deserialize_trace_propagation_style, }, merge_hashmap, merge_option, merge_option_to_value, merge_string, merge_vec, }; +use datadog_opentelemetry::propagation::TracePropagationStyle; #[derive(Debug, PartialEq, Deserialize, Clone, Default)] #[serde(default)] @@ -719,8 +720,8 @@ mod tests { flush_strategy::{FlushStrategy, PeriodicStrategy}, log_level::LogLevel, processing_rule::{Kind, ProcessingRule}, - trace_propagation_style::TracePropagationStyle, }; + use datadog_opentelemetry::propagation::TracePropagationStyle; #[test] #[allow(clippy::too_many_lines)] @@ -802,7 +803,7 @@ mod tests { jail.set_env("DD_METRICS_CONFIG_COMPRESSION_LEVEL", "3"); // Trace Propagation jail.set_env("DD_TRACE_PROPAGATION_STYLE", "datadog"); - jail.set_env("DD_TRACE_PROPAGATION_STYLE_EXTRACT", "b3"); + jail.set_env("DD_TRACE_PROPAGATION_STYLE_EXTRACT", "tracecontext"); jail.set_env("DD_TRACE_PROPAGATION_EXTRACT_FIRST", "true"); jail.set_env("DD_TRACE_PROPAGATION_HTTP_BAGGAGE_ENABLED", "true"); jail.set_env("DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "true"); @@ -984,7 +985,7 @@ mod tests { "debug:^true$".to_string(), ]), trace_propagation_style: vec![TracePropagationStyle::Datadog], - trace_propagation_style_extract: vec![TracePropagationStyle::B3], + trace_propagation_style_extract: vec![TracePropagationStyle::TraceContext], trace_propagation_extract_first: true, trace_propagation_http_baggage_enabled: true, trace_aws_service_representation_enabled: true, diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index 23fe110a3..f220028d5 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -29,9 +29,9 @@ use crate::config::{ log_level::LogLevel, logs_additional_endpoints::LogsAdditionalEndpoint, processing_rule::{ProcessingRule, deserialize_processing_rules}, - trace_propagation_style::TracePropagationStyle, yaml::YamlConfigSource, }; +use datadog_opentelemetry::propagation::TracePropagationStyle; /// Helper macro to merge Option fields to String fields /// @@ -488,6 +488,38 @@ impl Default for Config { } } +impl datadog_opentelemetry::propagation::PropagationConfig for Config { + fn trace_propagation_style(&self) -> Option<&[TracePropagationStyle]> { + if self.trace_propagation_style.is_empty() { + None + } else { + Some(&self.trace_propagation_style) + } + } + + fn trace_propagation_style_extract(&self) -> Option<&[TracePropagationStyle]> { + if self.trace_propagation_style_extract.is_empty() { + None + } else { + Some(&self.trace_propagation_style_extract) + } + } + + fn trace_propagation_style_inject(&self) -> Option<&[TracePropagationStyle]> { + // Bottlecap does not configure injection styles separately + None + } + + fn trace_propagation_extract_first(&self) -> bool { + self.trace_propagation_extract_first + } + + fn datadog_tags_max_length(&self) -> usize { + // Default max length matching dd-trace-rs + 512 + } +} + #[allow(clippy::module_name_repetitions)] #[inline] #[must_use] @@ -819,8 +851,8 @@ pub mod tests { flush_strategy::{FlushStrategy, PeriodicStrategy}, log_level::LogLevel, processing_rule::ProcessingRule, - trace_propagation_style::TracePropagationStyle, }; + use datadog_opentelemetry::propagation::TracePropagationStyle; #[test] fn test_default_logs_intake_url() { @@ -1299,17 +1331,12 @@ pub mod tests { fn test_parse_trace_propagation_style() { figment::Jail::expect_with(|jail| { jail.clear_env(); - jail.set_env( - "DD_TRACE_PROPAGATION_STYLE", - "datadog,tracecontext,b3,b3multi", - ); + jail.set_env("DD_TRACE_PROPAGATION_STYLE", "datadog,tracecontext"); let config = get_config(Path::new("")); let expected_styles = vec![ TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext, - TracePropagationStyle::B3, - TracePropagationStyle::B3Multi, ]; assert_eq!(config.trace_propagation_style, expected_styles); assert_eq!(config.trace_propagation_style_extract, expected_styles); diff --git a/bottlecap/src/config/trace_propagation_style.rs b/bottlecap/src/config/trace_propagation_style.rs index 65971bfae..1e32e77f9 100644 --- a/bottlecap/src/config/trace_propagation_style.rs +++ b/bottlecap/src/config/trace_propagation_style.rs @@ -1,48 +1,9 @@ -use std::{fmt::Display, str::FromStr}; +use std::str::FromStr; +use datadog_opentelemetry::propagation::TracePropagationStyle; use serde::{Deserialize, Deserializer}; use tracing::error; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TracePropagationStyle { - Datadog, - B3Multi, - B3, - TraceContext, - None, -} - -impl FromStr for TracePropagationStyle { - type Err = String; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "datadog" => Ok(TracePropagationStyle::Datadog), - "b3multi" => Ok(TracePropagationStyle::B3Multi), - "b3" => Ok(TracePropagationStyle::B3), - "tracecontext" => Ok(TracePropagationStyle::TraceContext), - "none" => Ok(TracePropagationStyle::None), - _ => { - error!("Trace propagation style is invalid: {:?}, using None", s); - Ok(TracePropagationStyle::None) - } - } - } -} - -impl Display for TracePropagationStyle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let style = match self { - TracePropagationStyle::Datadog => "datadog", - TracePropagationStyle::B3Multi => "b3multi", - TracePropagationStyle::B3 => "b3", - TracePropagationStyle::TraceContext => "tracecontext", - TracePropagationStyle::None => "none", - }; - write!(f, "{style}") - } -} - #[allow(clippy::module_name_repetitions)] pub fn deserialize_trace_propagation_style<'de, D>( deserializer: D, @@ -57,7 +18,7 @@ where |style| match TracePropagationStyle::from_str(style.trim()) { Ok(parsed_style) => Some(parsed_style), Err(e) => { - tracing::error!("Failed to parse trace propagation style: {}, ignoring", e); + error!("Failed to parse trace propagation style: {}, ignoring", e); None } }, diff --git a/bottlecap/src/config/yaml.rs b/bottlecap/src/config/yaml.rs index 0934d9663..37e90ec85 100644 --- a/bottlecap/src/config/yaml.rs +++ b/bottlecap/src/config/yaml.rs @@ -1,21 +1,20 @@ use std::time::Duration; use std::{collections::HashMap, path::PathBuf}; +use datadog_opentelemetry::propagation::TracePropagationStyle; + use crate::{ config::{ Config, ConfigError, ConfigSource, ProcessingRule, - additional_endpoints::deserialize_additional_endpoints, - deserialize_apm_replace_rules, deserialize_key_value_pair_array_to_hashmap, - deserialize_option_lossless, deserialize_optional_bool_from_anything, - deserialize_optional_duration_from_microseconds, + additional_endpoints::deserialize_additional_endpoints, deserialize_apm_replace_rules, + deserialize_key_value_pair_array_to_hashmap, deserialize_option_lossless, + deserialize_optional_bool_from_anything, deserialize_optional_duration_from_microseconds, deserialize_optional_duration_from_seconds, deserialize_optional_duration_from_seconds_ignore_zero, deserialize_optional_string, - deserialize_processing_rules, deserialize_string_or_int, - flush_strategy::FlushStrategy, - log_level::LogLevel, - logs_additional_endpoints::LogsAdditionalEndpoint, + deserialize_processing_rules, deserialize_string_or_int, flush_strategy::FlushStrategy, + log_level::LogLevel, logs_additional_endpoints::LogsAdditionalEndpoint, service_mapping::deserialize_service_mapping, - trace_propagation_style::{TracePropagationStyle, deserialize_trace_propagation_style}, + trace_propagation_style::deserialize_trace_propagation_style, }, merge_hashmap, merge_option, merge_option_to_value, merge_string, merge_vec, }; @@ -826,7 +825,7 @@ service_mapping: old-service:new-service # Trace Propagation trace_propagation_style: "datadog" -trace_propagation_style_extract: "b3" +trace_propagation_style_extract: "tracecontext" trace_propagation_extract_first: true trace_propagation_http_baggage_enabled: true trace_aws_service_representation_enabled: true @@ -972,7 +971,7 @@ api_security_sample_delay: 60 # Seconds ), ]), trace_propagation_style: vec![TracePropagationStyle::Datadog], - trace_propagation_style_extract: vec![TracePropagationStyle::B3], + trace_propagation_style_extract: vec![TracePropagationStyle::TraceContext], trace_propagation_extract_first: true, trace_propagation_http_baggage_enabled: true, trace_aws_service_representation_enabled: true, diff --git a/bottlecap/src/lifecycle/invocation/context.rs b/bottlecap/src/lifecycle/invocation/context.rs index 2c72786fd..04894f9c6 100644 --- a/bottlecap/src/lifecycle/invocation/context.rs +++ b/bottlecap/src/lifecycle/invocation/context.rs @@ -1,7 +1,7 @@ use crate::{ lifecycle::invocation::processor::MS_TO_NS, metrics::enhanced::lambda::EnhancedMetricData, - traces::context::SpanContext, }; +use datadog_opentelemetry::propagation::context::SpanContext; use std::{ collections::{HashMap, VecDeque}, time::{SystemTime, UNIX_EPOCH}, diff --git a/bottlecap/src/lifecycle/invocation/processor.rs b/bottlecap/src/lifecycle/invocation/processor.rs index 7e274d3ce..eeb6cb9d7 100644 --- a/bottlecap/src/lifecycle/invocation/processor.rs +++ b/bottlecap/src/lifecycle/invocation/processor.rs @@ -5,6 +5,13 @@ use std::{ }; use chrono::{DateTime, Utc}; +use datadog_opentelemetry::propagation::{ + context::SpanContext, + datadog::{ + DATADOG_PARENT_ID_KEY, DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TAGS_KEY, + DATADOG_TRACE_ID_KEY, + }, +}; use libdd_trace_protobuf::pb::Span; use libdd_trace_utils::tracer_header_tags; use serde_json::Value; @@ -31,14 +38,7 @@ use crate::{ }, tags::{lambda::tags::resolve_runtime_from_proc, provider}, traces::{ - context::SpanContext, - propagation::{ - DatadogCompositePropagator, Propagator, - text_map_propagator::{ - DATADOG_PARENT_ID_KEY, DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_SPAN_ID_KEY, - DATADOG_TRACE_ID_KEY, DatadogHeaderPropagator, - }, - }, + propagation::{DatadogCompositePropagator, carrier::JsonCarrier}, trace_processor::SendingTraceProcessor, }, }; @@ -52,6 +52,7 @@ pub const DATADOG_INVOCATION_ERROR_MESSAGE_KEY: &str = "x-datadog-invocation-err pub const DATADOG_INVOCATION_ERROR_TYPE_KEY: &str = "x-datadog-invocation-error-type"; pub const DATADOG_INVOCATION_ERROR_STACK_KEY: &str = "x-datadog-invocation-error-stack"; pub const DATADOG_INVOCATION_ERROR_KEY: &str = "x-datadog-invocation-error"; +const DATADOG_SPAN_ID_KEY: &str = "x-datadog-span-id"; const TAG_SAMPLING_PRIORITY: &str = "_sampling_priority_v1"; pub struct Processor { @@ -979,7 +980,10 @@ impl Processor { // Set the extracted trace context to the spans if let Some(sc) = &context.extracted_span_context { - context.invocation_span.trace_id = sc.trace_id; + #[allow(clippy::cast_possible_truncation)] // Datadog protocol uses lower 64 bits + { + context.invocation_span.trace_id = sc.trace_id as u64; + } context.invocation_span.parent_id = sc.span_id; // Set the right data to the correct root level span, @@ -1082,7 +1086,7 @@ impl Processor { pub fn extract_span_context( headers: &HashMap, payload_value: &Value, - propagator: Arc, + propagator: Arc, ) -> Option { if let Some(sc) = span_inferrer::extract_span_context(payload_value, Arc::clone(&propagator)) @@ -1093,14 +1097,14 @@ impl Processor { if let Some(sc) = payload_value .get("request") .and_then(|req| req.get("headers")) - .and_then(|headers| propagator.extract(headers)) + .and_then(|headers| propagator.extract(&JsonCarrier(headers))) { debug!("Extracted trace context from event.request.headers"); return Some(sc); } if let Some(payload_headers) = payload_value.get("headers") - && let Some(sc) = propagator.extract(payload_headers) + && let Some(sc) = propagator.extract(&JsonCarrier(payload_headers)) { debug!("Extracted trace context from event headers"); return Some(sc); @@ -1202,14 +1206,17 @@ impl Processor { self.inferrer.set_status_code(status_code_as_string); } - let mut trace_id = 0; - let mut parent_id = 0; + let mut trace_id: u64 = 0; + let mut parent_id: u64 = 0; let mut tags: HashMap = HashMap::new(); // If we have a trace context, this means we got it from // distributed tracing if let Some(sc) = &context.extracted_span_context { - trace_id = sc.trace_id; + #[allow(clippy::cast_possible_truncation)] // Datadog protocol uses lower 64 bits + { + trace_id = sc.trace_id as u64; + } parent_id = sc.span_id; tags.extend(sc.tags.clone()); } @@ -1235,9 +1242,9 @@ impl Processor { .insert(TAG_SAMPLING_PRIORITY.to_string(), priority); } - // Extract tags from headers - // Used for 128 bit trace ids - tags = DatadogHeaderPropagator::extract_tags(&headers); + // Extract _dd.p.* propagation tags from x-datadog-tags header + let carrier_tags = headers.get(DATADOG_TAGS_KEY).map_or("", String::as_str); + tags = crate::traces::propagation::extract_propagation_tags(carrier_tags); } // We should always use the generated span id from the tracer @@ -2048,8 +2055,8 @@ mod tests { fn test_extract_span_context_priority_order() { let config = Arc::new(config::Config { trace_propagation_style_extract: vec![ - config::trace_propagation_style::TracePropagationStyle::Datadog, - config::trace_propagation_style::TracePropagationStyle::TraceContext, + datadog_opentelemetry::propagation::TracePropagationStyle::Datadog, + datadog_opentelemetry::propagation::TracePropagationStyle::TraceContext, ], ..config::Config::default() }); @@ -2086,8 +2093,8 @@ mod tests { fn test_extract_span_context_no_request_headers() { let config = Arc::new(config::Config { trace_propagation_style_extract: vec![ - config::trace_propagation_style::TracePropagationStyle::Datadog, - config::trace_propagation_style::TracePropagationStyle::TraceContext, + datadog_opentelemetry::propagation::TracePropagationStyle::Datadog, + datadog_opentelemetry::propagation::TracePropagationStyle::TraceContext, ], ..config::Config::default() }); diff --git a/bottlecap/src/lifecycle/invocation/processor_service.rs b/bottlecap/src/lifecycle/invocation/processor_service.rs index 13f41cf01..c221d35a3 100644 --- a/bottlecap/src/lifecycle/invocation/processor_service.rs +++ b/bottlecap/src/lifecycle/invocation/processor_service.rs @@ -1,6 +1,7 @@ use std::{collections::HashMap, sync::Arc}; use chrono::{DateTime, Utc}; +use datadog_opentelemetry::propagation::context::SpanContext; use dogstatsd::aggregator::AggregatorHandle; use libdd_trace_protobuf::pb::Span; use serde_json::Value; @@ -18,10 +19,7 @@ use crate::{ processor::Processor, }, tags::provider, - traces::{ - context::SpanContext, propagation::DatadogCompositePropagator, - trace_processor::SendingTraceProcessor, - }, + traces::{propagation::DatadogCompositePropagator, trace_processor::SendingTraceProcessor}, }; #[derive(Error, Debug)] diff --git a/bottlecap/src/lifecycle/invocation/span_inferrer.rs b/bottlecap/src/lifecycle/invocation/span_inferrer.rs index 6c4eddd32..10abf56dd 100644 --- a/bottlecap/src/lifecycle/invocation/span_inferrer.rs +++ b/bottlecap/src/lifecycle/invocation/span_inferrer.rs @@ -7,8 +7,8 @@ use tracing::debug; use crate::config::Config; use crate::lifecycle::invocation::triggers::IdentifiedTrigger; +use crate::traces::propagation::DatadogCompositePropagator; use crate::traces::span_pointers::SpanPointer; -use crate::traces::{context::SpanContext, propagation::Propagator}; use crate::{ config::aws::AwsConfig, lifecycle::invocation::{ @@ -21,6 +21,7 @@ use crate::{ }, }, }; +use datadog_opentelemetry::propagation::context::SpanContext; #[derive(Default)] pub struct SpanInferrer { @@ -363,7 +364,7 @@ fn propagate_appsec( pub fn extract_span_context( payload_value: &Value, - propagator: Arc, + propagator: Arc, ) -> Option { let identified_trigger = IdentifiedTrigger::from_value(payload_value); let generated_span_context = extract_generated_span_context(&identified_trigger); @@ -405,13 +406,18 @@ pub fn extract_generated_span_context( mod tests { use super::*; use crate::lifecycle::invocation::triggers::test_utils::read_json_file; - use crate::traces::propagation::text_map_propagator::DatadogHeaderPropagator; + use crate::traces::propagation::DatadogCompositePropagator; + use datadog_opentelemetry::propagation::TracePropagationStyle; use serde_json::json; use std::sync::Arc; use tokio::time::Instant; fn test_context_source(payload: &Value, expected_source: &str) { - let propagator = Arc::new(DatadogHeaderPropagator); + let config = Arc::new(Config { + trace_propagation_style_extract: vec![TracePropagationStyle::Datadog], + ..Config::default() + }); + let propagator = Arc::new(DatadogCompositePropagator::new(config)); let context = extract_span_context(payload, propagator); let context = context.expect("Should return a span context"); diff --git a/bottlecap/src/lifecycle/invocation/triggers/sqs_event.rs b/bottlecap/src/lifecycle/invocation/triggers/sqs_event.rs index 607174ad6..eb81944eb 100644 --- a/bottlecap/src/lifecycle/invocation/triggers/sqs_event.rs +++ b/bottlecap/src/lifecycle/invocation/triggers/sqs_event.rs @@ -7,7 +7,7 @@ use crate::lifecycle::invocation::{ sns_event::{SnsEntity, SnsRecord}, }, }; -use crate::traces::context::{Sampling, SpanContext}; +use datadog_opentelemetry::propagation::context::{Sampling, SpanContext}; use libdd_trace_protobuf::pb::Span; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -259,15 +259,16 @@ pub(crate) fn extract_trace_context_from_aws_trace_header( Some(SpanContext { // the context from AWS Header is used by Datadog only and does not contain the upper // 64 bits like other 128 w3c compliant trace ids - trace_id, + trace_id: u128::from(trace_id), span_id: parent_id, - sampling: Some(Sampling { - priority: Some(sampling_priority), + sampling: Sampling { + priority: sampling_priority.to_string().parse().ok(), mechanism: None, - }), + }, origin: None, tags: HashMap::new(), links: Vec::new(), + ..Default::default() }) } @@ -612,13 +613,13 @@ mod tests { SpanContext { trace_id: 130_944_522_478_755_159, span_id: 9_032_698_535_745_367_362, - sampling: Some(Sampling { - priority: Some("0".parse().unwrap()), + sampling: Sampling { + priority: "0".parse().ok(), mechanism: None, - }), + }, origin: None, tags: HashMap::new(), - links: Vec::new(), + ..Default::default() } ); } diff --git a/bottlecap/src/lifecycle/invocation/triggers/step_function_event.rs b/bottlecap/src/lifecycle/invocation/triggers/step_function_event.rs index 259b06e4e..49071769b 100644 --- a/bottlecap/src/lifecycle/invocation/triggers/step_function_event.rs +++ b/bottlecap/src/lifecycle/invocation/triggers/step_function_event.rs @@ -5,16 +5,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use sha2::{Digest, Sha256}; -use crate::{ - lifecycle::invocation::triggers::{ - FUNCTION_TRIGGER_EVENT_SOURCE_TAG, ServiceNameResolver, Trigger, - }, - traces::{ - context::{Sampling, SpanContext}, - propagation::text_map_propagator::{ - DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY, DATADOG_TAGS_KEY, DatadogHeaderPropagator, - }, - }, +use crate::lifecycle::invocation::triggers::{ + FUNCTION_TRIGGER_EVENT_SOURCE_TAG, ServiceNameResolver, Trigger, +}; +use datadog_opentelemetry::propagation::{ + context::{Sampling, SpanContext}, + datadog::DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY, }; use super::DATADOG_CARRIER_KEY; @@ -155,10 +151,7 @@ impl StepFunctionEvent { .parse() .unwrap_or(Self::generate_trace_id(self.execution.id.clone()).0); - let tags = DatadogHeaderPropagator::extract_tags(&HashMap::from([( - DATADOG_TAGS_KEY.to_string(), - trace_tags.clone(), - )])); + let tags = crate::traces::propagation::extract_propagation_tags(trace_tags); (lo_tid, tags) } else { @@ -184,16 +177,17 @@ impl StepFunctionEvent { ); SpanContext { - trace_id: lo_tid, + trace_id: u128::from(lo_tid), span_id: parent_id, // Priority Auto Keep - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags, links: vec![], + ..Default::default() } } @@ -259,7 +253,7 @@ impl ServiceNameResolver for StepFunctionEvent { mod tests { use super::*; use crate::lifecycle::invocation::triggers::test_utils::read_json_file; - use crate::traces::propagation::text_map_propagator::DATADOG_SAMPLING_DECISION_KEY; + use datadog_opentelemetry::constants::SAMPLING_DECISION_MAKER_TAG_KEY as DATADOG_SAMPLING_DECISION_KEY; #[test] fn test_new_event() { @@ -468,16 +462,16 @@ mod tests { SpanContext { trace_id: 5_744_042_798_732_701_615, span_id: 2_902_498_116_043_018_663, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([( DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY.to_string(), "1914fe7789eb32be".to_string(), )]), - links: vec![], + ..Default::default() }, ), ( @@ -485,16 +479,16 @@ mod tests { SpanContext { trace_id: 5_744_042_798_732_701_615, span_id: 2_902_498_116_043_018_663, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([( DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY.to_string(), "1914fe7789eb32be".to_string(), )]), - links: vec![], + ..Default::default() }, ), ( @@ -502,16 +496,16 @@ mod tests { SpanContext { trace_id: 1_322_229_001_489_018_110, span_id: 8_947_638_978_974_359_093, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([( DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY.to_string(), "579d19b3ee216ee9".to_string(), )]), - links: vec![], + ..Default::default() }, ), ( @@ -519,16 +513,16 @@ mod tests { SpanContext { trace_id: 1_322_229_001_489_018_110, span_id: 8_947_638_978_974_359_093, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([( DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY.to_string(), "579d19b3ee216ee9".to_string(), )]), - links: vec![], + ..Default::default() }, ), ( @@ -536,10 +530,10 @@ mod tests { SpanContext { trace_id: 5_821_803_790_426_892_636, span_id: 8_947_638_978_974_359_093, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([ ( @@ -548,7 +542,7 @@ mod tests { ), (DATADOG_SAMPLING_DECISION_KEY.to_string(), "-0".to_string()), ]), - links: vec![], + ..Default::default() }, ), ( @@ -556,10 +550,10 @@ mod tests { SpanContext { trace_id: 5_821_803_790_426_892_636, span_id: 8_947_638_978_974_359_093, - sampling: Some(Sampling { - priority: Some(1), + sampling: Sampling { + priority: "1".parse().ok(), mechanism: None, - }), + }, origin: Some("states".to_string()), tags: HashMap::from([ ( @@ -568,7 +562,7 @@ mod tests { ), (DATADOG_SAMPLING_DECISION_KEY.to_string(), "-0".to_string()), ]), - links: vec![], + ..Default::default() }, ), ]; diff --git a/bottlecap/src/lifecycle/listener.rs b/bottlecap/src/lifecycle/listener.rs index a77625bba..058b71b44 100644 --- a/bottlecap/src/lifecycle/listener.rs +++ b/bottlecap/src/lifecycle/listener.rs @@ -9,6 +9,13 @@ use axum::{ routing::{get, post}, }; use bytes::Bytes; +use datadog_opentelemetry::propagation::{ + context::SpanContext, + datadog::{ + DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY, DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TAGS_KEY, + DATADOG_TRACE_ID_KEY, + }, +}; use serde_json::{Value, json}; use std::collections::HashMap; use std::net::SocketAddr; @@ -21,16 +28,7 @@ use tracing::{debug, error, warn}; use crate::{ http::{extract_request_body, headers_to_map}, lifecycle::invocation::processor_service::InvocationProcessorHandle, - traces::{ - context::SpanContext, - propagation::{ - DatadogCompositePropagator, - text_map_propagator::{ - DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY, DATADOG_SAMPLING_PRIORITY_KEY, - DATADOG_TAGS_KEY, DATADOG_TRACE_ID_KEY, - }, - }, - }, + traces::propagation::DatadogCompositePropagator, }; const HELLO_PATH: &str = "/lambda/hello"; @@ -220,14 +218,17 @@ impl Listener { fn inject_span_context_to_headers(headers: &mut HeaderMap, span_context: &SpanContext) { headers.insert( DATADOG_TRACE_ID_KEY, - span_context - .trace_id - .to_string() - .parse() - .expect("Failed to parse trace id"), + { + #[allow(clippy::cast_possible_truncation)] // Datadog protocol uses lower 64 bits + let trace_id = span_context.trace_id as u64; + trace_id + } + .to_string() + .parse() + .expect("Failed to parse trace id"), ); - if let Some(priority) = span_context.sampling.and_then(|s| s.priority) { + if let Some(priority) = span_context.sampling.priority { headers.insert( DATADOG_SAMPLING_PRIORITY_KEY, priority diff --git a/bottlecap/src/otlp/transform.rs b/bottlecap/src/otlp/transform.rs index 451647d8c..43bbc7a0f 100644 --- a/bottlecap/src/otlp/transform.rs +++ b/bottlecap/src/otlp/transform.rs @@ -32,7 +32,7 @@ use std::sync::{Arc, LazyLock}; use tracing::debug; use crate::config::Config; -use crate::traces::propagation::text_map_propagator::DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY; +use datadog_opentelemetry::propagation::datadog::DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY; // Constants for Datadog namespace keys pub const KEY_DATADOG_SERVICE: &str = "datadog.service"; diff --git a/bottlecap/src/traces/context.rs b/bottlecap/src/traces/context.rs deleted file mode 100644 index 4c31d619e..000000000 --- a/bottlecap/src/traces/context.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::collections::HashMap; - -use libdd_trace_protobuf::pb::SpanLink; - -#[derive(Copy, Clone, Default, Debug, PartialEq)] -pub struct Sampling { - pub priority: Option, - pub mechanism: Option, -} - -#[derive(Clone, Default, Debug, PartialEq)] -#[allow(clippy::module_name_repetitions)] -pub struct SpanContext { - pub trace_id: u64, - pub span_id: u64, - pub sampling: Option, - pub origin: Option, - pub tags: HashMap, - pub links: Vec, -} diff --git a/bottlecap/src/traces/mod.rs b/bottlecap/src/traces/mod.rs index 2efc1de65..a198682f7 100644 --- a/bottlecap/src/traces/mod.rs +++ b/bottlecap/src/traces/mod.rs @@ -1,7 +1,6 @@ // Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -pub mod context; pub mod http_client; pub mod propagation; pub mod proxy_aggregator; diff --git a/bottlecap/src/traces/propagation/carrier.rs b/bottlecap/src/traces/propagation/carrier.rs index d0f2182fa..8edf23940 100644 --- a/bottlecap/src/traces/propagation/carrier.rs +++ b/bottlecap/src/traces/propagation/carrier.rs @@ -1,67 +1,21 @@ -/// Code inspired, and copied, by OpenTelemetry Rust project. -/// -/// -use std::collections::HashMap; - +use datadog_opentelemetry::propagation::carrier::{Extractor, Injector}; use serde_json::Value; -/// Injector provides an interface for a carrier to be used -/// with a Propagator to inject a Context into the carrier. -/// -pub trait Injector { - /// Set a value in the carrier. - fn set(&mut self, key: &str, value: String); -} - -pub trait Extractor { - /// Get a value from the carrier. - fn get(&self, key: &str) -> Option<&str>; - - /// Get all keys from the carrier. - fn keys(&self) -> Vec<&str>; -} - -impl Injector for HashMap { - /// Set a key and value in the `HashMap`. - fn set(&mut self, key: &str, value: String) { - self.insert(key.to_lowercase(), value); - } -} +/// Newtype wrapper around `serde_json::Value` to implement carrier traits +/// without violating the orphan rule. +pub struct JsonCarrier<'a>(pub &'a Value); -impl Extractor for HashMap { - /// Get a value for a key from the `HashMap`. +impl Extractor for JsonCarrier<'_> { fn get(&self, key: &str) -> Option<&str> { - self.get(&key.to_lowercase()).map(String::as_str) - } - - /// Collect all the keys from the `HashMap`. - fn keys(&self) -> Vec<&str> { - self.keys().map(String::as_str).collect::>() - } -} - -impl Injector for Value { - /// Set a key and value in the `Value`. - fn set(&mut self, key: &str, value: String) { - if let Value::Object(map) = self { - map.insert(key.to_lowercase(), Value::String(value)); - } - } -} - -impl Extractor for Value { - /// Get a value for a key from the `Value`. - fn get(&self, key: &str) -> Option<&str> { - if let Value::Object(map) = self { + if let Value::Object(map) = self.0 { map.get(&key.to_lowercase()).and_then(|v| v.as_str()) } else { None } } - /// Collect all the keys from the `Value`. fn keys(&self) -> Vec<&str> { - if let Value::Object(map) = self { + if let Value::Object(map) = self.0 { map.keys().map(String::as_str).collect::>() } else { Vec::new() @@ -69,39 +23,28 @@ impl Extractor for Value { } } -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn hash_map_get() { - let mut carrier = HashMap::new(); - carrier.set("headerName", "value".to_string()); +pub struct JsonCarrierMut<'a>(pub &'a mut Value); - assert_eq!( - Extractor::get(&carrier, "HEADERNAME"), - Some("value"), - "case insensitive extraction" - ); +impl Injector for JsonCarrierMut<'_> { + fn set(&mut self, key: &str, value: String) { + if let Value::Object(map) = self.0 { + map.insert(key.to_lowercase(), Value::String(value)); + } } +} - #[test] - fn hash_map_keys() { - let mut carrier = HashMap::new(); - carrier.set("headerName1", "value1".to_string()); - carrier.set("headerName2", "value2".to_string()); +#[cfg(test)] +mod test { + use datadog_opentelemetry::propagation::carrier::{Extractor, Injector}; - let got = Extractor::keys(&carrier); - assert_eq!(got.len(), 2); - assert!(got.contains(&"headername1")); - assert!(got.contains(&"headername2")); - } + use super::*; #[test] fn serde_value_get() { - let mut carrier = Value::Object(serde_json::Map::new()); - carrier.set("headerName", "value".to_string()); + let mut value = Value::Object(serde_json::Map::new()); + JsonCarrierMut(&mut value).set("headerName", "value".to_string()); + let carrier = JsonCarrier(&value); assert_eq!( Extractor::get(&carrier, "HEADERNAME"), Some("value"), @@ -111,10 +54,11 @@ mod test { #[test] fn serde_value_keys() { - let mut carrier = Value::Object(serde_json::Map::new()); - carrier.set("headerName1", "value1".to_string()); - carrier.set("headerName2", "value2".to_string()); + let mut value = Value::Object(serde_json::Map::new()); + JsonCarrierMut(&mut value).set("headerName1", "value1".to_string()); + JsonCarrierMut(&mut value).set("headerName2", "value2".to_string()); + let carrier = JsonCarrier(&value); let got = Extractor::keys(&carrier); assert_eq!(got.len(), 2); assert!(got.contains(&"headername1")); diff --git a/bottlecap/src/traces/propagation/error.rs b/bottlecap/src/traces/propagation/error.rs deleted file mode 100644 index af7a37d9b..000000000 --- a/bottlecap/src/traces/propagation/error.rs +++ /dev/null @@ -1,33 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug, Copy, Clone)] -#[error("Cannot {} from {}, {}", operation, message, propagator_name)] -pub struct Error { - message: &'static str, - // which propagator this error comes from - propagator_name: &'static str, - // what operation was attempted - operation: &'static str, -} - -impl Error { - /// Error when extracting a value from a carrier - #[must_use] - pub fn extract(message: &'static str, propagator_name: &'static str) -> Self { - Self { - message, - propagator_name, - operation: "extract", - } - } - - /// Error when injecting a value into a carrier - #[allow(clippy::must_use_candidate)] - pub fn inject(message: &'static str, propagator_name: &'static str) -> Self { - Self { - message, - propagator_name, - operation: "inject", - } - } -} diff --git a/bottlecap/src/traces/propagation/mod.rs b/bottlecap/src/traces/propagation/mod.rs index 828e210b1..95425ecfe 100644 --- a/bottlecap/src/traces/propagation/mod.rs +++ b/bottlecap/src/traces/propagation/mod.rs @@ -1,194 +1,61 @@ -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; +use std::sync::Arc; -use crate::{ - config::{self, trace_propagation_style::TracePropagationStyle}, - traces::context::SpanContext, -}; -use carrier::{Extractor, Injector}; -use libdd_trace_protobuf::pb::SpanLink; -use text_map_propagator::{ - BAGGAGE_PREFIX, DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY, DATADOG_LAST_PARENT_ID_KEY, - TRACESTATE_KEY, +use crate::config; +use datadog_opentelemetry::propagation::{ + self as dd_propagation, carrier::Extractor, context::SpanContext, }; pub mod carrier; -pub mod error; -pub mod text_map_propagator; -pub trait Propagator { - fn extract(&self, carrier: &dyn Extractor) -> Option; - fn inject(&self, context: SpanContext, carrier: &mut dyn Injector); +const BAGGAGE_PREFIX: &str = "ot-baggage-"; +const PROPAGATION_TAG_PREFIX: &str = "_dd.p."; + +#[must_use] +pub fn extract_propagation_tags(tags_str: &str) -> HashMap { + tags_str + .split(',') + .filter_map(|pair| { + let (k, v) = pair.split_once('=')?; + if k.starts_with(PROPAGATION_TAG_PREFIX) { + Some((k.to_string(), v.to_string())) + } else { + None + } + }) + .collect() } +// Thin wrapper around dd-trace-rs's propagator to add `ot-baggage-*` header +// extraction, which is not yet supported upstream in datadog-opentelemetry. pub struct DatadogCompositePropagator { - propagators: Vec>, + inner: dd_propagation::DatadogCompositePropagator, config: Arc, } -impl Propagator for DatadogCompositePropagator { - fn extract(&self, carrier: &dyn Extractor) -> Option { - if self.config.trace_propagation_extract_first { - for propagator in &self.propagators { - let context = propagator.extract(carrier); - - if let Some(mut context) = context { - if self.config.trace_propagation_http_baggage_enabled { - Self::attach_baggage(&mut context, carrier); - } - return Some(context); - } - } - } - - let (contexts, styles) = self.extract_available_contexts(carrier); - if contexts.is_empty() { - return None; - } - - let mut context = Self::resolve_contexts(contexts, styles, carrier); - if self.config.trace_propagation_http_baggage_enabled { - Self::attach_baggage(&mut context, carrier); - } - - Some(context) - } - - fn inject(&self, _context: SpanContext, _carrier: &mut dyn Injector) { - todo!() - } -} - impl DatadogCompositePropagator { #[must_use] pub fn new(config: Arc) -> Self { - let propagators: Vec> = config - .trace_propagation_style_extract - .iter() - .filter_map(|style| match style { - TracePropagationStyle::Datadog => { - Some(Box::new(text_map_propagator::DatadogHeaderPropagator) - as Box) - } - TracePropagationStyle::TraceContext => { - Some(Box::new(text_map_propagator::TraceContextPropagator) - as Box) - } - _ => None, - }) - .collect(); - - Self { - propagators, - config, - } - } - - fn extract_available_contexts( - &self, - carrier: &dyn Extractor, - ) -> (Vec, Vec) { - let mut contexts = Vec::::new(); - let mut styles = Vec::::new(); - - for (i, propagator) in self.propagators.iter().enumerate() { - if let Some(context) = propagator.extract(carrier) { - contexts.push(context); - styles.push(self.config.trace_propagation_style_extract[i]); - } - } - - (contexts, styles) + let inner = dd_propagation::DatadogCompositePropagator::new(Arc::clone(&config)); + Self { inner, config } } - fn resolve_contexts( - contexts: Vec, - styles: Vec, - _carrier: &dyn Extractor, - ) -> SpanContext { - let mut primary_context = contexts[0].clone(); - let mut links = Vec::::new(); + pub fn extract(&self, carrier: &dyn Extractor) -> Option { + let mut context = self.inner.extract(carrier)?; - let mut i = 1; - for context in contexts.iter().skip(1) { - let style = styles[i]; - - if context.span_id != 0 - && context.trace_id != 0 - && context.trace_id != primary_context.trace_id - { - let sampling = context.sampling.unwrap_or_default().priority.unwrap_or(0); - let tracestate: Option = match style { - TracePropagationStyle::TraceContext => { - context.tags.get(TRACESTATE_KEY).cloned() - } - _ => None, - }; - let attributes = HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), style.to_string()), - ]); - let trace_id_high_str = context - .tags - .get(DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY) - .cloned() - .unwrap_or_default(); - let trace_ig_high = u64::from_str_radix(&trace_id_high_str, 16).unwrap_or_default(); - - links.push(SpanLink { - trace_id: context.trace_id, - trace_id_high: trace_ig_high, - span_id: context.span_id, - flags: u32::from(sampling > 0), - tracestate: tracestate.unwrap_or_default(), - attributes, - }); - } else if style == TracePropagationStyle::TraceContext { - if let Some(tracestate) = context.tags.get(TRACESTATE_KEY) { - primary_context - .tags - .insert(TRACESTATE_KEY.to_string(), tracestate.clone()); - } - - if primary_context.trace_id == context.trace_id - && primary_context.span_id != context.span_id - { - let mut dd_context: Option = None; - if styles.contains(&TracePropagationStyle::Datadog) { - let position = styles - .iter() - .position(|&s| s == TracePropagationStyle::Datadog) - .unwrap_or_default(); - dd_context = contexts.get(position).cloned(); - } - - if let Some(parent_id) = context.tags.get(DATADOG_LAST_PARENT_ID_KEY) { - primary_context - .tags - .insert(DATADOG_LAST_PARENT_ID_KEY.to_string(), parent_id.clone()); - } else if let Some(sc) = dd_context { - primary_context.tags.insert( - DATADOG_LAST_PARENT_ID_KEY.to_string(), - format!("{:016x}", sc.span_id), - ); - } - - primary_context.span_id = context.span_id; - } - } - - i += 1; + if self.config.trace_propagation_http_baggage_enabled { + Self::attach_baggage(&mut context, carrier); } - primary_context.links = links; - - primary_context + Some(context) } fn attach_baggage(context: &mut SpanContext, carrier: &dyn Extractor) { let keys = carrier.keys(); for key in keys { - if let Some(stripped) = key.strip_prefix(BAGGAGE_PREFIX) { + let lower = key.to_ascii_lowercase(); + if let Some(stripped) = lower.strip_prefix(BAGGAGE_PREFIX) { context.tags.insert( stripped.to_string(), carrier.get(key).unwrap_or_default().to_string(), @@ -199,625 +66,13 @@ impl DatadogCompositePropagator { } #[cfg(test)] -pub mod tests { - use std::sync::LazyLock; - use std::vec; +mod tests { + use std::collections::HashMap; - use crate::traces::context::Sampling; + use datadog_opentelemetry::propagation::TracePropagationStyle; use super::*; - fn lower_64_bits(value: u128) -> u64 { - (value & 0xFFFF_FFFF_FFFF_FFFF) as u64 - } - - static TRACE_ID: LazyLock = - LazyLock::new(|| 171_395_628_812_617_415_352_188_477_958_425_669_623); - static TRACE_ID_LOWER_ORDER_BITS: LazyLock = LazyLock::new(|| lower_64_bits(*TRACE_ID)); - static TRACE_ID_HEX: LazyLock = - LazyLock::new(|| String::from("80f198ee56343ba864fe8b2a57d3eff7")); - - // TraceContext Headers - static VALID_TRACECONTEXT_HEADERS_BASIC: LazyLock> = - LazyLock::new(|| { - HashMap::from([ - ( - "traceparent".to_string(), - format!("00-{}-00f067aa0ba902b7-01", *TRACE_ID_HEX), - ), - ( - "tracestate".to_string(), - "dd=p:00f067aa0ba902b7;s:2;o:rum".to_string(), - ), - ]) - }); - static VALID_TRACECONTEXT_HEADERS_RUM_NO_SAMPLING_DECISION: LazyLock> = - LazyLock::new(|| { - HashMap::from([ - ( - "traceparent".to_string(), - format!("00-{}-00f067aa0ba902b7-00", *TRACE_ID_HEX), - ), - ("tracestate".to_string(), "dd=o:rum".to_string()), - ]) - }); - static VALID_TRACECONTEXT_HEADERS: LazyLock> = LazyLock::new(|| { - HashMap::from([ - ( - "traceparent".to_string(), - format!("00-{}-00f067aa0ba902b7-01", *TRACE_ID_HEX), - ), - ( - "tracestate".to_string(), - "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMz".to_string(), - ), - ]) - }); - static VALID_TRACECONTEXT_HEADERS_VALID_64_BIT_TRACE_ID: LazyLock> = - LazyLock::new(|| { - HashMap::from([ - ( - "traceparent".to_string(), - "00-000000000000000064fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string(), - ), - ( - "tracestate".to_string(), - "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMzE".to_string(), - ), - ]) - }); - - // Datadog Headers - static VALID_DATADOG_HEADERS: LazyLock> = LazyLock::new(|| { - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - "13088165645273925489".to_string(), - ), - ("x-datadog-parent-id".to_string(), "5678".to_string()), - ("x-datadog-sampling-priority".to_string(), "1".to_string()), - ("x-datadog-origin".to_string(), "synthetics".to_string()), - ]) - }); - static VALID_DATADOG_HEADERS_NO_PRIORITY: LazyLock> = - LazyLock::new(|| { - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - "13088165645273925489".to_string(), - ), - ("x-datadog-parent-id".to_string(), "5678".to_string()), - ("x-datadog-origin".to_string(), "synthetics".to_string()), - ]) - }); - static VALID_DATADOG_HEADERS_MATCHING_TRACE_CONTEXT_VALID_TRACE_ID: LazyLock< - HashMap, - > = LazyLock::new(|| { - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - TRACE_ID_LOWER_ORDER_BITS.to_string(), - ), - ("x-datadog-parent-id".to_string(), "5678".to_string()), - ("x-datadog-origin".to_string(), "synthetics".to_string()), - ("x-datadog-sampling-priority".to_string(), "1".to_string()), - ]) - }); - static INVALID_DATADOG_HEADERS: LazyLock> = LazyLock::new(|| { - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - "13088165645273925489".to_string(), - ), - ("x-datadog-parent-id".to_string(), "parent_id".to_string()), - ( - "x-datadog-sampling-priority".to_string(), - "sample".to_string(), - ), - ]) - }); - - // Fixtures - static ALL_VALID_HEADERS: LazyLock> = LazyLock::new(|| { - let mut h = HashMap::new(); - h.extend(VALID_DATADOG_HEADERS.clone()); - h.extend(VALID_TRACECONTEXT_HEADERS.clone()); - // todo: add b3 - h - }); - static DATADOG_TRACECONTEXT_MATCHING_TRACE_ID_HEADERS: LazyLock> = - LazyLock::new(|| { - let mut h = HashMap::new(); - h.extend(VALID_DATADOG_HEADERS_MATCHING_TRACE_CONTEXT_VALID_TRACE_ID.clone()); - // We use 64-bit traceparent trace id value here so it can match for - // both 128-bit enabled and disabled - h.extend(VALID_TRACECONTEXT_HEADERS_VALID_64_BIT_TRACE_ID.clone()); - h - }); - // Edge cases - #[allow(dead_code)] - static ALL_HEADERS_CHAOTIC_1: LazyLock> = LazyLock::new(|| { - let mut h = HashMap::new(); - h.extend(VALID_DATADOG_HEADERS_MATCHING_TRACE_CONTEXT_VALID_TRACE_ID.clone()); - h.extend(VALID_TRACECONTEXT_HEADERS_VALID_64_BIT_TRACE_ID.clone()); - // todo: add b3 - h - }); - static ALL_HEADERS_CHAOTIC_2: LazyLock> = LazyLock::new(|| { - let mut h = HashMap::new(); - h.extend(VALID_DATADOG_HEADERS.clone()); - h.extend(VALID_TRACECONTEXT_HEADERS_VALID_64_BIT_TRACE_ID.clone()); - // todo: add b3 - h - }); - static NO_TRACESTATE_SUPPORT_NOT_MATCHING_TRACE_ID: LazyLock> = - LazyLock::new(|| { - let mut h = HashMap::new(); - h.extend(VALID_DATADOG_HEADERS.clone()); - h.extend(VALID_TRACECONTEXT_HEADERS_RUM_NO_SAMPLING_DECISION.clone()); - h - }); - - macro_rules! test_propagation_extract { - ($($name:ident: $value:expr,)*) => { - $( - #[test] - fn $name() { - let (styles, carrier, expected) = $value; - let mut config = config::Config::default(); - config.trace_propagation_style_extract = vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]; - if let Some(s) = styles { - config.trace_propagation_style_extract.clone_from(&s); - } - - let propagator = DatadogCompositePropagator::new(Arc::new(config)); - - let context = propagator.extract(&carrier).unwrap_or_default(); - - assert_eq!(context, expected); - } - )* - } - } - - test_propagation_extract! { - // Datadog Headers - valid_datadog_default: ( - None, - VALID_DATADOG_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![], - } - ), - valid_datadog_no_priority: ( - None, - VALID_DATADOG_HEADERS_NO_PRIORITY.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(2), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![], - }, - ), - invalid_datadog: ( - Some(vec![TracePropagationStyle::Datadog]), - INVALID_DATADOG_HEADERS.clone(), - SpanContext::default(), - ), - valid_datadog_explicit_style: ( - Some(vec![TracePropagationStyle::Datadog]), - VALID_DATADOG_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![], - }, - ), - invalid_datadog_negative_trace_id: ( - Some(vec![TracePropagationStyle::Datadog]), - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - "-1".to_string(), - ), - ("x-datadog-parent-id".to_string(), "5678".to_string(),), - ("x-datadog-sampling-priority".to_string(), "1".to_string()), - ("x-datadog-origin".to_string(), "synthetics".to_string()), - ]), - SpanContext::default(), - ), - valid_datadog_no_datadog_style: ( - Some(vec![TracePropagationStyle::TraceContext]), - VALID_DATADOG_HEADERS.clone(), - SpanContext::default(), - ), - // TraceContext Headers - valid_tracecontext_simple: ( - Some(vec![TracePropagationStyle::TraceContext]), - VALID_TRACECONTEXT_HEADERS_BASIC.clone(), - SpanContext { - trace_id: 7_277_407_061_855_694_839, - span_id: 67_667_974_448_284_343, - sampling: Some(Sampling { - priority: Some(2), - mechanism: None, - }), - origin: Some("rum".to_string()), - tags: HashMap::from([ - ("tracestate".to_string(), "dd=p:00f067aa0ba902b7;s:2;o:rum".to_string()), - ("_dd.p.tid".to_string(), "9291375655657946024".to_string()), - ("traceparent".to_string(), "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string()), - ("_dd.parent_id".to_string(), "00f067aa0ba902b7".to_string()), - ]), - links: vec![], - } - ), - valid_tracecontext_rum_no_sampling_decision: ( - Some(vec![TracePropagationStyle::TraceContext]), - VALID_TRACECONTEXT_HEADERS_RUM_NO_SAMPLING_DECISION.clone(), - SpanContext { - trace_id: 7_277_407_061_855_694_839, - span_id: 67_667_974_448_284_343, - sampling: Some(Sampling { - priority: Some(0), - mechanism: None, - }), - origin: Some("rum".to_string()), - tags: HashMap::from([ - ("_dd.p.tid".to_string(), "9291375655657946024".to_string()), - ("tracestate".to_string(), "dd=o:rum".to_string()), - ("traceparent".to_string(), "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-00".to_string()), - ]), - links: vec![], - } - ), - // B3 Headers - // todo: all of them - // B3 single Headers - // todo: all of them - // All Headers - valid_all_headers: ( - None, - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![ - SpanLink { - trace_id: 7_277_407_061_855_694_839, - trace_id_high: 0, - span_id: 67_667_974_448_284_343, - flags: 1, - tracestate: "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMz".to_string(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "tracecontext".to_string()), - ]), - } - ], - }, - ), - valid_all_headers_all_styles: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]), - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![ - SpanLink { - trace_id: 7_277_407_061_855_694_839, - trace_id_high: 0, - span_id: 67_667_974_448_284_343, - flags: 1, - tracestate: "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMz".to_string(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "tracecontext".to_string()), - ]), - } - // todo: b3 span links - ], - }, - ), - valid_all_headers_datadog_style: ( - Some(vec![TracePropagationStyle::Datadog]), - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![] - }, - ), - // todo: valid_all_headers_b3_style - // todo: valid_all_headers_both_b3_styles - // todo: valid_all_headers_b3_single_style - none_style: ( - Some(vec![TracePropagationStyle::None]), - ALL_VALID_HEADERS.clone(), - SpanContext::default(), - ), - valid_style_and_none_still_extracts: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::None]), - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![], - } - ), - // Order matters - // todo: order_matters_b3_single_header_first - // todo: order_matters_b3_first - // todo: order_matters_b3_second_no_datadog_headers - // Tracestate is still added when TraceContext style comes later and matches - // first style's `trace_id` - additional_tracestate_support_when_present_and_matches_first_style_trace_id: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]), - DATADOG_TRACECONTEXT_MATCHING_TRACE_ID_HEADERS.clone(), - SpanContext { - trace_id: 7_277_407_061_855_694_839, - span_id: 67_667_974_448_284_343, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()), - ("_dd.parent_id".to_string(), "000000000000162e".to_string()), - (TRACESTATE_KEY.to_string(), "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMzE".to_string()) - ]), - links: vec![], - } - ), - // Tracestate is not added when TraceContext style comes later and does not - // match first style's `trace_id` - no_additional_tracestate_support_when_present_and_trace_id_does_not_match: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]), - NO_TRACESTATE_SUPPORT_NOT_MATCHING_TRACE_ID.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![ - SpanLink { - trace_id: 7_277_407_061_855_694_839, - trace_id_high: 0, - span_id: 67_667_974_448_284_343, - flags: 0, - tracestate: "dd=o:rum".to_string(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "tracecontext".to_string()), - ]), - } - ], - } - ), - valid_all_headers_no_style: ( - Some(vec![]), - ALL_VALID_HEADERS.clone(), - SpanContext::default(), - ), - datadog_tracecontext_conflicting_span_ids: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]), - HashMap::from([ - ( - "x-datadog-trace-id".to_string(), - "9291375655657946024".to_string(), - ), - ("x-datadog-parent-id".to_string(), "15".to_string(),), - ("traceparent".to_string(), "00-000000000000000080f198ee56343ba8-000000000000000a-01".to_string()), - ]), - SpanContext { - trace_id: 9_291_375_655_657_946_024, - span_id: 10, - sampling: Some(Sampling { - priority: Some(2), - mechanism: None, - }), - origin: None, - tags: HashMap::from([ - ("_dd.parent_id".to_string(), "000000000000000f".to_string()), - ("_dd.p.dm".to_string(), "-3".to_string()), - ]), - links: vec![], - } - ), - // todo: all_headers_all_styles_tracecontext_t_id_match_no_span_link - all_headers_all_styles_do_not_create_span_link_for_context_w_out_span_id: ( - Some(vec![TracePropagationStyle::TraceContext, TracePropagationStyle::Datadog]), - ALL_HEADERS_CHAOTIC_2.clone(), - SpanContext { - trace_id: 7_277_407_061_855_694_839, - span_id: 67_667_974_448_284_343, - sampling: Some(Sampling { - priority: Some(2), - mechanism: None, - }), - origin: Some("rum".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-4".to_string()), - ("_dd.p.tid".to_string(), "0".to_string()), - ("_dd.p.usr.id".to_string(), "baz64".to_string()), - ("traceparent".to_string(), "00-000000000000000064fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string()), - ("tracestate".to_string(), "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMzE".to_string()), - ]), - links: vec![ - SpanLink { - trace_id: 13_088_165_645_273_925_489, - trace_id_high: 0, - span_id: 5678, - flags: 1, - tracestate: String::new(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "datadog".to_string()), - ]), - } - ], - } - ), - all_headers_all_styles_tracecontext_primary_only_datadog_t_id_diff: ( - Some(vec![TracePropagationStyle::TraceContext, TracePropagationStyle::Datadog]), - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 7_277_407_061_855_694_839, - span_id: 67_667_974_448_284_343, - sampling: Some(Sampling { - priority: Some(2), - mechanism: None, - }), - origin: Some("rum".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-4".to_string()), - ("_dd.p.tid".to_string(), "9291375655657946024".to_string()), - ("_dd.p.usr.id".to_string(), "baz64".to_string()), - ("traceparent".to_string(), "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string()), - ("tracestate".to_string(), "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMz".to_string()), - ]), - links: vec![ - SpanLink { - trace_id: 13_088_165_645_273_925_489, - trace_id_high: 0, - span_id: 5678, - flags: 1, - tracestate: String::new(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "datadog".to_string()), - ]), - } - ], - } - ), - // todo: fix this test - all_headers_all_styles_datadog_primary_only_datadog_t_id_diff: ( - Some(vec![TracePropagationStyle::Datadog, TracePropagationStyle::TraceContext]), - ALL_VALID_HEADERS.clone(), - SpanContext { - trace_id: 13_088_165_645_273_925_489, - span_id: 5678, - sampling: Some(Sampling { - priority: Some(1), - mechanism: None, - }), - origin: Some("synthetics".to_string()), - tags: HashMap::from([ - ("_dd.p.dm".to_string(), "-3".to_string()) - ]), - links: vec![ - SpanLink { - trace_id: 7_277_407_061_855_694_839, - // this should be `9291375655657946024` not `0`, but we don't have this data - // with the current definition of `SpanContext` - trace_id_high: 0, - span_id: 67_667_974_448_284_343, - flags: 1, - tracestate: "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64,congo=t61rcWkgMz".to_string(), - attributes: HashMap::from([ - ("reason".to_string(), "terminated_context".to_string()), - ("context_headers".to_string(), "tracecontext".to_string()), - ]), - } - ], - } - ), - // todo: datadog_primary_match_tracecontext_dif_from_b3_b3multi_invalid - } - - #[test] - fn test_new_filter_propagators() { - let config = config::Config { - trace_propagation_style_extract: vec![ - TracePropagationStyle::Datadog, - TracePropagationStyle::TraceContext, - TracePropagationStyle::B3, - TracePropagationStyle::B3Multi, - ], - ..Default::default() - }; - - let propagator = DatadogCompositePropagator::new(Arc::new(config)); - - assert_eq!(propagator.propagators.len(), 2); - } - - #[test] - fn test_new_no_propagators() { - let config = config::Config { - trace_propagation_style_extract: vec![TracePropagationStyle::None], - ..Default::default() - }; - let propagator = DatadogCompositePropagator::new(Arc::new(config)); - - assert_eq!(propagator.propagators.len(), 0); - } - #[test] fn test_extract_available_contexts() { let config = config::Config { @@ -854,49 +109,46 @@ pub mod tests { "_dd.p.test=value,_dd.p.tid=9291375655657946024,any=tag".to_string(), ), ]); - let (contexts, styles) = propagator.extract_available_contexts(&carrier); - - assert_eq!(contexts.len(), 2); - assert_eq!(styles.len(), 2); + let context = propagator.extract(&carrier); + assert!(context.is_some()); } #[test] - fn test_extract_available_contexts_no_contexts() { - let config = config::Config { - trace_propagation_style_extract: vec![TracePropagationStyle::Datadog], - ..Default::default() - }; - - let propagator = DatadogCompositePropagator::new(Arc::new(config)); - + fn test_attach_baggage() { + let mut context = SpanContext::default(); let carrier = HashMap::from([ - ( - "traceparent".to_string(), - "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string(), - ), - ( - "tracestate".to_string(), - "dd=p:00f067aa0ba902b7;s:2;o:rum".to_string(), - ), + ("x-datadog-trace-id".to_string(), "123".to_string()), + ("x-datadog-parent-id".to_string(), "5678".to_string()), + ("ot-baggage-key1".to_string(), "value1".to_string()), ]); - let (contexts, styles) = propagator.extract_available_contexts(&carrier); - assert_eq!(contexts.len(), 0); - assert_eq!(styles.len(), 0); + DatadogCompositePropagator::attach_baggage(&mut context, &carrier); + + assert_eq!(context.tags.len(), 1); + assert_eq!(context.tags.get("key1").expect("Missing tag"), "value1"); } #[test] - fn test_attach_baggage() { + fn test_attach_baggage_multiple_keys() { let mut context = SpanContext::default(); let carrier = HashMap::from([ - ("x-datadog-trace-id".to_string(), "123".to_string()), - ("x-datadog-parent-id".to_string(), "5678".to_string()), ("ot-baggage-key1".to_string(), "value1".to_string()), + ("ot-baggage-key2".to_string(), "value2".to_string()), + ("x-datadog-trace-id".to_string(), "123".to_string()), ]); DatadogCompositePropagator::attach_baggage(&mut context, &carrier); - assert_eq!(context.tags.len(), 1); + assert_eq!(context.tags.len(), 2); assert_eq!(context.tags.get("key1").expect("Missing tag"), "value1"); + assert_eq!(context.tags.get("key2").expect("Missing tag"), "value2"); + } + + #[test] + fn test_extract_propagation_tags() { + let tags = extract_propagation_tags("_dd.p.tid=abc123,any=tag,_dd.p.dm=-4"); + assert_eq!(tags.len(), 2); + assert_eq!(tags.get("_dd.p.tid").expect("Missing tag"), "abc123"); + assert_eq!(tags.get("_dd.p.dm").expect("Missing tag"), "-4"); } } diff --git a/bottlecap/src/traces/propagation/text_map_propagator.rs b/bottlecap/src/traces/propagation/text_map_propagator.rs deleted file mode 100644 index acd95ff18..000000000 --- a/bottlecap/src/traces/propagation/text_map_propagator.rs +++ /dev/null @@ -1,536 +0,0 @@ -use std::collections::HashMap; -use std::sync::LazyLock; - -use regex::Regex; -use tracing::{debug, error, warn}; - -use crate::traces::context::{Sampling, SpanContext}; -use crate::traces::propagation::{ - Propagator, - carrier::{Extractor, Injector}, - error::Error, -}; - -// Datadog Keys -pub const DATADOG_TRACE_ID_KEY: &str = "x-datadog-trace-id"; -pub const DATADOG_PARENT_ID_KEY: &str = "x-datadog-parent-id"; -pub const DATADOG_SPAN_ID_KEY: &str = "x-datadog-span-id"; -pub const DATADOG_SAMPLING_PRIORITY_KEY: &str = "x-datadog-sampling-priority"; -const DATADOG_ORIGIN_KEY: &str = "x-datadog-origin"; -pub const DATADOG_TAGS_KEY: &str = "x-datadog-tags"; - -pub const DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY: &str = "_dd.p.tid"; -const DATADOG_PROPAGATION_ERROR_KEY: &str = "_dd.propagation_error"; -pub const DATADOG_LAST_PARENT_ID_KEY: &str = "_dd.parent_id"; -pub const DATADOG_SAMPLING_DECISION_KEY: &str = "_dd.p.dm"; - -// Traceparent Keys -const TRACEPARENT_KEY: &str = "traceparent"; -pub const TRACESTATE_KEY: &str = "tracestate"; - -pub const BAGGAGE_PREFIX: &str = "ot-baggage-"; - -static TRACEPARENT_REGEX: LazyLock = LazyLock::new(|| { - Regex::new(r"(?i)^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$") - .expect("failed creating regex") -}); -static INVALID_SEGMENT_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"^0+$").expect("failed creating regex")); -#[allow(dead_code)] -static VALID_TAG_KEY_REGEX: LazyLock = LazyLock::new(|| { - Regex::new(r"^_dd\.p\.[\x21-\x2b\x2d-\x7e]+$").expect("failed creating regex") -}); -#[allow(dead_code)] -static VALID_TAG_VALUE_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"^[\x20-\x2b\x2d-\x7e]*$").expect("failed creating regex")); -static INVALID_ASCII_CHARACTERS_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"[^\x20-\x7E]+").expect("failed creating regex")); -static VALID_SAMPLING_DECISION_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"^-([0-9])$").expect("failed creating regex")); - -#[derive(Clone, Copy)] -pub struct DatadogHeaderPropagator; - -impl Propagator for DatadogHeaderPropagator { - fn extract(&self, carrier: &dyn Extractor) -> Option { - Self::extract_context(carrier) - } - - fn inject(&self, _context: SpanContext, _carrier: &mut dyn Injector) { - todo!(); - } -} - -impl DatadogHeaderPropagator { - fn extract_context(carrier: &dyn Extractor) -> Option { - let trace_id = match Self::extract_trace_id(carrier) { - Ok(trace_id) => trace_id, - Err(e) => { - debug!("{e}"); - return None; - } - }; - - let parent_id = Self::extract_parent_id(carrier).unwrap_or(0); - let sampling_priority = match Self::extract_sampling_priority(carrier) { - Ok(sampling_priority) => sampling_priority, - Err(e) => { - debug!("{e}"); - return None; - } - }; - let origin = Self::extract_origin(carrier); - let mut tags = Self::extract_tags(carrier); - Self::validate_sampling_decision(&mut tags); - - Some(SpanContext { - trace_id, - span_id: parent_id, - sampling: Some(Sampling { - priority: Some(sampling_priority), - mechanism: None, - }), - origin, - tags, - links: Vec::new(), - }) - } - - fn validate_sampling_decision(tags: &mut HashMap) { - let should_remove = - tags.get(DATADOG_SAMPLING_DECISION_KEY) - .is_some_and(|sampling_decision| { - let is_invalid = !VALID_SAMPLING_DECISION_REGEX.is_match(sampling_decision); - if is_invalid { - warn!("Failed to decode `_dd.p.dm`: {}", sampling_decision); - } - is_invalid - }); - - if should_remove { - tags.remove(DATADOG_SAMPLING_DECISION_KEY); - tags.insert( - DATADOG_PROPAGATION_ERROR_KEY.to_string(), - "decoding_error".to_string(), - ); - } - - // todo: appsec standalone - } - - fn extract_trace_id(carrier: &dyn Extractor) -> Result { - let trace_id = carrier - .get(DATADOG_TRACE_ID_KEY) - .ok_or(Error::extract("`trace_id` not found", "datadog"))?; - - if INVALID_SEGMENT_REGEX.is_match(trace_id) { - return Err(Error::extract("Invalid `trace_id` found", "datadog")); - } - - trace_id - .parse::() - .map_err(|_| Error::extract("Failed to decode `trace_id`", "datadog")) - } - - fn extract_parent_id(carrier: &dyn Extractor) -> Option { - let parent_id = carrier.get(DATADOG_PARENT_ID_KEY)?; - - parent_id.parse::().ok() - } - - fn extract_sampling_priority(carrier: &dyn Extractor) -> Result { - // todo: enum? Default is USER_KEEP=2 - let sampling_priority = carrier.get(DATADOG_SAMPLING_PRIORITY_KEY).unwrap_or("2"); - - sampling_priority - .parse::() - .map_err(|_| Error::extract("Failed to decode `sampling_priority`", "datadog")) - } - - fn extract_origin(carrier: &dyn Extractor) -> Option { - let origin = carrier.get(DATADOG_ORIGIN_KEY)?; - Some(origin.to_string()) - } - - pub fn extract_tags(carrier: &dyn Extractor) -> HashMap { - let carrier_tags = carrier.get(DATADOG_TAGS_KEY).unwrap_or_default(); - let mut tags: HashMap = HashMap::new(); - - // todo: - // - trace propagation disabled - // - trace propagation max lenght - - let pairs = carrier_tags.split(','); - for pair in pairs { - if let Some((k, v)) = pair.split_once('=') { - // todo: reject key on tags extract reject - if k.starts_with("_dd.p.") { - tags.insert(k.to_string(), v.to_string()); - } - } - } - - // Handle 128bit trace ID - if !tags.is_empty() - && let Some(trace_id_higher_order_bits) = - carrier.get(DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY) - && !Self::higher_order_bits_valid(trace_id_higher_order_bits) - { - warn!( - "Malformed Trace ID: {trace_id_higher_order_bits} Failed to decode trace ID from carrier." - ); - tags.insert( - DATADOG_PROPAGATION_ERROR_KEY.to_string(), - format!("malformed tid {trace_id_higher_order_bits}"), - ); - tags.remove(DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY); - } - - if !tags.contains_key(DATADOG_SAMPLING_DECISION_KEY) { - tags.insert(DATADOG_SAMPLING_DECISION_KEY.to_string(), "-3".to_string()); - } - - tags - } - - fn higher_order_bits_valid(trace_id_higher_order_bits: &str) -> bool { - if trace_id_higher_order_bits.len() != 16 { - return false; - } - - match u64::from_str_radix(trace_id_higher_order_bits, 16) { - Ok(_) => {} - Err(_) => return false, - } - - true - } -} - -struct Traceparent { - sampling_priority: i8, - trace_id: u128, - span_id: u64, -} - -struct Tracestate { - sampling_priority: Option, - origin: Option, - lower_order_trace_id: Option, -} - -#[derive(Clone, Copy)] -pub struct TraceContextPropagator; - -impl Propagator for TraceContextPropagator { - fn extract(&self, carrier: &dyn Extractor) -> Option { - Self::extract_context(carrier) - } - - fn inject(&self, _context: SpanContext, _carrier: &mut dyn Injector) { - todo!() - } -} - -impl TraceContextPropagator { - fn extract_context(carrier: &dyn Extractor) -> Option { - let tp = carrier.get(TRACEPARENT_KEY)?.trim(); - - match Self::extract_traceparent(tp) { - Ok(traceparent) => { - let mut tags = HashMap::new(); - tags.insert(TRACEPARENT_KEY.to_string(), tp.to_string()); - - let mut origin = None; - let mut sampling_priority = traceparent.sampling_priority; - if let Some(ts) = carrier.get(TRACESTATE_KEY) { - if let Some(tracestate) = Self::extract_tracestate(ts, &mut tags) { - if let Some(lpid) = tracestate.lower_order_trace_id { - tags.insert(DATADOG_LAST_PARENT_ID_KEY.to_string(), lpid); - } - - origin = tracestate.origin; - - sampling_priority = Self::define_sampling_priority( - traceparent.sampling_priority, - tracestate.sampling_priority, - ); - } - } else { - debug!("No `dd` value found in tracestate"); - } - - let (trace_id_higher_order_bits, trace_id_lower_order_bits) = - Self::split_trace_id(traceparent.trace_id); - tags.insert( - DATADOG_HIGHER_ORDER_TRACE_ID_BITS_KEY.to_string(), - trace_id_higher_order_bits.to_string(), - ); - - Some(SpanContext { - trace_id: trace_id_lower_order_bits, - span_id: traceparent.span_id, - sampling: Some(Sampling { - priority: Some(sampling_priority), - mechanism: None, - }), - origin, - tags, - links: Vec::new(), - }) - } - Err(e) => { - error!("Failed to extract traceparent: {e}"); - None - } - } - } - - fn extract_tracestate( - tracestate: &str, - tags: &mut HashMap, - ) -> Option { - let ts_v = tracestate.split(',').map(str::trim); - let ts = ts_v.clone().collect::>().join(","); - - if INVALID_ASCII_CHARACTERS_REGEX.is_match(&ts) { - debug!("Received invalid tracestate header {tracestate}"); - return None; - } - - tags.insert(TRACESTATE_KEY.to_string(), ts.clone()); - - let mut dd: Option> = None; - for v in ts_v.clone() { - if let Some(stripped) = v.strip_prefix("dd=") { - dd = Some( - stripped - .split(';') - .filter_map(|item| { - let mut parts = item.splitn(2, ':'); - Some((parts.next()?.to_string(), parts.next()?.to_string())) - }) - .collect(), - ); - } - } - - if let Some(dd) = dd { - let mut tracestate = Tracestate { - sampling_priority: None, - origin: None, - lower_order_trace_id: None, - }; - - if let Some(ts_sp) = dd.get("s") - && let Ok(p_sp) = ts_sp.parse::() - { - tracestate.sampling_priority = Some(p_sp); - } - - if let Some(o) = dd.get("o") { - tracestate.origin = Some(Self::decode_tag_value(o)); - } - - if let Some(lo_tid) = dd.get("p") { - tracestate.lower_order_trace_id = Some(lo_tid.clone()); - } - - // Convert from `t.` to `_dd.p.` - for (k, v) in &dd { - if let Some(stripped) = k.strip_prefix("t.") { - let nk = format!("_dd.p.{stripped}"); - tags.insert(nk, Self::decode_tag_value(v)); - } - } - - return Some(tracestate); - } - - None - } - - fn decode_tag_value(value: &str) -> String { - value.replace('~', "=") - } - - fn define_sampling_priority( - traceparent_sampling_priority: i8, - tracestate_sampling_priority: Option, - ) -> i8 { - if let Some(ts_sp) = tracestate_sampling_priority - && ((traceparent_sampling_priority == 1 && ts_sp > 0) - || (traceparent_sampling_priority == 0 && ts_sp < 0)) - { - return ts_sp; - } - - traceparent_sampling_priority - } - - fn extract_traceparent(traceparent: &str) -> Result { - let captures = TRACEPARENT_REGEX - .captures(traceparent) - .ok_or_else(|| Error::extract("invalid traceparent", "traceparent"))?; - - let version = &captures[1]; - let trace_id = &captures[2]; - let span_id = &captures[3]; - let flags = &captures[4]; - let tail = captures.get(5).map_or("", |m| m.as_str()); - - Self::extract_version(version, tail)?; - - let trace_id = Self::extract_trace_id(trace_id)?; - let span_id = Self::extract_span_id(span_id)?; - - let trace_flags = Self::extract_trace_flags(flags)?; - let sampling_priority = i8::from(trace_flags & 0x1 != 0); - - Ok(Traceparent { - sampling_priority, - trace_id, - span_id, - }) - } - - fn extract_version(version: &str, tail: &str) -> Result<(), Error> { - match version { - "ff" => { - return Err(Error::extract( - "`ff` is an invalid traceparent version", - "traceparent", - )); - } - "00" => { - if !tail.is_empty() { - return Err(Error::extract( - "Traceparent with version `00` should contain only 4 values delimited by `-`", - "traceparent", - )); - } - } - _ => { - warn!("Unsupported traceparent version {version}, still atempenting to parse"); - } - } - - Ok(()) - } - - fn extract_trace_id(trace_id: &str) -> Result { - if INVALID_SEGMENT_REGEX.is_match(trace_id) { - return Err(Error::extract( - "`0` value for trace_id is invalid", - "traceparent", - )); - } - - u128::from_str_radix(trace_id, 16) - .map_err(|_| Error::extract("Failed to decode trace_id", "traceparent")) - } - - #[allow(clippy::cast_possible_truncation)] - fn split_trace_id(trace_id: u128) -> (u64, u64) { - let trace_id_lower_order_bits = trace_id as u64; - let trace_id_higher_order_bits = (trace_id >> 64) as u64; - - (trace_id_higher_order_bits, trace_id_lower_order_bits) - } - - fn extract_span_id(span_id: &str) -> Result { - if INVALID_SEGMENT_REGEX.is_match(span_id) { - return Err(Error::extract( - "`0` value for span_id is invalid", - "traceparent", - )); - } - - u64::from_str_radix(span_id, 16) - .map_err(|_| Error::extract("Failed to decode span_id", "traceparent")) - } - - fn extract_trace_flags(flags: &str) -> Result { - if flags.len() != 2 { - return Err(Error::extract("Invalid trace flags length", "traceparent")); - } - - u8::from_str_radix(flags, 16) - .map_err(|_| Error::extract("Failed to decode trace_flags", "traceparent")) - } -} - -#[cfg(test)] -#[allow(clippy::unwrap_used)] -mod test { - use super::*; - - #[test] - fn test_extract_datadog_propagator() { - let headers = HashMap::from([ - ("x-datadog-trace-id".to_string(), "1234".to_string()), - ("x-datadog-parent-id".to_string(), "5678".to_string()), - ("x-datadog-sampling-priority".to_string(), "1".to_string()), - ("x-datadog-origin".to_string(), "synthetics".to_string()), - ( - "x-datadog-tags".to_string(), - "_dd.p.test=value,_dd.p.tid=4321,any=tag".to_string(), - ), - ]); - - let propagator = DatadogHeaderPropagator; - - let context = propagator - .extract(&headers) - .expect("couldn't extract trace context"); - - assert_eq!(context.trace_id, 1234); - assert_eq!(context.span_id, 5678); - assert_eq!(context.sampling.unwrap().priority, Some(1)); - assert_eq!(context.origin, Some("synthetics".to_string())); - println!("{:?}", context.tags); - assert_eq!(context.tags.get("_dd.p.test").unwrap(), "value"); - assert_eq!(context.tags.get("_dd.p.tid").unwrap(), "4321"); - assert_eq!(context.tags.get("_dd.p.dm").unwrap(), "-3"); - } - - #[test] - fn test_extract_traceparent_propagator() { - let headers = HashMap::from([ - ( - "traceparent".to_string(), - "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-01".to_string(), - ), - ( - "tracestate".to_string(), - "dd=p:00f067aa0ba902b7;s:2;o:rum".to_string(), - ), - ]); - - let propagator = TraceContextPropagator; - let context = propagator - .extract(&headers) - .expect("couldn't extract trace context"); - - assert_eq!(context.trace_id, 7_277_407_061_855_694_839); - assert_eq!(context.span_id, 67_667_974_448_284_343); - assert_eq!(context.sampling.unwrap().priority, Some(2)); - assert_eq!(context.origin, Some("rum".to_string())); - assert_eq!( - context.tags.get("traceparent").unwrap(), - "00-80f198ee56343ba864fe8b2a57d3eff7-00f067aa0ba902b7-01" - ); - assert_eq!( - context.tags.get("tracestate").unwrap(), - "dd=p:00f067aa0ba902b7;s:2;o:rum" - ); - assert_eq!( - context.tags.get("_dd.p.tid").unwrap(), - "9291375655657946024" - ); - assert_eq!( - context.tags.get("_dd.parent_id").unwrap(), - "00f067aa0ba902b7" - ); - } -}