diff --git a/instrumentation/aws/Cargo.lock b/instrumentation/aws/Cargo.lock new file mode 100644 index 00000000..7685209e --- /dev/null +++ b/instrumentation/aws/Cargo.lock @@ -0,0 +1,3086 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arc-swap" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6" +dependencies = [ + "rustversion", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-credential-types" +version = "1.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-lc-rs" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "aws-runtime" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc0651c57e384202e47153c1260b84a9936e19803d747615edf199dc3b98d17" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "bytes-utils", + "fastrand", + "http 1.4.0", + "http-body 1.0.1", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-eventbridge" +version = "1.104.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfae3beab373916ae2ab94d0549304677475534d77fb6891ae57944db353113" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sns" +version = "1.98.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa03e65dbad2dd07b57bcd44f48dbd65283b71ee33ea7e6efe8dcc26b82e98e" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sqs" +version = "1.97.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d497fb382b906b04167e62848ad00e56c5ad523791a461d5a5611c186531d81" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b660013a6683ab23797778e21f1f854744fdf05f68204b4cca4c8c04b5d1f4" +dependencies = [ + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "p256", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-http" +version = "0.63.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.13", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.9.0", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.37", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower 0.5.3", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.62.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9648b0bb82a2eedd844052c6ad2a1a822d1f8e3adee5fbf668366717e428856a" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-observability" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" +dependencies = [ + "aws-smithy-runtime-api", +] + +[[package]] +name = "aws-smithy-query" +version = "0.60.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028999056d2d2fd58a697232f9eec4a643cf73a71cf327690a7edad1d2af2110" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876ab3c9c29791ba4ba02b780a3049e21ec63dabda09268b175272c3733a79e6" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8323699dd9b3c8d5b3c13051ae9cdef58fd179957c882f8374dd8725962d9" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[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.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "datadog-aws" +version = "0.3.1" +dependencies = [ + "aws-credential-types", + "aws-sdk-eventbridge", + "aws-sdk-sns", + "aws-sdk-sqs", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http-body-util", + "hyper 1.9.0", + "hyper-util", + "opentelemetry", + "opentelemetry_sdk", + "serde_json", + "serial_test", + "tokio", + "tracing", +] + +[[package]] +name = "datadog-aws-lambda" +version = "0.3.1" +dependencies = [ + "base64 0.22.1", + "datadog-opentelemetry", + "lambda_runtime", + "opentelemetry", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "serde", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "datadog-opentelemetry" +version = "0.3.2" +dependencies = [ + "anyhow", + "arc-swap", + "base64 0.21.7", + "foldhash 0.1.5", + "hashbrown 0.15.5", + "http-body-util", + "hyper 1.9.0", + "hyper-util", + "libdd-common", + "libdd-data-pipeline", + "libdd-telemetry", + "libdd-tinybytes", + "libdd-trace-utils", + "lru", + "opentelemetry", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "rand 0.8.5", + "rustc_version_runtime", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "uuid", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint 0.4.9", + "der", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[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 = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.0", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +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 = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "http-serde" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" +dependencies = [ + "http 1.4.0", + "serde", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.4.0", + "hyper 1.9.0", + "hyper-util", + "rustls 0.23.37", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.9.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.3", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lambda_runtime" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed49669d6430292aead991e19bf13153135a884f916e68f32997c951af637ebe" +dependencies = [ + "async-stream", + "base64 0.22.1", + "bytes", + "futures", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "http-serde", + "hyper 1.9.0", + "hyper-util", + "lambda_runtime_api_client", + "pin-project", + "serde", + "serde_json", + "serde_path_to_error", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tracing", +] + +[[package]] +name = "lambda_runtime_api_client" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c90a10f094475a34a04da2be11686c4dcfe214d93413162db9ffdff3d3af293a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.9.0", + "hyper-util", + "tokio", + "tower 0.4.13", + "tower-service", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lazy_static" +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 = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "libdd-common" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c779949577250487179d904508f18750070e9a01eb58dce378409ec5fa066f3b" +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.9.0", + "hyper-util", + "libc", + "nix", + "pin-project", + "regex", + "serde", + "static_assertions", + "thiserror 1.0.69", + "tokio", + "tower-service", + "windows-sys 0.52.0", +] + +[[package]] +name = "libdd-data-pipeline" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358411451d99011f13c7628acee25dc144f2bbeade87acf10fa7d5ffce1053dc" +dependencies = [ + "anyhow", + "arc-swap", + "bytes", + "either", + "http 1.4.0", + "http-body-util", + "libdd-common", + "libdd-ddsketch", + "libdd-dogstatsd-client", + "libdd-telemetry", + "libdd-tinybytes", + "libdd-trace-protobuf", + "libdd-trace-stats", + "libdd-trace-utils", + "rmp-serde", + "serde", + "serde_json", + "sha2", + "tokio", + "tokio-util", + "tracing", + "uuid", +] + +[[package]] +name = "libdd-ddsketch" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b31b2435e2e8eaba0e35a96df3e1407b68f8ef76055383ceb2ba5a09e5a1bb5" +dependencies = [ + "prost", +] + +[[package]] +name = "libdd-dogstatsd-client" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f8eca39d1e2ef6267cf77fc51eb7ebc7d4f44827e150b4d317c29d8c33bf87" +dependencies = [ + "anyhow", + "cadence", + "http 1.4.0", + "libdd-common", + "serde", + "tracing", +] + +[[package]] +name = "libdd-telemetry" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78774ffce79da677602829d7fe27468283e5349010e974257233edf4cd12b783" +dependencies = [ + "anyhow", + "base64 0.22.1", + "futures", + "hashbrown 0.15.5", + "http 1.4.0", + "http-body-util", + "libc", + "libdd-common", + "libdd-ddsketch", + "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-trace-normalization" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e095f3589d02ceed76556e7aa8a1b5bc928a900e143b624e2331294e54b5" +dependencies = [ + "anyhow", + "libdd-trace-protobuf", +] + +[[package]] +name = "libdd-trace-protobuf" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1809242895edc53ac51a21287829f42474e749dbc222ea7f414cb3f0d1f91d4e" +dependencies = [ + "prost", + "serde", + "serde_bytes", +] + +[[package]] +name = "libdd-trace-stats" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92b882863f7c531d51e73f7bc5930c705e47829332128d9bdcad0fea3b2b942" +dependencies = [ + "hashbrown 0.15.5", + "libdd-ddsketch", + "libdd-trace-protobuf", + "libdd-trace-utils", +] + +[[package]] +name = "libdd-trace-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870506e9bb79c93ce5bbfe9d715c53c7ea393a177c7299f0bf43745c0adea0c7" +dependencies = [ + "anyhow", + "bytes", + "futures", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "indexmap", + "libdd-common", + "libdd-tinybytes", + "libdd-trace-normalization", + "libdd-trace-protobuf", + "prost", + "rand 0.8.5", + "rmp", + "rmp-serde", + "rmpv", + "serde", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[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 = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", +] + +[[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.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.2", + "thiserror 2.0.18", + "tokio", + "tokio-stream", +] + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "rmpv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4e1d4b9b938a26d2996af33229f0ca0956c652c1375067f0b45291c1df8417" +dependencies = [ + "rmp", +] + +[[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 = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.10", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serial_test" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[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.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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 = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tokio" +version = "1.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2 0.6.3", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.37", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[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", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +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", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[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.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", + "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", + "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", + "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 = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/instrumentation/aws/datadog-aws/Cargo.lock b/instrumentation/aws/datadog-aws/Cargo.lock index 884bf332..b9356789 100644 --- a/instrumentation/aws/datadog-aws/Cargo.lock +++ b/instrumentation/aws/datadog-aws/Cargo.lock @@ -484,7 +484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -495,7 +495,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -513,13 +513,22 @@ dependencies = [ name = "datadog-aws-sdk" version = "0.3.1" dependencies = [ + "aws-credential-types", "aws-sdk-eventbridge", "aws-sdk-sns", "aws-sdk-sqs", "aws-smithy-runtime-api", "aws-smithy-types", + "aws-types", + "bytes", + "http-body-util", + "hyper 1.8.1", + "hyper-util", "opentelemetry", + "opentelemetry_sdk", "serde_json", + "serial_test", + "tokio", "tracing", ] @@ -591,7 +600,7 @@ dependencies = [ "generic-array", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -615,7 +624,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -661,6 +670,28 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.32" @@ -680,8 +711,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", + "futures-macro", + "futures-sink", "futures-task", "pin-project-lite", + "slab", ] [[package]] @@ -724,7 +758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -892,6 +926,7 @@ dependencies = [ "http 1.4.0", "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -1003,6 +1038,15 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -1073,6 +1117,24 @@ dependencies = [ "js-sys", "pin-project-lite", "thiserror", + "tracing", +] + +[[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", + "percent-encoding", + "rand", + "thiserror", + "tokio", + "tokio-stream", ] [[package]] @@ -1092,6 +1154,29 @@ dependencies = [ "sha2", ] +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -1126,6 +1211,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -1150,6 +1244,26 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1159,6 +1273,24 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + [[package]] name = "regex-lite" version = "0.1.9" @@ -1280,6 +1412,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.29" @@ -1289,6 +1430,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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" @@ -1299,6 +1446,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + [[package]] name = "sec1" version = "0.3.0" @@ -1385,6 +1538,32 @@ dependencies = [ "zmij", ] +[[package]] +name = "serial_test" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1409,7 +1588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1532,9 +1711,21 @@ dependencies = [ "mio", "pin-project-lite", "socket2 0.6.3", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -1555,6 +1746,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -1842,6 +2044,26 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zeroize" version = "1.8.2" diff --git a/instrumentation/aws/datadog-aws/Cargo.toml b/instrumentation/aws/datadog-aws/Cargo.toml index 664f936d..3293fc0b 100644 --- a/instrumentation/aws/datadog-aws/Cargo.toml +++ b/instrumentation/aws/datadog-aws/Cargo.toml @@ -18,8 +18,17 @@ aws-sdk-sns = "1.96" aws-sdk-sqs = "1.93" aws-smithy-runtime-api = { version = "1.11", features = ["client"] } aws-smithy-types = "1.4" +aws-types = "1.3" serde_json = { workspace = true } opentelemetry = { workspace = true } tracing = { workspace = true } [dev-dependencies] +aws-credential-types = { version = "1", features = ["test-util"] } +bytes = "1" +http-body-util = "0.1" +hyper = { version = "1", features = ["server", "http1"] } +hyper-util = { version = "0.1", features = ["tokio", "server"] } +opentelemetry_sdk = { workspace = true, features = ["trace", "testing"] } +serial_test = "3" +tokio = { workspace = true, features = ["rt", "macros", "net", "io-util"] } diff --git a/instrumentation/aws/datadog-aws/src/attribute_keys.rs b/instrumentation/aws/datadog-aws/src/attribute_keys.rs new file mode 100644 index 00000000..3efd3750 --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/attribute_keys.rs @@ -0,0 +1,46 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +// Trace propagation payload keys. +pub(crate) const DATADOG_ATTRIBUTE_KEY: &str = "_datadog"; +pub(crate) const START_TIME_KEY: &str = "x-datadog-start-time"; +pub(crate) const DATADOG_RESOURCE_NAME_KEY: &str = "x-datadog-resource-name"; + +// AWS partition identifiers. +pub(crate) const PARTITION_AWS: &str = "aws"; +pub(crate) const PARTITION_AWS_CN: &str = "aws-cn"; +pub(crate) const PARTITION_AWS_GOV: &str = "aws-us-gov"; +pub(crate) const PARTITION_AWS_ISO: &str = "aws-iso"; +pub(crate) const PARTITION_AWS_ISO_B: &str = "aws-iso-b"; +pub(crate) const PARTITION_AWS_ISO_E: &str = "aws-iso-e"; +pub(crate) const PARTITION_AWS_ISO_F: &str = "aws-iso-f"; + +// OTel tracer name. +pub(crate) const TRACER_NAME: &str = "datadog-aws-sdk"; + +// Generic aws.sdk span attributes. +pub(crate) const OPERATION_NAME: &str = "operation.name"; +pub(crate) const AWS_SERVICE: &str = "aws.service"; +pub(crate) const AWS_OPERATION: &str = "aws.operation"; +pub(crate) const AWS_REGION: &str = "aws.region"; +pub(crate) const AWS_PARTITION: &str = "aws.partition"; +pub(crate) const AWS_AGENT: &str = "aws.agent"; +pub(crate) const AWS_REQUEST_ID: &str = "aws.request_id"; +pub(crate) const HTTP_METHOD: &str = "http.method"; +pub(crate) const HTTP_URL: &str = "http.url"; +pub(crate) const HTTP_STATUS_CODE: &str = "http.status_code"; +pub(crate) const COMPONENT: &str = "component"; +pub(crate) const SPAN_KIND: &str = "span.kind"; +pub(crate) const RESOURCE_NAME: &str = "resource.name"; + +// SQS aws.sdk span attributes. +pub(crate) const CLOUD_RESOURCE_ID: &str = "cloud.resource_id"; +pub(crate) const QUEUE_NAME: &str = "queuename"; +pub(crate) const MESSAGING_SYSTEM: &str = "messaging.system"; + +// SNS aws.sdk span attributes. +pub(crate) const TOPIC_NAME: &str = "topicname"; +pub(crate) const TARGET_NAME: &str = "targetname"; + +// EventBridge aws.sdk span attributes. +pub(crate) const RULE_NAME: &str = "rulename"; diff --git a/instrumentation/aws/datadog-aws/src/interceptor.rs b/instrumentation/aws/datadog-aws/src/interceptor.rs new file mode 100644 index 00000000..637b85eb --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/interceptor.rs @@ -0,0 +1,280 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt; + +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::{ + BeforeDeserializationInterceptorContextRef, BeforeSerializationInterceptorContextMut, + BeforeTransmitInterceptorContextRef, FinalizerInterceptorContextRef, +}; +use aws_smithy_runtime_api::client::interceptors::Intercept; +use aws_smithy_runtime_api::client::orchestrator::Metadata; +use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; +use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace}; +use aws_types::region::Region; +use opentelemetry::trace::{SpanKind, Status, TraceContextExt, Tracer}; +use opentelemetry::{global, Context, KeyValue}; + +use crate::attribute_keys::{ + AWS_AGENT, AWS_REQUEST_ID, HTTP_METHOD, HTTP_STATUS_CODE, HTTP_URL, PARTITION_AWS, + PARTITION_AWS_CN, PARTITION_AWS_GOV, PARTITION_AWS_ISO, PARTITION_AWS_ISO_B, + PARTITION_AWS_ISO_E, PARTITION_AWS_ISO_F, TRACER_NAME, +}; +use crate::services::{base_tags, AwsService}; + +/// AWS SDK interceptor that injects Datadog trace context into messaging payloads +/// and creates spans representing managed service operations. +/// +/// # Example +/// +/// ```rust,ignore +/// use datadog_aws_sdk::AwsInterceptor; +/// +/// let sqs_config = aws_sdk_sqs::config::Builder::from(&sdk_config) +/// .interceptor(AwsInterceptor::new()) +/// .build(); +/// let sqs_client = aws_sdk_sqs::Client::from_conf(sqs_config); +/// ``` +#[derive(Debug, Clone)] +pub struct AwsInterceptor {} + +impl AwsInterceptor { + /// Creates a new [`AwsInterceptor`]. + pub fn new() -> Self { + Self {} + } +} + +impl Default for AwsInterceptor { + fn default() -> Self { + Self::new() + } +} + +// Stores the OTel Context (which owns the active span) in ConfigBag so it can +// be accessed across interceptor hooks for the same request. +struct SpanContext(Context); + +impl fmt::Debug for SpanContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SpanContext").finish_non_exhaustive() + } +} + +impl Storable for SpanContext { + type Storer = StoreReplace; +} + +struct PropagatorCarrier(std::collections::HashMap); + +impl opentelemetry::propagation::Injector for PropagatorCarrier { + fn set(&mut self, key: &str, value: String) { + self.0.insert(key.to_string(), value); + } +} + +fn extract_trace_headers(cx: &Context) -> std::collections::HashMap { + global::get_text_map_propagator(|p| { + let mut carrier = PropagatorCarrier(std::collections::HashMap::new()); + p.inject_context(cx, &mut carrier); + carrier.0 + }) +} + +fn set_response_tags( + span: &opentelemetry::trace::SpanRef<'_>, + response: &aws_smithy_runtime_api::http::Response, +) { + span.set_attribute(KeyValue::new( + HTTP_STATUS_CODE, + response.status().as_u16() as i64, + )); + if let Some(request_id) = response.headers().get("x-amzn-requestid") { + span.set_attribute(KeyValue::new(AWS_REQUEST_ID, request_id.to_owned())); + } +} + +// The AWS SDK for Rust does not expose partition publicly, so we derive it from the region prefix. +// Longest-prefix-first: us-isof- and us-isob- must be checked before the shorter us-iso- prefix. +fn partition_from_region(region: &str) -> &'static str { + if region.starts_with("cn-") { + PARTITION_AWS_CN + } else if region.starts_with("us-gov-") { + PARTITION_AWS_GOV + } else if region.starts_with("us-isof-") { + PARTITION_AWS_ISO_F + } else if region.starts_with("us-isob-") { + PARTITION_AWS_ISO_B + } else if region.starts_with("us-iso-") { + PARTITION_AWS_ISO + } else if region.starts_with("eu-isoe-") { + PARTITION_AWS_ISO_E + } else { + PARTITION_AWS + } +} + +impl Intercept for AwsInterceptor { + fn name(&self) -> &'static str { + "AwsInterceptor" + } + + fn modify_before_serialization( + &self, + context: &mut BeforeSerializationInterceptorContextMut<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let Some(metadata) = cfg.load::() else { + return Ok(()); + }; + let service = metadata.service(); + let operation = metadata.name(); + let region = cfg + .load::() + .map(|r| r.as_ref()) + .unwrap_or_default(); + let partition = partition_from_region(region); + + // Resolve the service handler; skip span creation for unsupported services. + let Some(handler) = AwsService::from_sdk_service(service) else { + return Ok(()); + }; + let service_id = handler.span_service_id(); + let sdk_service_name = handler.sdk_service_name(); + let mut tags = base_tags(service_id, sdk_service_name, operation, region, partition); + tags.extend(handler.service_tags(operation, context.input(), region, partition)); + + // Create the span as a child of the current context. This must happen + // before extracting trace headers so the injected context points to + // this span, not the caller's span. + let parent_cx = Context::current(); + let tracer = global::tracer(TRACER_NAME); + let span = tracer + .span_builder(format!("{service_id}.request")) + .with_kind(SpanKind::Client) + .with_attributes(tags) + .start_with_context(&tracer, &parent_cx); + let cx = parent_cx.with_span(span); + + // Extract trace headers from the new span's context so downstream + // services see this span as their parent. + let trace_headers = extract_trace_headers(&cx); + + // Swallow injection errors - trace propagation must never fail the AWS call. + if !trace_headers.is_empty() { + if let Err(err) = handler.inject(operation, &trace_headers, context.input_mut()) { + tracing::debug!( + error = %err, + service = handler.span_service_id(), + operation, + "failed to inject Datadog trace context" + ); + } + } + + cfg.interceptor_state().store_put(SpanContext(cx)); + Ok(()) + } + + fn read_before_transmit( + &self, + context: &BeforeTransmitInterceptorContextRef<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let Some(span_ctx) = cfg.load::() else { + return Ok(()); + }; + let span = span_ctx.0.span(); + let request = context.request(); + span.set_attribute(KeyValue::new(HTTP_METHOD, request.method().to_string())); + span.set_attribute(KeyValue::new(HTTP_URL, request.uri().to_string())); + if let Some(user_agent) = request.headers().get("user-agent") { + span.set_attribute(KeyValue::new(AWS_AGENT, user_agent.to_owned())); + } + Ok(()) + } + + fn read_after_transmit( + &self, + context: &BeforeDeserializationInterceptorContextRef<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let Some(span_ctx) = cfg.load::() else { + return Ok(()); + }; + set_response_tags(&span_ctx.0.span(), context.response()); + Ok(()) + } + + fn read_after_execution( + &self, + context: &FinalizerInterceptorContextRef<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let Some(span_ctx) = cfg.load::() else { + return Ok(()); + }; + let span = span_ctx.0.span(); + + // Re-set response tags to cover cases where read_after_transmit did not run + // (e.g. the request failed before transmission or was retried with a different response). + if let Some(response) = context.response() { + set_response_tags(&span, response); + } + + if let Some(Err(err)) = context.output_or_error() { + span.set_status(Status::error(err.to_string())); + } + + span.end(); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn returns_no_trace_headers_without_active_span() { + let cx = Context::current(); + let headers = extract_trace_headers(&cx); + assert!(headers.is_empty()); + } + + #[test] + fn partition_from_region_standard() { + assert_eq!(partition_from_region("us-east-1"), PARTITION_AWS); + assert_eq!(partition_from_region("eu-west-1"), PARTITION_AWS); + assert_eq!(partition_from_region("ap-southeast-2"), PARTITION_AWS); + } + + #[test] + fn partition_from_region_china() { + assert_eq!(partition_from_region("cn-north-1"), PARTITION_AWS_CN); + assert_eq!(partition_from_region("cn-northwest-1"), PARTITION_AWS_CN); + } + + #[test] + fn partition_from_region_govcloud() { + assert_eq!(partition_from_region("us-gov-east-1"), PARTITION_AWS_GOV); + assert_eq!(partition_from_region("us-gov-west-1"), PARTITION_AWS_GOV); + } + + #[test] + fn partition_from_region_isolated() { + assert_eq!(partition_from_region("us-iso-east-1"), PARTITION_AWS_ISO); + assert_eq!(partition_from_region("us-iso-west-1"), PARTITION_AWS_ISO); + assert_eq!(partition_from_region("us-isob-east-1"), PARTITION_AWS_ISO_B); + assert_eq!( + partition_from_region("us-isof-south-1"), + PARTITION_AWS_ISO_F + ); + assert_eq!(partition_from_region("eu-isoe-west-1"), PARTITION_AWS_ISO_E); + } +} diff --git a/instrumentation/aws/datadog-aws/src/lib.rs b/instrumentation/aws/datadog-aws/src/lib.rs index 5a97e724..80210bc3 100644 --- a/instrumentation/aws/datadog-aws/src/lib.rs +++ b/instrumentation/aws/datadog-aws/src/lib.rs @@ -1,2 +1,24 @@ // Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 + +//! Datadog instrumentation for AWS SDK for Rust. +//! +//! Provides automatic trace context injection for AWS SDK requests, +//! enabling distributed tracing across SQS, SNS, and EventBridge. +//! +//! # Usage +//! +//! ```rust,ignore +//! use datadog_aws::AwsInterceptor; +//! +//! let sqs_config = aws_sdk_sqs::config::Builder::from(&sdk_config) +//! .interceptor(AwsInterceptor::new()) +//! .build(); +//! let sqs_client = aws_sdk_sqs::Client::from_conf(sqs_config); +//! ``` + +mod attribute_keys; +mod interceptor; +mod services; + +pub use interceptor::AwsInterceptor; diff --git a/instrumentation/aws/datadog-aws/src/services/eventbridge.rs b/instrumentation/aws/datadog-aws/src/services/eventbridge.rs new file mode 100644 index 00000000..8517dbf5 --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/services/eventbridge.rs @@ -0,0 +1,247 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; +use std::time::{SystemTime, UNIX_EPOCH}; + +use aws_sdk_eventbridge::operation::delete_rule::DeleteRuleInput; +use aws_sdk_eventbridge::operation::describe_rule::DescribeRuleInput; +use aws_sdk_eventbridge::operation::disable_rule::DisableRuleInput; +use aws_sdk_eventbridge::operation::enable_rule::EnableRuleInput; +use aws_sdk_eventbridge::operation::put_events::PutEventsInput; +use aws_sdk_eventbridge::operation::put_rule::PutRuleInput; +use aws_sdk_eventbridge::operation::put_targets::PutTargetsInput; +use aws_sdk_eventbridge::operation::remove_targets::RemoveTargetsInput; +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::Input; +use opentelemetry::KeyValue; + +use crate::attribute_keys::{ + DATADOG_ATTRIBUTE_KEY, DATADOG_RESOURCE_NAME_KEY, RULE_NAME, START_TIME_KEY, +}; + +use super::ONE_MB; + +#[derive(Debug, Clone, Copy)] +pub(super) enum EventBridgeOperation { + PutEvents, + PutRule, + DescribeRule, + DeleteRule, + EnableRule, + DisableRule, + PutTargets, + RemoveTargets, +} + +impl EventBridgeOperation { + pub(super) fn from_name(operation: &str) -> Option { + match operation { + "PutEvents" => Some(Self::PutEvents), + "PutRule" => Some(Self::PutRule), + "DescribeRule" => Some(Self::DescribeRule), + "DeleteRule" => Some(Self::DeleteRule), + "EnableRule" => Some(Self::EnableRule), + "DisableRule" => Some(Self::DisableRule), + "PutTargets" => Some(Self::PutTargets), + "RemoveTargets" => Some(Self::RemoveTargets), + _ => None, + } + } +} + +// Only PutEvents carries a detail payload that supports trace context injection. +pub(super) fn inject( + operation: EventBridgeOperation, + trace_headers: &HashMap, + input: &mut Input, +) -> Result<(), BoxError> { + if !matches!(operation, EventBridgeOperation::PutEvents) { + return Ok(()); + } + + if let Some(put_input) = input.downcast_mut::() { + inject_into_put_events(put_input, trace_headers)?; + } + Ok(()) +} + +pub(super) fn service_tags(operation: EventBridgeOperation, input: &Input) -> Vec { + match extract_rule_name(operation, input) { + Some(name) => vec![KeyValue::new(RULE_NAME, name.to_owned())], + None => vec![], + } +} + +fn extract_rule_name(operation: EventBridgeOperation, input: &Input) -> Option<&str> { + match operation { + EventBridgeOperation::PutRule => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()), + EventBridgeOperation::DescribeRule => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()), + EventBridgeOperation::DeleteRule => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()), + EventBridgeOperation::EnableRule => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()), + EventBridgeOperation::DisableRule => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()), + EventBridgeOperation::PutTargets => input + .downcast_ref::() + .and_then(|i| i.rule.as_deref()), + EventBridgeOperation::RemoveTargets => input + .downcast_ref::() + .and_then(|i| i.rule.as_deref()), + EventBridgeOperation::PutEvents => None, + } +} + +fn inject_into_put_events( + input: &mut PutEventsInput, + trace_headers: &HashMap, +) -> Result<(), BoxError> { + let Some(entries) = input.entries.as_mut() else { + return Ok(()); + }; + + let start_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() + .to_string(); + + let mut ctx: serde_json::Map = trace_headers + .iter() + .map(|(k, v)| (k.clone(), serde_json::Value::String(v.clone()))) + .collect(); + ctx.insert(START_TIME_KEY.into(), serde_json::Value::String(start_time)); + + for entry in entries.iter_mut() { + let mut entry_ctx = ctx.clone(); + if let Some(name) = entry.event_bus_name.as_deref() { + entry_ctx.insert( + DATADOG_RESOURCE_NAME_KEY.into(), + serde_json::Value::String(name.into()), + ); + } + + let trace_ctx = serde_json::Value::Object(entry_ctx); + + let detail = entry.detail.as_deref().unwrap_or("{}"); + let mut detail_map: serde_json::Map = + match serde_json::from_str(detail) { + Ok(map) => map, + Err(_) => continue, + }; + + detail_map.insert(DATADOG_ATTRIBUTE_KEY.into(), trace_ctx); + + let new_detail = match serde_json::to_string(&detail_map) { + Ok(s) => s, + Err(_) => continue, + }; + + // EventBridge entries have a 1 MB detail size limit. + if new_detail.len() > ONE_MB { + continue; + } + + entry.detail = Some(new_detail); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::services::test_helpers::{ + collect_string_tags, sample_trace_headers, DATADOG_PARENT_ID_KEY, + DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TRACE_ID_KEY, + }; + use aws_sdk_eventbridge::types::PutEventsRequestEntry; + use aws_smithy_runtime_api::client::interceptors::context::Input; + + fn parse_detail_datadog(detail: &str) -> HashMap { + let parsed: serde_json::Value = serde_json::from_str(detail).unwrap(); + let dd = parsed + .get(DATADOG_ATTRIBUTE_KEY) + .unwrap() + .as_object() + .unwrap(); + dd.iter() + .map(|(k, v)| (k.clone(), v.as_str().unwrap().to_string())) + .collect() + } + + #[test] + fn skips_injection_for_invalid_put_events_detail() { + let trace_headers = sample_trace_headers(); + let entry = PutEventsRequestEntry::builder() + .source("my.source") + .detail_type("MyDetailType") + .detail("not json") + .build(); + let mut input = PutEventsInput::builder().entries(entry).build().unwrap(); + + inject_into_put_events(&mut input, &trace_headers).unwrap(); + + let entries = input.entries.as_ref().unwrap(); + assert_eq!(entries[0].detail.as_deref(), Some("not json")); + } + + #[test] + fn skips_injection_when_put_events_detail_would_exceed_size_limit() { + let trace_headers = sample_trace_headers(); + let large_value = "x".repeat(ONE_MB); + let detail = format!("{{\"big\":\"{large_value}\"}}"); + let entry = PutEventsRequestEntry::builder() + .source("my.source") + .detail_type("MyDetailType") + .detail(&detail) + .build(); + let mut input = PutEventsInput::builder().entries(entry).build().unwrap(); + + inject_into_put_events(&mut input, &trace_headers).unwrap(); + + let entries = input.entries.as_ref().unwrap(); + assert_eq!(entries[0].detail.as_deref(), Some(detail.as_str())); + } + + #[test] + fn overwrites_existing_datadog_key_in_put_events_detail() { + let trace_headers = sample_trace_headers(); + let entry = PutEventsRequestEntry::builder() + .source("my.source") + .detail_type("MyDetailType") + .detail(r#"{"_datadog":{"stale":"context"},"existing":"data"}"#) + .build(); + let mut input = PutEventsInput::builder().entries(entry).build().unwrap(); + + inject_into_put_events(&mut input, &trace_headers).unwrap(); + + let entries = input.entries.as_ref().unwrap(); + let detail = entries[0].detail.as_ref().unwrap(); + let dd = parse_detail_datadog(detail); + assert_eq!(dd[DATADOG_TRACE_ID_KEY], "123456789"); + assert!(!dd.contains_key("stale")); + let parsed: serde_json::Value = serde_json::from_str(detail).unwrap(); + assert_eq!(parsed["existing"], "data"); + } + + #[test] + fn service_tags_for_put_events_returns_empty() { + let input = Input::erase(PutEventsInput::builder().build().unwrap()); + + let tags = collect_string_tags(service_tags(EventBridgeOperation::PutEvents, &input)); + assert!(!tags.contains_key(RULE_NAME)); + } + + #[test] + fn unsupported_eventbridge_operation_returns_none() { + assert!(EventBridgeOperation::from_name("ListRules").is_none()); + } +} diff --git a/instrumentation/aws/datadog-aws/src/services/mod.rs b/instrumentation/aws/datadog-aws/src/services/mod.rs new file mode 100644 index 00000000..839c294e --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/services/mod.rs @@ -0,0 +1,154 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +mod eventbridge; +mod sns; +mod sqs; + +use std::collections::HashMap; + +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::Input; +use opentelemetry::KeyValue; + +use crate::attribute_keys::{ + AWS_OPERATION, AWS_PARTITION, AWS_REGION, AWS_SERVICE, COMPONENT, OPERATION_NAME, RESOURCE_NAME, + SPAN_KIND, TRACER_NAME, +}; + +// SQS and SNS both cap message attributes at 10. +pub(crate) const MAX_MESSAGE_ATTRIBUTES: usize = 10; +// EventBridge entry detail size limit. +pub(crate) const ONE_MB: usize = 1024 * 1024; + +#[derive(Debug, Clone, Copy)] +pub(crate) enum AwsService { + Sqs, + Sns, + EventBridge, +} + +impl AwsService { + pub(crate) fn from_sdk_service(name: &str) -> Option { + match name { + "SQS" => Some(Self::Sqs), + "SNS" => Some(Self::Sns), + "EventBridge" => Some(Self::EventBridge), + _ => None, + } + } + + pub(crate) fn span_service_id(self) -> &'static str { + match self { + Self::Sqs => "sqs", + Self::Sns => "sns", + Self::EventBridge => "eventbridge", + } + } + + pub(crate) fn sdk_service_name(self) -> &'static str { + match self { + Self::Sqs => "SQS", + Self::Sns => "SNS", + Self::EventBridge => "EventBridge", + } + } + + pub(crate) fn inject( + self, + operation: &str, + trace_headers: &HashMap, + input: &mut Input, + ) -> Result<(), BoxError> { + match self { + Self::Sqs => { + if let Some(op) = sqs::SqsOperation::from_name(operation) { + sqs::inject(op, trace_headers, input)?; + } + Ok(()) + } + Self::Sns => { + if let Some(op) = sns::SnsOperation::from_name(operation) { + sns::inject(op, trace_headers, input)?; + } + Ok(()) + } + Self::EventBridge => { + if let Some(op) = eventbridge::EventBridgeOperation::from_name(operation) { + eventbridge::inject(op, trace_headers, input)?; + } + Ok(()) + } + } + } + + pub(crate) fn service_tags( + self, + operation: &str, + input: &Input, + region: &str, + partition: &str, + ) -> Vec { + match self { + Self::Sqs => sqs::SqsOperation::from_name(operation) + .map(|op| sqs::service_tags(op, input, region, partition)) + .unwrap_or_default(), + Self::Sns => sns::SnsOperation::from_name(operation) + .map(|op| sns::service_tags(op, input)) + .unwrap_or_default(), + Self::EventBridge => eventbridge::EventBridgeOperation::from_name(operation) + .map(|op| eventbridge::service_tags(op, input)) + .unwrap_or_default(), + } + } +} + +/// Base tags common to all AWS service spans. +pub(crate) fn base_tags( + service_id: &'static str, + sdk_service_name: &'static str, + operation: &str, + region: &str, + partition: &str, +) -> Vec { + vec![ + KeyValue::new(OPERATION_NAME, format!("aws.{service_id}.request")), + KeyValue::new(AWS_SERVICE, sdk_service_name), + KeyValue::new(AWS_OPERATION, operation.to_owned()), + KeyValue::new(AWS_REGION, region.to_owned()), + KeyValue::new(AWS_PARTITION, partition.to_owned()), + KeyValue::new(RESOURCE_NAME, format!("{sdk_service_name}.{operation}")), + KeyValue::new(COMPONENT, TRACER_NAME), + KeyValue::new(SPAN_KIND, "client"), + ] +} + +#[cfg(test)] +pub(crate) mod test_helpers { + use std::collections::HashMap; + + use opentelemetry::{KeyValue, Value}; + + pub(crate) const DATADOG_TRACE_ID_KEY: &str = "x-datadog-trace-id"; + pub(crate) const DATADOG_PARENT_ID_KEY: &str = "x-datadog-parent-id"; + pub(crate) const DATADOG_SAMPLING_PRIORITY_KEY: &str = "x-datadog-sampling-priority"; + + pub(crate) fn sample_trace_headers() -> HashMap { + let mut headers = HashMap::new(); + headers.insert(DATADOG_TRACE_ID_KEY.to_string(), "123456789".to_string()); + headers.insert(DATADOG_PARENT_ID_KEY.to_string(), "987654321".to_string()); + headers.insert(DATADOG_SAMPLING_PRIORITY_KEY.to_string(), "1".to_string()); + headers + } + + pub(crate) fn collect_string_tags(tags: Vec) -> HashMap { + tags.into_iter() + .map(|KeyValue { key, value, .. }| { + let Value::String(value) = value else { + panic!("expected string tag value for {}", key.as_str()); + }; + (key.as_str().to_string(), value.to_string()) + }) + .collect() + } +} diff --git a/instrumentation/aws/datadog-aws/src/services/sns.rs b/instrumentation/aws/datadog-aws/src/services/sns.rs new file mode 100644 index 00000000..225ff5cd --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/services/sns.rs @@ -0,0 +1,387 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use aws_sdk_sns::operation::create_topic::CreateTopicInput; +use aws_sdk_sns::operation::get_topic_attributes::GetTopicAttributesInput; +use aws_sdk_sns::operation::list_subscriptions_by_topic::ListSubscriptionsByTopicInput; +use aws_sdk_sns::operation::publish::PublishInput; +use aws_sdk_sns::operation::publish_batch::PublishBatchInput; +use aws_sdk_sns::operation::remove_permission::RemovePermissionInput; +use aws_sdk_sns::operation::set_topic_attributes::SetTopicAttributesInput; +use aws_sdk_sns::operation::subscribe::SubscribeInput; +use aws_sdk_sns::types::MessageAttributeValue; +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::Input; +use aws_smithy_types::Blob; +use opentelemetry::KeyValue; + +use crate::attribute_keys::{DATADOG_ATTRIBUTE_KEY, TARGET_NAME, TOPIC_NAME}; + +use super::MAX_MESSAGE_ATTRIBUTES; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) enum SnsOperation { + Publish, + PublishBatch, + GetTopicAttributes, + ListSubscriptionsByTopic, + RemovePermission, + SetTopicAttributes, + Subscribe, + CreateTopic, +} + +impl SnsOperation { + pub(super) fn from_name(operation: &str) -> Option { + match operation { + "Publish" => Some(Self::Publish), + "PublishBatch" => Some(Self::PublishBatch), + "GetTopicAttributes" => Some(Self::GetTopicAttributes), + "ListSubscriptionsByTopic" => Some(Self::ListSubscriptionsByTopic), + "RemovePermission" => Some(Self::RemovePermission), + "SetTopicAttributes" => Some(Self::SetTopicAttributes), + "Subscribe" => Some(Self::Subscribe), + "CreateTopic" => Some(Self::CreateTopic), + _ => None, + } + } +} + +pub(super) fn inject( + operation: SnsOperation, + trace_headers: &HashMap, + input: &mut Input, +) -> Result<(), BoxError> { + match operation { + SnsOperation::Publish => { + if let Some(publish_input) = input.downcast_mut::() { + inject_into_publish(publish_input, trace_headers)?; + } + } + SnsOperation::PublishBatch => { + if let Some(batch_input) = input.downcast_mut::() { + inject_into_publish_batch(batch_input, trace_headers)?; + } + } + + _ => {} + } + Ok(()) +} + +pub(super) fn service_tags(operation: SnsOperation, input: &Input) -> Vec { + match operation { + SnsOperation::Publish => { + let Some(input) = input.downcast_ref::() else { + return vec![]; + }; + if let Some(arn) = input.topic_arn.as_deref() { + vec![KeyValue::new(TOPIC_NAME, arn_resource_name(arn).to_owned())] + } else if let Some(arn) = input.target_arn.as_deref() { + vec![KeyValue::new( + TARGET_NAME, + arn_resource_name(arn).to_owned(), + )] + } else { + vec![] + } + } + SnsOperation::PublishBatch => topic_arn_tag::(input), + SnsOperation::GetTopicAttributes => topic_arn_tag::(input), + SnsOperation::ListSubscriptionsByTopic => { + topic_arn_tag::(input) + } + SnsOperation::RemovePermission => topic_arn_tag::(input), + SnsOperation::SetTopicAttributes => topic_arn_tag::(input), + SnsOperation::Subscribe => topic_arn_tag::(input), + SnsOperation::CreateTopic => input + .downcast_ref::() + .and_then(|i| i.name.as_deref()) + .map(|name| vec![KeyValue::new(TOPIC_NAME, name.to_owned())]) + .unwrap_or_default(), + } +} + +fn inject_into_publish( + input: &mut PublishInput, + trace_headers: &HashMap, +) -> Result<(), BoxError> { + let attrs = input.message_attributes.get_or_insert_with(HashMap::new); + if should_skip_injection(attrs) { + return Ok(()); + } + attrs.insert( + DATADOG_ATTRIBUTE_KEY.to_string(), + build_datadog_attribute(trace_headers)?, + ); + Ok(()) +} + +fn inject_into_publish_batch( + input: &mut PublishBatchInput, + trace_headers: &HashMap, +) -> Result<(), BoxError> { + let Some(entries) = input.publish_batch_request_entries.as_mut() else { + return Ok(()); + }; + let dd_key = DATADOG_ATTRIBUTE_KEY.to_string(); + let dd_attr = build_datadog_attribute(trace_headers)?; + for entry in entries.iter_mut() { + let attrs = entry.message_attributes.get_or_insert_with(HashMap::new); + if should_skip_injection(attrs) { + continue; + } + attrs.insert(dd_key.clone(), dd_attr.clone()); + } + Ok(()) +} + +// Respect the 10-attribute cap unless replacing an existing _datadog attribute. +fn should_skip_injection(attrs: &HashMap) -> bool { + attrs.len() >= MAX_MESSAGE_ATTRIBUTES && !attrs.contains_key(DATADOG_ATTRIBUTE_KEY) +} + +trait HasTopicArn: std::fmt::Debug + 'static { + fn topic_arn(&self) -> Option<&str>; +} + +macro_rules! impl_has_topic_arn { + ($($ty:ty),+ $(,)?) => { + $(impl HasTopicArn for $ty { + fn topic_arn(&self) -> Option<&str> { self.topic_arn.as_deref() } + })+ + }; +} + +impl_has_topic_arn!( + PublishBatchInput, + GetTopicAttributesInput, + ListSubscriptionsByTopicInput, + RemovePermissionInput, + SetTopicAttributesInput, + SubscribeInput, +); + +// `Input` is type-erased at this layer, so SNS operations that carry a `topic_arn` +// downcast to their concrete input type and all derive the same `topic.name` tag +// from the ARN resource component. +fn topic_arn_tag(input: &Input) -> Vec { + input + .downcast_ref::() + .and_then(|i| i.topic_arn()) + .map(|arn| vec![KeyValue::new(TOPIC_NAME, arn_resource_name(arn).to_owned())]) + .unwrap_or_default() +} + +fn arn_resource_name(arn: &str) -> &str { + arn.rsplit(':').next().unwrap_or(arn) +} + +// SNS trace context is a Binary-typed attribute. String-typed JSON attributes interfere +// with SNS subscription filter policies, which silently drop messages they cannot parse. +fn build_datadog_attribute( + trace_headers: &HashMap, +) -> Result { + let json_bytes = serde_json::to_vec(trace_headers)?; + Ok(MessageAttributeValue::builder() + .data_type("Binary") + .binary_value(Blob::new(json_bytes)) + .build()?) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::services::test_helpers::{ + collect_string_tags, sample_trace_headers, DATADOG_PARENT_ID_KEY, + DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TRACE_ID_KEY, + }; + use aws_sdk_sns::types::PublishBatchRequestEntry; + use aws_smithy_runtime_api::client::interceptors::context::Input; + + fn parse_binary_attr(attr: &MessageAttributeValue) -> HashMap { + assert_eq!(attr.data_type(), "Binary"); + let blob = attr.binary_value().unwrap(); + serde_json::from_slice(blob.as_ref()).unwrap() + } + + #[test] + fn skips_injection_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut builder = PublishInput::builder() + .topic_arn("arn:aws:sns:us-east-1:123456789012:test-topic") + .message("test message"); + for i in 0..10 { + let attr = MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{i}")) + .build() + .unwrap(); + builder = builder.message_attributes(format!("attr{i}"), attr); + } + let mut input = builder.build().unwrap(); + + inject_into_publish(&mut input, &trace_headers).unwrap(); + + let attrs = input.message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + assert!(!attrs.contains_key(DATADOG_ATTRIBUTE_KEY)); + } + + #[test] + fn overwrites_existing_datadog_attribute_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut builder = PublishInput::builder() + .topic_arn("arn:aws:sns:us-east-1:123456789012:test-topic") + .message("test message"); + for i in 0..9 { + let attr = MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{i}")) + .build() + .unwrap(); + builder = builder.message_attributes(format!("attr{i}"), attr); + } + let stale = MessageAttributeValue::builder() + .data_type("Binary") + .binary_value(Blob::new(b"old".to_vec())) + .build() + .unwrap(); + builder = builder.message_attributes(DATADOG_ATTRIBUTE_KEY, stale); + let mut input = builder.build().unwrap(); + + inject_into_publish(&mut input, &trace_headers).unwrap(); + + let attrs = input.message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + let parsed = parse_binary_attr(&attrs[DATADOG_ATTRIBUTE_KEY]); + assert_eq!(parsed[DATADOG_TRACE_ID_KEY], "123456789"); + assert_eq!(parsed[DATADOG_PARENT_ID_KEY], "987654321"); + assert_eq!(parsed[DATADOG_SAMPLING_PRIORITY_KEY], "1"); + } + + #[test] + fn skips_injection_per_batch_entry_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut full_attrs = HashMap::new(); + for i in 0..10 { + full_attrs.insert( + format!("attr{i}"), + MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{i}")) + .build() + .unwrap(), + ); + } + let full_entry = PublishBatchRequestEntry::builder() + .id("full") + .message("body") + .set_message_attributes(Some(full_attrs)) + .build() + .unwrap(); + let empty_entry = PublishBatchRequestEntry::builder() + .id("empty") + .message("body") + .build() + .unwrap(); + let mut input = PublishBatchInput::builder() + .topic_arn("arn:aws:sns:us-east-1:123456789012:test-topic") + .publish_batch_request_entries(full_entry) + .publish_batch_request_entries(empty_entry) + .build() + .unwrap(); + + inject_into_publish_batch(&mut input, &trace_headers).unwrap(); + + let entries = input.publish_batch_request_entries.as_ref().unwrap(); + let full = &entries[0]; + assert_eq!(full.message_attributes.as_ref().unwrap().len(), 10); + assert!(!full + .message_attributes + .as_ref() + .unwrap() + .contains_key(DATADOG_ATTRIBUTE_KEY)); + + let empty = &entries[1]; + assert!(empty + .message_attributes + .as_ref() + .unwrap() + .contains_key(DATADOG_ATTRIBUTE_KEY)); + } + + #[test] + fn overwrites_existing_datadog_attribute_in_batch_entries_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut full_attrs = HashMap::new(); + for i in 0..9 { + full_attrs.insert( + format!("attr{i}"), + MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{i}")) + .build() + .unwrap(), + ); + } + full_attrs.insert( + DATADOG_ATTRIBUTE_KEY.to_string(), + MessageAttributeValue::builder() + .data_type("Binary") + .binary_value(Blob::new(b"old".to_vec())) + .build() + .unwrap(), + ); + let entry = PublishBatchRequestEntry::builder() + .id("full") + .message("body") + .set_message_attributes(Some(full_attrs)) + .build() + .unwrap(); + let mut input = PublishBatchInput::builder() + .topic_arn("arn:aws:sns:us-east-1:123456789012:test-topic") + .publish_batch_request_entries(entry) + .build() + .unwrap(); + + inject_into_publish_batch(&mut input, &trace_headers).unwrap(); + + let entries = input.publish_batch_request_entries.as_ref().unwrap(); + let attrs = entries[0].message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + let parsed = parse_binary_attr(&attrs[DATADOG_ATTRIBUTE_KEY]); + assert_eq!(parsed[DATADOG_TRACE_ID_KEY], "123456789"); + assert_eq!(parsed[DATADOG_PARENT_ID_KEY], "987654321"); + assert_eq!(parsed[DATADOG_SAMPLING_PRIORITY_KEY], "1"); + } + + #[test] + fn overwrites_existing_datadog_attribute() { + let trace_headers = sample_trace_headers(); + let existing = MessageAttributeValue::builder() + .data_type("Binary") + .binary_value(Blob::new(b"old".to_vec())) + .build() + .unwrap(); + let mut input = PublishInput::builder() + .topic_arn("arn:aws:sns:us-east-1:123456789012:test-topic") + .message("test message") + .message_attributes(DATADOG_ATTRIBUTE_KEY, existing) + .build() + .unwrap(); + + inject_into_publish(&mut input, &trace_headers).unwrap(); + + let attrs = input.message_attributes.as_ref().unwrap(); + let parsed = parse_binary_attr(&attrs[DATADOG_ATTRIBUTE_KEY]); + assert_eq!(parsed[DATADOG_TRACE_ID_KEY], "123456789"); + } + + #[test] + fn unsupported_sns_operation_returns_none() { + assert!(SnsOperation::from_name("Puppy").is_none()); + } +} diff --git a/instrumentation/aws/datadog-aws/src/services/sqs.rs b/instrumentation/aws/datadog-aws/src/services/sqs.rs new file mode 100644 index 00000000..21450b78 --- /dev/null +++ b/instrumentation/aws/datadog-aws/src/services/sqs.rs @@ -0,0 +1,282 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +use aws_sdk_sqs::operation::delete_message::DeleteMessageInput; +use aws_sdk_sqs::operation::delete_message_batch::DeleteMessageBatchInput; +use aws_sdk_sqs::operation::receive_message::ReceiveMessageInput; +use aws_sdk_sqs::operation::send_message::SendMessageInput; +use aws_sdk_sqs::operation::send_message_batch::SendMessageBatchInput; +use aws_sdk_sqs::types::MessageAttributeValue; +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::Input; +use opentelemetry::KeyValue; + +use crate::attribute_keys::{ + CLOUD_RESOURCE_ID, DATADOG_ATTRIBUTE_KEY, MESSAGING_SYSTEM, QUEUE_NAME, +}; + +use super::MAX_MESSAGE_ATTRIBUTES; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) enum SqsOperation { + SendMessage, + SendMessageBatch, + ReceiveMessage, + DeleteMessage, + DeleteMessageBatch, +} + +impl SqsOperation { + pub(super) fn from_name(operation: &str) -> Option { + match operation { + "SendMessage" => Some(Self::SendMessage), + "SendMessageBatch" => Some(Self::SendMessageBatch), + "ReceiveMessage" => Some(Self::ReceiveMessage), + "DeleteMessage" => Some(Self::DeleteMessage), + "DeleteMessageBatch" => Some(Self::DeleteMessageBatch), + _ => None, + } + } +} + +pub(super) fn inject( + operation: SqsOperation, + trace_headers: &HashMap, + input: &mut Input, +) -> Result<(), BoxError> { + match operation { + SqsOperation::SendMessage => { + if let Some(send_input) = input.downcast_mut::() { + inject_into_send_message(send_input, trace_headers)?; + } + } + SqsOperation::SendMessageBatch => { + if let Some(batch_input) = input.downcast_mut::() { + inject_into_send_message_batch(batch_input, trace_headers)?; + } + } + _ => {} + } + Ok(()) +} + +pub(super) fn service_tags( + operation: SqsOperation, + input: &Input, + region: &str, + partition: &str, +) -> Vec { + let mut tags = vec![KeyValue::new(MESSAGING_SYSTEM, "amazonsqs")]; + + let queue_url = match operation { + SqsOperation::SendMessage => input + .downcast_ref::() + .and_then(|r| r.queue_url.as_deref()), + SqsOperation::SendMessageBatch => input + .downcast_ref::() + .and_then(|r| r.queue_url.as_deref()), + SqsOperation::ReceiveMessage => input + .downcast_ref::() + .and_then(|r| r.queue_url.as_deref()), + SqsOperation::DeleteMessage => input + .downcast_ref::() + .and_then(|r| r.queue_url.as_deref()), + SqsOperation::DeleteMessageBatch => input + .downcast_ref::() + .and_then(|r| r.queue_url.as_deref()), + }; + + if let Some((queue_name, cloud_resource_id)) = + queue_url.and_then(|url| extract_sqs_metadata(url, region, partition)) + { + tags.push(KeyValue::new(QUEUE_NAME, queue_name)); + tags.push(KeyValue::new(CLOUD_RESOURCE_ID, cloud_resource_id)); + } + + tags +} + +fn inject_into_send_message( + input: &mut SendMessageInput, + trace_headers: &HashMap, +) -> Result<(), BoxError> { + let attrs = input.message_attributes.get_or_insert_with(HashMap::new); + if should_skip_injection(attrs) { + return Ok(()); + } + attrs.insert( + DATADOG_ATTRIBUTE_KEY.to_string(), + build_datadog_attribute(trace_headers)?, + ); + Ok(()) +} + +fn inject_into_send_message_batch( + input: &mut SendMessageBatchInput, + trace_headers: &HashMap, +) -> Result<(), BoxError> { + let Some(entries) = input.entries.as_mut() else { + return Ok(()); + }; + let dd_key = DATADOG_ATTRIBUTE_KEY.to_string(); + let dd_attr = build_datadog_attribute(trace_headers)?; + for entry in entries.iter_mut() { + let attrs = entry.message_attributes.get_or_insert_with(HashMap::new); + if should_skip_injection(attrs) { + continue; + } + attrs.insert(dd_key.clone(), dd_attr.clone()); + } + Ok(()) +} + +// Respect the 10-attribute cap unless replacing an existing _datadog attribute. +fn should_skip_injection(attrs: &HashMap) -> bool { + attrs.len() >= MAX_MESSAGE_ATTRIBUTES && !attrs.contains_key(DATADOG_ATTRIBUTE_KEY) +} + +/// Returns `(queue_name, cloud_resource_id)` parsed from a SQS queue URL. +fn extract_sqs_metadata( + queue_url: &str, + region: &str, + partition: &str, +) -> Option<(String, String)> { + let queue_url = queue_url.trim_end_matches('/'); + let mut parts = queue_url.rsplitn(3, '/'); + let queue_name = parts.next()?; + let account_id = parts.next()?; + let cloud_resource_id = format!("arn:{partition}:sqs:{region}:{account_id}:{queue_name}"); + Some((queue_name.to_string(), cloud_resource_id)) +} + +fn build_datadog_attribute( + trace_headers: &HashMap, +) -> Result { + let json = serde_json::to_string(trace_headers)?; + Ok(MessageAttributeValue::builder() + .data_type("String") + .string_value(json) + .build()?) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::services::test_helpers::{ + collect_string_tags, sample_trace_headers, DATADOG_PARENT_ID_KEY, + DATADOG_SAMPLING_PRIORITY_KEY, DATADOG_TRACE_ID_KEY, + }; + use aws_sdk_sqs::types::SendMessageBatchRequestEntry; + use aws_smithy_runtime_api::client::interceptors::context::Input; + + #[test] + fn skips_injection_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut builder = SendMessageInput::builder() + .queue_url("https://example.com/test-queue") + .message_body("test body"); + for i in 0..10 { + let attr = MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{}", i)) + .build() + .unwrap(); + builder = builder.message_attributes(format!("attr{}", i), attr); + } + let mut input = builder.build().unwrap(); + + inject_into_send_message(&mut input, &trace_headers).unwrap(); + + let attrs = input.message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + assert!(!attrs.contains_key(DATADOG_ATTRIBUTE_KEY)); + } + + #[test] + fn overwrites_existing_datadog_attribute_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut builder = SendMessageInput::builder() + .queue_url("https://example.com/test-queue") + .message_body("test body"); + for i in 0..9 { + let attr = MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{}", i)) + .build() + .unwrap(); + builder = builder.message_attributes(format!("attr{}", i), attr); + } + let stale = MessageAttributeValue::builder() + .data_type("String") + .string_value("stale") + .build() + .unwrap(); + builder = builder.message_attributes(DATADOG_ATTRIBUTE_KEY, stale); + let mut input = builder.build().unwrap(); + + inject_into_send_message(&mut input, &trace_headers).unwrap(); + + let attrs = input.message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + let dd_attr = &attrs[DATADOG_ATTRIBUTE_KEY]; + let json_str = dd_attr.string_value().unwrap(); + let parsed: HashMap = serde_json::from_str(json_str).unwrap(); + assert_eq!(parsed[DATADOG_TRACE_ID_KEY], "123456789"); + assert_eq!(parsed[DATADOG_PARENT_ID_KEY], "987654321"); + assert_eq!(parsed[DATADOG_SAMPLING_PRIORITY_KEY], "1"); + } + + #[test] + fn overwrites_existing_datadog_attribute_in_batch_entries_when_message_attributes_are_full() { + let trace_headers = sample_trace_headers(); + let mut full_attrs = HashMap::new(); + for i in 0..9 { + full_attrs.insert( + format!("attr{i}"), + MessageAttributeValue::builder() + .data_type("String") + .string_value(format!("value{i}")) + .build() + .unwrap(), + ); + } + full_attrs.insert( + DATADOG_ATTRIBUTE_KEY.to_string(), + MessageAttributeValue::builder() + .data_type("String") + .string_value("stale") + .build() + .unwrap(), + ); + let entry = SendMessageBatchRequestEntry::builder() + .id("full") + .message_body("body") + .set_message_attributes(Some(full_attrs)) + .build() + .unwrap(); + let mut input = SendMessageBatchInput::builder() + .queue_url("https://example.com/test-queue") + .entries(entry) + .build() + .unwrap(); + + inject_into_send_message_batch(&mut input, &trace_headers).unwrap(); + + let entries = input.entries.as_ref().unwrap(); + let attrs = entries[0].message_attributes.as_ref().unwrap(); + assert_eq!(attrs.len(), 10); + let dd_attr = &attrs[DATADOG_ATTRIBUTE_KEY]; + let json_str = dd_attr.string_value().unwrap(); + let parsed: HashMap = serde_json::from_str(json_str).unwrap(); + assert_eq!(parsed[DATADOG_TRACE_ID_KEY], "123456789"); + assert_eq!(parsed[DATADOG_PARENT_ID_KEY], "987654321"); + assert_eq!(parsed[DATADOG_SAMPLING_PRIORITY_KEY], "1"); + } + + #[test] + fn unsupported_sqs_operation_returns_none() { + assert!(SqsOperation::from_name("ListQueues").is_none()); + } +} diff --git a/instrumentation/aws/datadog-aws/tests/integration.rs b/instrumentation/aws/datadog-aws/tests/integration.rs new file mode 100644 index 00000000..692c92ce --- /dev/null +++ b/instrumentation/aws/datadog-aws/tests/integration.rs @@ -0,0 +1,733 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +//! End-to-end integration tests for AwsInterceptor. +//! +//! Each test starts a minimal mock HTTP server, makes a real AWS SDK call with +//! the interceptor attached, and asserts on the finished OTel span and any +//! trace context injected into the request payload. +//! +//! Tests are serialized with `#[serial]` because they share OTel global state +//! (tracer provider + propagator). + +use std::collections::HashMap; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::sync::{Arc, Mutex}; + +use aws_credential_types::provider::SharedCredentialsProvider; +use aws_credential_types::Credentials; +use aws_sdk_eventbridge::types::PutEventsRequestEntry; +use aws_sdk_sqs::types::SendMessageBatchRequestEntry; +use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion; +use aws_types::region::Region; +use aws_types::SdkConfig; +use bytes::Bytes; +use http_body_util::{combinators::BoxBody, BodyExt, Full}; +use hyper::body::Incoming; +use hyper::{Request, Response}; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use hyper_util::server::conn::auto::Builder; +use opentelemetry::trace::{SpanKind, TraceContextExt, Tracer}; +use opentelemetry::{global, Context}; +use opentelemetry_sdk::propagation::TraceContextPropagator; +use opentelemetry_sdk::trace::{InMemorySpanExporter, SdkTracerProvider, SimpleSpanProcessor, SpanData}; +use serial_test::serial; +use tokio::net::TcpListener; +use tokio::task::JoinHandle; + +use datadog_aws::AwsInterceptor; + + +/// Starts a minimal mock HTTP server: every request gets `x-amzn-requestid: test_req`, +/// the given status code, and body `{}`. +/// Returns `(base_url, server_handle, captured_bodies)` where `captured_bodies` +/// accumulates each request body as a UTF-8 string for injection assertions. +async fn mock_aws(status: u16) -> (String, JoinHandle<()>, Arc>>) { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr: SocketAddr = listener.local_addr().unwrap(); + let bodies: Arc>> = Arc::new(Mutex::new(Vec::new())); + let bodies_server = bodies.clone(); + let handle = tokio::spawn(async move { + loop { + let Ok((stream, _)) = listener.accept().await else { + break; + }; + let bodies_conn = bodies_server.clone(); + tokio::spawn(async move { + let _ = Builder::new(TokioExecutor::new()) + .serve_connection( + TokioIo::new(stream), + hyper::service::service_fn(move |req: Request| { + let bodies_req = bodies_conn.clone(); + async move { + let raw = req.into_body().collect().await.unwrap_or_default(); + let text = String::from_utf8_lossy(&raw.to_bytes()).into_owned(); + bodies_req.lock().unwrap().push(text); + let body: BoxBody = + Full::new(Bytes::from_static(b"{}")) + .map_err(|e| match e {}) + .boxed(); + let resp = Response::builder() + .status(status) + .header("x-amzn-requestid", "test_req") + .header("Content-Type", "application/json") + .body(body) + .unwrap(); + Ok::<_, Infallible>(resp) + } + }), + ) + .await; + }); + } + }); + (format!("http://{addr}"), handle, bodies) +} + +/// Registers an `InMemorySpanExporter` as the global tracer provider and +/// a `TraceContextPropagator` as the global propagator, then returns the +/// exporter so tests can retrieve finished spans. +/// +/// The inject functions in all three services treat trace headers as an opaque +/// `HashMap`, so the W3C propagator's header format is fine for +/// testing that injection wiring works end-to-end. +fn init_test_tracer() -> InMemorySpanExporter { + let exporter = InMemorySpanExporter::default(); + let provider = SdkTracerProvider::builder() + .with_span_processor(SimpleSpanProcessor::new(exporter.clone())) + .build(); + global::set_tracer_provider(provider); + global::set_text_map_propagator(TraceContextPropagator::new()); + exporter +} + +fn sdk_config(endpoint: &str) -> SdkConfig { + SdkConfig::builder() + .behavior_version(BehaviorVersion::latest()) + .endpoint_url(endpoint) + .region(Region::new("us-east-1")) + .credentials_provider(SharedCredentialsProvider::new(Credentials::for_tests())) + .build() +} + +fn sqs_client(cfg: &SdkConfig) -> aws_sdk_sqs::Client { + let config = aws_sdk_sqs::config::Builder::from(cfg) + .interceptor(AwsInterceptor::new()) + .build(); + aws_sdk_sqs::Client::from_conf(config) +} + +fn sns_client(cfg: &SdkConfig) -> aws_sdk_sns::Client { + let config = aws_sdk_sns::config::Builder::from(cfg) + .interceptor(AwsInterceptor::new()) + .build(); + aws_sdk_sns::Client::from_conf(config) +} + +fn eventbridge_client(cfg: &SdkConfig) -> aws_sdk_eventbridge::Client { + let config = aws_sdk_eventbridge::config::Builder::from(cfg) + .interceptor(AwsInterceptor::new()) + .build(); + aws_sdk_eventbridge::Client::from_conf(config) +} + +/// Flattens OTel span attributes into a `HashMap`. +fn span_attrs(span: &SpanData) -> HashMap { + span.attributes + .iter() + .map(|kv| (kv.key.to_string(), kv.value.to_string())) + .collect() +} + +/// Extracts the W3C `traceparent` value (`00-{trace_id}-{span_id}-{flags}`) from +/// a request body string, whether form-encoded (SQS/SNS) or JSON (EventBridge). +/// `traceparent` and hex characters never require URL-encoding, so this works on +/// the raw body without a decode step. +fn extract_traceparent(body: &str) -> Option { + // Find "traceparent" key, then find the value starting with "00-". + let after_key = &body[body.find("traceparent")? + "traceparent".len()..]; + let val_start = after_key.find("00-")?; + let val = &after_key[val_start..]; + // W3C format: 00-{32 hex}-{16 hex}-{2 hex} = 55 chars total. + (val.len() >= 55).then(|| val[..55].to_string()) +} + +/// Returns `(trace_id_hex, span_id_hex)` from a W3C traceparent string. +fn split_traceparent(tp: &str) -> (String, String) { + let parts: Vec<&str> = tp.splitn(4, '-').collect(); + (parts[1].to_string(), parts[2].to_string()) +} + +const QUEUE_URL: &str = "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue"; +const QUEUE_URL_TRAILING: &str = "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue/"; +const TOPIC_ARN: &str = "arn:aws:sns:us-east-1:111111111111:MyTopic"; +const TARGET_ARN: &str = "arn:aws:sns:us-east-1:111111111111:MyTarget"; + +// --------------------------------------------------------------------------- +// SQS tests +// --------------------------------------------------------------------------- + +#[tokio::test] +#[serial] +async fn sqs_send_message_creates_span_with_tags_and_injects_context() { + let exporter = init_test_tracer(); + let (url, _srv, captured) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + // SQS uses query/XML protocol; the mock returns JSON which causes a parse + // error, but read_after_execution still runs and ends the span. + let _ = client + .send_message() + .queue_url(QUEUE_URL) + .message_body("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + + assert_eq!(spans[0].name, "sqs.request"); + assert_eq!(attrs["aws.service"], "SQS"); + assert_eq!(attrs["aws.operation"], "SendMessage"); + assert_eq!(attrs["aws.region"], "us-east-1"); + assert_eq!(attrs["aws.partition"], "aws"); + assert_eq!(attrs["operation.name"], "aws.sqs.request"); + assert_eq!(attrs["resource.name"], "SQS.SendMessage"); + assert_eq!(attrs["component"], "datadog-aws-sdk"); + assert_eq!(attrs["span.kind"], "client"); + assert_eq!(attrs["queuename"], "MyQueue"); + assert_eq!( + attrs["cloud.resource_id"], + "arn:aws:sqs:us-east-1:123456789012:MyQueue" + ); + assert_eq!(attrs["messaging.system"], "amazonsqs"); + assert_eq!(attrs["http.status_code"], "200"); + assert_eq!(attrs["aws.request_id"], "test_req"); + assert_eq!(spans[0].span_kind, SpanKind::Client); + + // Verify _datadog trace context was injected and points to the span we created, + // not the caller's context, proving the injected downstream parent is correct. + let bodies = captured.lock().unwrap(); + assert_eq!(bodies.len(), 1); + assert!(bodies[0].contains("_datadog"), "body should contain _datadog attribute name"); + let tp = extract_traceparent(&bodies[0]).expect("traceparent should be in body"); + let (injected_trace_id, injected_parent_id) = split_traceparent(&tp); + assert_eq!(injected_trace_id, format!("{}", spans[0].span_context.trace_id())); + assert_eq!(injected_parent_id, format!("{}", spans[0].span_context.span_id())); +} + +#[tokio::test] +#[serial] +async fn sqs_send_message_batch_creates_span_and_injects_into_all_entries() { + let exporter = init_test_tracer(); + let (url, _srv, captured) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let entry1 = SendMessageBatchRequestEntry::builder() + .id("1") + .message_body("body1") + .build() + .unwrap(); + let entry2 = SendMessageBatchRequestEntry::builder() + .id("2") + .message_body("body2") + .build() + .unwrap(); + + let _ = client + .send_message_batch() + .queue_url(QUEUE_URL) + .entries(entry1) + .entries(entry2) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(spans[0].name, "sqs.request"); + assert_eq!(attrs["aws.operation"], "SendMessageBatch"); + assert_eq!(attrs["queuename"], "MyQueue"); + + // Verify _datadog was injected into the batch entries. + let bodies = captured.lock().unwrap(); + assert_eq!(bodies.len(), 1); + assert!(bodies[0].contains("_datadog"), "body should contain _datadog attribute"); + assert!(bodies[0].contains("traceparent"), "body should contain traceparent"); +} + +#[tokio::test] +#[serial] +async fn sqs_receive_message_creates_span_with_queue_tags() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .receive_message() + .queue_url(QUEUE_URL) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "ReceiveMessage"); + assert_eq!(attrs["queuename"], "MyQueue"); + assert_eq!( + attrs["cloud.resource_id"], + "arn:aws:sqs:us-east-1:123456789012:MyQueue" + ); +} + +#[tokio::test] +#[serial] +async fn sqs_delete_message_creates_span_with_queue_tags() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .delete_message() + .queue_url(QUEUE_URL) + .receipt_handle("handle") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "DeleteMessage"); + assert_eq!(attrs["queuename"], "MyQueue"); +} + +#[tokio::test] +#[serial] +async fn sqs_delete_message_batch_creates_span_with_queue_tags() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .delete_message_batch() + .queue_url(QUEUE_URL) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "DeleteMessageBatch"); + assert_eq!(attrs["queuename"], "MyQueue"); +} + +#[tokio::test] +#[serial] +async fn sqs_queue_url_trailing_slash_parsed_correctly() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .send_message() + .queue_url(QUEUE_URL_TRAILING) + .message_body("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["queuename"], "MyQueue"); + assert_eq!( + attrs["cloud.resource_id"], + "arn:aws:sqs:us-east-1:123456789012:MyQueue" + ); +} + +#[tokio::test] +#[serial] +async fn sqs_error_response_sets_span_error_status_and_http_code() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(400).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .send_message() + .queue_url(QUEUE_URL) + .message_body("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["http.status_code"], "400"); + assert!(matches!( + spans[0].status, + opentelemetry::trace::Status::Error { .. } + )); +} + +// --------------------------------------------------------------------------- +// SNS tests +// --------------------------------------------------------------------------- + +#[tokio::test] +#[serial] +async fn sns_publish_with_topic_creates_span_and_injects_binary_context() { + let exporter = init_test_tracer(); + let (url, _srv, captured) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client + .publish() + .topic_arn(TOPIC_ARN) + .message("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(spans[0].name, "sns.request"); + assert_eq!(attrs["aws.service"], "SNS"); + assert_eq!(attrs["aws.operation"], "Publish"); + assert_eq!(attrs["topicname"], "MyTopic"); + assert_eq!(attrs["operation.name"], "aws.sns.request"); + assert_eq!(attrs["resource.name"], "SNS.Publish"); + + // SNS injects _datadog as a Binary attribute; the value is base64-encoded + // so traceparent won't appear in plaintext. Assert the attribute name and type. + let bodies = captured.lock().unwrap(); + assert_eq!(bodies.len(), 1); + assert!(bodies[0].contains("_datadog"), "body should contain _datadog attribute name"); + assert!(bodies[0].contains("Binary"), "body should indicate Binary data type"); +} + +#[tokio::test] +#[serial] +async fn sns_publish_with_target_sets_targetname_tag() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client + .publish() + .target_arn(TARGET_ARN) + .message("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["targetname"], "MyTarget"); + assert!(!attrs.contains_key("topicname")); +} + +#[tokio::test] +#[serial] +async fn sns_publish_batch_creates_span_with_topicname() { + let exporter = init_test_tracer(); + let (url, _srv, captured) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let entry = aws_sdk_sns::types::PublishBatchRequestEntry::builder() + .id("1") + .message("body") + .build() + .unwrap(); + + let _ = client + .publish_batch() + .topic_arn(TOPIC_ARN) + .publish_batch_request_entries(entry) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(spans[0].name, "sns.request"); + assert_eq!(attrs["aws.operation"], "PublishBatch"); + assert_eq!(attrs["topicname"], "MyTopic"); + + // SNS batch injects _datadog Binary attribute into each entry. + let bodies = captured.lock().unwrap(); + assert_eq!(bodies.len(), 1); + assert!(bodies[0].contains("_datadog"), "batch body should contain _datadog attribute"); + assert!(bodies[0].contains("Binary"), "batch body should indicate Binary data type"); +} + +#[tokio::test] +#[serial] +async fn sns_subscribe_creates_span_with_topicname() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client + .subscribe() + .topic_arn(TOPIC_ARN) + .protocol("sqs") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "Subscribe"); + assert_eq!(attrs["topicname"], "MyTopic"); +} + +#[tokio::test] +#[serial] +async fn sns_create_topic_uses_name_field_not_arn() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client.create_topic().name("MyNewTopic").send().await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "CreateTopic"); + assert_eq!(attrs["topicname"], "MyNewTopic"); +} + +#[tokio::test] +#[serial] +async fn sns_get_topic_attributes_creates_span_with_topicname() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client + .get_topic_attributes() + .topic_arn(TOPIC_ARN) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "GetTopicAttributes"); + assert_eq!(attrs["topicname"], "MyTopic"); +} + +#[tokio::test] +#[serial] +async fn sns_error_response_sets_span_error_status() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(400).await; + let client = sns_client(&sdk_config(&url)); + + let _ = client + .publish() + .topic_arn(TOPIC_ARN) + .message("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["http.status_code"], "400"); + assert!(matches!( + spans[0].status, + opentelemetry::trace::Status::Error { .. } + )); +} + +// --------------------------------------------------------------------------- +// EventBridge tests +// --------------------------------------------------------------------------- + +#[tokio::test] +#[serial] +async fn eventbridge_put_events_creates_span_and_injects_detail() { + let exporter = init_test_tracer(); + let (url, _srv, captured) = mock_aws(200).await; + let client = eventbridge_client(&sdk_config(&url)); + + let entry = PutEventsRequestEntry::builder() + .source("my.source") + .detail_type("MyType") + .detail(r#"{"key":"value"}"#) + .build(); + + let _ = client.put_events().entries(entry).send().await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(spans[0].name, "eventbridge.request"); + assert_eq!(attrs["aws.service"], "EventBridge"); + assert_eq!(attrs["aws.operation"], "PutEvents"); + assert_eq!(attrs["operation.name"], "aws.eventbridge.request"); + assert_eq!(attrs["resource.name"], "EventBridge.PutEvents"); + + // EventBridge uses JSON protocol, so we can fully parse the body and verify + // the injected traceparent points to the span that was created. + let bodies = captured.lock().unwrap(); + assert_eq!(bodies.len(), 1); + let body: serde_json::Value = serde_json::from_str(&bodies[0]).unwrap(); + let entries = body["Entries"].as_array().unwrap(); + let detail: serde_json::Value = + serde_json::from_str(entries[0]["Detail"].as_str().unwrap()).unwrap(); + let tp = detail["_datadog"]["traceparent"] + .as_str() + .expect("_datadog.traceparent should be a string"); + let (injected_trace_id, injected_parent_id) = split_traceparent(tp); + assert_eq!(injected_trace_id, format!("{}", spans[0].span_context.trace_id())); + assert_eq!(injected_parent_id, format!("{}", spans[0].span_context.span_id())); +} + +#[tokio::test] +#[serial] +async fn eventbridge_put_events_with_bus_name_creates_span() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = eventbridge_client(&sdk_config(&url)); + + let entry = PutEventsRequestEntry::builder() + .source("my.source") + .detail_type("MyType") + .detail(r#"{"key":"value"}"#) + .event_bus_name("my-bus") + .build(); + + let _ = client.put_events().entries(entry).send().await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + assert_eq!(span_attrs(&spans[0])["aws.operation"], "PutEvents"); +} + +#[tokio::test] +#[serial] +async fn eventbridge_put_events_multi_entry_creates_single_span() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = eventbridge_client(&sdk_config(&url)); + + let entry1 = PutEventsRequestEntry::builder() + .source("src1") + .detail_type("T1") + .detail(r#"{"a":1}"#) + .event_bus_name("bus-1") + .build(); + let entry2 = PutEventsRequestEntry::builder() + .source("src2") + .detail_type("T2") + .detail(r#"{"b":2}"#) + .build(); + + let _ = client + .put_events() + .entries(entry1) + .entries(entry2) + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + assert_eq!(span_attrs(&spans[0])["aws.operation"], "PutEvents"); +} + +#[tokio::test] +#[serial] +async fn eventbridge_put_rule_creates_span_with_rulename() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = eventbridge_client(&sdk_config(&url)); + + let _ = client.put_rule().name("my-rule").send().await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "PutRule"); + assert_eq!(attrs["rulename"], "my-rule"); +} + +#[tokio::test] +#[serial] +async fn eventbridge_put_targets_creates_span_with_rulename() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = eventbridge_client(&sdk_config(&url)); + + let _ = client.put_targets().rule("my-rule").send().await; + + let spans = exporter.get_finished_spans().unwrap(); + assert_eq!(spans.len(), 1); + let attrs = span_attrs(&spans[0]); + assert_eq!(attrs["aws.operation"], "PutTargets"); + assert_eq!(attrs["rulename"], "my-rule"); +} + +// --------------------------------------------------------------------------- +// Cross-cutting: HTTP tags +// --------------------------------------------------------------------------- + +#[tokio::test] +#[serial] +async fn http_tags_set_on_span() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + let _ = client + .send_message() + .queue_url(QUEUE_URL) + .message_body("hello") + .send() + .await; + + let spans = exporter.get_finished_spans().unwrap(); + let attrs = span_attrs(&spans[0]); + assert_eq!(spans[0].name, "sqs.request"); + assert_eq!(attrs["http.method"], "POST"); + assert!(attrs["http.url"].starts_with(&url)); + assert_eq!(attrs["http.status_code"], "200"); + assert_eq!(attrs["aws.request_id"], "test_req"); + assert!(attrs.contains_key("aws.agent"), "aws.agent should be set from user-agent header"); +} + +#[tokio::test] +#[serial] +async fn interceptor_span_is_child_of_active_parent() { + let exporter = init_test_tracer(); + let (url, _srv, _bodies) = mock_aws(200).await; + let client = sqs_client(&sdk_config(&url)); + + // Create a parent span and make the AWS call within its context. + let tracer = global::tracer("test"); + let parent_span = tracer.start("parent-operation"); + let parent_cx = Context::current().with_span(parent_span); + let _guard = parent_cx.clone().attach(); + + let parent_span_id = parent_cx.span().span_context().span_id(); + let parent_trace_id = parent_cx.span().span_context().trace_id(); + + let _ = client + .send_message() + .queue_url(QUEUE_URL) + .message_body("hello") + .send() + .await; + + // Drop the guard so the parent span can be exported. + drop(_guard); + parent_cx.span().end(); + + let spans = exporter.get_finished_spans().unwrap(); + // Find the interceptor span (not the parent). + let interceptor_span = spans + .iter() + .find(|s| s.name == "sqs.request") + .expect("should have an sqs.request span"); + + // The interceptor span must be a child of the parent, in the same trace. + assert_eq!(interceptor_span.span_context.trace_id(), parent_trace_id); + assert_eq!(interceptor_span.parent_span_id, parent_span_id); +}