diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 4cd702b93..6e2a70315 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -53,7 +53,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -79,9 +79,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -121,9 +121,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -138,20 +138,32 @@ dependencies = [ name = "bottlecap" version = "0.1.0" dependencies = [ + "anyhow", + "async-trait", "base64 0.22.1", "chrono", "datadog-protos", + "datadog-trace-mini-agent", + "datadog-trace-normalization", + "datadog-trace-obfuscation", + "datadog-trace-protobuf", + "datadog-trace-utils", + "ddcommon", "ddsketch-agent", "figment", "fnv", - "hashbrown 0.14.5", + "hashbrown", "hex", "hmac", + "hyper 0.14.29", "log", "proptest", "protobuf", "regex", "reqwest", + "rmp", + "rmp-serde", + "rmpv", "serde", "serde_json", "sha2", @@ -173,9 +185,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" [[package]] name = "byteorder" @@ -191,9 +203,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.98" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cfg-if" @@ -211,6 +223,22 @@ dependencies = [ "serde", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -220,6 +248,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -233,20 +270,125 @@ dependencies = [ [[package]] name = "datadog-protos" version = "0.1.0" -source = "git+https://github.com/DataDog/saluki/#0e55b345e6d2a215474147542f5e776d4f593af9" +source = "git+https://github.com/DataDog/saluki/#ecebc9a69134b01e9e3f2a17ae271289fc67f02d" dependencies = [ "bytes", - "prost", + "prost 0.12.6", "protobuf", "protobuf-codegen", "tonic", "tonic-build", ] +[[package]] +name = "datadog-trace-mini-agent" +version = "0.4.2" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "anyhow", + "async-trait", + "datadog-trace-normalization", + "datadog-trace-obfuscation", + "datadog-trace-protobuf", + "datadog-trace-utils", + "ddcommon", + "hyper 0.14.29", + "log", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "datadog-trace-normalization" +version = "10.0.0" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "anyhow", + "datadog-trace-protobuf", +] + +[[package]] +name = "datadog-trace-obfuscation" +version = "10.0.0" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "anyhow", + "datadog-trace-protobuf", + "datadog-trace-utils", + "ddcommon", + "log", + "percent-encoding", + "regex", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "datadog-trace-protobuf" +version = "10.0.0" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "prost 0.11.9", + "serde", + "serde_bytes", +] + +[[package]] +name = "datadog-trace-utils" +version = "10.0.0" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "anyhow", + "bytes", + "datadog-trace-normalization", + "datadog-trace-protobuf", + "ddcommon", + "flate2", + "futures", + "hyper 0.14.29", + "hyper-rustls 0.23.2", + "log", + "prost 0.11.9", + "rand", + "rmp", + "rmp-serde", + "rmpv", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "ddcommon" +version = "10.0.0" +source = "git+https://github.com/DataDog/libdatadog#15aa48dae5f53b853cee7ba0a0f4860a48d7970f" +dependencies = [ + "anyhow", + "futures", + "futures-core", + "futures-util", + "hex", + "http 0.2.12", + "hyper 0.14.29", + "hyper-rustls 0.23.2", + "lazy_static", + "log", + "pin-project", + "regex", + "rustls 0.20.9", + "rustls-native-certs", + "serde", + "static_assertions", + "tokio", + "tokio-rustls 0.23.4", +] + [[package]] name = "ddsketch-agent" version = "0.1.0" -source = "git+https://github.com/DataDog/saluki/#0e55b345e6d2a215474147542f5e776d4f593af9" +source = "git+https://github.com/DataDog/saluki/#ecebc9a69134b01e9e3f2a17ae271289fc67f02d" dependencies = [ "datadog-protos", "float_eq", @@ -266,9 +408,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -314,6 +456,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "float_eq" version = "1.0.1" @@ -335,6 +487,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -342,6 +509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -350,6 +518,34 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -368,10 +564,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -413,19 +615,13 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.5" @@ -513,12 +709,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", "http-body 1.0.0", "pin-project-lite", @@ -526,9 +722,38 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] [[package]] name = "hyper" @@ -552,19 +777,34 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +dependencies = [ + "http 0.2.12", + "hyper 0.14.29", + "rustls 0.20.9", + "rustls-native-certs", + "tokio", + "tokio-rustls 0.23.4", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper", + "hyper 1.3.1", "hyper-util", - "rustls", + "rustls 0.23.10", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", + "webpki-roots", ] [[package]] @@ -578,7 +818,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper", + "hyper 1.3.1", "pin-project-lite", "socket2", "tokio", @@ -597,16 +837,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.2.6" @@ -614,7 +844,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -629,6 +859,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -655,9 +894,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -704,9 +943,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -716,9 +955,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -762,9 +1001,9 @@ dependencies = [ [[package]] name = "object" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] @@ -775,6 +1014,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "ordered-float" version = "4.2.0" @@ -807,6 +1052,12 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pear" version = "0.2.9" @@ -827,7 +1078,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -843,7 +1094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap", ] [[package]] @@ -863,7 +1114,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -891,14 +1142,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.68", ] [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -911,16 +1162,16 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", "version_check", "yansi", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", @@ -930,12 +1181,22 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "rusty-fork", "tempfile", "unarray", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + [[package]] name = "prost" version = "0.12.6" @@ -943,7 +1204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.6", ] [[package]] @@ -954,19 +1215,32 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck", - "itertools", + "itertools 0.12.1", "log", "multimap", "once_cell", "petgraph", "prettyplease", - "prost", + "prost 0.12.6", "prost-types", "regex", - "syn", + "syn 2.0.68", "tempfile", ] +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "prost-derive" version = "0.12.6" @@ -974,10 +1248,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -986,14 +1260,14 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost", + "prost 0.12.6", ] [[package]] name = "protobuf" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0" +checksum = "df67496db1a89596beaced1579212e9b7c53c22dca1d9745de00ead76573d514" dependencies = [ "bytes", "once_cell", @@ -1003,9 +1277,9 @@ dependencies = [ [[package]] name = "protobuf-codegen" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32777b0b3f6538d9d2e012b3fad85c7e4b9244b5958d04a6415f4333782b7a77" +checksum = "eab09155fad2d39333d3796f67845d43e29b266eea74f7bc93f153f707f126dc" dependencies = [ "anyhow", "once_cell", @@ -1018,12 +1292,12 @@ dependencies = [ [[package]] name = "protobuf-parse" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cb37955261126624a25b5e6bda40ae34cf3989d52a783087ca6091b29b5642" +checksum = "1a16027030d4ec33e423385f73bb559821827e9ec18c50e7874e4d6de5a4e96f" dependencies = [ "anyhow", - "indexmap 1.9.3", + "indexmap", "log", "protobuf", "protobuf-support", @@ -1034,9 +1308,9 @@ dependencies = [ [[package]] name = "protobuf-support" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7" +checksum = "70e2d30ab1878b2e72d1e2fc23ff5517799c9929e2cf81a8516f9f4dcf2b9cf3" dependencies = [ "thiserror", ] @@ -1047,6 +1321,53 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.10", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash", + "rustls 0.23.10", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -1097,23 +1418,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -1127,13 +1448,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -1144,15 +1465,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -1162,8 +1483,8 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.3.1", + "hyper-rustls 0.27.2", "hyper-util", "ipnet", "js-sys", @@ -1172,15 +1493,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "quinn", + "rustls 0.23.10", + "rustls-pemfile 2.1.2", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", "url", "wasm-bindgen", @@ -1190,6 +1512,21 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -1200,17 +1537,55 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rmpv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58450723cd9ee93273ce44a20b6ec4efe17f8ed2e3631474387bfdecf18bb2a9" +dependencies = [ + "num-traits", + "rmp", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.34" @@ -1226,18 +1601,51 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", - "ring", + "ring 0.16.20", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -1260,9 +1668,9 @@ version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -1283,12 +1691,54 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.203" @@ -1298,6 +1748,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.203" @@ -1306,14 +1765,14 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -1338,7 +1797,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap", "itoa", "ryu", "serde", @@ -1390,23 +1849,46 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" -version = "2.0.66" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -1415,9 +1897,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "tempfile" @@ -1448,7 +1930,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -1463,9 +1945,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" dependencies = [ "tinyvec_macros", ] @@ -1501,16 +1983,27 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.10", "rustls-pki-types", "tokio", ] @@ -1552,7 +2045,7 @@ dependencies = [ "http-body 0.4.6", "percent-encoding", "pin-project", - "prost", + "prost 0.12.6", "tokio", "tokio-stream", "tower-layer", @@ -1570,7 +2063,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -1619,7 +2112,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] @@ -1712,6 +2205,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -1720,9 +2219,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -1798,7 +2297,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -1832,7 +2331,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1853,11 +2352,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] @@ -1874,6 +2383,28 @@ dependencies = [ "rustix", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" @@ -2046,7 +2577,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index ff98a5c28..e8f500a01 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -5,12 +5,21 @@ edition = "2021" publish = false [dependencies] +async-trait = { version = "0.1.64", default-features = false } +anyhow = { version = "1.0", default-features = false } chrono = { version = "0.4.38", features = ["serde", "std", "now"], default-features = false} datadog-protos = { version = "0.1.0", default-features = false, git = "https://github.com/DataDog/saluki/" } ddsketch-agent = { version = "0.1.0", default-features = false, git = "https://github.com/DataDog/saluki/" } +ddcommon = { version = "10.0", git = "https://github.com/DataDog/libdatadog" } +datadog-trace-protobuf = { version = "10.0.0", git = "https://github.com/DataDog/libdatadog" } +datadog-trace-utils = { version = "10.0.0", git= "https://github.com/DataDog/libdatadog" } +datadog-trace-mini-agent = { version = "0.4.2", git= "https://github.com/DataDog/libdatadog" } +datadog-trace-normalization = { version = "10.0.0", git= "https://github.com/DataDog/libdatadog" } +datadog-trace-obfuscation = { version = "10.0.0", git= "https://github.com/DataDog/libdatadog" } figment = { version = "0.10.15", default-features = false, features = ["yaml", "env"] } fnv = { version = "1.0.7", default-features = false } hashbrown = { version = "0.14.3", default-features = false, features = ["inline-more"] } +hyper = { version = "0.14", default-features = false, features = ["server"] } log = { version = "0.4.21", default-features = false } protobuf = { version = "3.4.0", default-features = false } regex = { version = "1.10.4", default-features = false } @@ -29,6 +38,9 @@ hmac = { version = "0.12.1", default-features = false } sha2 = { version = "0.10.8", default-features = false } hex = { version = "0.4.3", default-features = false, features = ["std"] } base64 = { version = "0.22.0", default-features = false } +rmp-serde = { version = "1.3.0", default-features = false } +rmpv = { version = "1.3.0", default-features = false } +rmp = { version = "0.8.14", default-features = false } [dev-dependencies] figment = { version = "0.10.15", default-features = false, features = ["yaml", "env", "test"] } diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index f5ba32652..4657e2f93 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -10,22 +10,6 @@ #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] -use decrypt::resolve_secrets; -use std::{ - collections::hash_map, - collections::HashMap, - env, - io::Error, - io::Result, - os::unix::process::CommandExt, - path::Path, - process::Command, - sync::{Arc, Mutex}, -}; -use telemetry::listener::TelemetryListenerConfig; -use tracing::{debug, error, info}; -use tracing_subscriber::EnvFilter; - use bottlecap::{ base_url, config::{self, AwsConfig, Config}, @@ -53,10 +37,33 @@ use bottlecap::{ events::{Status, TelemetryRecord}, listener::TelemetryListener, }, + traces::{ + stats_flusher::{self, StatsFlusher}, + stats_processor, trace_agent, + trace_flusher::{self, TraceFlusher}, + trace_processor, + }, DOGSTATSD_PORT, EXTENSION_ACCEPT_FEATURE_HEADER, EXTENSION_FEATURES, EXTENSION_HOST, EXTENSION_ID_HEADER, EXTENSION_NAME, EXTENSION_NAME_HEADER, EXTENSION_ROUTE, LAMBDA_RUNTIME_SLUG, TELEMETRY_PORT, }; +use datadog_trace_obfuscation::obfuscation_config; +use decrypt::resolve_secrets; +use std::{ + collections::hash_map, + collections::HashMap, + env, + io::Error, + io::Result, + os::unix::process::CommandExt, + path::Path, + process::Command, + sync::{Arc, Mutex}, +}; +use telemetry::listener::TelemetryListenerConfig; +use tokio::sync::Mutex as TokioMutex; +use tracing::{debug, error, info}; +use tracing_subscriber::EnvFilter; use reqwest::Client; use serde::Deserialize; @@ -261,6 +268,40 @@ async fn extension_loop_active( Arc::clone(&metrics_aggr), config.site.clone(), ); + + let trace_flusher = Arc::new(trace_flusher::ServerlessTraceFlusher { + buffer: Arc::new(TokioMutex::new(Vec::new())), + }); + let trace_processor = Arc::new(trace_processor::ServerlessTraceProcessor { + obfuscation_config: Arc::new( + obfuscation_config::ObfuscationConfig::new() + .map_err(|e| Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?, + ), + }); + + let stats_flusher = Arc::new(stats_flusher::ServerlessStatsFlusher { + buffer: Arc::new(TokioMutex::new(Vec::new())), + config: Arc::clone(config), + }); + let stats_processor = Arc::new(stats_processor::ServerlessStatsProcessor {}); + + let trace_flusher_clone = trace_flusher.clone(); + let stats_flusher_clone = stats_flusher.clone(); + + let trace_agent = Box::new(trace_agent::TraceAgent { + config: Arc::clone(config), + trace_processor, + trace_flusher: trace_flusher_clone, + stats_processor, + stats_flusher: stats_flusher_clone, + tags_provider, + }); + tokio::spawn(async move { + let res = trace_agent.start_trace_agent().await; + if let Err(e) = res { + error!("Error starting trace agent: {e:?}"); + } + }); let lambda_enhanced_metrics = enhanced_metrics::new(Arc::clone(&metrics_aggr)); let dogstatsd_cancel_token = start_dogstatsd(event_bus.get_sender_copy(), &metrics_aggr).await; @@ -364,7 +405,12 @@ async fn extension_loop_active( // pass the invocation deadline to // flush tasks here, so they can // retry if we have more time - tokio::join!(logs_flusher.flush(), metrics_flusher.flush()); + tokio::join!( + logs_flusher.flush(), + metrics_flusher.flush(), + trace_flusher.manual_flush(), + stats_flusher.manual_flush() + ); break; } TelemetryRecord::PlatformReport { @@ -410,7 +456,12 @@ async fn extension_loop_active( if shutdown { dogstatsd_cancel_token.cancel(); telemetry_listener_cancel_token.cancel(); - tokio::join!(logs_flusher.flush(), metrics_flusher.flush()); + tokio::join!( + logs_flusher.flush(), + metrics_flusher.flush(), + trace_flusher.manual_flush(), + stats_flusher.manual_flush() + ); return Ok(()); } } diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index 590ec9e2e..aafb0b39a 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -17,6 +17,7 @@ use crate::config::processing_rule::{deserialize_processing_rules, ProcessingRul #[derive(Debug, PartialEq, Deserialize, Clone)] #[serde(deny_unknown_fields)] #[serde(default)] +#[allow(clippy::struct_excessive_bools)] pub struct Config { pub site: String, pub api_key: String, @@ -33,6 +34,13 @@ pub struct Config { pub apm_enabled: bool, pub lambda_handler: String, pub serverless_flush_strategy: FlushStrategy, + pub trace_enabled: bool, + pub serverless_trace_enabled: bool, + pub capture_lambda_payload: bool, + // Deprecated or ignored, just here so we don't failover + pub flush_to_log: bool, + pub logs_injection: bool, + pub merge_xray_traces: bool, } impl Default for Config { @@ -57,6 +65,12 @@ impl Default for Config { // APM apm_enabled: false, lambda_handler: String::default(), + serverless_trace_enabled: true, + trace_enabled: true, + capture_lambda_payload: false, + flush_to_log: false, + logs_injection: false, + merge_xray_traces: false, } } } diff --git a/bottlecap/src/lib.rs b/bottlecap/src/lib.rs index 180f81ef8..7b1c658e9 100644 --- a/bottlecap/src/lib.rs +++ b/bottlecap/src/lib.rs @@ -27,6 +27,7 @@ pub mod metrics; pub mod secrets; pub mod tags; pub mod telemetry; +pub mod traces; use std::{env, io}; diff --git a/bottlecap/src/secrets/decrypt.rs b/bottlecap/src/secrets/decrypt.rs index 139a8a8cc..a00677a2d 100644 --- a/bottlecap/src/secrets/decrypt.rs +++ b/bottlecap/src/secrets/decrypt.rs @@ -2,7 +2,6 @@ use crate::config::{AwsConfig, Config}; use base64::prelude::*; use chrono::{DateTime, Utc}; use hmac::{Hmac, Mac}; -use log::error; use reqwest::header::{HeaderMap, HeaderValue}; use reqwest::Client; use serde_json::Value; @@ -11,6 +10,7 @@ use std::io::Error; use std::sync::Arc; use std::time::Instant; use tracing::debug; +use tracing::error; pub async fn resolve_secrets(config: Arc, aws_config: &AwsConfig) -> Option { if !config.api_key.is_empty() { diff --git a/bottlecap/src/tags/lambda/tags.rs b/bottlecap/src/tags/lambda/tags.rs index 2739b6345..eaf820482 100644 --- a/bottlecap/src/tags/lambda/tags.rs +++ b/bottlecap/src/tags/lambda/tags.rs @@ -155,6 +155,11 @@ impl Lambda { pub fn get_function_arn(&self) -> Option<&String> { self.tags_map.get(FUNCTION_ARN_KEY) } + + #[must_use] + pub fn get_tags_map(&self) -> &hash_map::HashMap { + &self.tags_map + } } #[cfg(test)] diff --git a/bottlecap/src/tags/provider.rs b/bottlecap/src/tags/provider.rs index c1b15ed7a..a3a6881df 100644 --- a/bottlecap/src/tags/provider.rs +++ b/bottlecap/src/tags/provider.rs @@ -46,11 +46,17 @@ impl Provider { pub fn get_canonical_id(&self) -> Option { self.tag_provider.get_canonical_id() } + + #[must_use] + pub fn get_tags_map(&self) -> &hash_map::HashMap { + self.tag_provider.get_tags_map() + } } trait GetTags { fn get_tags_vec(&self) -> Vec; fn get_canonical_id(&self) -> Option; + fn get_tags_map(&self) -> &hash_map::HashMap; } impl GetTags for TagProvider { @@ -65,6 +71,12 @@ impl GetTags for TagProvider { TagProvider::Lambda(lambda_tags) => lambda_tags.get_function_arn().cloned(), } } + + fn get_tags_map(&self) -> &hash_map::HashMap { + match self { + TagProvider::Lambda(lambda_tags) => lambda_tags.get_tags_map(), + } + } } #[cfg(test)] diff --git a/bottlecap/src/traces/mod.rs b/bottlecap/src/traces/mod.rs new file mode 100644 index 000000000..8545fbe40 --- /dev/null +++ b/bottlecap/src/traces/mod.rs @@ -0,0 +1,8 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +pub mod stats_flusher; +pub mod stats_processor; +pub mod trace_agent; +pub mod trace_flusher; +pub mod trace_processor; diff --git a/bottlecap/src/traces/stats_flusher.rs b/bottlecap/src/traces/stats_flusher.rs new file mode 100644 index 000000000..d373d2fc0 --- /dev/null +++ b/bottlecap/src/traces/stats_flusher.rs @@ -0,0 +1,92 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use std::str::FromStr; +use std::sync::Arc; +use tokio::sync::{mpsc::Receiver, Mutex}; +use tracing::{debug, error}; + +use crate::config; +use datadog_trace_protobuf::pb; +use datadog_trace_utils::config_utils::trace_stats_url; +use datadog_trace_utils::stats_utils; +use ddcommon::Endpoint; + +#[async_trait] +pub trait StatsFlusher { + /// Starts a stats flusher that listens for stats payloads sent to the tokio mpsc Receiver, + /// implementing flushing logic that calls flush_stats. + async fn start_stats_flusher(&self, mut rx: Receiver); + /// Flushes stats to the Datadog trace stats intake. + async fn flush_stats(&self, traces: Vec); + + async fn manual_flush(&self); +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Clone)] +pub struct ServerlessStatsFlusher { + pub buffer: Arc>>, + pub config: Arc, +} + +#[async_trait] +impl StatsFlusher for ServerlessStatsFlusher { + async fn start_stats_flusher(&self, mut rx: Receiver) { + let buffer_producer = self.buffer.clone(); + + tokio::spawn(async move { + while let Some(stats_payload) = rx.recv().await { + let mut buffer = buffer_producer.lock().await; + buffer.push(stats_payload); + } + }); + } + + async fn manual_flush(&self) { + let mut buffer = self.buffer.lock().await; + if !buffer.is_empty() { + self.flush_stats(buffer.to_vec()).await; + buffer.clear(); + } + } + async fn flush_stats(&self, stats: Vec) { + if stats.is_empty() { + return; + } + debug!("Flushing {} stats", stats.len()); + + let stats_payload = stats_utils::construct_stats_payload(stats); + + debug!("Stats payload to be sent: {stats_payload:?}"); + + let serialized_stats_payload = match stats_utils::serialize_stats_payload(stats_payload) { + Ok(res) => res, + Err(err) => { + error!("Failed to serialize stats payload, dropping stats: {err}"); + return; + } + }; + + let stats_url = trace_stats_url(&self.config.site); + + let endpoint = Endpoint { + url: hyper::Uri::from_str(&stats_url).expect("can't make URI from stats url, exiting"), + api_key: Some(self.config.api_key.clone().into()), + }; + + match stats_utils::send_stats_payload( + serialized_stats_payload, + &endpoint, + &self.config.api_key, + ) + .await + { + Ok(()) => debug!("Successfully flushed stats"), + Err(e) => { + error!("Error sending stats: {e:?}"); + } + } + } +} diff --git a/bottlecap/src/traces/stats_processor.rs b/bottlecap/src/traces/stats_processor.rs new file mode 100644 index 000000000..60c8019c8 --- /dev/null +++ b/bottlecap/src/traces/stats_processor.rs @@ -0,0 +1,94 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use std::time::{SystemTime, UNIX_EPOCH}; + +use async_trait::async_trait; +use hyper::{http, Body, Request, Response, StatusCode}; +use tokio::sync::mpsc::Sender; +use tracing::debug; + +use datadog_trace_protobuf::pb; +use datadog_trace_utils::stats_utils; + +use super::trace_agent::MAX_CONTENT_LENGTH; +use datadog_trace_mini_agent::http_utils::{self, log_and_create_http_response}; + +#[async_trait] +pub trait StatsProcessor { + /// Deserializes trace stats from a hyper request body and sends them through + /// the provided tokio mpsc Sender. + async fn process_stats( + &self, + req: Request, + tx: Sender, + ) -> http::Result>; +} + +#[derive(Clone, Copy)] +#[allow(clippy::module_name_repetitions)] +pub struct ServerlessStatsProcessor {} + +#[async_trait] +impl StatsProcessor for ServerlessStatsProcessor { + async fn process_stats( + &self, + req: Request, + tx: Sender, + ) -> http::Result> { + debug!("Recieved trace stats to process"); + let (parts, body) = req.into_parts(); + + if let Some(response) = http_utils::verify_request_content_length( + &parts.headers, + MAX_CONTENT_LENGTH, + "Error processing trace stats", + ) { + return response; + } + + // deserialize trace stats from the request body, convert to protobuf structs (see + // trace-protobuf crate) + let mut stats: pb::ClientStatsPayload = + match stats_utils::get_stats_from_request_body(body).await { + Ok(result) => result, + Err(err) => { + return log_and_create_http_response( + &format!("Error deserializing trace stats from request body: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + }; + + let start = SystemTime::now(); + let timestamp = start + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_nanos(); + stats.stats[0].start = match u64::try_from(timestamp) { + Ok(result) => result, + Err(_) => { + return log_and_create_http_response( + "Error converting timestamp to u64", + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + }; + + // send trace payload to our trace flusher + match tx.send(stats).await { + Ok(()) => { + return log_and_create_http_response( + "Successfully buffered stats to be flushed.", + StatusCode::ACCEPTED, + ); + } + Err(err) => { + return log_and_create_http_response( + &format!("Error sending stats to the stats flusher: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + } + } +} diff --git a/bottlecap/src/traces/trace_agent.rs b/bottlecap/src/traces/trace_agent.rs new file mode 100644 index 000000000..8d34cd5c8 --- /dev/null +++ b/bottlecap/src/traces/trace_agent.rs @@ -0,0 +1,203 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use hyper::service::{make_service_fn, service_fn}; +use hyper::{http, Body, Method, Request, Response, Server, StatusCode}; +use serde_json::json; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::sync::Arc; +use std::time::Instant; +use tokio::sync::mpsc::{self, Receiver, Sender}; +use tracing::{error, info}; + +use crate::config; +use crate::tags::provider; +use crate::traces::{stats_flusher, stats_processor, trace_flusher, trace_processor}; +use datadog_trace_mini_agent::http_utils::log_and_create_http_response; +use datadog_trace_protobuf::pb; +use datadog_trace_utils::trace_utils::SendData; + +const TRACE_AGENT_PORT: usize = 8126; +const V4_TRACE_ENDPOINT_PATH: &str = "/v0.4/traces"; +const V5_TRACE_ENDPOINT_PATH: &str = "/v0.5/traces"; +const STATS_ENDPOINT_PATH: &str = "/v0.6/stats"; +const INFO_ENDPOINT_PATH: &str = "/info"; +const TRACER_PAYLOAD_CHANNEL_BUFFER_SIZE: usize = 10; +const STATS_PAYLOAD_CHANNEL_BUFFER_SIZE: usize = 10; +pub const MAX_CONTENT_LENGTH: usize = 10 * 1024 * 1024; + +pub struct TraceAgent { + pub config: Arc, + pub trace_processor: Arc, + pub trace_flusher: Arc, + pub stats_processor: Arc, + pub stats_flusher: Arc, + pub tags_provider: Arc, +} + +#[derive(Clone, Copy)] +pub enum ApiVersion { + V04, + V05, +} + +impl TraceAgent { + pub async fn start_trace_agent(&self) -> Result<(), Box> { + let now = Instant::now(); + info!( + "Time taken to fetch Trace Agent metadata: {} ms", + now.elapsed().as_millis() + ); + + // setup a channel to send processed traces to our flusher. tx is passed through each + // endpoint_handler to the trace processor, which uses it to send de-serialized + // processed trace payloads to our trace flusher. + let (trace_tx, trace_rx): (Sender, Receiver) = + mpsc::channel(TRACER_PAYLOAD_CHANNEL_BUFFER_SIZE); + + // start our trace flusher. receives trace payloads and handles buffering + deciding when to + // flush to backend. + let trace_flusher = self.trace_flusher.clone(); + trace_flusher.start_trace_flusher(trace_rx).await; + + // channels to send processed stats to our stats flusher. + let (stats_tx, stats_rx): ( + Sender, + Receiver, + ) = mpsc::channel(STATS_PAYLOAD_CHANNEL_BUFFER_SIZE); + + // start our stats flusher. + let stats_flusher = self.stats_flusher.clone(); + // let stats_config = self.config.clone(); + tokio::spawn(async move { + let stats_flusher = stats_flusher.clone(); + stats_flusher.start_stats_flusher(stats_rx).await; + }); + + // setup our hyper http server, where the endpoint_handler handles incoming requests + let trace_processor = self.trace_processor.clone(); + let stats_processor = self.stats_processor.clone(); + let endpoint_config = self.config.clone(); + let tags_provider = self.tags_provider.clone(); + + let make_svc = make_service_fn(move |_| { + let trace_processor = trace_processor.clone(); + let trace_tx = trace_tx.clone(); + + let stats_processor = stats_processor.clone(); + let stats_tx = stats_tx.clone(); + + let endpoint_config = endpoint_config.clone(); + let tags_provider = tags_provider.clone(); + + let service = service_fn(move |req| { + TraceAgent::trace_endpoint_handler( + endpoint_config.clone(), + req, + trace_processor.clone(), + trace_tx.clone(), + stats_processor.clone(), + stats_tx.clone(), + tags_provider.clone(), + ) + }); + + async move { Ok::<_, Infallible>(service) } + }); + + let port = u16::try_from(TRACE_AGENT_PORT).expect("TRACE_AGENT_PORT is too large"); + let addr = SocketAddr::from(([127, 0, 0, 1], port)); + let server_builder = Server::try_bind(&addr)?; + + let server = server_builder.serve(make_svc); + + info!("Trace Agent started: listening on port {TRACE_AGENT_PORT}"); + info!( + "Time taken start the Trace Agent: {} ms", + now.elapsed().as_millis() + ); + + // start hyper http server + if let Err(e) = server.await { + error!("Server error: {e}"); + return Err(e.into()); + } + + Ok(()) + } + + async fn trace_endpoint_handler( + config: Arc, + req: Request, + trace_processor: Arc, + trace_tx: Sender, + stats_processor: Arc, + stats_tx: Sender, + tags_provider: Arc, + ) -> http::Result> { + match (req.method(), req.uri().path()) { + (&Method::PUT | &Method::POST, V4_TRACE_ENDPOINT_PATH) => { + match trace_processor + .process_traces(config, req, trace_tx, tags_provider, ApiVersion::V04) + .await + { + Ok(result) => Ok(result), + Err(err) => log_and_create_http_response( + &format!("Error processing traces: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ), + } + } + (&Method::PUT | &Method::POST, V5_TRACE_ENDPOINT_PATH) => { + match trace_processor + .process_traces(config, req, trace_tx, tags_provider, ApiVersion::V05) + .await + { + Ok(result) => Ok(result), + Err(err) => log_and_create_http_response( + &format!("Error processing traces: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ), + } + } + (&Method::PUT | &Method::POST, STATS_ENDPOINT_PATH) => { + match stats_processor.process_stats(req, stats_tx).await { + Ok(result) => Ok(result), + Err(err) => log_and_create_http_response( + &format!("Error processing trace stats: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ), + } + } + (_, INFO_ENDPOINT_PATH) => match Self::info_handler() { + Ok(result) => Ok(result), + Err(err) => log_and_create_http_response( + &format!("Info endpoint error: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ), + }, + _ => { + let mut not_found = Response::default(); + *not_found.status_mut() = StatusCode::NOT_FOUND; + Ok(not_found) + } + } + } + + fn info_handler() -> http::Result> { + let response_json = json!( + { + "endpoints": [ + V4_TRACE_ENDPOINT_PATH, + STATS_ENDPOINT_PATH, + INFO_ENDPOINT_PATH + ], + "client_drop_p0s": true, + } + ); + Response::builder() + .status(200) + .body(Body::from(response_json.to_string())) + } +} diff --git a/bottlecap/src/traces/trace_flusher.rs b/bottlecap/src/traces/trace_flusher.rs new file mode 100644 index 000000000..aec839e8b --- /dev/null +++ b/bottlecap/src/traces/trace_flusher.rs @@ -0,0 +1,64 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use std::sync::Arc; +use tokio::sync::{mpsc::Receiver, Mutex}; +use tracing::{debug, error}; + +use datadog_trace_utils::trace_utils::{self, SendData}; + +#[async_trait] +pub trait TraceFlusher { + /// Starts a trace flusher that listens for trace payloads sent to the tokio mpsc Receiver, + /// implementing flushing logic that calls flush_traces. + async fn start_trace_flusher(&self, mut rx: Receiver); + /// Flushes traces to the Datadog trace intake. + async fn flush_traces(&self, traces: Vec); + + async fn manual_flush(&self); +} + +#[derive(Clone)] +#[allow(clippy::module_name_repetitions)] +pub struct ServerlessTraceFlusher { + pub buffer: Arc>>, +} + +#[async_trait] +impl TraceFlusher for ServerlessTraceFlusher { + async fn start_trace_flusher(&self, mut rx: Receiver) { + let buffer_producer = self.buffer.clone(); + tokio::spawn(async move { + while let Some(tracer_payload) = rx.recv().await { + let mut buffer = buffer_producer.lock().await; + buffer.push(tracer_payload); + } + }); + } + + async fn manual_flush(&self) { + let mut buffer = self.buffer.lock().await; + if !buffer.is_empty() { + self.flush_traces(buffer.to_vec()).await; + buffer.clear(); + } + } + + async fn flush_traces(&self, traces: Vec) { + if traces.is_empty() { + return; + } + debug!("Flushing {} traces", traces.len()); + + for traces in trace_utils::coalesce_send_data(traces) { + match traces.send().await.last_result { + Ok(_) => debug!("Successfully flushed traces"), + Err(e) => { + error!("Error sending trace: {e:?}"); + // TODO: Retries + } + } + } + } +} diff --git a/bottlecap/src/traces/trace_processor.rs b/bottlecap/src/traces/trace_processor.rs new file mode 100644 index 000000000..3a2a20cf3 --- /dev/null +++ b/bottlecap/src/traces/trace_processor.rs @@ -0,0 +1,324 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::tags::provider; +use datadog_trace_obfuscation::obfuscation_config; +use datadog_trace_utils::config_utils::trace_intake_url; +use datadog_trace_utils::tracer_payload::TraceEncoding; +use ddcommon::Endpoint; +use std::str::FromStr; +use std::sync::Arc; + +use async_trait::async_trait; +use hyper::{http, Body, Request, Response, StatusCode}; +use tokio::sync::mpsc::Sender; +use tracing::debug; + +use crate::config; +use datadog_trace_mini_agent::http_utils::{self, log_and_create_http_response}; +use datadog_trace_obfuscation::obfuscate::obfuscate_span; +use datadog_trace_utils::trace_utils::SendData; +use datadog_trace_utils::trace_utils::{self}; + +use super::trace_agent::{ApiVersion, MAX_CONTENT_LENGTH}; + +#[async_trait] +pub trait TraceProcessor { + /// Deserializes traces from a hyper request body and sends them through the provided tokio mpsc + /// Sender. + async fn process_traces( + &self, + config: Arc, + req: Request, + tx: Sender, + tags_provider: Arc, + version: ApiVersion, + ) -> http::Result>; +} +#[derive(Clone)] +#[allow(clippy::module_name_repetitions)] +pub struct ServerlessTraceProcessor { + pub obfuscation_config: Arc, +} + +#[async_trait] +impl TraceProcessor for ServerlessTraceProcessor { + async fn process_traces( + &self, + config: Arc, + req: Request, + tx: Sender, + tags_provider: Arc, + version: ApiVersion, + ) -> http::Result> { + debug!("Recieved traces to process"); + let (parts, body) = req.into_parts(); + + if let Some(response) = http_utils::verify_request_content_length( + &parts.headers, + MAX_CONTENT_LENGTH, + "Error processing traces", + ) { + return response; + } + + let tracer_header_tags = (&parts.headers).into(); + + // deserialize traces from the request body, convert to protobuf structs (see trace-protobuf + // crate) + let (body_size, traces) = match version { + ApiVersion::V04 => match trace_utils::get_traces_from_request_body(body).await { + Ok(result) => result, + Err(err) => { + return log_and_create_http_response( + &format!("Error deserializing trace from request body: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + }, + ApiVersion::V05 => match trace_utils::get_v05_traces_from_request_body(body).await { + Ok(result) => result, + Err(err) => { + return log_and_create_http_response( + &format!("Error deserializing trace from request body: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + }, + }; + + let payload = trace_utils::collect_trace_chunks( + traces, + &tracer_header_tags, + |chunk, _root_span_index| { + chunk.spans.retain(|span| { + (span.resource != "127.0.0.1" || span.resource != "0.0.0.0") + && span.name != "dns.lookup" + }); + for span in &mut chunk.spans { + tags_provider.get_tags_map().iter().for_each(|(k, v)| { + span.meta.insert(k.clone(), v.clone()); + }); + // TODO(astuyve) generalize this and delegate to an enum + span.meta.insert("origin".to_string(), "lambda".to_string()); + span.meta + .insert("_dd.origin".to_string(), "lambda".to_string()); + obfuscate_span(span, &self.obfuscation_config); + } + }, + true, + TraceEncoding::V07, + ); + let intake_url = trace_intake_url(&config.site); + let endpoint = Endpoint { + url: hyper::Uri::from_str(&intake_url).expect("can't parse trace intake URL, exiting"), + api_key: Some(config.api_key.clone().into()), + }; + + let send_data = SendData::new(body_size, payload, tracer_header_tags, &endpoint); + + // send trace payload to our trace flusher + match tx.send(send_data).await { + Ok(()) => { + return log_and_create_http_response( + "Successfully buffered traces to be flushed.", + StatusCode::ACCEPTED, + ); + } + Err(err) => { + return log_and_create_http_response( + &format!("Error sending traces to the trace flusher: {err}"), + StatusCode::INTERNAL_SERVER_ERROR, + ); + } + } + } +} + +#[cfg(test)] +mod tests { + use datadog_trace_obfuscation::obfuscation_config::ObfuscationConfig; + use hyper::Request; + use serde_json::json; + use std::{ + collections::HashMap, + sync::Arc, + time::{SystemTime, UNIX_EPOCH}, + }; + use tokio::sync::mpsc::{self, Receiver, Sender}; + + use crate::config::Config; + use crate::tags::provider::Provider; + use crate::traces::trace_processor::{self, TraceProcessor}; + use crate::LAMBDA_RUNTIME_SLUG; + use datadog_trace_protobuf::pb; + use datadog_trace_utils::{trace_utils, tracer_payload::TracerPayloadCollection}; + + fn get_current_timestamp_nanos() -> i64 { + i64::try_from( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(), + ) + .expect("can't parse time") + } + + fn create_test_config() -> Arc { + Arc::new(Config { + service: Some("test-service".to_string()), + tags: Some("test:tag,env:test".to_string()), + ..Config::default() + }) + } + + fn create_tags_provider(config: Arc) -> Arc { + let mut metadata = HashMap::new(); + metadata.insert( + "function_arn".to_string(), + "arn:aws:lambda:us-west-2:123456789012:function:my-function".to_string(), + ); + let provider = Provider::new(config, LAMBDA_RUNTIME_SLUG.to_string(), &metadata); + Arc::new(provider) + } + fn create_test_span( + trace_id: u64, + span_id: u64, + parent_id: u64, + start: i64, + is_top_level: bool, + tags_provider: Arc, + ) -> pb::Span { + let mut meta: HashMap = tags_provider.get_tags_map().clone(); + meta.insert( + "runtime-id".to_string(), + "test-runtime-id-value".to_string(), + ); + + let mut span = pb::Span { + trace_id, + span_id, + service: "test-service".to_string(), + name: "test_name".to_string(), + resource: "test-resource".to_string(), + parent_id, + start, + duration: 5, + error: 0, + meta: meta.clone(), + metrics: HashMap::new(), + r#type: String::new(), + meta_struct: HashMap::new(), + span_links: vec![], + }; + if is_top_level { + span.metrics.insert("_top_level".to_string(), 1.0); + span.meta + .insert("_dd.origin".to_string(), "lambda".to_string()); + span.meta.insert("origin".to_string(), "lambda".to_string()); + span.meta + .insert("functionname".to_string(), "my-function".to_string()); + span.r#type = String::new(); + } + span + } + + fn create_test_json_span( + trace_id: u64, + span_id: u64, + parent_id: u64, + start: i64, + ) -> serde_json::Value { + json!( + { + "trace_id": trace_id, + "span_id": span_id, + "service": "test-service", + "name": "test_name", + "resource": "test-resource", + "parent_id": parent_id, + "start": start, + "duration": 5, + "error": 0, + "meta": { + "service": "test-service", + "env": "test-env", + "runtime-id": "test-runtime-id-value", + }, + "metrics": {}, + "meta_struct": {}, + } + ) + } + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_process_trace() { + let (tx, mut rx): ( + Sender, + Receiver, + ) = mpsc::channel(1); + + let start = get_current_timestamp_nanos(); + + let json_span = create_test_json_span(11, 222, 333, start); + + let bytes = rmp_serde::to_vec(&vec![vec![json_span]]).unwrap(); + let request = Request::builder() + .header("datadog-meta-tracer-version", "4.0.0") + .header("datadog-meta-lang", "nodejs") + .header("datadog-meta-lang-version", "v19.7.0") + .header("datadog-meta-lang-interpreter", "v8") + .header("datadog-container-id", "33") + .header("content-length", "100") + .body(hyper::body::Body::from(bytes)) + .unwrap(); + + let trace_processor = trace_processor::ServerlessTraceProcessor { + obfuscation_config: Arc::new(ObfuscationConfig::new().unwrap()), + }; + let config = create_test_config(); + let tags_provider = create_tags_provider(config.clone()); + let res = trace_processor + .process_traces( + config, + request, + tx, + tags_provider.clone(), + crate::traces::trace_agent::ApiVersion::V04, + ) + .await; + assert!(res.is_ok()); + + let tracer_payload = rx.recv().await; + + assert!(tracer_payload.is_some()); + + let expected_tracer_payload = pb::TracerPayload { + container_id: "33".to_string(), + language_name: "nodejs".to_string(), + language_version: "v19.7.0".to_string(), + tracer_version: "4.0.0".to_string(), + runtime_id: "test-runtime-id-value".to_string(), + chunks: vec![pb::TraceChunk { + priority: i32::from(i8::MIN), + origin: String::new(), + spans: vec![create_test_span(11, 222, 333, start, true, tags_provider)], + tags: HashMap::new(), + dropped_trace: false, + }], + tags: HashMap::new(), + env: "test-env".to_string(), + hostname: String::new(), + app_version: String::new(), + }; + + let received_payload = + if let TracerPayloadCollection::V07(payload) = tracer_payload.unwrap().get_payloads() { + Some(payload[0].clone()) + } else { + None + }; + + assert_eq!(expected_tracer_payload, received_payload.unwrap()); + } +}