diff --git a/.github/codecov.yaml b/.github/codecov.yaml index 317422a6f2..2bfdd7105a 100644 --- a/.github/codecov.yaml +++ b/.github/codecov.yaml @@ -13,13 +13,10 @@ coverage: ignore: - "opentelemetry/src/testing" # test harnesses - - "opentelemetry-jaeger/src/testing" # test harness - - "opentelemetry-jaeger/src/exporter/thrift" # auto generated files - "opentelemetry-otlp/src/proto" # auto generated files - "opentelemetry-proto/src/proto" # auto generated files # examples below - "examples" - - "opentelemetry-jaeger/examples" - "opentelemetry-zipkin/examples" - "opentelemetry-otlp/examples" - "opentelemetry-http/examples" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c009b40c8d..295c69bc6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,6 @@ jobs: - name: Run tests run: cargo --version && cargo test --manifest-path=opentelemetry/Cargo.toml --features trace,metrics,testing && - cargo test --manifest-path=opentelemetry-jaeger/Cargo.toml --features rt-tokio && cargo test --manifest-path=opentelemetry-zipkin/Cargo.toml cargo-deny: runs-on: ubuntu-latest # This uses the step `EmbarkStudios/cargo-deny-action@v1` which is only supported on Linux diff --git a/opentelemetry-jaeger/CHANGELOG.md b/opentelemetry-jaeger/CHANGELOG.md deleted file mode 100644 index 179a8e874d..0000000000 --- a/opentelemetry-jaeger/CHANGELOG.md +++ /dev/null @@ -1,244 +0,0 @@ -# Changelog - -## Deprecation Notice - -Starting with [Jaeger v1.38](https://github.com/jaegertracing/jaeger/releases/tag/v1.38.0) Jaeger supports the OpenTelemetry Protocol (OTLP). -[OpenTelemetry has recommended](https://opentelemetry.io/blog/2022/jaeger-native-otlp/) migrating to OTLP. - -Please check the [README](https://crates.io/crates/opentelemetry-jaeger) for more information. - -## v0.22.0 - -- **This is the last release of this crate.** - Jaeger propagator is part of [opentelemetry-jaeger-propagator](../opentelemetry-jaeger-propagator/). - For exporting to Jaeger, use [opentelemetry-otlp](../opentelemetry-otlp/). -- Update `opentelemetry` dependency version to 0.23 -- Update `opentelemetry_sdk` dependency version to 0.23 -- Update `opentelemetry-http` dependency version to 0.12 -- Update `opentelemetry-semantic-conventions` dependency version to 0.15 - -## v0.21.0 - -### Changed - -- Update to tonic 0.11 and prost 0.12 [#1536](https://github.com/open-telemetry/opentelemetry-rust/pull/1536) - -### Removed - -- **Breaking** Jaeger propagator functionality has been moved to a new crate [opentelemetry-jaeger-propagator](../opentelemetry-jaeger-propagator/) - to prepare for opentelemetry-jaeger exporter deprecation. [#1487](https://github.com/open-telemetry/opentelemetry-rust/pull/1487) -- **Breaking** Remove support for surf HTTP client [#1537](https://github.com/open-telemetry/opentelemetry-rust/pull/1537) - -## v0.20.0 - -### Changed - -- Bump MSRV to 1.65 [#1318](https://github.com/open-telemetry/opentelemetry-rust/pull/1318) -- Bump MSRV to 1.64 [#1203](https://github.com/open-telemetry/opentelemetry-rust/pull/1203) -- Prioritize environment variables over compiling time variables [#1323](https://github.com/open-telemetry/opentelemetry-rust/pull/1323) - -## v0.19.0 - -### Changed - -- Add warning to jaeger docs about future deprecation #996 -- Update to opentelemetry-api v0.20.0 - -### Fixed -- allow span id to be less than 16 characters in propagator [#1084](https://github.com/open-telemetry/opentelemetry-rust/pull/1084) -- `reqwest_rustls_collector_client` now includes `with_reqwest` [#1159](https://github.com/open-telemetry/opentelemetry-rust/pull/1159) - -## v0.18.0 - -### Added - -- Added `CollectorPipeline::build_collector_exporter` [#894](https://github.com/open-telemetry/opentelemetry-rust/pull/894). -- Support IPv6 in sync uploader [#938](https://github.com/open-telemetry/opentelemetry-rust/pull/938). - -### Changed -- Update `opentelemetry` to 0.19 -- Update `opentelemetry-http` to 0.8 -- Update `opentelemetry-semantic-conventions` to 0.11. -- Bump MSRV to 1.57 [#953](https://github.com/open-telemetry/opentelemetry-rust/pull/953). -- Include packet length for `SizeLimit` error messages [#938](https://github.com/open-telemetry/opentelemetry-rust/pull/938). -- Update dependencies and bump MSRV to 1.60 [#969](https://github.com/open-telemetry/opentelemetry-rust/pull/969). -- Make `JaegerRemoteSampler` public, revise doc [#975](https://github.com/open-telemetry/opentelemetry-rust/pull/975). -- Add warnings to docs about future deprecation [#996](https://github.com/open-telemetry/opentelemetry-rust/pull/996). -- Fix array encoding length of datadog version v5 exporter(#1002)(https://github.com/open-telemetry/opentelemetry-rust/pull/1002). - -## v0.17.0 - -### Added - -- Support rustls in jaeger reqwest collector #834 -- Customisation support in Jaeger Propagator. #852 -- Add IPv6 support for Jaeger agent addresses #856 -- Add `with_batch_processor_config` for jaeger pipline #869 - -### Changed - -- Consolidate the config errors #762 -- Better configuration pipeline #748 -- Add Timeout Environment Var #729 -- add propagator initialisation with custom headers and baggage prefix #852 -- Update to opentelemetry v0.18.0 -- Update to opentelemetry-http v0.7.0 -- Update to opentelemetry-semantic-conventions v0.10.0 - -### Fixed - -- Fix clearing span context in Propagator #810 -- Fix reqwest client runs inside a non-tokio runtime #829 - -## v0.16.0 - -### Changed - -- try split batch if payload size larger than max_package_size #619 -- update to thrift 0.15 #697 -- Update to opentelemetry v0.17.0 -- Update to opentelemetry-http v0.6.0 -- Update to opentelemetry-semantic-conventions v0.9.0 - -### Fixed - -- Mapping between Jaeger processes and Otel process. #663 - -## v0.15.0 - -### Changed - -- Set client-to-agent UDP comm based on runtime #599. Users should change their `tokio` feature to `rt-tokio`. Similar with async-std -- Update to opentelemetry v0.16.0 - -## v0.14.0 - -### Changed - -- Update to opentelemetry v0.15.0 - -## v0.13.0 - -### Changed - -- Use follows from instead of child of for links #524 -- Remove default surf features #546 -- Update to opentelemetry v0.14.0 - -## v0.12.1 - -### Fixed - -- jaeger span error reporting and spec compliance #489 - -## v0.12.0 - -### Added -- Add max packet size constraint #457 - -### Fixed -- Allow user to use hostname like `localhost` in the `OTEL_EXPORTER_JAEGER_AGENT_HOST` environment variable. #448 - -### Removed -- Removed `from_env` and use environment variables to initialize the configurations by default #459 - -### Changed -- Update to opentelemetry v0.13.0 -- Rename trace config with_default_sampler to with_sampler #482 - -## v0.11.0 - -### Changed - -- Update to opentelemetry v0.12.0 -- Update tokio to v1 #421 -- Make `with_collector_endpoint` function less error prune #428 -- Use opentelemetry-http for http integration #415 - -## v0.10.0 - -### Added - -- Add wasm support #365 -- Allow user to use their own http clients or use 4 of the default implementation - (`surf_collector_client`, `reqwest_collector_client`, `reqwest_blocking_collector_client`, `isahc_collector_client`) -- Set `otel.status_code` and `otel.status_description` values #383 - -### Changed - -- Update to opentelemetry v0.11.0 -- Use http client trait #378 - -## v0.9.0 - -### Added - -- Option to disable exporting instrumentation library information #288 - -### Changed - -- Update to opentelemetry v0.10.0 -- Update mapping otel events to Jaeger logs attributes #285 -- Add MSRV 1.42.0 #296 - -## v0.8.0 - -### Added - -- Map `Resource`s to jaeger process tags #215 -- Export instrument library information #243 - -### Changed - -- Switch to pipeline configuration #189 -- Update to opentelemetry v0.9.0 - -## v0.7.0 - -### Changed - -- Update to opentelemetry v0.8.0 - -## v0.6.0 - -### Changed -- Update to opentelemetry v0.7.0 - -### Fixed -- Do not add `span.kind` tag if it has been set as an attribute #140 - -## v0.5.0 - -### Changed -- Update to opentelemetry v0.6.0 - -### Fixed -- Switch internally to `ureq` from `reqwest` to fix #106 -- Fix exported link span id format #118 - -## v0.4.0 - -### Added -- Support for resource attributes - -### Changed -- Update to opentelemetry v0.5.0 - -### Removed -- `as_any` method on exporter - -## v0.3.0 - -### Changed -- Update to opentelemetry v0.4.0 - -## v0.2.0 - -### Changed -- Update to opentelemetry v0.3.0 - -## v0.1.0 - -### Added -- Jaeger agent Thrift UDP client -- Jaeger collector Thrift HTTP client diff --git a/opentelemetry-jaeger/CODEOWNERS b/opentelemetry-jaeger/CODEOWNERS deleted file mode 100644 index d6962a905a..0000000000 --- a/opentelemetry-jaeger/CODEOWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# Code owners file. -# This file controls who is tagged for review for any given pull request. - -# For anything not explicitly taken by someone else: -* @open-telemetry/rust-approvers diff --git a/opentelemetry-jaeger/Cargo.toml b/opentelemetry-jaeger/Cargo.toml deleted file mode 100644 index eabfa4ee45..0000000000 --- a/opentelemetry-jaeger/Cargo.toml +++ /dev/null @@ -1,110 +0,0 @@ -[package] -name = "opentelemetry-jaeger" -version = "0.22.0" -description = "Jaeger exporter for OpenTelemetry" -homepage = "https://github.com/open-telemetry/opentelemetry-rust/tree/main/opentelemetry-jaeger" -repository = "https://github.com/open-telemetry/opentelemetry-rust/tree/main/opentelemetry-jaeger" -readme = "README.md" -categories = [ - "development-tools::debugging", - "development-tools::profiling", - "asynchronous", -] -keywords = ["opentelemetry", "jaeger", "tracing", "async"] -license = "Apache-2.0" -edition = "2021" -rust-version = "1.65" - -[badges] -maintenance = { status = "deprecated" } - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[dependencies] -async-std = { workspace = true, optional = true } -async-trait = { workspace = true } -base64 = { version = "0.21.0", optional = true } -headers = { version = "0.3.2", optional = true } -http = { workspace = true, optional = true } -hyper = { workspace = true, features = ["client"], optional = true } -hyper-tls = { version = "0.5.0", default-features = false, optional = true } -isahc = { workspace = true, optional = true } -js-sys = { version = "0.3", optional = true } -opentelemetry = { version = "0.23", default-features = false, features = ["trace"], path = "../opentelemetry" } -opentelemetry_sdk = { version = "0.23", default-features = false, features = ["trace"], path = "../opentelemetry-sdk" } -opentelemetry-http = { version = "0.12", path = "../opentelemetry-http", optional = true } -opentelemetry-semantic-conventions = { version = "0.15", path = "../opentelemetry-semantic-conventions" } -pin-project-lite = { workspace = true, optional = true } -reqwest = { workspace = true, optional = true } -thrift = "0.17.0" -tokio = { workspace = true, features = ["net", "sync"], optional = true } -wasm-bindgen = { version = "0.2", optional = true } -wasm-bindgen-futures = { version = "0.4.18", optional = true } - -tonic = { workspace = true, optional = true, features = ["transport", "codegen", "prost"] } -prost = { workspace = true, optional = true } -prost-types = { workspace = true, optional = true } - -# Futures -futures-executor = { workspace = true, features = ["std"], optional = true } -futures-core = { workspace = true } -futures-util = { workspace = true, features = ["std", "alloc"]} - -[dev-dependencies] -tokio = { workspace = true, features = ["net", "sync"] } -bytes = { workspace = true } -futures-executor = { workspace = true } -opentelemetry-jaeger-propagator = { path = "../opentelemetry-jaeger-propagator" } # for doctests -opentelemetry_sdk = { features = ["trace", "testing", "rt-tokio"], path = "../opentelemetry-sdk" } - -[dependencies.web-sys] -version = "0.3.4" -features = [ - 'Headers', - 'Request', - 'RequestCredentials', - 'RequestInit', - 'RequestMode', - 'Response', - 'Window', -] -optional = true - -[features] -full = [ - "collector_client", - "hyper_collector_client", - "hyper_tls_collector_client", - "isahc_collector_client", - "reqwest_collector_client", - "reqwest_blocking_collector_client", - "reqwest_rustls_collector_client", - "wasm_collector_client", - "rt-tokio", - "rt-tokio-current-thread", - "rt-async-std", - "integration_test", -] -default = [] -collector_client = ["http", "opentelemetry-http"] -hyper_collector_client = ["collector_client", "headers", "http", "hyper", "opentelemetry-http/tokio", "opentelemetry-http/hyper"] -hyper_tls_collector_client = ["hyper_collector_client", "hyper-tls"] -isahc_collector_client = ["isahc", "opentelemetry-http/isahc"] -reqwest_blocking_collector_client = ["reqwest/blocking", "collector_client", "headers", "opentelemetry-http/reqwest"] -reqwest_collector_client = ["reqwest", "collector_client", "headers", "opentelemetry-http/reqwest"] -reqwest_rustls_collector_client = ["reqwest_collector_client", "reqwest/rustls-tls-native-roots"] -wasm_collector_client = [ - "base64", - "http", - "js-sys", - "pin-project-lite", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] -rt-tokio = ["tokio", "opentelemetry_sdk/rt-tokio"] -rt-tokio-current-thread = ["tokio", "opentelemetry_sdk/rt-tokio-current-thread"] -rt-async-std = ["async-std", "opentelemetry_sdk/rt-async-std"] -integration_test = ["tonic", "prost", "prost-types", "rt-tokio", "collector_client", "hyper_collector_client", "hyper_tls_collector_client", "reqwest_collector_client", "isahc_collector_client"] diff --git a/opentelemetry-jaeger/LICENSE b/opentelemetry-jaeger/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/opentelemetry-jaeger/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/opentelemetry-jaeger/README.md b/opentelemetry-jaeger/README.md deleted file mode 100644 index d6b0cb639d..0000000000 --- a/opentelemetry-jaeger/README.md +++ /dev/null @@ -1,178 +0,0 @@ -![OpenTelemetry — An observability framework for cloud-native software.][splash] - -[splash]: https://raw.githubusercontent.com/open-telemetry/opentelemetry-rust/main/assets/logo-text.png - -# OpenTelemetry Jaeger (Deprecated) - -**WARNING** -As of [Jaeger 1.35.0], released in Sept 2022, ingesting the OpenTelemetry Protocol (OTLP) is stable and -as a result, language specific Jaeger exporters within OpenTelemetry SDKs are [recommended for deprecation by the OpenTelemetry project][jaeger-deprecation]. -More information and examples of using OTLP with Jaeger can be found in [Introducing native support for OpenTelemetry in Jaeger][jaeger-otlp] -and [Exporting OTLP traces to Jaeger][exporting-otlp]. - -The opentelemetry-jaeger crate previously contained both a Jaeger exporter and a Jaeger propagator. -To prepare for the deprecation of the Jaeger exporter, the Jaeger propagator implementation has been migrated to -[opentelemetry-jaeger-propagator](../opentelemetry-jaeger-propagator/). - -The 0.22.0 is the last release of the Jaeger exporter. This means that future versions of the OpenTelemetry -SDK will not work with the exporter. - -If you have any questions please comment on the [Jaeger Deprecation Issue][deprecation-issue]. - -[`Jaeger`] integration for applications instrumented with [`OpenTelemetry`]. This includes a jaeger exporter and a jaeger propagator. - -[![Crates.io: opentelemetry-jaeger](https://img.shields.io/crates/v/opentelemetry-jaeger.svg)](https://crates.io/crates/opentelemetry-jaeger) -[![Documentation](https://docs.rs/opentelemetry-jaeger/badge.svg)](https://docs.rs/opentelemetry-jaeger) -[![LICENSE](https://img.shields.io/crates/l/opentelemetry-jaeger)](./LICENSE) -[![GitHub Actions CI](https://github.com/open-telemetry/opentelemetry-rust/workflows/CI/badge.svg)](https://github.com/open-telemetry/opentelemetry-rust/actions?query=workflow%3ACI+branch%3Amain) -[![Slack](https://img.shields.io/badge/slack-@cncf/otel/rust-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C03GDP0H023) - -## Overview - -[`OpenTelemetry`] is a collection of tools, APIs, and SDKs used to instrument, -generate, collect, and export telemetry data (metrics, logs, and traces) for -analysis in order to understand your software's performance and behavior. This -crate provides a trace pipeline and exporter for sending span information to a -Jaeger `agent` or `collector` endpoint for processing and visualization. - -*Compiler support: [requires `rustc` 1.65+][msrv]* - -[`Jaeger`]: https://www.jaegertracing.io/ -[jaeger-otlp]: https://medium.com/jaegertracing/introducing-native-support-for-opentelemetry-in-jaeger-eb661be8183c -[jaeger-deprecation]: https://opentelemetry.io/blog/2022/jaeger-native-otlp/ -[exporting-otlp]: https://github.com/open-telemetry/opentelemetry-rust/tree/main/examples/tracing-jaeger -[Jaeger 1.35.0]: https://github.com/jaegertracing/jaeger/releases/tag/v1.35.0 -[deprecation-issue]: https://github.com/open-telemetry/opentelemetry-rust/issues/995 -[`OpenTelemetry`]: https://crates.io/crates/opentelemetry -[msrv]: #supported-rust-versions - -### Quickstart - -First make sure you have a running version of the Jaeger instance you want to -send data to: - -```shell -$ docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest -``` - -Then install a new jaeger pipeline with the recommended defaults to start -exporting telemetry: - -```rust -use opentelemetry::global; -use opentelemetry::trace::Tracer; -use opentelemetry_jaeger_propagator; - -fn main() -> Result<(), Box> { - global::set_text_map_propagator(opentelemetry_jaeger_propagator::Propagator::new()); - let tracer = opentelemetry_jaeger::new_agent_pipeline().install_simple()?; - - tracer.in_span("doing_work", |cx| { - // Traced app logic here... - }); - - global::shutdown_tracer_provider(); // sending remaining spans - - Ok(()) -} -``` - -![Jaeger UI](https://raw.githubusercontent.com/open-telemetry/opentelemetry-rust/main/opentelemetry-jaeger/trace.png) - -## Performance - -For optimal performance, a batch exporter is recommended as the simple exporter -will export each span synchronously on drop. You can enable the [`rt-tokio`], -[`rt-tokio-current-thread`] or [`rt-async-std`] features and specify a runtime -on the pipeline builder to have a batch exporter configured for you -automatically. - -```toml -[dependencies] -opentelemetry_sdk = { version = "*", features = ["rt-tokio"] } -opentelemetry-jaeger = { version = "*", features = ["rt-tokio"] } -``` - -```rust -let tracer = opentelemetry_jaeger::new_agent_pipeline() - .install_batch(opentelemetry_sdk::runtime::Tokio)?; -``` - -[`rt-tokio`]: https://tokio.rs -[`rt-tokio-current-thread`]: https://tokio.rs -[`rt-async-std`]: https://async.rs - -### Jaeger Exporter From Environment Variables - -The jaeger pipeline builder can be configured dynamically via environment -variables. All variables are optional, a full list of accepted options can be -found in the [jaeger variables spec]. - -[jaeger variables spec]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md - -### Jaeger Collector Example - -If you want to skip the agent and submit spans directly to a Jaeger collector, -you can enable the optional `collector_client` feature for this crate. This -example expects a Jaeger collector running on `http://localhost:14268`. - -```toml -[dependencies] -opentelemetry-jaeger = { version = "..", features = ["isahc_collector_client"] } -``` - -Then you can use the [`with_collector_endpoint`] method to specify the endpoint: - -[`with_collector_endpoint`]: https://docs.rs/opentelemetry-jaeger/latest/opentelemetry_jaeger/config/collector/struct.CollectorPipeline.html#method.with_endpoint - -```rust -// Note that this requires one of the following features enabled so that there is a default http client implementation -// * hyper_collector_client -// * reqwest_collector_client -// * reqwest_blocking_collector_client -// * reqwest_rustls_collector_client -// * isahc_collector_client - -// You can also provide your own implementation by enable -// `collector_client` and set it with -// new_pipeline().with_http_client() method. -use opentelemetry::trace::Tracer; - -fn main() -> Result<(), Box> { - let tracer = opentelemetry_jaeger::new_collector_pipeline() - .with_endpoint("http://localhost:14268/api/traces") - // optionally set username and password as well. - .with_username("username") - .with_password("s3cr3t") - .install_batch()?; - - tracer.in_span("doing_work", |cx| { - // Traced app logic here... - }); - - opentelemetry::global::shutdown_tracer_provider(); // sending remaining spans - - Ok(()) -} -``` - -## Kitchen Sink Full Configuration - -[`Example`] showing how to override all configuration options. See the -[`AgentPipeline`] docs for details of each option. - -[`Example`]: https://docs.rs/opentelemetry-jaeger/latest/opentelemetry_jaeger/#kitchen-sink-full-configuration -[`AgentPipeline`]: https://docs.rs/opentelemetry-jaeger/latest/opentelemetry_jaeger/config/agent/struct.AgentPipeline.html - -## Supported Rust Versions - -OpenTelemetry is built against the latest stable release. The minimum supported -version is 1.65. The current OpenTelemetry version is not guaranteed to build -on Rust versions earlier than the minimum supported version. - -The current stable Rust compiler and the three most recent minor versions -before it will always be supported. For example, if the current stable compiler -version is 1.49, the minimum supported version will not be increased past 1.46, -three minor versions prior. Increasing the minimum supported compiler version -is not considered a semver breaking change as long as doing so complies with -this policy. diff --git a/opentelemetry-jaeger/examples/actix-udp/Cargo.toml b/opentelemetry-jaeger/examples/actix-udp/Cargo.toml deleted file mode 100644 index 2b282cc4ff..0000000000 --- a/opentelemetry-jaeger/examples/actix-udp/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "actix-udp-example" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -opentelemetry = { path = "../../../opentelemetry" } -opentelemetry-jaeger = { path = "../.." } -opentelemetry_sdk = { path = "../../../opentelemetry-sdk" } -actix-web = "4.1" -actix-service = "2" -env_logger = "0.10.0" diff --git a/opentelemetry-jaeger/examples/actix-udp/README.md b/opentelemetry-jaeger/examples/actix-udp/README.md deleted file mode 100644 index 5afeeaa41b..0000000000 --- a/opentelemetry-jaeger/examples/actix-udp/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Actix-web - Jaeger example with UDP agent - -This example shows how to export spans from an actix-web application and ship them - to the Jaeger agent over UDP. - -## Usage - -Launch the application: -```shell -# Run jaeger in background -$ docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest - -# Start the actix-web server -$ cargo run - -# View spans -$ firefox http://localhost:16686/ -``` - -Fire a request: -```bash -curl http://localhost:8080 -``` diff --git a/opentelemetry-jaeger/examples/actix-udp/src/main.rs b/opentelemetry-jaeger/examples/actix-udp/src/main.rs deleted file mode 100644 index 6f861f1d35..0000000000 --- a/opentelemetry-jaeger/examples/actix-udp/src/main.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![allow(deprecated)] -use actix_service::Service; -use actix_web::middleware::Logger; -use actix_web::{web, App, HttpServer}; -use opentelemetry::{ - global, - trace::{FutureExt, TraceContextExt, TraceError, Tracer}, - Key, KeyValue, -}; -use opentelemetry_sdk::{trace::config, Resource}; - -fn init_tracer() -> Result { - opentelemetry_jaeger::new_agent_pipeline() - .with_endpoint("localhost:6831") - .with_service_name("trace-udp-demo") - .with_trace_config(config().with_resource(Resource::new(vec![ - KeyValue::new("service.name", "my-service"), // this will not override the trace-udp-demo - KeyValue::new("service.namespace", "my-namespace"), - KeyValue::new("exporter", "jaeger"), - ]))) - .install_simple() -} - -async fn index() -> &'static str { - let tracer = global::tracer("request"); - tracer.in_span("index", |ctx| { - ctx.span().set_attribute(Key::new("parameter").i64(10)); - "Index" - }) -} - -#[actix_web::main] -async fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "debug"); - env_logger::init(); - let _tracer = init_tracer().expect("Failed to initialise tracer."); - - HttpServer::new(|| { - App::new() - .wrap(Logger::default()) - .wrap_fn(|req, srv| { - let tracer = global::tracer("request"); - tracer.in_span("middleware", move |cx| { - cx.span() - .set_attribute(Key::new("path").string(req.path().to_string())); - srv.call(req).with_context(cx) - }) - }) - .route("/", web::get().to(index)) - }) - .bind("127.0.0.1:8080") - .unwrap() - .run() - .await -} diff --git a/opentelemetry-jaeger/examples/remote-sampler/Cargo.toml b/opentelemetry-jaeger/examples/remote-sampler/Cargo.toml deleted file mode 100644 index 170fca5f3d..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "remote-sampler" -version = "0.1.0" -license = "Apache-2.0" -edition = "2021" - -[dependencies] -opentelemetry = { path = "../../../opentelemetry" } -opentelemetry_sdk = { path = "../../../opentelemetry-sdk", features = ["rt-tokio", "jaeger_remote_sampler"] } -opentelemetry-stdout = { path = "../../../opentelemetry-stdout", features = ["trace"] } -reqwest = { workspace = true } -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/opentelemetry-jaeger/examples/remote-sampler/README.md b/opentelemetry-jaeger/examples/remote-sampler/README.md deleted file mode 100644 index 69fba687eb..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Jaeger remote sampler - -When services generate too many spans. We need to sample some spans to save cost and speed up the queries. - -Adaptive sampling works in the Jaeger collector by observing the spans received from services and recalculating sampling -probabilities for each service/endpoint combination to ensure that the volume is relatively constant. - -For a full list of configurations. See SDK docs of [JaegerRemoteSamplerBuilder](https://docs.rs/opentelemetry_sdk/latest/opentelemetry_sdk/trace/struct.JaegerRemoteSamplerBuilder.html). - -## Setup - -Start a jaeger collector and an opentelemetry collector locally using docker - -``` -docker-compose run -d -``` - -It will allow you to - -- query sampling strategies from jaeger collect at port 5578. `http://localhost:5778/sampling?service=foo` -- query sampling strategies from opentelemetry collector at port 5579. `http://localhost:5779/sampling?service=foo` - -## Run the example - -After start the jaeger remote sampling server successfully. We can run - -`cargo run` - -command to start the example, you should only see one span is printed out. - -Looking at the example, you will notice we use `AlwaysOff` as our default sampler. It means before the SDK get the sampling strategy from remote server, no span will be sampled. - -Once the SDK fetched the remote strategy, we will start a probability sampler internally. In this case, we set the probability to 1.0 for all spans. This is defined by - -``` -"service": "foo", -"type": "probabilistic", -"param": 1, -``` - -Feel free to tune the `param` and see if the probability of sampling changes. - -## Strategies - -The sampling strategies is defined in `srategies.json` files. It defines two set of strategies. - -The first strategy is returned for `foo` service. The second strategy is catch all default strategy for all other -services. diff --git a/opentelemetry-jaeger/examples/remote-sampler/docker-compose.yaml b/opentelemetry-jaeger/examples/remote-sampler/docker-compose.yaml deleted file mode 100644 index 8f41f07319..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/docker-compose.yaml +++ /dev/null @@ -1,26 +0,0 @@ -version: "3" -services: - - # jaeger collector - jaeger-all-in-one: - image: jaegertracing/all-in-one:latest - ports: - - "16686:16686" - - "14268" - - "14250" - - "5778:5778" - container_name: jaeger-collector - volumes: - - ./strategies.json:/etc/jaeger/custom_strategies.json - environment: - - SAMPLING_STRATEGIES_FILE=/etc/jaeger/custom_strategies.json - - # opentelemetry collector - otel-collector: - image: otel/opentelemetry-collector:latest - command: [ "--config=/etc/otel-collector.yaml" ] - volumes: - - ./otel-collector.yaml:/etc/otel-collector.yaml - - ./strategies.json:/etc/strategies.json - ports: - - "5779:5778" # default jaeger remote sampling port \ No newline at end of file diff --git a/opentelemetry-jaeger/examples/remote-sampler/otel-collector.yaml b/opentelemetry-jaeger/examples/remote-sampler/otel-collector.yaml deleted file mode 100644 index e5f1280a2e..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/otel-collector.yaml +++ /dev/null @@ -1,17 +0,0 @@ -receivers: - jaeger: - protocols: - grpc: - remote_sampling: - host_endpoint: "0.0.0.0:5778" # default port - insecure: true - strategy_file: "/etc/strategies.json" - -exporters: - logging: - -service: - pipelines: - traces: - receivers: [ jaeger ] - exporters: [ logging ] \ No newline at end of file diff --git a/opentelemetry-jaeger/examples/remote-sampler/src/main.rs b/opentelemetry-jaeger/examples/remote-sampler/src/main.rs deleted file mode 100644 index 140c4d059f..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use opentelemetry::global; -use opentelemetry::trace::Tracer; -use opentelemetry_sdk::runtime; -use opentelemetry_sdk::trace::{Sampler, TracerProvider as SdkTracerProvider}; -use std::time::Duration; - -fn setup() { - let client = reqwest::Client::new(); - - let sampler = Sampler::jaeger_remote(runtime::Tokio, client, Sampler::AlwaysOff, "foo") - .with_endpoint("http://localhost:5778/sampling") // setup jaeger remote sampler endpoint - .with_update_interval(Duration::from_secs(5)) // will call jaeger sampling endpoint every 5 secs. - .build() - .unwrap(); - - let config = opentelemetry_sdk::trace::config().with_sampler(sampler); - - let provider = SdkTracerProvider::builder() - .with_config(config) - .with_simple_exporter(opentelemetry_stdout::SpanExporter::default()) - .build(); - - global::set_tracer_provider(provider); -} - -#[tokio::main] -async fn main() { - setup(); - let tracer = global::tracer("test"); - - { - let _not_sampled_span = tracer.start("test"); - } - - tokio::time::sleep(Duration::from_secs(10)).await; - - { - let _sampled_span = tracer.start("should_record"); - } -} diff --git a/opentelemetry-jaeger/examples/remote-sampler/strategies.json b/opentelemetry-jaeger/examples/remote-sampler/strategies.json deleted file mode 100644 index 3ba614e48e..0000000000 --- a/opentelemetry-jaeger/examples/remote-sampler/strategies.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "service_strategies": [ - { - "service": "foo", - "type": "probabilistic", - "param": 1, - "operation_strategies": [ - { - "operation": "op1", - "type": "probabilistic", - "param": 0.2 - }, - { - "operation": "op2", - "type": "probabilistic", - "param": 0.4 - } - ] - } - ], - "default_strategy": { - "type": "probabilistic", - "param": 0.5, - "operation_strategies": [ - { - "operation": "/health", - "type": "probabilistic", - "param": 0.0 - }, - { - "operation": "/metrics", - "type": "probabilistic", - "param": 0.0 - } - ] - } -} diff --git a/opentelemetry-jaeger/src/exporter/agent.rs b/opentelemetry-jaeger/src/exporter/agent.rs deleted file mode 100644 index 8982d526c8..0000000000 --- a/opentelemetry-jaeger/src/exporter/agent.rs +++ /dev/null @@ -1,207 +0,0 @@ -//! # UDP Jaeger Agent Client -use crate::exporter::address_family; -use crate::exporter::runtime::JaegerTraceRuntime; -use crate::exporter::thrift::{ - agent::{self, TAgentSyncClient}, - jaeger, -}; -use crate::exporter::transport::{TBufferChannel, TNoopChannel}; -use std::fmt; -use std::net::{SocketAddr, UdpSocket}; -use thrift::{ - protocol::{TCompactInputProtocol, TCompactOutputProtocol}, - transport::{ReadHalf, TIoChannel, WriteHalf}, -}; - -struct BufferClient { - buffer: ReadHalf, - client: agent::AgentSyncClient< - TCompactInputProtocol, - TCompactOutputProtocol>, - >, -} - -impl fmt::Debug for BufferClient { - /// Debug info - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufferClient") - .field("buffer", &self.buffer) - .field("client", &"AgentSyncClient") - .finish() - } -} - -/// `AgentSyncClientUDP` implements a version of the `TAgentSyncClient` -/// interface over UDP. -#[derive(Debug)] -pub(crate) struct AgentSyncClientUdp { - conn: UdpSocket, - buffer_client: BufferClient, - max_packet_size: usize, - auto_split: bool, -} - -impl AgentSyncClientUdp { - /// Create a new UDP agent client - pub(crate) fn new( - max_packet_size: usize, - auto_split: bool, - agent_address: Vec, - ) -> thrift::Result { - let (buffer, write) = TBufferChannel::with_capacity(max_packet_size).split()?; - let client = agent::AgentSyncClient::new( - TCompactInputProtocol::new(TNoopChannel), - TCompactOutputProtocol::new(write), - ); - - let conn = UdpSocket::bind(address_family(agent_address.as_slice()))?; - conn.connect(agent_address.as_slice())?; - - Ok(AgentSyncClientUdp { - conn, - buffer_client: BufferClient { buffer, client }, - max_packet_size, - auto_split, - }) - } - - /// Emit standard Jaeger batch - pub(crate) fn emit_batch(&mut self, batch: jaeger::Batch) -> thrift::Result<()> { - if !self.auto_split { - let payload = serialize_batch(&mut self.buffer_client, batch, self.max_packet_size)?; - self.conn.send(&payload)?; - return Ok(()); - } - - let mut buffers = vec![]; - serialize_batch_vectored( - &mut self.buffer_client, - batch, - self.max_packet_size, - &mut buffers, - )?; - for payload in buffers { - self.conn.send(&payload)?; - } - - Ok(()) - } -} - -/// `AgentAsyncClientUDP` implements an async version of the `TAgentSyncClient` -/// interface over UDP. -#[derive(Debug)] -pub(crate) struct AgentAsyncClientUdp { - runtime: R, - conn: ::Socket, - buffer_client: BufferClient, - max_packet_size: usize, - auto_split: bool, -} - -impl AgentAsyncClientUdp { - /// Create a new UDP agent client - pub(crate) fn new( - max_packet_size: usize, - runtime: R, - auto_split: bool, - agent_address: Vec, - ) -> thrift::Result { - let (buffer, write) = TBufferChannel::with_capacity(max_packet_size).split()?; - let client = agent::AgentSyncClient::new( - TCompactInputProtocol::new(TNoopChannel), - TCompactOutputProtocol::new(write), - ); - - let conn = runtime.create_socket(agent_address.as_slice())?; - - Ok(AgentAsyncClientUdp { - runtime, - conn, - buffer_client: BufferClient { buffer, client }, - max_packet_size, - auto_split, - }) - } - - /// Emit standard Jaeger batch - pub(crate) async fn emit_batch(&mut self, batch: jaeger::Batch) -> thrift::Result<()> { - if !self.auto_split { - let payload = serialize_batch(&mut self.buffer_client, batch, self.max_packet_size)?; - self.runtime.write_to_socket(&self.conn, payload).await?; - return Ok(()); - } - - let mut buffers = vec![]; - serialize_batch_vectored( - &mut self.buffer_client, - batch, - self.max_packet_size, - &mut buffers, - )?; - for payload in buffers { - self.runtime.write_to_socket(&self.conn, payload).await?; - } - - Ok(()) - } -} - -fn serialize_batch( - client: &mut BufferClient, - batch: jaeger::Batch, - max_packet_size: usize, -) -> thrift::Result> { - client.client.emit_batch(batch)?; - let payload = client.buffer.take_bytes(); - - if payload.len() > max_packet_size { - return Err(thrift::ProtocolError::new( - thrift::ProtocolErrorKind::SizeLimit, - format!( - "jaeger exporter payload size of {} bytes over max UDP packet size of {} bytes. Try setting a smaller batch size or turn auto split on.", - payload.len(), - max_packet_size, - ), - ) - .into()); - } - - Ok(payload) -} - -fn serialize_batch_vectored( - client: &mut BufferClient, - mut batch: jaeger::Batch, - max_packet_size: usize, - output: &mut Vec>, -) -> thrift::Result<()> { - client.client.emit_batch(batch.clone())?; - let payload = client.buffer.take_bytes(); - - if payload.len() <= max_packet_size { - output.push(payload); - return Ok(()); - } - - if batch.spans.len() <= 1 { - return Err(thrift::ProtocolError::new( - thrift::ProtocolErrorKind::SizeLimit, - format!( - "single span's jaeger exporter payload size of {} bytes over max UDP packet size of {} bytes", - payload.len(), - max_packet_size, - ), - ) - .into()); - } - - let mid = batch.spans.len() / 2; - let new_spans = batch.spans.drain(mid..).collect::>(); - let new_batch = jaeger::Batch::new(batch.process.clone(), new_spans); - - serialize_batch_vectored(client, batch, max_packet_size, output)?; - serialize_batch_vectored(client, new_batch, max_packet_size, output)?; - - Ok(()) -} diff --git a/opentelemetry-jaeger/src/exporter/collector.rs b/opentelemetry-jaeger/src/exporter/collector.rs deleted file mode 100644 index dc8800d874..0000000000 --- a/opentelemetry-jaeger/src/exporter/collector.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! # HTTP Jaeger Collector Client -//! -#[cfg(feature = "collector_client")] -use http::Uri; -#[cfg(feature = "collector_client")] -use opentelemetry_http::{HttpClient, ResponseExt as _}; - -#[cfg(feature = "collector_client")] -pub(crate) use collector_client::AsyncHttpClient; -#[cfg(feature = "wasm_collector_client")] -pub(crate) use wasm_collector_client::WasmCollector; - -#[cfg(feature = "collector_client")] -mod collector_client { - use super::*; - use crate::exporter::thrift::jaeger; - use opentelemetry_sdk::export::trace::ExportResult; - use std::io::Cursor; - use std::sync::atomic::{AtomicUsize, Ordering}; - use thrift::protocol::TBinaryOutputProtocol; - - /// `AsyncHttpClient` implements an async version of the - /// `TCollectorSyncClient` interface over HTTP - #[derive(Debug)] - pub(crate) struct AsyncHttpClient { - endpoint: Uri, - http_client: Box, - payload_size_estimate: AtomicUsize, - } - - impl AsyncHttpClient { - /// Create a new HTTP collector client - pub(crate) fn new(endpoint: Uri, client: Box) -> Self { - let payload_size_estimate = AtomicUsize::new(512); - - AsyncHttpClient { - endpoint, - http_client: client, - payload_size_estimate, - } - } - - /// Submit list of Jaeger batches - pub(crate) async fn submit_batch(&self, batch: jaeger::Batch) -> ExportResult { - // estimate transport capacity based on last request - let estimate = self.payload_size_estimate.load(Ordering::Relaxed); - - // Write payload to transport buffer - let transport = Cursor::new(Vec::with_capacity(estimate)); - let mut protocol = TBinaryOutputProtocol::new(transport, true); - batch - .write_to_out_protocol(&mut protocol) - .map_err(crate::Error::from)?; - - // Use current batch capacity as new estimate - self.payload_size_estimate - .store(protocol.transport.get_ref().len(), Ordering::Relaxed); - - // Build collector request - let req = http::Request::builder() - .method(http::Method::POST) - .uri(&self.endpoint) - .header("Content-Type", "application/vnd.apache.thrift.binary") - .body(protocol.transport.into_inner()) - .expect("request should always be valid"); - - // Send request to collector - let _ = self.http_client.send(req).await?.error_for_status()?; - Ok(()) - } - } -} - -#[cfg(feature = "wasm_collector_client")] -mod wasm_collector_client { - use crate::exporter::thrift::jaeger; - use base64::engine::general_purpose; - use base64::Engine; - use futures_util::future; - use http::Uri; - use js_sys::Uint8Array; - use pin_project_lite::pin_project; - use std::future::Future; - use std::io::{self, Cursor}; - use std::pin::Pin; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::task::{Context, Poll}; - use thrift::protocol::TBinaryOutputProtocol; - use wasm_bindgen::JsCast; - use wasm_bindgen_futures::JsFuture; - use web_sys::{Request, RequestCredentials, RequestInit, RequestMode, Response}; - - #[derive(Debug)] - pub(crate) struct WasmCollector { - endpoint: Uri, - payload_size_estimate: AtomicUsize, - client: WasmHttpClient, - } - - #[derive(Debug, Default)] - struct WasmHttpClient { - auth: Option, - } - - impl WasmCollector { - /// Create a new HTTP collector client - pub(crate) fn new( - endpoint: Uri, - username: Option, - password: Option, - ) -> thrift::Result { - let auth = if let (Some(username), Some(password)) = (username, password) { - let mut auth = String::from("Basic "); - general_purpose::STANDARD.encode_string(username, &mut auth); - auth.push(':'); - general_purpose::STANDARD.encode_string(password, &mut auth); - Some(auth) - } else { - None - }; - let payload_size_estimate = AtomicUsize::new(512); - - Ok(Self { - endpoint, - client: WasmHttpClient { auth }, - payload_size_estimate, - }) - } - - /// Submit list of Jaeger batches - pub(crate) fn submit_batch( - &self, - batch: jaeger::Batch, - ) -> impl Future> + Send + 'static - { - self.build_request(batch) - .map(post_request) - .map(|fut| future::Either::Left(SubmitBatchFuture { fut })) - .unwrap_or_else(|e| future::Either::Right(future::err(e))) - } - - fn build_request(&self, batch: jaeger::Batch) -> thrift::Result { - // estimate transport capacity based on last request - let estimate = self.payload_size_estimate.load(Ordering::Relaxed); - - // Write payload to transport buffer - let transport = Cursor::new(Vec::with_capacity(estimate)); - let mut protocol = TBinaryOutputProtocol::new(transport, true); - batch.write_to_out_protocol(&mut protocol)?; - - // Use current batch capacity as new estimate - self.payload_size_estimate - .store(protocol.transport.get_ref().len(), Ordering::Relaxed); - - // Build collector request - let mut options = RequestInit::new(); - options.method("POST"); - options.mode(RequestMode::Cors); - - let body: Uint8Array = protocol.transport.get_ref().as_slice().into(); - options.body(Some(body.as_ref())); - - if self.client.auth.is_some() { - options.credentials(RequestCredentials::Include); - } - - let request = Request::new_with_str_and_init(&self.endpoint.to_string(), &options) - .map_err(jsvalue_into_ioerror)?; - let headers = request.headers(); - headers - .set("Content-Type", "application/vnd.apache.thrift.binary") - .map_err(jsvalue_into_ioerror)?; - if let Some(auth) = self.client.auth.as_ref() { - headers - .set("Authorization", auth) - .map_err(jsvalue_into_ioerror)?; - } - - Ok(request) - } - } - - async fn post_request(request: Request) -> thrift::Result { - // Send request to collector - let window = web_sys::window().unwrap(); - let res_value = JsFuture::from(window.fetch_with_request(&request)) - .await - .map_err(jsvalue_into_ioerror)?; - let res: Response = res_value.dyn_into().unwrap(); - - if !res.ok() { - return Err(thrift::Error::from(io::Error::new( - io::ErrorKind::Other, - format!( - "Expected success response, got {} ({})", - res.status(), - res.status_text() - ), - ))); - } - - Ok(jaeger::BatchSubmitResponse { ok: true }) - } - - pin_project! { - /// Wrapper of web fetch API future marked as Send. - /// - /// At the moment, the web APIs are single threaded. Since all opentelemetry futures are - /// required to be Send, we mark this future as Send. - struct SubmitBatchFuture { - #[pin] fut: F - } - } - - unsafe impl Send for SubmitBatchFuture {} - - impl Future for SubmitBatchFuture { - type Output = F::Output; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().fut.poll(cx) - } - } - - fn jsvalue_into_ioerror(value: wasm_bindgen::JsValue) -> io::Error { - io::Error::new( - io::ErrorKind::Other, - js_sys::JSON::stringify(&value) - .map(String::from) - .unwrap_or_else(|_| "unknown error".to_string()), - ) - } -} diff --git a/opentelemetry-jaeger/src/exporter/config/agent.rs b/opentelemetry-jaeger/src/exporter/config/agent.rs deleted file mode 100644 index 1c523307f3..0000000000 --- a/opentelemetry-jaeger/src/exporter/config/agent.rs +++ /dev/null @@ -1,465 +0,0 @@ -use std::borrow::BorrowMut; -use std::net::ToSocketAddrs; -use std::sync::Arc; -use std::{env, net}; - -use opentelemetry::trace::TraceError; -use opentelemetry_sdk::trace::{BatchConfig, Config, TracerProvider}; -use opentelemetry_sdk::trace::{BatchSpanProcessor, Tracer}; - -use crate::exporter::agent::{AgentAsyncClientUdp, AgentSyncClientUdp}; -use crate::exporter::config::{ - build_config_and_process, install_tracer_provider_and_get_tracer, HasRequiredConfig, - TransformationConfig, -}; -use crate::exporter::uploader::{AsyncUploader, SyncUploader, Uploader}; -use crate::{Error, Exporter, JaegerTraceRuntime}; - -/// The max size of UDP packet we want to send, synced with jaeger-agent -const UDP_PACKET_MAX_LENGTH: usize = 65_000; - -/// The hostname for the Jaeger agent. -/// e.g. "localhost" -const ENV_AGENT_HOST: &str = "OTEL_EXPORTER_JAEGER_AGENT_HOST"; - -/// The port for the Jaeger agent. -/// e.g. 6832 -const ENV_AGENT_PORT: &str = "OTEL_EXPORTER_JAEGER_AGENT_PORT"; - -/// Default agent host if none is provided -const DEFAULT_AGENT_ENDPOINT_HOST: &str = "127.0.0.1"; - -/// Default agent port if none is provided -const DEFAULT_AGENT_ENDPOINT_PORT: &str = "6831"; - -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// AgentPipeline config and build a exporter targeting a jaeger agent using UDP as transport layer protocol. -/// -/// ## UDP packet max length -/// The exporter uses UDP to communicate with the agent. UDP requests may be rejected if it's too long. -/// See [UDP packet size] for details. -/// -/// Users can utilise [`with_max_packet_size`] and [`with_auto_split_batch`] to avoid spans loss or UDP requests failure. -/// -/// The default `max_packet_size` is `65000`([why 65000]?). If your platform has a smaller limit on UDP packet. -/// You will need to adjust the `max_packet_size` accordingly. -/// -/// Set `auto_split_batch` to true will config the exporter to split the batch based on `max_packet_size` -/// automatically. Note that it has a performance overhead as every batch could require multiple requests to export. -/// -/// For example, OSX UDP packet limit is 9216 by default. You can configure the pipeline as following -/// to avoid UDP packet breaches the limit. -/// -/// ```no_run -/// # use opentelemetry_sdk::runtime::Tokio; -/// # fn main() { -/// let tracer = opentelemetry_jaeger::new_agent_pipeline() -/// .with_endpoint("localhost:6831") -/// .with_service_name("my_app") -/// .with_max_packet_size(9_216) -/// .with_auto_split_batch(true) -/// .install_batch(Tokio).unwrap(); -/// # } -/// ``` -/// -/// [`with_auto_split_batch`]: AgentPipeline::with_auto_split_batch -/// [`with_max_packet_size`]: AgentPipeline::with_max_packet_size -/// [UDP packet size]: https://stackoverflow.com/questions/1098897/what-is-the-largest-safe-udp-packet-size-on-the-internet -/// [why 65000]: https://serverfault.com/questions/246508/how-is-the-mtu-is-65535-in-udp-but-ethernet-does-not-allow-frame-size-more-than -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -/// -/// ## Environment variables -/// The following environment variables are available to configure the agent exporter. -/// -/// - `OTEL_EXPORTER_JAEGER_AGENT_HOST`, set the host of the agent. If the `OTEL_EXPORTER_JAEGER_AGENT_HOST` -/// is not set, the value will be ignored. -/// - `OTEL_EXPORTER_JAEGER_AGENT_PORT`, set the port of the agent. If the `OTEL_EXPORTER_JAEGER_AGENT_HOST` -/// is not set, the exporter will use 127.0.0.1 as the host. -#[derive(Debug)] -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub struct AgentPipeline { - transformation_config: TransformationConfig, - trace_config: Option, - batch_config: Option, - agent_endpoint: Option, - max_packet_size: usize, - auto_split_batch: bool, -} - -impl Default for AgentPipeline { - fn default() -> Self { - AgentPipeline { - transformation_config: Default::default(), - trace_config: Default::default(), - batch_config: Some(Default::default()), - agent_endpoint: Some(format!( - "{DEFAULT_AGENT_ENDPOINT_HOST}:{DEFAULT_AGENT_ENDPOINT_PORT}" - )), - max_packet_size: UDP_PACKET_MAX_LENGTH, - auto_split_batch: false, - } - } -} - -// implement the seal trait -impl HasRequiredConfig for AgentPipeline { - fn set_transformation_config(&mut self, f: T) - where - T: FnOnce(&mut TransformationConfig), - { - f(self.transformation_config.borrow_mut()) - } - - fn set_trace_config(&mut self, config: Config) { - self.trace_config = Some(config) - } - - fn set_batch_config(&mut self, config: BatchConfig) { - self.batch_config = Some(config) - } -} - -/// Start a new pipeline to configure a exporter that target a jaeger agent. -/// -/// See details for each configurations at [`AgentPipeline`] -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [`AgentPipeline`]: crate::config::agent::AgentPipeline -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub fn new_agent_pipeline() -> AgentPipeline { - AgentPipeline::default() -} - -impl AgentPipeline { - /// set the endpoint of the agent. - /// - /// It usually composed by host ip and the port number. - /// Any valid socket address can be used. - /// - /// Default to be `127.0.0.1:6831`. - pub fn with_endpoint>(self, agent_endpoint: T) -> Self { - AgentPipeline { - agent_endpoint: Some(agent_endpoint.into()), - ..self - } - } - - /// Assign the max packet size in bytes. - /// - /// It should be consistent with the limit of platforms. Otherwise, UDP requests maybe reject with - /// error like `thrift agent failed with transport error` or `thrift agent failed with message too long`. - /// - /// The exporter will cut off spans if the batch is long. To avoid this, set [auto_split_batch](AgentPipeline::with_auto_split_batch) to `true` - /// to split a batch into multiple UDP packets. - /// - /// Default to be `65000`. - pub fn with_max_packet_size(self, max_packet_size: usize) -> Self { - AgentPipeline { - max_packet_size, - ..self - } - } - - /// Config whether to auto split batches. - /// - /// When auto split is set to `true`, the exporter will try to split the - /// batch into smaller ones so that there will be minimal data loss. It - /// will impact the performance. - /// - /// Note that if the length of one serialized span is longer than the `max_packet_size`. - /// The exporter will return an error as it cannot export the span. Use jaeger collector - /// instead of jaeger agent may be help in this case as the exporter will use HTTP to communicate - /// with jaeger collector. - /// - /// Default to be `false`. - pub fn with_auto_split_batch(mut self, should_auto_split: bool) -> Self { - self.auto_split_batch = should_auto_split; - self - } - - /// Set the service name of the application. It generally is the name of application. - /// Critically, Jaeger backend depends on `Span.Process.ServiceName` to identify the service - /// that produced the spans. - /// - /// Opentelemetry allows set the service name using multiple methods. - /// This functions takes priority over all other methods. - /// - /// If the service name is not set. It will default to be `unknown_service`. - pub fn with_service_name>(mut self, service_name: T) -> Self { - self.set_transformation_config(|config| { - config.service_name = Some(service_name.into()); - }); - self - } - - /// Config whether to export information of instrumentation library. - /// - /// It's required to [report instrumentation library as span tags]. - /// However it does have a overhead on performance, performance sensitive applications can - /// use this function to opt out reporting instrumentation library. - /// - /// Default to be `true`. - /// - /// [report instrumentation library as span tags]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/non-otlp.md#instrumentationscope - pub fn with_instrumentation_library_tags(mut self, should_export: bool) -> Self { - self.set_transformation_config(|config| { - config.export_instrument_library = should_export; - }); - self - } - - /// Assign the opentelemetry SDK configurations for the exporter pipeline. - /// - /// For mapping between opentelemetry configurations and Jaeger spans. Please refer [the spec]. - /// - /// [the spec]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#mappings - /// # Examples - /// Set service name via resource. - /// ```rust - /// use opentelemetry::KeyValue; - /// use opentelemetry_sdk::{Resource, trace::Config}; - /// - /// let pipeline = opentelemetry_jaeger::new_agent_pipeline() - /// .with_trace_config( - /// Config::default() - /// .with_resource(Resource::new(vec![KeyValue::new("service.name", "my-service")])) - /// ); - /// - /// ``` - pub fn with_trace_config(mut self, config: Config) -> Self { - self.set_trace_config(config); - self - } - - /// Assign the batch span processor for the exporter pipeline. - /// - /// If a simple span processor is used by [`install_simple`][AgentPipeline::install_simple] - /// or [`build_simple`][AgentPipeline::install_simple], then this config will not be ignored. - /// - /// # Examples - /// Set max queue size. - /// ```rust - /// use opentelemetry_sdk::trace::BatchConfigBuilder; - /// - /// let pipeline = opentelemetry_jaeger::new_agent_pipeline() - /// .with_batch_processor_config( - /// BatchConfigBuilder::default() - /// .with_max_queue_size(200) - /// .build() - /// ); - /// - /// ``` - pub fn with_batch_processor_config(mut self, config: BatchConfig) -> Self { - self.set_batch_config(config); - self - } - - /// Build a `TracerProvider` using a blocking exporter and configurations from the pipeline. - /// - /// The exporter will send each span to the agent upon the span ends. - pub fn build_simple(mut self) -> Result { - let mut builder = TracerProvider::builder(); - - let (config, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - let exporter = Exporter::new( - process.into(), - self.transformation_config.export_instrument_library, - self.build_sync_agent_uploader()?, - ); - - builder = builder.with_simple_exporter(exporter); - builder = builder.with_config(config); - - Ok(builder.build()) - } - - /// Build a `TracerProvider` using a async exporter and configurations from the pipeline. - /// - /// The exporter will collect spans in a batch and send them to the agent. - /// - /// It's possible to lose spans up to a batch when the application shuts down. So users should - /// use [`shut_down_tracer_provider`] to block the shut down process until - /// all remaining spans have been sent. - /// - /// Commonly used runtime are provided via `rt-tokio`, `rt-tokio-current-thread`, `rt-async-std` - /// features. - /// - /// [`shut_down_tracer_provider`]: opentelemetry::global::shutdown_tracer_provider - pub fn build_batch(mut self, runtime: R) -> Result - where - R: JaegerTraceRuntime, - { - let mut builder = TracerProvider::builder(); - - let export_instrument_library = self.transformation_config.export_instrument_library; - // build sdk trace config and jaeger process. - // some attributes like service name has attributes like service name - let (config, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - let batch_config = self.batch_config.take(); - let uploader = self.build_async_agent_uploader(runtime.clone())?; - let exporter = Exporter::new(process.into(), export_instrument_library, uploader); - let batch_processor = BatchSpanProcessor::builder(exporter, runtime) - .with_batch_config(batch_config.unwrap_or_default()) - .build(); - - builder = builder.with_span_processor(batch_processor); - builder = builder.with_config(config); - - Ok(builder.build()) - } - - /// Similar to [`build_simple`][AgentPipeline::build_simple] but also returns a tracer from the - /// tracer provider. - /// - /// The tracer name is `opentelemetry-jaeger`. The tracer version will be the version of this crate. - pub fn install_simple(self) -> Result { - let tracer_provider = self.build_simple()?; - install_tracer_provider_and_get_tracer(tracer_provider) - } - - /// Similar to [`build_batch`][AgentPipeline::build_batch] but also returns a tracer from the - /// tracer provider. - /// - /// The tracer name is `opentelemetry-jaeger`. The tracer version will be the version of this crate. - pub fn install_batch(self, runtime: R) -> Result - where - R: JaegerTraceRuntime, - { - let tracer_provider = self.build_batch(runtime)?; - install_tracer_provider_and_get_tracer(tracer_provider) - } - - /// Build an jaeger exporter targeting a jaeger agent and running on the async runtime. - pub fn build_async_agent_exporter( - mut self, - runtime: R, - ) -> Result - where - R: JaegerTraceRuntime, - { - let export_instrument_library = self.transformation_config.export_instrument_library; - // build sdk trace config and jaeger process. - // some attributes like service name has attributes like service name - let (_, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - let uploader = self.build_async_agent_uploader(runtime)?; - Ok(Exporter::new( - process.into(), - export_instrument_library, - uploader, - )) - } - - /// Build an jaeger exporter targeting a jaeger agent and running on the sync runtime. - pub fn build_sync_agent_exporter(mut self) -> Result { - let (_, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - Ok(Exporter::new( - process.into(), - self.transformation_config.export_instrument_library, - self.build_sync_agent_uploader()?, - )) - } - - fn build_async_agent_uploader(self, runtime: R) -> Result, TraceError> - where - R: JaegerTraceRuntime, - { - let agent = AgentAsyncClientUdp::new( - self.max_packet_size, - runtime, - self.auto_split_batch, - self.resolve_endpoint()?, - ) - .map_err::(Into::into)?; - Ok(Arc::new(AsyncUploader::Agent( - futures_util::lock::Mutex::new(agent), - ))) - } - - fn build_sync_agent_uploader(self) -> Result, TraceError> { - let agent = AgentSyncClientUdp::new( - self.max_packet_size, - self.auto_split_batch, - self.resolve_endpoint()?, - ) - .map_err::(Into::into)?; - Ok(Arc::new(SyncUploader::Agent(std::sync::Mutex::new(agent)))) - } - - // resolve the agent endpoint from the environment variables or the builder - // if only one of the environment variables is set, the other one will be set to the default value - // if no environment variable is set, the builder value will be used. - fn resolve_endpoint(self) -> Result, TraceError> { - let endpoint_str = match (env::var(ENV_AGENT_HOST), env::var(ENV_AGENT_PORT)) { - (Ok(host), Ok(port)) => format!("{}:{}", host.trim(), port.trim()), - (Ok(host), _) => format!("{}:{DEFAULT_AGENT_ENDPOINT_PORT}", host.trim()), - (_, Ok(port)) => format!("{DEFAULT_AGENT_ENDPOINT_HOST}:{}", port.trim()), - (_, _) => self.agent_endpoint.unwrap_or(format!( - "{DEFAULT_AGENT_ENDPOINT_HOST}:{DEFAULT_AGENT_ENDPOINT_PORT}" - )), - }; - endpoint_str - .to_socket_addrs() - .map(|addrs| addrs.collect()) - .map_err(|io_err| { - Error::ConfigError { - pipeline_name: "agent", - config_name: "endpoint", - reason: io_err.to_string(), - } - .into() - }) - } -} - -#[cfg(test)] -mod tests { - use crate::config::agent::AgentPipeline; - - #[test] - fn set_socket_address() { - let test_cases = vec![ - // invalid inputs - ("invalid_endpoint", false), - ("0.0.0.0.0:9123", false), - ("127.0.0.1", false), // port is needed - // valid inputs - ("[::0]:9123", true), - ("127.0.0.1:1001", true), - ]; - for (socket_str, is_ok) in test_cases.into_iter() { - let resolved_endpoint = AgentPipeline::default() - .with_endpoint(socket_str) - .resolve_endpoint(); - assert_eq!( - resolved_endpoint.is_ok(), - // if is_ok is true, use socket_str, otherwise use the default endpoint - is_ok, - "endpoint string {}", - socket_str - ); - } - } -} diff --git a/opentelemetry-jaeger/src/exporter/config/collector/http_client.rs b/opentelemetry-jaeger/src/exporter/config/collector/http_client.rs deleted file mode 100644 index 69bafcc985..0000000000 --- a/opentelemetry-jaeger/src/exporter/config/collector/http_client.rs +++ /dev/null @@ -1,192 +0,0 @@ -use opentelemetry_http::HttpClient; -use std::time::Duration; - -#[derive(Debug)] -pub(crate) enum CollectorHttpClient { - None, - Custom(Box), - #[cfg(feature = "hyper_collector_client")] - Hyper, - #[cfg(feature = "isahc_collector_client")] - Isahc, - #[cfg(feature = "reqwest_collector_client")] - Reqwest, - #[cfg(feature = "reqwest_blocking_collector_client")] - ReqwestBlocking, -} - -impl CollectorHttpClient { - // try to build a build in http client if users chose one. If none available return NoHttpClient error - #[allow(unused_variables)] // if the user enabled no build in client features. all parameters are unused. - pub(crate) fn build_client( - self, - collector_username: Option, - collector_password: Option, - collector_timeout: Duration, - ) -> Result, crate::Error> { - match self { - CollectorHttpClient::Custom(client) => Ok(client), - CollectorHttpClient::None => Err(crate::Error::ConfigError { - pipeline_name: "http_client", - config_name: "collector", - reason: - "No http client provided. Consider enable one of the `hyper_collector_client`, `surf_collector_client`, \ - `reqwest_collector_client`, `reqwest_blocking_collector_client`, `isahc_collector_client` \ - features to use a build in http client. Or use `with_http_client` method in pipeline to \ - provide your own implementation." - .to_string(), - }), - #[cfg(feature = "isahc_collector_client")] - CollectorHttpClient::Isahc => { - use isahc::config::Configurable; - - let mut builder = isahc::HttpClient::builder().timeout(collector_timeout); - - if let (Some(username), Some(password)) = (collector_username, collector_password) { - builder = builder - .authentication(isahc::auth::Authentication::basic()) - .credentials(isahc::auth::Credentials::new(username, password)); - } - - let client = builder.build().map_err(|err| crate::Error::ConfigError { - config_name: "http_client", - pipeline_name: "collector", - reason: format!("cannot create isahc http client, {}", err), - })?; - Ok(Box::new(client)) - } - #[cfg(feature = "reqwest_blocking_collector_client")] - CollectorHttpClient::ReqwestBlocking => { - use headers::authorization::Credentials; - - let mut builder = - reqwest::blocking::ClientBuilder::new().timeout(collector_timeout); - if let (Some(username), Some(password)) = (collector_username, collector_password) { - let mut map = http::HeaderMap::with_capacity(1); - let auth_header_val = - headers::Authorization::basic(username.as_str(), password.as_str()); - map.insert(http::header::AUTHORIZATION, auth_header_val.0.encode()); - builder = builder.default_headers(map); - } - let client = builder.build().map_err::(|err| { - crate::Error::ConfigError { - pipeline_name: "http_client", - config_name: "collector", - reason: format!("cannot create reqwest blocking http client, {}", err), - } - })?; - Ok(Box::new(client)) - } - #[cfg(feature = "reqwest_collector_client")] - CollectorHttpClient::Reqwest => { - use headers::authorization::Credentials; - - let mut builder = reqwest::ClientBuilder::new().timeout(collector_timeout); - if let (Some(username), Some(password)) = (collector_username, collector_password) { - let mut map = http::HeaderMap::with_capacity(1); - let auth_header_val = - headers::Authorization::basic(username.as_str(), password.as_str()); - map.insert(http::header::AUTHORIZATION, auth_header_val.0.encode()); - builder = builder.default_headers(map); - } - let client = builder.build().map_err::(|err| { - crate::Error::ConfigError { - pipeline_name: "http_client", - config_name: "collector", - reason: format!("cannot create reqwest http client, {}", err), - } - })?; - Ok(Box::new(client)) - } - #[cfg(any(feature = "hyper_collector_client", feature = "hyper_tls_collector_client"))] - CollectorHttpClient::Hyper => { - use headers::authorization::Credentials; - use opentelemetry_http::hyper::HyperClient; - use hyper::{Client, Body}; - - #[cfg(feature = "hyper_tls_collector_client")] - let inner: Client<_, Body> = Client::builder().build(hyper_tls::HttpsConnector::new()); - #[cfg(feature = "hyper_collector_client")] - let inner: Client<_, Body> = Client::new(); - - let client = if let (Some(username), Some(password)) = - (collector_username, collector_password) - { - let auth_header_val = - headers::Authorization::basic(username.as_str(), password.as_str()); - HyperClient::new_with_timeout_and_authorization_header( - inner, - collector_timeout, - auth_header_val.0.encode(), - ) - } else { - HyperClient::new_with_timeout(inner, collector_timeout) - }; - Ok(Box::new(client)) - } - } - } -} - -#[cfg(test)] -#[cfg(feature = "rt-tokio")] -pub(crate) mod test_http_client { - use async_trait::async_trait; - use bytes::Bytes; - use http::{Request, Response}; - use opentelemetry_http::{HttpClient, HttpError}; - use std::fmt::Debug; - - pub(crate) struct TestHttpClient; - - impl Debug for TestHttpClient { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("test http client") - } - } - - #[async_trait] - impl HttpClient for TestHttpClient { - async fn send(&self, _request: Request>) -> Result, HttpError> { - Err("wrong uri set in http client".into()) - } - } -} - -#[cfg(test)] -#[cfg(all(feature = "collector_client", feature = "rt-tokio"))] -mod collector_client_tests { - use crate::config::build_config_and_process; - use crate::config::collector::http_client::test_http_client; - use crate::exporter::thrift::jaeger::Batch; - use crate::new_collector_pipeline; - use opentelemetry::trace::TraceError; - use opentelemetry_sdk::runtime::Tokio; - - // Ignore this test as it is flaky and the opentelemetry-jaeger is on-track for deprecation - #[ignore] - #[test] - fn test_bring_your_own_client() -> Result<(), TraceError> { - let invalid_uri_builder = new_collector_pipeline() - .with_endpoint("localhost:6831") - .with_http_client(test_http_client::TestHttpClient); - let (_, process) = build_config_and_process(None, None); - let uploader = invalid_uri_builder.build_uploader::()?; - let res = futures_executor::block_on(async { - uploader - .upload(Batch::new(process.into(), Vec::new())) - .await - }); - assert_eq!( - format!("{:?}", res.err().unwrap()), - "Other(\"wrong uri set in http client\")" - ); - - let valid_uri_builder = new_collector_pipeline() - .with_http_client(test_http_client::TestHttpClient) - .build_uploader::(); - - assert!(valid_uri_builder.is_ok()); - Ok(()) - } -} diff --git a/opentelemetry-jaeger/src/exporter/config/collector/mod.rs b/opentelemetry-jaeger/src/exporter/config/collector/mod.rs deleted file mode 100644 index 9400beadf2..0000000000 --- a/opentelemetry-jaeger/src/exporter/config/collector/mod.rs +++ /dev/null @@ -1,706 +0,0 @@ -use std::borrow::BorrowMut; -use std::env; -use std::sync::Arc; -#[cfg(feature = "collector_client")] -use std::time::Duration; - -use http::Uri; - -use opentelemetry::trace::TraceError; -#[cfg(feature = "collector_client")] -use opentelemetry_http::HttpClient; -use opentelemetry_sdk::trace::{BatchConfig, BatchSpanProcessor, Config, Tracer, TracerProvider}; - -#[cfg(feature = "collector_client")] -use crate::config::collector::http_client::CollectorHttpClient; -#[cfg(feature = "collector_client")] -use crate::exporter::collector::AsyncHttpClient; -#[cfg(feature = "wasm_collector_client")] -use crate::exporter::collector::WasmCollector; -use crate::exporter::config::{ - build_config_and_process, install_tracer_provider_and_get_tracer, HasRequiredConfig, - TransformationConfig, -}; -use crate::exporter::uploader::{AsyncUploader, Uploader}; -use crate::{Exporter, JaegerTraceRuntime}; - -#[cfg(feature = "collector_client")] -mod http_client; - -/// HTTP endpoint for Jaeger collector. -/// e.g. "http://localhost:14250" -const ENV_ENDPOINT: &str = "OTEL_EXPORTER_JAEGER_ENDPOINT"; - -const DEFAULT_ENDPOINT: &str = "http://localhost:14250/api/trace"; - -/// Timeout for Jaeger collector. -#[cfg(feature = "collector_client")] -const ENV_TIMEOUT: &str = "OTEL_EXPORTER_JAEGER_TIMEOUT"; - -/// Default of 10s -#[cfg(feature = "collector_client")] -const DEFAULT_COLLECTOR_TIMEOUT: Duration = Duration::from_secs(10); - -/// Username to send as part of "Basic" authentication to the collector endpoint. -const ENV_USERNAME: &str = "OTEL_EXPORTER_JAEGER_USER"; - -/// Password to send as part of "Basic" authentication to the collector endpoint. -const ENV_PASSWORD: &str = "OTEL_EXPORTER_JAEGER_PASSWORD"; - -/// CollectorPipeline config and build a exporter targeting a jaeger collector using HTTP protocol. -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// ## Environment variables -/// -/// - `OTEL_EXPORTER_JAEGER_ENDPOINT`: set the endpoint of the collector. Usually starts with `http://` or `https://` -/// -/// - `OTEL_EXPORTER_JAEGER_TIMEOUT`: set the timeout of the http client timeout. It only applies to build in http clients. -/// -/// - `OTEL_EXPORTER_JAEGER_USER`: set the username. Part of the authentication for the collector. It only applies to build in http clients. -/// -/// - `OTEL_EXPORTER_JAEGER_PASSWORD`: set the password. Part of the authentication for the collector. It only applies to build in http clients. -/// -/// ## Built-in http clients -/// To help user setup the exporter, `opentelemetry-jaeger` provides the following build in http client -/// implementation and relative configurations. -/// -/// - [hyper], requires `hyper_collector_client` feature enabled, use [`with_hyper`][CollectorPipeline::with_hyper] function to setup. -/// - [isahc], requires `isahc_collector_client` feature enabled, use [`with_isahc`][CollectorPipeline::with_isahc] function to setup. -/// - [reqwest], requires `reqwest_collector_client` feature enabled, use [`with_reqwest`][CollectorPipeline::with_reqwest] function to setup. -/// - [reqwest blocking client], requires `reqwest_blocking_collector_client` feature enabled, use [`with_reqwest_blocking`][CollectorPipeline::with_reqwest_blocking] function to setup. -/// -/// Additionally you can enable https -/// -/// Note that the functions to setup build in http clients override each other. That means if you have a pipeline with the following setup -/// -/// ```no_run -/// # use opentelemetry::trace::TraceError; -/// # #[cfg(all(feature="reqwest_collector_client", feature="surf_collector_client"))] -/// let tracer = opentelemetry_jaeger::new_collector_pipeline() -/// .with_surf() -/// .with_reqwest() -/// .install_batch(opentelemetry_sdk::runtime::Tokio) -/// # .unwrap(); -/// ``` -/// -/// The pipeline will use [reqwest] http client. -/// -/// [reqwest]: reqwest::Client -/// [reqwest blocking client]: reqwest::blocking::Client -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[derive(Debug)] -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub struct CollectorPipeline { - transformation_config: TransformationConfig, - trace_config: Option, - batch_config: Option, - - #[cfg(feature = "collector_client")] - collector_timeout: Duration, - // only used by builtin http clients. - collector_endpoint: Option, - collector_username: Option, - collector_password: Option, - - client_config: ClientConfig, -} - -impl Default for CollectorPipeline { - fn default() -> Self { - Self { - #[cfg(feature = "collector_client")] - collector_timeout: DEFAULT_COLLECTOR_TIMEOUT, - collector_endpoint: None, - collector_username: None, - collector_password: None, - client_config: ClientConfig::default(), - transformation_config: Default::default(), - trace_config: Default::default(), - batch_config: Some(Default::default()), - } - } -} - -// implement the seal trait -impl HasRequiredConfig for CollectorPipeline { - fn set_transformation_config(&mut self, f: T) - where - T: FnOnce(&mut TransformationConfig), - { - f(self.transformation_config.borrow_mut()) - } - - fn set_trace_config(&mut self, config: Config) { - self.trace_config = Some(config) - } - - fn set_batch_config(&mut self, config: BatchConfig) { - self.batch_config = Some(config) - } -} - -#[derive(Debug)] -enum ClientConfig { - #[cfg(feature = "collector_client")] - Http { client_type: CollectorHttpClient }, - #[cfg(feature = "wasm_collector_client")] - Wasm, // no config is available for wasm for now. But we can add in the future -} - -#[allow(clippy::derivable_impls)] -impl Default for ClientConfig { - fn default() -> Self { - // as long as collector is enabled, we will in favor of it - #[cfg(feature = "collector_client")] - { - ClientConfig::Http { - client_type: CollectorHttpClient::None, - } - } - // when collector_client is disabled and wasm_collector_client is enabled - #[cfg(not(feature = "collector_client"))] - ClientConfig::Wasm - } -} - -/// Start a new pipeline to configure a exporter that target a jaeger collector. -/// -/// See details for each configurations at [`CollectorPipeline`]. -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [`CollectorPipeline`]: crate::config::collector::CollectorPipeline -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[cfg(feature = "collector_client")] -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub fn new_collector_pipeline() -> CollectorPipeline { - CollectorPipeline::default() -} - -/// Similar to [`new_collector_pipeline`] but the exporter is configured to run with wasm. -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[cfg(feature = "wasm_collector_client")] -#[allow(clippy::field_reassign_with_default)] -// make sure when collector_cilent and wasm_collector_client are both set. We will create a wasm type client -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub fn new_wasm_collector_pipeline() -> CollectorPipeline { - let mut pipeline = CollectorPipeline::default(); - pipeline.client_config = ClientConfig::Wasm; - pipeline -} - -impl CollectorPipeline { - /// Set the http client timeout. - /// - /// This function only applies to build in http clients. - /// - /// Default to be 10s. - #[cfg(feature = "collector_client")] - pub fn with_timeout(self, collector_timeout: Duration) -> Self { - Self { - collector_timeout, - ..self - } - } - - /// Set the collector endpoint. - /// - /// E.g. "http://localhost:14268/api/traces" - pub fn with_endpoint>(self, collector_endpoint: T) -> Self { - Self { - collector_endpoint: Some(collector_endpoint.into()), - ..self - } - } - - /// Set the username used in authentication to communicate with the collector. - /// - /// *Note* that if the password is not set by calling `with_password` or set `OTEL_EXPORTER_JAEGER_PASSWORD` - /// environment variables. The username will be ignored. - /// - /// This function only applies to build in http clients. - pub fn with_username>(self, collector_username: S) -> Self { - Self { - collector_username: Some(collector_username.into()), - ..self - } - } - - /// Set the password used in authentication to communicate with the collector. - /// - /// *Note* that if the username is not set by calling `with_username` or set `OTEL_EXPORTER_JAEGER_USER` - /// environment variables. The username will be ignored. - /// - /// This function only applies to build in http clients. - pub fn with_password>(self, collector_password: S) -> Self { - Self { - collector_password: Some(collector_password.into()), - ..self - } - } - - /// Get collector's username set in the builder. Default to be the value of - /// `OTEL_EXPORTER_JAEGER_USER` environment variable. - /// - /// If users uses custom http client. This function can help retrieve the value of - /// `OTEL_EXPORTER_JAEGER_USER` environment variable. - pub fn collector_username(&self) -> Option { - self.collector_username.clone() - } - - /// Get the collector's password set in the builder. Default to be the value of - /// `OTEL_EXPORTER_JAEGER_PASSWORD` environment variable. - /// - /// If users uses custom http client. This function can help retrieve the value of - /// `OTEL_EXPORTER_JAEGER_PASSWORD` environment variable. - pub fn collector_password(&self) -> Option { - self.collector_password.clone() - } - - /// Custom http client used to send spans. - /// - /// **Note** that all configuration other than the [`endpoint`][CollectorPipeline::with_endpoint] are not - /// applicable to custom clients. - #[cfg(feature = "collector_client")] - pub fn with_http_client(mut self, client: T) -> Self { - self.client_config = match self.client_config { - ClientConfig::Http { .. } => ClientConfig::Http { - client_type: CollectorHttpClient::Custom(Box::new(client)), - }, - // noop for wasm - #[cfg(feature = "wasm_collector_client")] - ClientConfig::Wasm => ClientConfig::Wasm, - }; - self - } - - /// Use isahc http client in the exporter. - #[cfg(feature = "isahc_collector_client")] - pub fn with_isahc(self) -> Self { - Self { - client_config: ClientConfig::Http { - client_type: CollectorHttpClient::Isahc, - }, - ..self - } - } - - /// Use reqwest http client in the exporter. - #[cfg(feature = "reqwest_collector_client")] - pub fn with_reqwest(self) -> Self { - Self { - client_config: ClientConfig::Http { - client_type: CollectorHttpClient::Reqwest, - }, - ..self - } - } - - /// Use reqwest blocking http client in the exporter. - #[cfg(feature = "reqwest_blocking_collector_client")] - pub fn with_reqwest_blocking(self) -> Self { - Self { - client_config: ClientConfig::Http { - client_type: CollectorHttpClient::ReqwestBlocking, - }, - ..self - } - } - - /// Use hyper http client in the exporter. - #[cfg(feature = "hyper_collector_client")] - pub fn with_hyper(self) -> Self { - Self { - client_config: ClientConfig::Http { - client_type: CollectorHttpClient::Hyper, - }, - ..self - } - } - - /// Set the service name of the application. It generally is the name of application. - /// Critically, Jaeger backend depends on `Span.Process.ServiceName` to identify the service - /// that produced the spans. - /// - /// Opentelemetry allows set the service name using multiple methods. - /// This functions takes priority over all other methods. - /// - /// If the service name is not set. It will default to be `unknown_service`. - pub fn with_service_name>(mut self, service_name: T) -> Self { - self.set_transformation_config(|config| { - config.service_name = Some(service_name.into()); - }); - self - } - - /// Config whether to export information of instrumentation library. - /// - /// It's required to [report instrumentation library as span tags]. - /// However it does have a overhead on performance, performance sensitive applications can - /// use this function to opt out reporting instrumentation library. - /// - /// Default to be `true`. - /// - /// [report instrumentation library as span tags]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/non-otlp.md#instrumentationscope - pub fn with_instrumentation_library_tags(mut self, should_export: bool) -> Self { - self.set_transformation_config(|config| { - config.export_instrument_library = should_export; - }); - self - } - - /// Assign the opentelemetry SDK configurations for the exporter pipeline. - /// - /// For mapping between opentelemetry configurations and Jaeger spans. Please refer [the spec]. - /// - /// [the spec]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#mappings - /// # Examples - /// Set service name via resource. - /// ```rust - /// use opentelemetry::KeyValue; - /// use opentelemetry_sdk::{Resource, trace::Config}; - /// - /// let pipeline = opentelemetry_jaeger::new_collector_pipeline() - /// .with_trace_config( - /// Config::default() - /// .with_resource(Resource::new(vec![KeyValue::new("service.name", "my-service")])) - /// ); - /// - /// ``` - pub fn with_trace_config(mut self, config: Config) -> Self { - self.set_trace_config(config); - self - } - - /// Assign the batch span processor for the exporter pipeline. - /// - /// # Examples - /// Set max queue size. - /// ```rust - /// use opentelemetry_sdk::trace::BatchConfigBuilder; - /// - /// let pipeline = opentelemetry_jaeger::new_collector_pipeline() - /// .with_batch_processor_config( - /// BatchConfigBuilder::default() - /// .with_max_queue_size(200) - /// .build() - /// ); - /// - /// ``` - pub fn with_batch_processor_config(mut self, config: BatchConfig) -> Self { - self.set_batch_config(config); - self - } - - /// Build a `TracerProvider` using a async exporter and configurations from the pipeline. - /// - /// The exporter will collect spans in a batch and send them to the agent. - /// - /// It's possible to lose spans up to a batch when the application shuts down. So users should - /// use [`shut_down_tracer_provider`] to block the shut down process until - /// all remaining spans have been sent. - /// - /// Commonly used runtime are provided via `rt-tokio`, `rt-tokio-current-thread`, `rt-async-std` - /// features. - /// - /// [`shut_down_tracer_provider`]: opentelemetry::global::shutdown_tracer_provider - // todo: we don't need JaegerTraceRuntime, we only need otel runtime - pub fn build_batch( - mut self, - runtime: R, - ) -> Result { - let mut builder = TracerProvider::builder(); - // build sdk trace config and jaeger process. - // some attributes like service name has attributes like service name - let export_instrument_library = self.transformation_config.export_instrument_library; - let (config, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - let batch_config = self.batch_config.take(); - let uploader = self.build_uploader::()?; - let exporter = Exporter::new(process.into(), export_instrument_library, uploader); - let batch_processor = BatchSpanProcessor::builder(exporter, runtime) - .with_batch_config(batch_config.unwrap_or_default()) - .build(); - - builder = builder.with_span_processor(batch_processor); - builder = builder.with_config(config); - - Ok(builder.build()) - } - - /// Similar to [`build_batch`][CollectorPipeline::build_batch] but also returns a tracer from the - /// tracer provider. - /// - /// The tracer name is `opentelemetry-jaeger`. The tracer version will be the version of this crate. - pub fn install_batch(self, runtime: R) -> Result { - let tracer_provider = self.build_batch(runtime)?; - install_tracer_provider_and_get_tracer(tracer_provider) - } - - /// Build an jaeger exporter targeting a jaeger collector. - pub fn build_collector_exporter(mut self) -> Result - where - R: JaegerTraceRuntime, - { - let export_instrument_library = self.transformation_config.export_instrument_library; - let (_, process) = build_config_and_process( - self.trace_config.take(), - self.transformation_config.service_name.take(), - ); - let uploader = self.build_uploader::()?; - let exporter = Exporter::new(process.into(), export_instrument_library, uploader); - Ok(exporter) - } - - fn build_uploader(self) -> Result, crate::Error> - where - R: JaegerTraceRuntime, - { - let endpoint = self.resolve_endpoint()?; - let username = self.resolve_username(); - let password = self.resolve_password(); - #[cfg(feature = "collector_client")] - let timeout = self.resolve_timeout(); - match self.client_config { - #[cfg(feature = "collector_client")] - ClientConfig::Http { client_type } => { - let client = client_type.build_client(username, password, timeout)?; - - let collector = AsyncHttpClient::new(endpoint, client); - Ok(Arc::new(AsyncUploader::::Collector(collector))) - } - #[cfg(feature = "wasm_collector_client")] - ClientConfig::Wasm => { - let collector = WasmCollector::new(endpoint, username, password) - .map_err::(Into::into)?; - Ok(Arc::new(AsyncUploader::::WasmCollector(collector))) - } - } - } - - fn resolve_env_var(env_var: &'static str) -> Option { - env::var(env_var).ok().filter(|var| !var.is_empty()) - } - - // if provided value from environment variable or the builder is invalid, return error - fn resolve_endpoint(&self) -> Result { - let endpoint_from_env = Self::resolve_env_var(ENV_ENDPOINT) - .map(|endpoint| { - Uri::try_from(endpoint.as_str()).map_err::(|err| { - crate::Error::ConfigError { - pipeline_name: "collector", - config_name: "collector_endpoint", - reason: format!("invalid uri from environment variable, {}", err), - } - }) - }) - .transpose()?; - - Ok(match endpoint_from_env { - Some(endpoint) => endpoint, - None => { - if let Some(endpoint) = &self.collector_endpoint { - Uri::try_from(endpoint.as_str()).map_err::(|err| { - crate::Error::ConfigError { - pipeline_name: "collector", - config_name: "collector_endpoint", - reason: format!("invalid uri from the builder, {}", err), - } - })? - } else { - Uri::try_from(DEFAULT_ENDPOINT).unwrap() // default endpoint should always valid - } - } - }) - } - - #[cfg(feature = "collector_client")] - fn resolve_timeout(&self) -> Duration { - match Self::resolve_env_var(ENV_TIMEOUT) { - Some(timeout) => match timeout.parse() { - Ok(timeout) => Duration::from_millis(timeout), - Err(e) => { - eprintln!("{} malformed default to 10s: {}", ENV_TIMEOUT, e); - self.collector_timeout - } - }, - None => self.collector_timeout, - } - } - - fn resolve_username(&self) -> Option { - Self::resolve_env_var(ENV_USERNAME).or_else(|| self.collector_username.clone()) - } - - fn resolve_password(&self) -> Option { - Self::resolve_env_var(ENV_PASSWORD).or_else(|| self.collector_password.clone()) - } -} - -#[cfg(test)] -#[cfg(feature = "rt-tokio")] -mod tests { - use super::*; - - #[test] - fn test_resolve_endpoint() { - struct TestCase<'a> { - description: &'a str, - env_var: &'a str, - builder_endpoint: Option<&'a str>, - expected_result: Result, - } - let test_cases = vec![ - TestCase { - description: "Positive: Endpoint from environment variable exists", - env_var: "http://example.com", - builder_endpoint: None, - expected_result: Ok(Uri::try_from("http://example.com").unwrap()), - }, - TestCase { - description: "Positive: Endpoint from builder", - env_var: "", - builder_endpoint: Some("http://example.com"), - expected_result: Ok(Uri::try_from("http://example.com").unwrap()), - }, - TestCase { - description: "Negative: Invalid URI from environment variable", - env_var: "invalid random uri", - builder_endpoint: None, - expected_result: Err(crate::Error::ConfigError { - pipeline_name: "collector", - config_name: "collector_endpoint", - reason: "invalid uri from environment variable, invalid uri character" - .to_string(), - }), - }, - TestCase { - description: "Negative: Invalid URI from builder", - env_var: "", - builder_endpoint: Some("invalid random uri"), - expected_result: Err(crate::Error::ConfigError { - pipeline_name: "collector", - config_name: "collector_endpoint", - reason: "invalid uri from the builder, invalid uri character".to_string(), - }), - }, - TestCase { - description: "Positive: Default endpoint (no environment variable set)", - env_var: "", - builder_endpoint: None, - expected_result: Ok(Uri::try_from(DEFAULT_ENDPOINT).unwrap()), - }, - ]; - for test_case in test_cases { - env::set_var(ENV_ENDPOINT, test_case.env_var); - let builder = CollectorPipeline { - collector_endpoint: test_case.builder_endpoint.map(|s| s.to_string()), - ..Default::default() - }; - let result = builder.resolve_endpoint(); - match test_case.expected_result { - Ok(expected) => { - assert_eq!(result.unwrap(), expected, "{}", test_case.description); - } - Err(expected_err) => { - assert!( - result.is_err(), - "{}, expected error, get {}", - test_case.description, - result.unwrap() - ); - match (result.unwrap_err(), expected_err) { - ( - crate::Error::ConfigError { - pipeline_name: result_pipeline_name, - config_name: result_config_name, - reason: result_reason, - }, - crate::Error::ConfigError { - pipeline_name: expected_pipeline_name, - config_name: expected_config_name, - reason: expected_reason, - }, - ) => { - assert_eq!( - result_pipeline_name, expected_pipeline_name, - "{}", - test_case.description - ); - assert_eq!( - result_config_name, expected_config_name, - "{}", - test_case.description - ); - assert_eq!(result_reason, expected_reason, "{}", test_case.description); - } - _ => panic!("we don't expect collector to return other error"), - } - } - } - env::remove_var(ENV_ENDPOINT); - } - } - - #[test] - fn test_resolve_timeout() { - struct TestCase<'a> { - description: &'a str, - env_var: &'a str, - builder_var: Option, - expected_duration: Duration, - } - let test_cases = vec![ - TestCase { - description: "Valid environment variable", - env_var: "5000", - builder_var: None, - expected_duration: Duration::from_millis(5000), - }, - TestCase { - description: "Invalid environment variable", - env_var: "invalid", - builder_var: None, - expected_duration: DEFAULT_COLLECTOR_TIMEOUT, - }, - TestCase { - description: "Missing environment variable", - env_var: "", - builder_var: Some(Duration::from_millis(5000)), - expected_duration: Duration::from_millis(5000), - }, - ]; - for test_case in test_cases { - env::set_var(ENV_TIMEOUT, test_case.env_var); - let mut builder = CollectorPipeline::default(); - if let Some(timeout) = test_case.builder_var { - builder = builder.with_timeout(timeout); - } - let result = builder.resolve_timeout(); - assert_eq!( - result, test_case.expected_duration, - "{}", - test_case.description - ); - env::remove_var(ENV_TIMEOUT); - } - } -} diff --git a/opentelemetry-jaeger/src/exporter/config/mod.rs b/opentelemetry-jaeger/src/exporter/config/mod.rs deleted file mode 100644 index 93218867af..0000000000 --- a/opentelemetry-jaeger/src/exporter/config/mod.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Configurations to build a jaeger exporter. -//! -//! The jaeger exporter can send spans to [jaeger agent] or [jaeger collector]. The agent is usually -//! deployed along with the application like a sidecar. The collector is usually deployed a stand alone -//! application and receive spans from multiple sources. The exporter will use UDP to send spans to -//! agents and use HTTP/TCP to send spans to collectors. See [jaeger deployment guide] for more details. -//! -//! [jaeger agent]: https://www.jaegertracing.io/docs/1.31/deployment/#agent -//! [jaeger collector]: https://www.jaegertracing.io/docs/1.31/deployment/#collector -//! [jaeger deployment guide]: https://www.jaegertracing.io/docs/1.31/deployment - -use crate::Process; -use opentelemetry::{global, trace::TraceError, KeyValue}; -use opentelemetry_sdk::trace::{BatchConfig, Config, Tracer, TracerProvider}; -use opentelemetry_semantic_conventions as semcov; - -/// Config a exporter that sends the spans to a [jaeger agent](https://www.jaegertracing.io/docs/1.31/deployment/#agent). -pub mod agent; -/// Config a exporter that bypass the agent and send spans directly to [jaeger collector](https://www.jaegertracing.io/docs/1.31/deployment/#collector). -#[cfg(any(feature = "collector_client", feature = "wasm_collector_client"))] -pub mod collector; - -// configurations and overrides on how to transform OTLP spans to Jaeger spans. -#[derive(Debug)] -struct TransformationConfig { - export_instrument_library: bool, - service_name: Option, -} - -impl Default for TransformationConfig { - fn default() -> Self { - TransformationConfig { - export_instrument_library: true, - service_name: None, - } - } -} - -// pipeline must have transformation config, trace config and batch config. -trait HasRequiredConfig { - fn set_transformation_config(&mut self, f: T) - where - T: FnOnce(&mut TransformationConfig); - - fn set_trace_config(&mut self, config: Config); - - fn set_batch_config(&mut self, config: BatchConfig); -} - -// To reduce the overhead of copying service name in every spans. We convert resource into jaeger tags -// and store them into process. And set the resource in trace config to empty. -// -// There are multiple ways to set the service name. A `service.name` tag will be always added -// to the process tags. -fn build_config_and_process( - config: Option, - service_name_opt: Option, -) -> (Config, Process) { - let config = config.unwrap_or_default(); - - let service_name = service_name_opt.unwrap_or_else(|| { - config - .resource - .get(semcov::resource::SERVICE_NAME.into()) - .map(|v| v.to_string()) - .unwrap_or_else(|| "unknown_service".to_string()) - }); - - // merge the tags and resource. Resources take priority. - let mut tags = config - .resource - .iter() - .filter(|(key, _)| key.as_str() != semcov::resource::SERVICE_NAME) - .map(|(key, value)| KeyValue::new(key.clone(), value.clone())) - .collect::>(); - - tags.push(KeyValue::new( - semcov::resource::SERVICE_NAME, - service_name.clone(), - )); - - (config, Process { service_name, tags }) -} - -pub(crate) fn install_tracer_provider_and_get_tracer( - tracer_provider: TracerProvider, -) -> Result { - let tracer = opentelemetry::trace::TracerProvider::tracer_builder( - &tracer_provider, - "opentelemetry-jaeger", - ) - .with_version(env!("CARGO_PKG_VERSION")) - .with_schema_url(semcov::SCHEMA_URL) - .build(); - let _ = global::set_tracer_provider(tracer_provider); - Ok(tracer) -} - -#[cfg(test)] -mod tests { - use crate::exporter::config::build_config_and_process; - use crate::new_agent_pipeline; - use opentelemetry::KeyValue; - use opentelemetry_sdk::{trace::Config, Resource}; - use std::env; - - #[test] - fn test_set_service_name() { - let service_name = "halloween_service".to_string(); - - // set via builder's service name, it has highest priority - let (_, process) = build_config_and_process(None, Some(service_name.clone())); - assert_eq!(process.service_name, service_name); - - // make sure the tags in resource are moved to process - let trace_config = Config::default() - .with_resource(Resource::new(vec![KeyValue::new("test-key", "test-value")])); - let (_, process) = build_config_and_process(Some(trace_config), Some(service_name)); - assert_eq!(process.tags.len(), 2); - } - - #[tokio::test] - async fn test_read_from_env() { - // OTEL_SERVICE_NAME env var also works - env::set_var("OTEL_SERVICE_NAME", "test service"); - let builder = new_agent_pipeline(); - let exporter = builder.build_sync_agent_exporter().unwrap(); - assert_eq!(exporter.process.service_name, "test service"); - env::set_var("OTEL_SERVICE_NAME", "") - } -} diff --git a/opentelemetry-jaeger/src/exporter/mod.rs b/opentelemetry-jaeger/src/exporter/mod.rs deleted file mode 100644 index 38aea1c411..0000000000 --- a/opentelemetry-jaeger/src/exporter/mod.rs +++ /dev/null @@ -1,473 +0,0 @@ -//! # Jaeger Exporter -//! -// Linting isn't detecting that it's used seems like linting bug. -#[allow(unused_imports)] -use std::convert::TryInto; -use std::fmt::Display; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; - -use futures_core::future::BoxFuture; -#[cfg(feature = "isahc_collector_client")] -#[allow(unused_imports)] // this is actually used to configure authentication -use isahc::prelude::Configurable; - -use opentelemetry::{ - trace::{Event, Link, SpanKind, Status}, - InstrumentationLibrary, Key, KeyValue, -}; -use opentelemetry_sdk::export::{ - trace::{ExportResult, SpanData, SpanExporter}, - ExportError, -}; -use opentelemetry_sdk::trace::SpanEvents; - -use crate::exporter::uploader::Uploader; - -use self::runtime::JaegerTraceRuntime; -use self::thrift::jaeger; - -mod agent; -#[cfg(any(feature = "collector_client", feature = "wasm_collector_client"))] -mod collector; -pub(crate) mod runtime; -#[allow(clippy::all, unreachable_pub, dead_code)] -#[rustfmt::skip] // don't format generated files -mod thrift; -pub mod config; -pub(crate) mod transport; -mod uploader; - -/// Instrument Library name MUST be reported in Jaeger Span tags with the following key -const INSTRUMENTATION_LIBRARY_NAME: &str = "otel.library.name"; - -/// Instrument Library version MUST be reported in Jaeger Span tags with the following key -const INSTRUMENTATION_LIBRARY_VERSION: &str = "otel.library.version"; - -/// Jaeger span exporter -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -#[derive(Debug)] -pub struct Exporter { - /// Whether or not to export instrumentation information. - export_instrumentation_lib: bool, - uploader: Arc, - process: jaeger::Process, -} - -impl Exporter { - fn new( - process: jaeger::Process, - export_instrumentation_lib: bool, - uploader: Arc, - ) -> Exporter { - Exporter { - export_instrumentation_lib, - uploader, - process, - } - } -} - -/// Jaeger process configuration -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -#[derive(Debug, Default)] -pub struct Process { - /// Jaeger service name - pub service_name: String, - /// Jaeger tags - pub tags: Vec, -} - -impl SpanExporter for Exporter { - fn export(&mut self, batch: Vec) -> BoxFuture<'static, ExportResult> { - let mut jaeger_spans: Vec = Vec::with_capacity(batch.len()); - let process = self.process.clone(); - - for span in batch.into_iter() { - jaeger_spans.push(convert_otel_span_into_jaeger_span( - span, - self.export_instrumentation_lib, - )); - } - - let uploader = self.uploader.clone(); - Box::pin(async move { - uploader - .upload(jaeger::Batch::new(process, jaeger_spans)) - .await - }) - } -} - -fn links_to_references(links: &[Link]) -> Option> { - if !links.is_empty() { - let refs = links - .iter() - .map(|link| { - let span_context = &link.span_context; - let trace_id_bytes = span_context.trace_id().to_bytes(); - let (high, low) = trace_id_bytes.split_at(8); - let trace_id_high = i64::from_be_bytes(high.try_into().unwrap()); - let trace_id_low = i64::from_be_bytes(low.try_into().unwrap()); - - jaeger::SpanRef::new( - jaeger::SpanRefType::FollowsFrom, - trace_id_low, - trace_id_high, - i64::from_be_bytes(span_context.span_id().to_bytes()), - ) - }) - .collect(); - Some(refs) - } else { - None - } -} - -/// Convert spans to jaeger thrift span for exporting. -fn convert_otel_span_into_jaeger_span(span: SpanData, export_instrument_lib: bool) -> jaeger::Span { - let trace_id_bytes = span.span_context.trace_id().to_bytes(); - let (high, low) = trace_id_bytes.split_at(8); - let trace_id_high = i64::from_be_bytes(high.try_into().unwrap()); - let trace_id_low = i64::from_be_bytes(low.try_into().unwrap()); - jaeger::Span { - trace_id_low, - trace_id_high, - span_id: i64::from_be_bytes(span.span_context.span_id().to_bytes()), - parent_span_id: i64::from_be_bytes(span.parent_span_id.to_bytes()), - operation_name: span.name.into_owned(), - references: links_to_references(span.links.as_ref()), - flags: span.span_context.trace_flags().to_u8() as i32, - start_time: span - .start_time - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| Duration::from_secs(0)) - .as_micros() as i64, - duration: span - .end_time - .duration_since(span.start_time) - .unwrap_or_else(|_| Duration::from_secs(0)) - .as_micros() as i64, - tags: Some(build_span_tags( - span.attributes, - if export_instrument_lib { - Some(span.instrumentation_lib) - } else { - None - }, - span.status, - span.span_kind, - )), - logs: events_to_logs(span.events), - } -} - -fn build_span_tags( - attrs: Vec, - instrumentation_lib: Option, - status: Status, - kind: SpanKind, -) -> Vec { - let mut user_overrides = UserOverrides::default(); - // TODO determine if namespacing is required to avoid collisions with set attributes - let mut tags = attrs - .into_iter() - .map(|kv| { - user_overrides.record_attr(kv.key.as_str()); - kv.into() - }) - .collect::>(); - - if let Some(instrumentation_lib) = instrumentation_lib { - // Set instrument library tags - tags.push(KeyValue::new(INSTRUMENTATION_LIBRARY_NAME, instrumentation_lib.name).into()); - if let Some(version) = instrumentation_lib.version { - tags.push(KeyValue::new(INSTRUMENTATION_LIBRARY_VERSION, version).into()) - } - } - - if !user_overrides.span_kind && kind != SpanKind::Internal { - tags.push(Key::new(SPAN_KIND).string(format_span_kind(kind)).into()); - } - - match status { - Status::Unset => {} - Status::Ok => { - if !user_overrides.status_code { - tags.push(KeyValue::new(OTEL_STATUS_CODE, "OK").into()); - } - } - Status::Error { - description: message, - } => { - if !user_overrides.error { - tags.push(Key::new(ERROR).bool(true).into()); - } - - if !user_overrides.status_code { - tags.push(KeyValue::new(OTEL_STATUS_CODE, "ERROR").into()); - } - - if !message.is_empty() && !user_overrides.status_description { - tags.push(Key::new(OTEL_STATUS_DESCRIPTION).string(message).into()); - } - } - } - - tags -} - -fn format_span_kind(kind: SpanKind) -> &'static str { - match kind { - SpanKind::Client => "client", - SpanKind::Server => "server", - SpanKind::Producer => "producer", - SpanKind::Consumer => "consumer", - SpanKind::Internal => "internal", - } -} - -const ERROR: &str = "error"; -const SPAN_KIND: &str = "span.kind"; -const OTEL_STATUS_CODE: &str = "otel.status_code"; -const OTEL_STATUS_DESCRIPTION: &str = "otel.status_description"; - -#[derive(Default)] -struct UserOverrides { - error: bool, - span_kind: bool, - status_code: bool, - status_description: bool, -} - -impl UserOverrides { - fn record_attr(&mut self, attr: &str) { - match attr { - ERROR => self.error = true, - SPAN_KIND => self.span_kind = true, - OTEL_STATUS_CODE => self.status_code = true, - OTEL_STATUS_DESCRIPTION => self.status_description = true, - _ => (), - } - } -} - -fn events_to_logs(events: SpanEvents) -> Option> { - if events.is_empty() { - None - } else { - Some(events.into_iter().map(Into::into).collect()) - } -} - -/// Wrap type for errors from opentelemetry jaeger -#[derive(Debug)] -pub enum Error { - /// Error from thrift agents. - /// - /// If the spans was sent to jaeger agent. Refer [AgentPipeline](config::agent::AgentPipeline) for more details. - /// If the spans was sent to jaeger collector. Refer [CollectorPipeline](config::collector::CollectorPipeline) for more details. - ThriftAgentError(::thrift::Error), - - /// Pipeline fails because one of the configurations is invalid. - ConfigError { - /// the name of the pipeline. It can be `agent`, `collector` or `wasm collector` - pipeline_name: &'static str, - /// config name that has the error. - config_name: &'static str, - /// the underlying error message. - reason: String, - }, -} - -impl std::error::Error for Error {} - -impl From<::thrift::Error> for Error { - fn from(value: ::thrift::Error) -> Self { - Error::ThriftAgentError(value) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Error::ThriftAgentError(err) => match err { - ::thrift::Error::Transport(transport_error) => { - write!( - f, - "thrift agent failed on transportation layer, {}, {}", - transport_error, transport_error.message - ) - } - ::thrift::Error::Protocol(protocol_error) => { - write!( - f, - "thrift agent failed on protocol layer, {}, {}", - protocol_error, protocol_error.message - ) - } - ::thrift::Error::Application(application_error) => { - write!( - f, - "thrift agent failed on application layer, {}, {}", - application_error, application_error.message - ) - } - ::thrift::Error::User(error) => { - write!(f, "thrift agent failed, {}", error) - } - }, - Error::ConfigError { - pipeline_name, - config_name, - reason, - } => write!( - f, - "{} pipeline fails because one of the configuration {} is invalid. {}", - pipeline_name, config_name, reason - ), - } - } -} - -impl ExportError for Error { - fn exporter_name(&self) -> &'static str { - "jaeger" - } -} - -/// Sample the first address provided to designate which IP family to bind the socket to. -/// IP families returned be INADDR_ANY as [`Ipv4Addr::UNSPECIFIED`] or -/// IN6ADDR_ANY as [`Ipv6Addr::UNSPECIFIED`]. -fn address_family(addrs: &[SocketAddr]) -> SocketAddr { - match addrs.first() { - Some(SocketAddr::V4(_)) | None => SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)), - Some(SocketAddr::V6(_)) => SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0)), - } -} - -#[cfg(test)] -mod tests { - use opentelemetry::{ - trace::{SpanKind, Status}, - KeyValue, - }; - - use crate::exporter::thrift::jaeger::Tag; - use crate::exporter::{build_span_tags, OTEL_STATUS_CODE, OTEL_STATUS_DESCRIPTION}; - - use super::SPAN_KIND; - - fn assert_tag_contains(tags: Vec, key: &'static str, expect_val: &'static str) { - assert_eq!( - tags.into_iter() - .filter(|tag| tag.key.as_str() == key - && tag.v_str.as_deref().unwrap_or("") == expect_val) - .count(), - 1, - "Expect a tag {} with value {} but found nothing", - key, - expect_val - ); - } - - fn assert_tag_not_contains(tags: Vec, key: &'static str) { - assert_eq!( - tags.into_iter() - .filter(|tag| tag.key.as_str() == key) - .count(), - 0, - "Not expect tag {}, but found something", - key - ); - } - - #[rustfmt::skip] - fn get_error_tag_test_data() -> Vec<(Status, Option<&'static str>, Option<&'static str>)> - { - // Status, OTEL_STATUS_CODE tag value, OTEL_STATUS_DESCRIPTION tag value - vec![ - (Status::error(""), Some("ERROR"), None), - (Status::Unset, None, None), - // When status is ok, no description should be in span data. This should be ensured by Otel API - (Status::Ok, Some("OK"), None), - (Status::error("have message"), Some("ERROR"), Some("have message")), - (Status::Unset, None, None), - ] - } - - #[test] - fn test_set_status() { - for (status, status_tag_val, msg_tag_val) in get_error_tag_test_data() { - let tags = build_span_tags(Vec::new(), None, status, SpanKind::Client); - if let Some(val) = status_tag_val { - assert_tag_contains(tags.clone(), OTEL_STATUS_CODE, val); - } else { - assert_tag_not_contains(tags.clone(), OTEL_STATUS_CODE); - } - - if let Some(val) = msg_tag_val { - assert_tag_contains(tags.clone(), OTEL_STATUS_DESCRIPTION, val); - } else { - assert_tag_not_contains(tags.clone(), OTEL_STATUS_DESCRIPTION); - } - } - } - - #[test] - fn ignores_user_set_values() { - let mut attributes = Vec::new(); - let user_error = true; - let user_kind = "server"; - let user_status_description = "Something bad happened"; - let user_status = Status::Error { - description: user_status_description.into(), - }; - attributes.push(KeyValue::new("error", user_error)); - attributes.push(KeyValue::new(SPAN_KIND, user_kind)); - attributes.push(KeyValue::new(OTEL_STATUS_CODE, "ERROR")); - attributes.push(KeyValue::new( - OTEL_STATUS_DESCRIPTION, - user_status_description, - )); - let tags = build_span_tags(attributes, None, user_status, SpanKind::Client); - - assert!(tags - .iter() - .filter(|tag| tag.key.as_str() == "error") - .all(|tag| tag.v_bool.unwrap())); - assert_tag_contains(tags.clone(), SPAN_KIND, user_kind); - assert_tag_contains(tags.clone(), OTEL_STATUS_CODE, "ERROR"); - assert_tag_contains(tags, OTEL_STATUS_DESCRIPTION, user_status_description); - } - - #[test] - fn error_message_should_contain_details() { - let size_limit_err = - crate::Error::from(::thrift::Error::Protocol(thrift::ProtocolError::new( - thrift::ProtocolErrorKind::SizeLimit, - "the error message should contain details".to_string(), - ))); - assert_eq!( - format!("{}", size_limit_err), - "thrift agent failed on protocol layer, message too long, the error message should contain details" - ); - } -} diff --git a/opentelemetry-jaeger/src/exporter/runtime.rs b/opentelemetry-jaeger/src/exporter/runtime.rs deleted file mode 100644 index 576eabc2e7..0000000000 --- a/opentelemetry-jaeger/src/exporter/runtime.rs +++ /dev/null @@ -1,89 +0,0 @@ -#[cfg(any( - feature = "rt-async-std", - feature = "rt-tokio", - feature = "rt-tokio-current-thread" -))] -use crate::exporter::address_family; -use async_trait::async_trait; -use opentelemetry_sdk::runtime::RuntimeChannel; -use std::net::ToSocketAddrs; - -/// Jaeger Trace Runtime is an extension to [`RuntimeChannel`]. -/// -/// Deprecation Notice: -/// Ingestion of OTLP is now supported in Jaeger please check [crates.io] for more details. -/// -/// [`RuntimeChannel`]: opentelemetry_sdk::runtime::RuntimeChannel -/// [crates.io]: https://crates.io/crates/opentelemetry-jaeger -#[async_trait] -#[deprecated( - since = "0.21.0", - note = "Please migrate to opentelemetry-otlp exporter." -)] -pub trait JaegerTraceRuntime: RuntimeChannel + std::fmt::Debug { - /// A communication socket between Jaeger client and agent. - type Socket: std::fmt::Debug + Send + Sync; - - /// Create a new communication socket. - fn create_socket(&self, endpoint: T) -> thrift::Result; - - /// Send payload over the socket. - async fn write_to_socket(&self, socket: &Self::Socket, payload: Vec) -> thrift::Result<()>; -} - -#[cfg(feature = "rt-tokio")] -#[async_trait] -impl JaegerTraceRuntime for opentelemetry_sdk::runtime::Tokio { - type Socket = tokio::net::UdpSocket; - - fn create_socket(&self, endpoint: T) -> thrift::Result { - let addrs = endpoint.to_socket_addrs()?.collect::>(); - let conn = std::net::UdpSocket::bind(address_family(addrs.as_slice()))?; - conn.connect(addrs.as_slice())?; - Ok(tokio::net::UdpSocket::from_std(conn)?) - } - - async fn write_to_socket(&self, socket: &Self::Socket, payload: Vec) -> thrift::Result<()> { - socket.send(&payload).await?; - - Ok(()) - } -} - -#[cfg(feature = "rt-tokio-current-thread")] -#[async_trait] -impl JaegerTraceRuntime for opentelemetry_sdk::runtime::TokioCurrentThread { - type Socket = tokio::net::UdpSocket; - - fn create_socket(&self, endpoint: T) -> thrift::Result { - let addrs = endpoint.to_socket_addrs()?.collect::>(); - let conn = std::net::UdpSocket::bind(address_family(addrs.as_slice()))?; - conn.connect(addrs.as_slice())?; - Ok(tokio::net::UdpSocket::from_std(conn)?) - } - - async fn write_to_socket(&self, socket: &Self::Socket, payload: Vec) -> thrift::Result<()> { - socket.send(&payload).await?; - - Ok(()) - } -} - -#[cfg(feature = "rt-async-std")] -#[async_trait] -impl JaegerTraceRuntime for opentelemetry_sdk::runtime::AsyncStd { - type Socket = async_std::net::UdpSocket; - - fn create_socket(&self, endpoint: T) -> thrift::Result { - let addrs = endpoint.to_socket_addrs()?.collect::>(); - let conn = std::net::UdpSocket::bind(address_family(addrs.as_slice()))?; - conn.connect(addrs.as_slice())?; - Ok(async_std::net::UdpSocket::from(conn)) - } - - async fn write_to_socket(&self, socket: &Self::Socket, payload: Vec) -> thrift::Result<()> { - socket.send(&payload).await?; - - Ok(()) - } -} diff --git a/opentelemetry-jaeger/src/exporter/thrift/agent.rs b/opentelemetry-jaeger/src/exporter/thrift/agent.rs deleted file mode 100644 index 06b6fce22d..0000000000 --- a/opentelemetry-jaeger/src/exporter/thrift/agent.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Autogenerated by Thrift Compiler (0.13.0) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -#![allow(unused_imports)] -#![allow(unused_extern_crates)] -#![allow(clippy::too_many_arguments, clippy::type_complexity)] -#![cfg_attr(rustfmt, rustfmt_skip)] - -extern crate thrift; - -use thrift::OrderedFloat; -use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::{From, TryFrom}; -use std::default::Default; -use std::error::Error; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::rc::Rc; - -use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient}; -use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType}; -use thrift::protocol::field_id; -use thrift::protocol::verify_expected_message_type; -use thrift::protocol::verify_expected_sequence_number; -use thrift::protocol::verify_expected_service_call; -use thrift::protocol::verify_required_field_exists; -use thrift::server::TProcessor; - -use super::jaeger; -use super::zipkincore; - -// -// Agent service client -// - -pub trait TAgentSyncClient { - fn emit_zipkin_batch(&mut self, spans: Vec) -> thrift::Result<()>; - fn emit_batch(&mut self, batch: jaeger::Batch) -> thrift::Result<()>; -} - -pub trait TAgentSyncClientMarker {} - -pub struct AgentSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - _i_prot: IP, - _o_prot: OP, - _sequence_number: i32, -} - -impl AgentSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - pub fn new(input_protocol: IP, output_protocol: OP) -> AgentSyncClient { - AgentSyncClient { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 } - } -} - -impl TThriftClient for AgentSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol { &mut self._i_prot } - fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol { &mut self._o_prot } - fn sequence_number(&self) -> i32 { self._sequence_number } - fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number } -} - -impl TAgentSyncClientMarker for AgentSyncClient where IP: TInputProtocol, OP: TOutputProtocol {} - -impl TAgentSyncClient for C { - fn emit_zipkin_batch(&mut self, spans: Vec) -> thrift::Result<()> { - ( - { - self.increment_sequence_number(); - let message_ident = TMessageIdentifier::new("emitZipkinBatch", TMessageType::OneWay, self.sequence_number()); - let call_args = AgentEmitZipkinBatchArgs { spans }; - self.o_prot_mut().write_message_begin(&message_ident)?; - call_args.write_to_out_protocol(self.o_prot_mut())?; - self.o_prot_mut().write_message_end()?; - self.o_prot_mut().flush() - } - )?; - Ok(()) - } - fn emit_batch(&mut self, batch: jaeger::Batch) -> thrift::Result<()> { - ( - { - self.increment_sequence_number(); - let message_ident = TMessageIdentifier::new("emitBatch", TMessageType::OneWay, self.sequence_number()); - let call_args = AgentEmitBatchArgs { batch }; - self.o_prot_mut().write_message_begin(&message_ident)?; - call_args.write_to_out_protocol(self.o_prot_mut())?; - self.o_prot_mut().write_message_end()?; - self.o_prot_mut().flush() - } - )?; - Ok(()) - } -} - -// -// Agent service processor -// - -pub trait AgentSyncHandler { - fn handle_emit_zipkin_batch(&self, spans: Vec) -> thrift::Result<()>; - fn handle_emit_batch(&self, batch: jaeger::Batch) -> thrift::Result<()>; -} - -pub struct AgentSyncProcessor { - handler: H, -} - -impl AgentSyncProcessor { - pub fn new(handler: H) -> AgentSyncProcessor { - AgentSyncProcessor { - handler, - } - } - fn process_emit_zipkin_batch(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - TAgentProcessFunctions::process_emit_zipkin_batch(&self.handler, incoming_sequence_number, i_prot, o_prot) - } - fn process_emit_batch(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - TAgentProcessFunctions::process_emit_batch(&self.handler, incoming_sequence_number, i_prot, o_prot) - } -} - -pub struct TAgentProcessFunctions; - -impl TAgentProcessFunctions { - pub fn process_emit_zipkin_batch(handler: &H, _: i32, i_prot: &mut dyn TInputProtocol, _: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let args = AgentEmitZipkinBatchArgs::read_from_in_protocol(i_prot)?; - match handler.handle_emit_zipkin_batch(args.spans) { - Ok(_) => { - Ok(()) - }, - Err(e) => { - match e { - thrift::Error::Application(app_err) => { - Err(thrift::Error::Application(app_err)) - }, - _ => { - let ret_err = { - ApplicationError::new( - ApplicationErrorKind::Unknown, - e.to_string() - ) - }; - Err(thrift::Error::Application(ret_err)) - }, - } - }, - } - } - pub fn process_emit_batch(handler: &H, _: i32, i_prot: &mut dyn TInputProtocol, _: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let args = AgentEmitBatchArgs::read_from_in_protocol(i_prot)?; - match handler.handle_emit_batch(args.batch) { - Ok(_) => { - Ok(()) - }, - Err(e) => { - match e { - thrift::Error::Application(app_err) => { - Err(thrift::Error::Application(app_err)) - }, - _ => { - let ret_err = { - ApplicationError::new( - ApplicationErrorKind::Unknown, - e.to_string() - ) - }; - Err(thrift::Error::Application(ret_err)) - }, - } - }, - } - } -} - -impl TProcessor for AgentSyncProcessor { - fn process(&self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let message_ident = i_prot.read_message_begin()?; - let res = match &*message_ident.name { - "emitZipkinBatch" => { - self.process_emit_zipkin_batch(message_ident.sequence_number, i_prot, o_prot) - }, - "emitBatch" => { - self.process_emit_batch(message_ident.sequence_number, i_prot, o_prot) - }, - method => { - Err( - thrift::Error::Application( - ApplicationError::new( - ApplicationErrorKind::UnknownMethod, - format!("unknown method {}", method) - ) - ) - ) - }, - }; - thrift::server::handle_process_result(&message_ident, res, o_prot) - } -} - -// -// AgentEmitZipkinBatchArgs -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct AgentEmitZipkinBatchArgs { - spans: Vec, -} - -impl AgentEmitZipkinBatchArgs { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_0 = zipkincore::Span::read_from_in_protocol(i_prot)?; - val.push(list_elem_0); - } - i_prot.read_list_end()?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("AgentEmitZipkinBatchArgs.spans", &f_1)?; - let ret = AgentEmitZipkinBatchArgs { - spans: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("emitZipkinBatch_args"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("spans", TType::List, 1))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.spans.len() as i32))?; - for e in &self.spans { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// AgentEmitBatchArgs -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct AgentEmitBatchArgs { - batch: jaeger::Batch, -} - -impl AgentEmitBatchArgs { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = jaeger::Batch::read_from_in_protocol(i_prot)?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("AgentEmitBatchArgs.batch", &f_1)?; - let ret = AgentEmitBatchArgs { - batch: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("emitBatch_args"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("batch", TType::Struct, 1))?; - self.batch.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} diff --git a/opentelemetry-jaeger/src/exporter/thrift/jaeger.rs b/opentelemetry-jaeger/src/exporter/thrift/jaeger.rs deleted file mode 100644 index 60e21e9e78..0000000000 --- a/opentelemetry-jaeger/src/exporter/thrift/jaeger.rs +++ /dev/null @@ -1,1116 +0,0 @@ -// Autogenerated by Thrift Compiler (0.13.0) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -#![allow(unused_imports)] -#![allow(unused_extern_crates)] -#![allow(clippy::too_many_arguments, clippy::type_complexity)] -#![cfg_attr(rustfmt, rustfmt_skip)] - -extern crate thrift; - -use thrift::OrderedFloat; -use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::{From, TryFrom}; -use std::default::Default; -use std::error::Error; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::rc::Rc; - -use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient}; -use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType}; -use thrift::protocol::field_id; -use thrift::protocol::verify_expected_message_type; -use thrift::protocol::verify_expected_sequence_number; -use thrift::protocol::verify_expected_service_call; -use thrift::protocol::verify_required_field_exists; -use thrift::server::TProcessor; - -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum TagType { - String = 0, - Double = 1, - Bool = 2, - Long = 3, - Binary = 4, -} - -impl TagType { - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - o_prot.write_i32(*self as i32) - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - let enum_value = i_prot.read_i32()?; - TagType::try_from(enum_value) } -} - -impl TryFrom for TagType { - type Error = thrift::Error; fn try_from(i: i32) -> Result { - match i { - 0 => Ok(TagType::String), - 1 => Ok(TagType::Double), - 2 => Ok(TagType::Bool), - 3 => Ok(TagType::Long), - 4 => Ok(TagType::Binary), - _ => { - Err( - thrift::Error::Protocol( - ProtocolError::new( - ProtocolErrorKind::InvalidData, - format!("cannot convert enum constant {} to TagType", i) - ) - ) - ) - }, - } - } -} - -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum SpanRefType { - ChildOf = 0, - FollowsFrom = 1, -} - -impl SpanRefType { - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - o_prot.write_i32(*self as i32) - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - let enum_value = i_prot.read_i32()?; - SpanRefType::try_from(enum_value) } -} - -impl TryFrom for SpanRefType { - type Error = thrift::Error; fn try_from(i: i32) -> Result { - match i { - 0 => Ok(SpanRefType::ChildOf), - 1 => Ok(SpanRefType::FollowsFrom), - _ => { - Err( - thrift::Error::Protocol( - ProtocolError::new( - ProtocolErrorKind::InvalidData, - format!("cannot convert enum constant {} to SpanRefType", i) - ) - ) - ) - }, - } - } -} - -// -// Tag -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Tag { - pub key: String, - pub v_type: TagType, - pub v_str: Option, - pub v_double: Option>, - pub v_bool: Option, - pub v_long: Option, - pub v_binary: Option>, -} - -impl Tag { - pub fn new(key: String, v_type: TagType, v_str: F3, v_double: F4, v_bool: F5, v_long: F6, v_binary: F7) -> Tag where F3: Into>, F4: Into>>, F5: Into>, F6: Into>, F7: Into>> { - Tag { - key, - v_type, - v_str: v_str.into(), - v_double: v_double.into(), - v_bool: v_bool.into(), - v_long: v_long.into(), - v_binary: v_binary.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option = None; - let mut f_3: Option = None; - let mut f_4: Option> = None; - let mut f_5: Option = None; - let mut f_6: Option = None; - let mut f_7: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_string()?; - f_1 = Some(val); - }, - 2 => { - let val = TagType::read_from_in_protocol(i_prot)?; - f_2 = Some(val); - }, - 3 => { - let val = i_prot.read_string()?; - f_3 = Some(val); - }, - 4 => { - let val = OrderedFloat::from(i_prot.read_double()?); - f_4 = Some(val); - }, - 5 => { - let val = i_prot.read_bool()?; - f_5 = Some(val); - }, - 6 => { - let val = i_prot.read_i64()?; - f_6 = Some(val); - }, - 7 => { - let val = i_prot.read_bytes()?; - f_7 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Tag.key", &f_1)?; - verify_required_field_exists("Tag.v_type", &f_2)?; - let ret = Tag { - key: f_1.expect("auto-generated code should have checked for presence of required fields"), - v_type: f_2.expect("auto-generated code should have checked for presence of required fields"), - v_str: f_3, - v_double: f_4, - v_bool: f_5, - v_long: f_6, - v_binary: f_7, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Tag"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("key", TType::String, 1))?; - o_prot.write_string(&self.key)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("vType", TType::I32, 2))?; - self.v_type.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - if let Some(ref fld_var) = self.v_str { - o_prot.write_field_begin(&TFieldIdentifier::new("vStr", TType::String, 3))?; - o_prot.write_string(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.v_double { - o_prot.write_field_begin(&TFieldIdentifier::new("vDouble", TType::Double, 4))?; - o_prot.write_double(fld_var.into())?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.v_bool { - o_prot.write_field_begin(&TFieldIdentifier::new("vBool", TType::Bool, 5))?; - o_prot.write_bool(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.v_long { - o_prot.write_field_begin(&TFieldIdentifier::new("vLong", TType::I64, 6))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.v_binary { - o_prot.write_field_begin(&TFieldIdentifier::new("vBinary", TType::String, 7))?; - o_prot.write_bytes(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// Log -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Log { - pub timestamp: i64, - pub fields: Vec, -} - -impl Log { - pub fn new(timestamp: i64, fields: Vec) -> Log { - Log { - timestamp, - fields, - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_i64()?; - f_1 = Some(val); - }, - 2 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_0 = Tag::read_from_in_protocol(i_prot)?; - val.push(list_elem_0); - } - i_prot.read_list_end()?; - f_2 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Log.timestamp", &f_1)?; - verify_required_field_exists("Log.fields", &f_2)?; - let ret = Log { - timestamp: f_1.expect("auto-generated code should have checked for presence of required fields"), - fields: f_2.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Log"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("timestamp", TType::I64, 1))?; - o_prot.write_i64(self.timestamp)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("fields", TType::List, 2))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.fields.len() as i32))?; - for e in &self.fields { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// SpanRef -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct SpanRef { - pub ref_type: SpanRefType, - pub trace_id_low: i64, - pub trace_id_high: i64, - pub span_id: i64, -} - -impl SpanRef { - pub fn new(ref_type: SpanRefType, trace_id_low: i64, trace_id_high: i64, span_id: i64) -> SpanRef { - SpanRef { - ref_type, - trace_id_low, - trace_id_high, - span_id, - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option = None; - let mut f_3: Option = None; - let mut f_4: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = SpanRefType::read_from_in_protocol(i_prot)?; - f_1 = Some(val); - }, - 2 => { - let val = i_prot.read_i64()?; - f_2 = Some(val); - }, - 3 => { - let val = i_prot.read_i64()?; - f_3 = Some(val); - }, - 4 => { - let val = i_prot.read_i64()?; - f_4 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("SpanRef.ref_type", &f_1)?; - verify_required_field_exists("SpanRef.trace_id_low", &f_2)?; - verify_required_field_exists("SpanRef.trace_id_high", &f_3)?; - verify_required_field_exists("SpanRef.span_id", &f_4)?; - let ret = SpanRef { - ref_type: f_1.expect("auto-generated code should have checked for presence of required fields"), - trace_id_low: f_2.expect("auto-generated code should have checked for presence of required fields"), - trace_id_high: f_3.expect("auto-generated code should have checked for presence of required fields"), - span_id: f_4.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("SpanRef"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("refType", TType::I32, 1))?; - self.ref_type.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("traceIdLow", TType::I64, 2))?; - o_prot.write_i64(self.trace_id_low)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("traceIdHigh", TType::I64, 3))?; - o_prot.write_i64(self.trace_id_high)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("spanId", TType::I64, 4))?; - o_prot.write_i64(self.span_id)?; - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// Span -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Span { - pub trace_id_low: i64, - pub trace_id_high: i64, - pub span_id: i64, - pub parent_span_id: i64, - pub operation_name: String, - pub references: Option>, - pub flags: i32, - pub start_time: i64, - pub duration: i64, - pub tags: Option>, - pub logs: Option>, -} - -impl Span { - pub fn new(trace_id_low: i64, trace_id_high: i64, span_id: i64, parent_span_id: i64, operation_name: String, references: F6, flags: i32, start_time: i64, duration: i64, tags: F10, logs: F11) -> Span where F6: Into>>, F10: Into>>, F11: Into>> { - Span { - trace_id_low, - trace_id_high, - span_id, - parent_span_id, - operation_name, - references: references.into(), - flags, - start_time, - duration, - tags: tags.into(), - logs: logs.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option = None; - let mut f_3: Option = None; - let mut f_4: Option = None; - let mut f_5: Option = None; - let mut f_6: Option> = None; - let mut f_7: Option = None; - let mut f_8: Option = None; - let mut f_9: Option = None; - let mut f_10: Option> = None; - let mut f_11: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_i64()?; - f_1 = Some(val); - }, - 2 => { - let val = i_prot.read_i64()?; - f_2 = Some(val); - }, - 3 => { - let val = i_prot.read_i64()?; - f_3 = Some(val); - }, - 4 => { - let val = i_prot.read_i64()?; - f_4 = Some(val); - }, - 5 => { - let val = i_prot.read_string()?; - f_5 = Some(val); - }, - 6 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_1 = SpanRef::read_from_in_protocol(i_prot)?; - val.push(list_elem_1); - } - i_prot.read_list_end()?; - f_6 = Some(val); - }, - 7 => { - let val = i_prot.read_i32()?; - f_7 = Some(val); - }, - 8 => { - let val = i_prot.read_i64()?; - f_8 = Some(val); - }, - 9 => { - let val = i_prot.read_i64()?; - f_9 = Some(val); - }, - 10 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_2 = Tag::read_from_in_protocol(i_prot)?; - val.push(list_elem_2); - } - i_prot.read_list_end()?; - f_10 = Some(val); - }, - 11 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_3 = Log::read_from_in_protocol(i_prot)?; - val.push(list_elem_3); - } - i_prot.read_list_end()?; - f_11 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Span.trace_id_low", &f_1)?; - verify_required_field_exists("Span.trace_id_high", &f_2)?; - verify_required_field_exists("Span.span_id", &f_3)?; - verify_required_field_exists("Span.parent_span_id", &f_4)?; - verify_required_field_exists("Span.operation_name", &f_5)?; - verify_required_field_exists("Span.flags", &f_7)?; - verify_required_field_exists("Span.start_time", &f_8)?; - verify_required_field_exists("Span.duration", &f_9)?; - let ret = Span { - trace_id_low: f_1.expect("auto-generated code should have checked for presence of required fields"), - trace_id_high: f_2.expect("auto-generated code should have checked for presence of required fields"), - span_id: f_3.expect("auto-generated code should have checked for presence of required fields"), - parent_span_id: f_4.expect("auto-generated code should have checked for presence of required fields"), - operation_name: f_5.expect("auto-generated code should have checked for presence of required fields"), - references: f_6, - flags: f_7.expect("auto-generated code should have checked for presence of required fields"), - start_time: f_8.expect("auto-generated code should have checked for presence of required fields"), - duration: f_9.expect("auto-generated code should have checked for presence of required fields"), - tags: f_10, - logs: f_11, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Span"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("traceIdLow", TType::I64, 1))?; - o_prot.write_i64(self.trace_id_low)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("traceIdHigh", TType::I64, 2))?; - o_prot.write_i64(self.trace_id_high)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("spanId", TType::I64, 3))?; - o_prot.write_i64(self.span_id)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("parentSpanId", TType::I64, 4))?; - o_prot.write_i64(self.parent_span_id)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("operationName", TType::String, 5))?; - o_prot.write_string(&self.operation_name)?; - o_prot.write_field_end()?; - if let Some(ref fld_var) = self.references { - o_prot.write_field_begin(&TFieldIdentifier::new("references", TType::List, 6))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_begin(&TFieldIdentifier::new("flags", TType::I32, 7))?; - o_prot.write_i32(self.flags)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("startTime", TType::I64, 8))?; - o_prot.write_i64(self.start_time)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("duration", TType::I64, 9))?; - o_prot.write_i64(self.duration)?; - o_prot.write_field_end()?; - if let Some(ref fld_var) = self.tags { - o_prot.write_field_begin(&TFieldIdentifier::new("tags", TType::List, 10))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.logs { - o_prot.write_field_begin(&TFieldIdentifier::new("logs", TType::List, 11))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// Process -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Process { - pub service_name: String, - pub tags: Option>, -} - -impl Process { - pub fn new(service_name: String, tags: F2) -> Process where F2: Into>> { - Process { - service_name, - tags: tags.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_string()?; - f_1 = Some(val); - }, - 2 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_4 = Tag::read_from_in_protocol(i_prot)?; - val.push(list_elem_4); - } - i_prot.read_list_end()?; - f_2 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Process.service_name", &f_1)?; - let ret = Process { - service_name: f_1.expect("auto-generated code should have checked for presence of required fields"), - tags: f_2, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Process"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("serviceName", TType::String, 1))?; - o_prot.write_string(&self.service_name)?; - o_prot.write_field_end()?; - if let Some(ref fld_var) = self.tags { - o_prot.write_field_begin(&TFieldIdentifier::new("tags", TType::List, 2))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// Batch -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Batch { - pub process: Process, - pub spans: Vec, -} - -impl Batch { - pub fn new(process: Process, spans: Vec) -> Batch { - Batch { - process, - spans, - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - let mut f_2: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = Process::read_from_in_protocol(i_prot)?; - f_1 = Some(val); - }, - 2 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_5 = Span::read_from_in_protocol(i_prot)?; - val.push(list_elem_5); - } - i_prot.read_list_end()?; - f_2 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Batch.process", &f_1)?; - verify_required_field_exists("Batch.spans", &f_2)?; - let ret = Batch { - process: f_1.expect("auto-generated code should have checked for presence of required fields"), - spans: f_2.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Batch"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("process", TType::Struct, 1))?; - self.process.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - o_prot.write_field_begin(&TFieldIdentifier::new("spans", TType::List, 2))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.spans.len() as i32))?; - for e in &self.spans { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// BatchSubmitResponse -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct BatchSubmitResponse { - pub ok: bool, -} - -impl BatchSubmitResponse { - pub fn new(ok: bool) -> BatchSubmitResponse { - BatchSubmitResponse { - ok, - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_bool()?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("BatchSubmitResponse.ok", &f_1)?; - let ret = BatchSubmitResponse { - ok: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("BatchSubmitResponse"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("ok", TType::Bool, 1))?; - o_prot.write_bool(self.ok)?; - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// Collector service client -// - -pub trait TCollectorSyncClient { - fn submit_batches(&mut self, batches: Vec) -> thrift::Result>; -} - -pub trait TCollectorSyncClientMarker {} - -pub struct CollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - _i_prot: IP, - _o_prot: OP, - _sequence_number: i32, -} - -impl CollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - pub fn new(input_protocol: IP, output_protocol: OP) -> CollectorSyncClient { - CollectorSyncClient { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 } - } -} - -impl TThriftClient for CollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol { &mut self._i_prot } - fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol { &mut self._o_prot } - fn sequence_number(&self) -> i32 { self._sequence_number } - fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number } -} - -impl TCollectorSyncClientMarker for CollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol {} - -impl TCollectorSyncClient for C { - fn submit_batches(&mut self, batches: Vec) -> thrift::Result> { - ( - { - self.increment_sequence_number(); - let message_ident = TMessageIdentifier::new("submitBatches", TMessageType::Call, self.sequence_number()); - let call_args = CollectorSubmitBatchesArgs { batches }; - self.o_prot_mut().write_message_begin(&message_ident)?; - call_args.write_to_out_protocol(self.o_prot_mut())?; - self.o_prot_mut().write_message_end()?; - self.o_prot_mut().flush() - } - )?; - { - let message_ident = self.i_prot_mut().read_message_begin()?; - verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?; - verify_expected_service_call("submitBatches", &message_ident.name)?; - if message_ident.message_type == TMessageType::Exception { - let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?; - self.i_prot_mut().read_message_end()?; - return Err(thrift::Error::Application(remote_error)) - } - verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?; - let result = CollectorSubmitBatchesResult::read_from_in_protocol(self.i_prot_mut())?; - self.i_prot_mut().read_message_end()?; - result.ok_or() - } - } -} - -// -// Collector service processor -// - -pub trait CollectorSyncHandler { - fn handle_submit_batches(&self, batches: Vec) -> thrift::Result>; -} - -pub struct CollectorSyncProcessor { - handler: H, -} - -impl CollectorSyncProcessor { - pub fn new(handler: H) -> CollectorSyncProcessor { - CollectorSyncProcessor { - handler, - } - } - fn process_submit_batches(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - TCollectorProcessFunctions::process_submit_batches(&self.handler, incoming_sequence_number, i_prot, o_prot) - } -} - -pub struct TCollectorProcessFunctions; - -impl TCollectorProcessFunctions { - pub fn process_submit_batches(handler: &H, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let args = CollectorSubmitBatchesArgs::read_from_in_protocol(i_prot)?; - match handler.handle_submit_batches(args.batches) { - Ok(handler_return) => { - let message_ident = TMessageIdentifier::new("submitBatches", TMessageType::Reply, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - let ret = CollectorSubmitBatchesResult { result_value: Some(handler_return) }; - ret.write_to_out_protocol(o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - Err(e) => { - match e { - thrift::Error::Application(app_err) => { - let message_ident = TMessageIdentifier::new("submitBatches", TMessageType::Exception, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - thrift::Error::write_application_error_to_out_protocol(&app_err, o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - _ => { - let ret_err = { - ApplicationError::new( - ApplicationErrorKind::Unknown, - e.to_string() - ) - }; - let message_ident = TMessageIdentifier::new("submitBatches", TMessageType::Exception, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - } - }, - } - } -} - -impl TProcessor for CollectorSyncProcessor { - fn process(&self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let message_ident = i_prot.read_message_begin()?; - let res = match &*message_ident.name { - "submitBatches" => { - self.process_submit_batches(message_ident.sequence_number, i_prot, o_prot) - }, - method => { - Err( - thrift::Error::Application( - ApplicationError::new( - ApplicationErrorKind::UnknownMethod, - format!("unknown method {}", method) - ) - ) - ) - }, - }; - thrift::server::handle_process_result(&message_ident, res, o_prot) - } -} - -// -// CollectorSubmitBatchesArgs -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct CollectorSubmitBatchesArgs { - batches: Vec, -} - -impl CollectorSubmitBatchesArgs { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_6 = Batch::read_from_in_protocol(i_prot)?; - val.push(list_elem_6); - } - i_prot.read_list_end()?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("CollectorSubmitBatchesArgs.batches", &f_1)?; - let ret = CollectorSubmitBatchesArgs { - batches: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("submitBatches_args"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("batches", TType::List, 1))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.batches.len() as i32))?; - for e in &self.batches { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// CollectorSubmitBatchesResult -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct CollectorSubmitBatchesResult { - result_value: Option>, -} - -impl CollectorSubmitBatchesResult { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_0: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 0 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_7 = BatchSubmitResponse::read_from_in_protocol(i_prot)?; - val.push(list_elem_7); - } - i_prot.read_list_end()?; - f_0 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = CollectorSubmitBatchesResult { - result_value: f_0, - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("CollectorSubmitBatchesResult"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(ref fld_var) = self.result_value { - o_prot.write_field_begin(&TFieldIdentifier::new("result_value", TType::List, 0))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } - fn ok_or(self) -> thrift::Result> { - if self.result_value.is_some() { - Ok(self.result_value.unwrap()) - } else { - Err( - thrift::Error::Application( - ApplicationError::new( - ApplicationErrorKind::MissingResult, - "no result received for CollectorSubmitBatches" - ) - ) - ) - } - } -} - diff --git a/opentelemetry-jaeger/src/exporter/thrift/mod.rs b/opentelemetry-jaeger/src/exporter/thrift/mod.rs deleted file mode 100644 index c6916fb592..0000000000 --- a/opentelemetry-jaeger/src/exporter/thrift/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Thrift generated Jaeger client -//! -//! Definitions: - -use opentelemetry::{trace::Event, Key, KeyValue, Value}; -use std::time::{Duration, SystemTime}; - -pub(crate) mod agent; -pub(crate) mod jaeger; -pub(crate) mod zipkincore; - -impl From for jaeger::Process { - fn from(process: super::Process) -> jaeger::Process { - jaeger::Process::new( - process.service_name, - Some(process.tags.into_iter().map(Into::into).collect()), - ) - } -} - -impl From for jaeger::Log { - fn from(event: crate::exporter::Event) -> jaeger::Log { - let timestamp = event - .timestamp - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| Duration::from_secs(0)) - .as_micros() as i64; - let mut event_set_via_attribute = false; - let mut fields = event - .attributes - .into_iter() - .map(|attr| { - if attr.key.as_str() == "event" { - event_set_via_attribute = true; - }; - attr.into() - }) - .collect::>(); - - if !event_set_via_attribute { - fields.push(Key::new("event").string(event.name).into()); - } - - if event.dropped_attributes_count != 0 { - fields.push( - Key::new("otel.event.dropped_attributes_count") - .i64(i64::from(event.dropped_attributes_count)) - .into(), - ); - } - - jaeger::Log::new(timestamp, fields) - } -} - -#[rustfmt::skip] -impl From for jaeger::Tag { - fn from(kv: KeyValue) -> jaeger::Tag { - let KeyValue { key, value } = kv; - match value { - Value::String(s) => jaeger::Tag::new(key.into(), jaeger::TagType::String, Some(s.into()), None, None, None, None), - Value::F64(f) => jaeger::Tag::new(key.into(), jaeger::TagType::Double, None, Some(f.into()), None, None, None), - Value::Bool(b) => jaeger::Tag::new(key.into(), jaeger::TagType::Bool, None, None, Some(b), None, None), - Value::I64(i) => jaeger::Tag::new(key.into(), jaeger::TagType::Long, None, None, None, Some(i), None), - // TODO: better Array handling, jaeger thrift doesn't support arrays - v @ Value::Array(_) => jaeger::Tag::new(key.into(), jaeger::TagType::String, Some(v.to_string()), None, None, None, None), - } - } -} diff --git a/opentelemetry-jaeger/src/exporter/thrift/zipkincore.rs b/opentelemetry-jaeger/src/exporter/thrift/zipkincore.rs deleted file mode 100644 index f9d54118db..0000000000 --- a/opentelemetry-jaeger/src/exporter/thrift/zipkincore.rs +++ /dev/null @@ -1,1093 +0,0 @@ -// Autogenerated by Thrift Compiler (0.13.0) -// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - -#![allow(unused_imports)] -#![allow(unused_extern_crates)] -#![allow(clippy::too_many_arguments, clippy::type_complexity)] -#![cfg_attr(rustfmt, rustfmt_skip)] - -extern crate thrift; - -use thrift::OrderedFloat; -use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::{From, TryFrom}; -use std::default::Default; -use std::error::Error; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::rc::Rc; - -use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient}; -use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType}; -use thrift::protocol::field_id; -use thrift::protocol::verify_expected_message_type; -use thrift::protocol::verify_expected_sequence_number; -use thrift::protocol::verify_expected_service_call; -use thrift::protocol::verify_required_field_exists; -use thrift::server::TProcessor; - -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum AnnotationType { - Bool = 0, - Bytes = 1, - I16 = 2, - I32 = 3, - I64 = 4, - Double = 5, - String = 6, -} - -impl AnnotationType { - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - o_prot.write_i32(*self as i32) - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - let enum_value = i_prot.read_i32()?; - AnnotationType::try_from(enum_value) } -} - -impl TryFrom for AnnotationType { - type Error = thrift::Error; fn try_from(i: i32) -> Result { - match i { - 0 => Ok(AnnotationType::Bool), - 1 => Ok(AnnotationType::Bytes), - 2 => Ok(AnnotationType::I16), - 3 => Ok(AnnotationType::I32), - 4 => Ok(AnnotationType::I64), - 5 => Ok(AnnotationType::Double), - 6 => Ok(AnnotationType::String), - _ => { - Err( - thrift::Error::Protocol( - ProtocolError::new( - ProtocolErrorKind::InvalidData, - format!("cannot convert enum constant {} to AnnotationType", i) - ) - ) - ) - }, - } - } -} - -// -// Endpoint -// - -/// Indicates the network context of a service recording an annotation with two -/// exceptions. -/// -/// When a BinaryAnnotation, and key is CLIENT_ADDR or SERVER_ADDR, -/// the endpoint indicates the source or destination of an RPC. This exception -/// allows zipkin to display network context of uninstrumented services, or -/// clients such as web browsers. -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Endpoint { - /// IPv4 host address packed into 4 bytes. - /// - /// Ex for the ip 1.2.3.4, it would be (1 << 24) | (2 << 16) | (3 << 8) | 4 - pub ipv4: Option, - /// IPv4 port - /// - /// Note: this is to be treated as an unsigned integer, so watch for negatives. - /// - /// Conventionally, when the port isn't known, port = 0. - pub port: Option, - /// Service name in lowercase, such as "memcache" or "zipkin-web" - /// - /// Conventionally, when the service name isn't known, service_name = "unknown". - pub service_name: Option, - /// IPv6 host address packed into 16 bytes. Ex Inet6Address.getBytes() - pub ipv6: Option>, -} - -impl Endpoint { - pub fn new(ipv4: F1, port: F2, service_name: F3, ipv6: F4) -> Endpoint where F1: Into>, F2: Into>, F3: Into>, F4: Into>> { - Endpoint { - ipv4: ipv4.into(), - port: port.into(), - service_name: service_name.into(), - ipv6: ipv6.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = Some(0); - let mut f_2: Option = Some(0); - let mut f_3: Option = Some("".to_owned()); - let mut f_4: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_i32()?; - f_1 = Some(val); - }, - 2 => { - let val = i_prot.read_i16()?; - f_2 = Some(val); - }, - 3 => { - let val = i_prot.read_string()?; - f_3 = Some(val); - }, - 4 => { - let val = i_prot.read_bytes()?; - f_4 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = Endpoint { - ipv4: f_1, - port: f_2, - service_name: f_3, - ipv6: f_4, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Endpoint"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(fld_var) = self.ipv4 { - o_prot.write_field_begin(&TFieldIdentifier::new("ipv4", TType::I32, 1))?; - o_prot.write_i32(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.port { - o_prot.write_field_begin(&TFieldIdentifier::new("port", TType::I16, 2))?; - o_prot.write_i16(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.service_name { - o_prot.write_field_begin(&TFieldIdentifier::new("service_name", TType::String, 3))?; - o_prot.write_string(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.ipv6 { - o_prot.write_field_begin(&TFieldIdentifier::new("ipv6", TType::String, 4))?; - o_prot.write_bytes(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -impl Default for Endpoint { - fn default() -> Self { - Endpoint{ - ipv4: Some(0), - port: Some(0), - service_name: Some("".to_owned()), - ipv6: Some(Vec::new()), - } - } -} - -// -// Annotation -// - -/// An annotation is similar to a log statement. It includes a host field which -/// allows these events to be attributed properly, and also aggregatable. -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Annotation { - /// Microseconds from epoch. - /// - /// This value should use the most precise value possible. For example, - /// gettimeofday or syncing nanoTime against a tick of currentTimeMillis. - pub timestamp: Option, - pub value: Option, - /// Always the host that recorded the event. By specifying the host you allow - /// rollup of all events (such as client requests to a service) by IP address. - pub host: Option, -} - -impl Annotation { - pub fn new(timestamp: F1, value: F2, host: F3) -> Annotation where F1: Into>, F2: Into>, F3: Into> { - Annotation { - timestamp: timestamp.into(), - value: value.into(), - host: host.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = Some(0); - let mut f_2: Option = Some("".to_owned()); - let mut f_3: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_i64()?; - f_1 = Some(val); - }, - 2 => { - let val = i_prot.read_string()?; - f_2 = Some(val); - }, - 3 => { - let val = Endpoint::read_from_in_protocol(i_prot)?; - f_3 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = Annotation { - timestamp: f_1, - value: f_2, - host: f_3, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Annotation"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(fld_var) = self.timestamp { - o_prot.write_field_begin(&TFieldIdentifier::new("timestamp", TType::I64, 1))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.value { - o_prot.write_field_begin(&TFieldIdentifier::new("value", TType::String, 2))?; - o_prot.write_string(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.host { - o_prot.write_field_begin(&TFieldIdentifier::new("host", TType::Struct, 3))?; - fld_var.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -impl Default for Annotation { - fn default() -> Self { - Annotation{ - timestamp: Some(0), - value: Some("".to_owned()), - host: None, - } - } -} - -// -// BinaryAnnotation -// - -/// Binary annotations are tags applied to a Span to give it context. For -/// example, a binary annotation of "http.uri" could the path to a resource in a -/// RPC call. -/// -/// Binary annotations of type STRING are always queryable, though more a -/// historical implementation detail than a structural concern. -/// -/// Binary annotations can repeat, and vary on the host. Similar to Annotation, -/// the host indicates who logged the event. This allows you to tell the -/// difference between the client and server side of the same key. For example, -/// the key "http.uri" might be different on the client and server side due to -/// rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field, -/// you can see the different points of view, which often help in debugging. -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct BinaryAnnotation { - pub key: Option, - pub value: Option>, - pub annotation_type: Option, - /// The host that recorded tag, which allows you to differentiate between - /// multiple tags with the same key. There are two exceptions to this. - /// - /// When the key is CLIENT_ADDR or SERVER_ADDR, host indicates the source or - /// destination of an RPC. This exception allows zipkin to display network - /// context of uninstrumented services, or clients such as web browsers. - pub host: Option, -} - -impl BinaryAnnotation { - pub fn new(key: F1, value: F2, annotation_type: F3, host: F4) -> BinaryAnnotation where F1: Into>, F2: Into>>, F3: Into>, F4: Into> { - BinaryAnnotation { - key: key.into(), - value: value.into(), - annotation_type: annotation_type.into(), - host: host.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = Some("".to_owned()); - let mut f_2: Option> = Some(Vec::new()); - let mut f_3: Option = None; - let mut f_4: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_string()?; - f_1 = Some(val); - }, - 2 => { - let val = i_prot.read_bytes()?; - f_2 = Some(val); - }, - 3 => { - let val = AnnotationType::read_from_in_protocol(i_prot)?; - f_3 = Some(val); - }, - 4 => { - let val = Endpoint::read_from_in_protocol(i_prot)?; - f_4 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = BinaryAnnotation { - key: f_1, - value: f_2, - annotation_type: f_3, - host: f_4, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("BinaryAnnotation"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(ref fld_var) = self.key { - o_prot.write_field_begin(&TFieldIdentifier::new("key", TType::String, 1))?; - o_prot.write_string(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.value { - o_prot.write_field_begin(&TFieldIdentifier::new("value", TType::String, 2))?; - o_prot.write_bytes(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.annotation_type { - o_prot.write_field_begin(&TFieldIdentifier::new("annotation_type", TType::I32, 3))?; - fld_var.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.host { - o_prot.write_field_begin(&TFieldIdentifier::new("host", TType::Struct, 4))?; - fld_var.write_to_out_protocol(o_prot)?; - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -impl Default for BinaryAnnotation { - fn default() -> Self { - BinaryAnnotation{ - key: Some("".to_owned()), - value: Some(Vec::new()), - annotation_type: None, - host: None, - } - } -} - -// -// Span -// - -/// A trace is a series of spans (often RPC calls) which form a latency tree. -/// -/// The root span is where trace_id = id and parent_id = Nil. The root span is -/// usually the longest interval in the trace, starting with a SERVER_RECV -/// annotation and ending with a SERVER_SEND. -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Span { - pub trace_id: Option, - /// Span name in lowercase, rpc method for example - /// - /// Conventionally, when the span name isn't known, name = "unknown". - pub name: Option, - pub id: Option, - pub parent_id: Option, - pub annotations: Option>, - pub binary_annotations: Option>, - pub debug: Option, - /// Microseconds from epoch of the creation of this span. - /// - /// This value should be set directly by instrumentation, using the most - /// precise value possible. For example, gettimeofday or syncing nanoTime - /// against a tick of currentTimeMillis. - /// - /// For compatibilty with instrumentation that precede this field, collectors - /// or span stores can derive this via Annotation.timestamp. - /// For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp. - /// - /// This field is optional for compatibility with old data: first-party span - /// stores are expected to support this at time of introduction. - pub timestamp: Option, - /// Measurement of duration in microseconds, used to support queries. - /// - /// This value should be set directly, where possible. Doing so encourages - /// precise measurement decoupled from problems of clocks, such as skew or NTP - /// updates causing time to move backwards. - /// - /// For compatibilty with instrumentation that precede this field, collectors - /// or span stores can derive this by subtracting Annotation.timestamp. - /// For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp. - /// - /// If this field is persisted as unset, zipkin will continue to work, except - /// duration query support will be implementation-specific. Similarly, setting - /// this field non-atomically is implementation-specific. - /// - /// This field is i64 vs i32 to support spans longer than 35 minutes. - pub duration: Option, - /// Optional unique 8-byte additional identifier for a trace. If non zero, this - /// means the trace uses 128 bit traceIds instead of 64 bit. - pub trace_id_high: Option, -} - -impl Span { - pub fn new(trace_id: F1, name: F3, id: F4, parent_id: F5, annotations: F6, binary_annotations: F8, debug: F9, timestamp: F10, duration: F11, trace_id_high: F12) -> Span where F1: Into>, F3: Into>, F4: Into>, F5: Into>, F6: Into>>, F8: Into>>, F9: Into>, F10: Into>, F11: Into>, F12: Into> { - Span { - trace_id: trace_id.into(), - name: name.into(), - id: id.into(), - parent_id: parent_id.into(), - annotations: annotations.into(), - binary_annotations: binary_annotations.into(), - debug: debug.into(), - timestamp: timestamp.into(), - duration: duration.into(), - trace_id_high: trace_id_high.into(), - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = Some(0); - let mut f_3: Option = Some("".to_owned()); - let mut f_4: Option = Some(0); - let mut f_5: Option = None; - let mut f_6: Option> = Some(Vec::new()); - let mut f_8: Option> = Some(Vec::new()); - let mut f_9: Option = None; - let mut f_10: Option = None; - let mut f_11: Option = None; - let mut f_12: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_i64()?; - f_1 = Some(val); - }, - 3 => { - let val = i_prot.read_string()?; - f_3 = Some(val); - }, - 4 => { - let val = i_prot.read_i64()?; - f_4 = Some(val); - }, - 5 => { - let val = i_prot.read_i64()?; - f_5 = Some(val); - }, - 6 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_0 = Annotation::read_from_in_protocol(i_prot)?; - val.push(list_elem_0); - } - i_prot.read_list_end()?; - f_6 = Some(val); - }, - 8 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_1 = BinaryAnnotation::read_from_in_protocol(i_prot)?; - val.push(list_elem_1); - } - i_prot.read_list_end()?; - f_8 = Some(val); - }, - 9 => { - let val = i_prot.read_bool()?; - f_9 = Some(val); - }, - 10 => { - let val = i_prot.read_i64()?; - f_10 = Some(val); - }, - 11 => { - let val = i_prot.read_i64()?; - f_11 = Some(val); - }, - 12 => { - let val = i_prot.read_i64()?; - f_12 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = Span { - trace_id: f_1, - name: f_3, - id: f_4, - parent_id: f_5, - annotations: f_6, - binary_annotations: f_8, - debug: f_9, - timestamp: f_10, - duration: f_11, - trace_id_high: f_12, - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Span"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(fld_var) = self.trace_id { - o_prot.write_field_begin(&TFieldIdentifier::new("trace_id", TType::I64, 1))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.name { - o_prot.write_field_begin(&TFieldIdentifier::new("name", TType::String, 3))?; - o_prot.write_string(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.id { - o_prot.write_field_begin(&TFieldIdentifier::new("id", TType::I64, 4))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.parent_id { - o_prot.write_field_begin(&TFieldIdentifier::new("parent_id", TType::I64, 5))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.annotations { - o_prot.write_field_begin(&TFieldIdentifier::new("annotations", TType::List, 6))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(ref fld_var) = self.binary_annotations { - o_prot.write_field_begin(&TFieldIdentifier::new("binary_annotations", TType::List, 8))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.debug { - o_prot.write_field_begin(&TFieldIdentifier::new("debug", TType::Bool, 9))?; - o_prot.write_bool(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.timestamp { - o_prot.write_field_begin(&TFieldIdentifier::new("timestamp", TType::I64, 10))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.duration { - o_prot.write_field_begin(&TFieldIdentifier::new("duration", TType::I64, 11))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - if let Some(fld_var) = self.trace_id_high { - o_prot.write_field_begin(&TFieldIdentifier::new("trace_id_high", TType::I64, 12))?; - o_prot.write_i64(fld_var)?; - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -impl Default for Span { - fn default() -> Self { - Span{ - trace_id: Some(0), - name: Some("".to_owned()), - id: Some(0), - parent_id: Some(0), - annotations: Some(Vec::new()), - binary_annotations: Some(Vec::new()), - debug: Some(false), - timestamp: Some(0), - duration: Some(0), - trace_id_high: Some(0), - } - } -} - -// -// Response -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Response { - pub ok: bool, -} - -impl Response { - pub fn new(ok: bool) -> Response { - Response { - ok, - - } - } - pub fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let val = i_prot.read_bool()?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("Response.ok", &f_1)?; - let ret = Response { - ok: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - pub fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("Response"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("ok", TType::Bool, 1))?; - o_prot.write_bool(self.ok)?; - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -pub const C_L_I_E_N_T_S_E_N_D: &str = "cs"; - -pub const C_L_I_E_N_T_R_E_C_V: &str = "cr"; - -pub const S_E_R_V_E_R_S_E_N_D: &str = "ss"; - -pub const S_E_R_V_E_R_R_E_C_V: &str = "sr"; - -pub const M_E_S_S_A_G_E_S_E_N_D: &str = "ms"; - -pub const M_E_S_S_A_G_E_R_E_C_V: &str = "mr"; - -pub const W_I_R_E_S_E_N_D: &str = "ws"; - -pub const W_I_R_E_R_E_C_V: &str = "wr"; - -pub const C_L_I_E_N_T_S_E_N_D_F_R_A_G_M_E_N_T: &str = "csf"; - -pub const C_L_I_E_N_T_R_E_C_V_F_R_A_G_M_E_N_T: &str = "crf"; - -pub const S_E_R_V_E_R_S_E_N_D_F_R_A_G_M_E_N_T: &str = "ssf"; - -pub const S_E_R_V_E_R_R_E_C_V_F_R_A_G_M_E_N_T: &str = "srf"; - -pub const L_O_C_A_L_C_O_M_P_O_N_E_N_T: &str = "lc"; - -pub const C_L_I_E_N_T_A_D_D_R: &str = "ca"; - -pub const S_E_R_V_E_R_A_D_D_R: &str = "sa"; - -pub const M_E_S_S_A_G_E_A_D_D_R: &str = "ma"; - -// -// ZipkinCollector service client -// - -pub trait TZipkinCollectorSyncClient { - fn submit_zipkin_batch(&mut self, spans: Vec) -> thrift::Result>; -} - -pub trait TZipkinCollectorSyncClientMarker {} - -pub struct ZipkinCollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - _i_prot: IP, - _o_prot: OP, - _sequence_number: i32, -} - -impl ZipkinCollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - pub fn new(input_protocol: IP, output_protocol: OP) -> ZipkinCollectorSyncClient { - ZipkinCollectorSyncClient { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 } - } -} - -impl TThriftClient for ZipkinCollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol { - fn i_prot_mut(&mut self) -> &mut dyn TInputProtocol { &mut self._i_prot } - fn o_prot_mut(&mut self) -> &mut dyn TOutputProtocol { &mut self._o_prot } - fn sequence_number(&self) -> i32 { self._sequence_number } - fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number } -} - -impl TZipkinCollectorSyncClientMarker for ZipkinCollectorSyncClient where IP: TInputProtocol, OP: TOutputProtocol {} - -impl TZipkinCollectorSyncClient for C { - fn submit_zipkin_batch(&mut self, spans: Vec) -> thrift::Result> { - ( - { - self.increment_sequence_number(); - let message_ident = TMessageIdentifier::new("submitZipkinBatch", TMessageType::Call, self.sequence_number()); - let call_args = ZipkinCollectorSubmitZipkinBatchArgs { spans }; - self.o_prot_mut().write_message_begin(&message_ident)?; - call_args.write_to_out_protocol(self.o_prot_mut())?; - self.o_prot_mut().write_message_end()?; - self.o_prot_mut().flush() - } - )?; - { - let message_ident = self.i_prot_mut().read_message_begin()?; - verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?; - verify_expected_service_call("submitZipkinBatch", &message_ident.name)?; - if message_ident.message_type == TMessageType::Exception { - let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?; - self.i_prot_mut().read_message_end()?; - return Err(thrift::Error::Application(remote_error)) - } - verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?; - let result = ZipkinCollectorSubmitZipkinBatchResult::read_from_in_protocol(self.i_prot_mut())?; - self.i_prot_mut().read_message_end()?; - result.ok_or() - } - } -} - -// -// ZipkinCollector service processor -// - -pub trait ZipkinCollectorSyncHandler { - fn handle_submit_zipkin_batch(&self, spans: Vec) -> thrift::Result>; -} - -pub struct ZipkinCollectorSyncProcessor { - handler: H, -} - -impl ZipkinCollectorSyncProcessor { - pub fn new(handler: H) -> ZipkinCollectorSyncProcessor { - ZipkinCollectorSyncProcessor { - handler, - } - } - fn process_submit_zipkin_batch(&self, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - TZipkinCollectorProcessFunctions::process_submit_zipkin_batch(&self.handler, incoming_sequence_number, i_prot, o_prot) - } -} - -pub struct TZipkinCollectorProcessFunctions; - -impl TZipkinCollectorProcessFunctions { - pub fn process_submit_zipkin_batch(handler: &H, incoming_sequence_number: i32, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let args = ZipkinCollectorSubmitZipkinBatchArgs::read_from_in_protocol(i_prot)?; - match handler.handle_submit_zipkin_batch(args.spans) { - Ok(handler_return) => { - let message_ident = TMessageIdentifier::new("submitZipkinBatch", TMessageType::Reply, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - let ret = ZipkinCollectorSubmitZipkinBatchResult { result_value: Some(handler_return) }; - ret.write_to_out_protocol(o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - Err(e) => { - match e { - thrift::Error::Application(app_err) => { - let message_ident = TMessageIdentifier::new("submitZipkinBatch", TMessageType::Exception, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - thrift::Error::write_application_error_to_out_protocol(&app_err, o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - _ => { - let ret_err = { - ApplicationError::new( - ApplicationErrorKind::Unknown, - e.to_string() - ) - }; - let message_ident = TMessageIdentifier::new("submitZipkinBatch", TMessageType::Exception, incoming_sequence_number); - o_prot.write_message_begin(&message_ident)?; - thrift::Error::write_application_error_to_out_protocol(&ret_err, o_prot)?; - o_prot.write_message_end()?; - o_prot.flush() - }, - } - }, - } - } -} - -impl TProcessor for ZipkinCollectorSyncProcessor { - fn process(&self, i_prot: &mut dyn TInputProtocol, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let message_ident = i_prot.read_message_begin()?; - let res = match &*message_ident.name { - "submitZipkinBatch" => { - self.process_submit_zipkin_batch(message_ident.sequence_number, i_prot, o_prot) - }, - method => { - Err( - thrift::Error::Application( - ApplicationError::new( - ApplicationErrorKind::UnknownMethod, - format!("unknown method {}", method) - ) - ) - ) - }, - }; - thrift::server::handle_process_result(&message_ident, res, o_prot) - } -} - -// -// ZipkinCollectorSubmitZipkinBatchArgs -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct ZipkinCollectorSubmitZipkinBatchArgs { - spans: Vec, -} - -impl ZipkinCollectorSubmitZipkinBatchArgs { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_1: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 1 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_2 = Span::read_from_in_protocol(i_prot)?; - val.push(list_elem_2); - } - i_prot.read_list_end()?; - f_1 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - verify_required_field_exists("ZipkinCollectorSubmitZipkinBatchArgs.spans", &f_1)?; - let ret = ZipkinCollectorSubmitZipkinBatchArgs { - spans: f_1.expect("auto-generated code should have checked for presence of required fields"), - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("submitZipkinBatch_args"); - o_prot.write_struct_begin(&struct_ident)?; - o_prot.write_field_begin(&TFieldIdentifier::new("spans", TType::List, 1))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.spans.len() as i32))?; - for e in &self.spans { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } -} - -// -// ZipkinCollectorSubmitZipkinBatchResult -// - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct ZipkinCollectorSubmitZipkinBatchResult { - result_value: Option>, -} - -impl ZipkinCollectorSubmitZipkinBatchResult { - fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result { - i_prot.read_struct_begin()?; - let mut f_0: Option> = None; - loop { - let field_ident = i_prot.read_field_begin()?; - if field_ident.field_type == TType::Stop { - break; - } - let field_id = field_id(&field_ident)?; - match field_id { - 0 => { - let list_ident = i_prot.read_list_begin()?; - let mut val: Vec = Vec::with_capacity(list_ident.size as usize); - for _ in 0..list_ident.size { - let list_elem_3 = Response::read_from_in_protocol(i_prot)?; - val.push(list_elem_3); - } - i_prot.read_list_end()?; - f_0 = Some(val); - }, - _ => { - i_prot.skip(field_ident.field_type)?; - }, - }; - i_prot.read_field_end()?; - } - i_prot.read_struct_end()?; - let ret = ZipkinCollectorSubmitZipkinBatchResult { - result_value: f_0, - }; - Ok(ret) - } - fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> { - let struct_ident = TStructIdentifier::new("ZipkinCollectorSubmitZipkinBatchResult"); - o_prot.write_struct_begin(&struct_ident)?; - if let Some(ref fld_var) = self.result_value { - o_prot.write_field_begin(&TFieldIdentifier::new("result_value", TType::List, 0))?; - o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, fld_var.len() as i32))?; - for e in fld_var { - e.write_to_out_protocol(o_prot)?; - o_prot.write_list_end()?; - } - o_prot.write_field_end()?; - () - } else { - () - } - o_prot.write_field_stop()?; - o_prot.write_struct_end() - } - fn ok_or(self) -> thrift::Result> { - if self.result_value.is_some() { - Ok(self.result_value.unwrap()) - } else { - Err( - thrift::Error::Application( - ApplicationError::new( - ApplicationErrorKind::MissingResult, - "no result received for ZipkinCollectorSubmitZipkinBatch" - ) - ) - ) - } - } -} - diff --git a/opentelemetry-jaeger/src/exporter/transport/buffer.rs b/opentelemetry-jaeger/src/exporter/transport/buffer.rs deleted file mode 100644 index f6d63f7d50..0000000000 --- a/opentelemetry-jaeger/src/exporter/transport/buffer.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::io; -use std::sync::{Arc, Mutex}; -use thrift::transport::{ReadHalf, TIoChannel, WriteHalf}; - -/// Custom TBufferChannel that can be dynamically grown and split off of. -#[derive(Debug, Clone)] -pub(crate) struct TBufferChannel { - inner: Arc>>, -} - -impl TBufferChannel { - /// Create a new buffer channel with the given initial capacity - pub(crate) fn with_capacity(capacity: usize) -> Self { - TBufferChannel { - inner: Arc::new(Mutex::new(Vec::with_capacity(capacity))), - } - } - - /// Take the accumulated bytes from the buffer, leaving capacity unchanged. - pub(crate) fn take_bytes(&mut self) -> Vec { - self.inner - .lock() - .map(|mut write| write.split_off(0)) - .unwrap_or_default() - } -} - -impl io::Read for TBufferChannel { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - unreachable!("jaeger protocol never reads") - } -} - -impl io::Write for TBufferChannel { - fn write(&mut self, buf: &[u8]) -> io::Result { - if let Ok(mut inner) = self.inner.lock() { - inner.extend_from_slice(buf); - } - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl TIoChannel for TBufferChannel { - fn split(self) -> thrift::Result<(ReadHalf, WriteHalf)> - where - Self: Sized, - { - Ok((ReadHalf::new(self.clone()), WriteHalf::new(self))) - } -} diff --git a/opentelemetry-jaeger/src/exporter/transport/mod.rs b/opentelemetry-jaeger/src/exporter/transport/mod.rs deleted file mode 100644 index 302927e4d4..0000000000 --- a/opentelemetry-jaeger/src/exporter/transport/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Additional Thrift transport implementations -mod buffer; -mod noop; - -pub(crate) use buffer::TBufferChannel; -pub(crate) use noop::TNoopChannel; diff --git a/opentelemetry-jaeger/src/exporter/transport/noop.rs b/opentelemetry-jaeger/src/exporter/transport/noop.rs deleted file mode 100644 index 5c51e0fb09..0000000000 --- a/opentelemetry-jaeger/src/exporter/transport/noop.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::io; - -#[derive(Debug)] -pub(crate) struct TNoopChannel; - -impl io::Read for TNoopChannel { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } -} diff --git a/opentelemetry-jaeger/src/exporter/uploader.rs b/opentelemetry-jaeger/src/exporter/uploader.rs deleted file mode 100644 index ce5a46b79b..0000000000 --- a/opentelemetry-jaeger/src/exporter/uploader.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! # Jaeger Span Uploader -#[cfg(any(feature = "collector_client", feature = "wasm_collector_client"))] -use crate::exporter::collector; -use crate::exporter::{agent, jaeger}; -use async_trait::async_trait; -use opentelemetry_sdk::export::trace::ExportResult; -use std::fmt::Debug; - -use crate::exporter::thrift::jaeger::Batch; -use crate::exporter::JaegerTraceRuntime; - -#[async_trait] -pub(crate) trait Uploader: Debug + Send + Sync { - async fn upload(&self, batch: jaeger::Batch) -> ExportResult; -} - -#[derive(Debug)] -pub(crate) enum SyncUploader { - Agent(std::sync::Mutex), -} - -#[async_trait] -impl Uploader for SyncUploader { - async fn upload(&self, batch: jaeger::Batch) -> ExportResult { - match self { - SyncUploader::Agent(client) => { - // TODO Implement retry behavior - client - .lock() - .expect("Failed to lock agent client") - .emit_batch(batch) - .map_err::(Into::into)?; - } - } - Ok(()) - } -} - -/// Uploads a batch of spans to Jaeger -#[derive(Debug)] -pub(crate) enum AsyncUploader { - /// Agent async client - Agent(futures_util::lock::Mutex>), - /// Collector sync client - #[cfg(feature = "collector_client")] - Collector(collector::AsyncHttpClient), - #[cfg(feature = "wasm_collector_client")] - WasmCollector(collector::WasmCollector), -} - -#[async_trait] -impl Uploader for AsyncUploader { - async fn upload(&self, batch: Batch) -> ExportResult { - match self { - Self::Agent(client) => { - // TODO Implement retry behaviour - client - .lock() - .await - .emit_batch(batch) - .await - .map_err::(Into::into)?; - } - #[cfg(feature = "collector_client")] - Self::Collector(collector) => { - // TODO Implement retry behaviour - collector.submit_batch(batch).await?; - } - #[cfg(feature = "wasm_collector_client")] - Self::WasmCollector(collector) => { - collector - .submit_batch(batch) - .await - .map_err::(Into::into)?; - } - } - Ok(()) - } -} diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs deleted file mode 100644 index de35884f69..0000000000 --- a/opentelemetry-jaeger/src/lib.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! Collects OpenTelemetry spans and reports them to a given Jaeger -//! `agent` or `collector` endpoint, propagate the tracing context between the applications using [Jaeger propagation format]. -//! -//! *Warning*: Note that the exporter component from this crate will be [deprecated][jaeger-deprecation] -//! in the future. Users are advised to move to [opentelemetry_otlp][otlp-exporter] instead as [Jaeger][jaeger-otlp] -//! supports accepting data in the OTLP protocol. -//! See the [Jaeger Docs] for details about Jaeger and deployment information. -//! -//! *Compiler support: [requires `rustc` 1.64+][msrv]* -//! -//! [Jaeger Docs]: https://www.jaegertracing.io/docs/ -//! [jaeger-deprecation]: https://github.com/open-telemetry/opentelemetry-specification/pull/2858/files -//! [jaeger-otlp]: https://www.jaegertracing.io/docs/1.38/apis/#opentelemetry-protocol-stable -//! [otlp-exporter]: https://docs.rs/opentelemetry-otlp/latest/opentelemetry_otlp/ -//! [msrv]: #supported-rust-versions -//! [jaeger propagation format]: https://www.jaegertracing.io/docs/1.18/client-libraries/#propagation-format -//! -//! ## Quickstart -//! -//! First make sure you have a running version of the Jaeger instance -//! you want to send data to: -//! -//! ```shell -//! $ docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest -//! ``` -//! -//! Then install a new jaeger pipeline with the recommended defaults to start -//! exporting telemetry: -//! -//! ```no_run -//! use opentelemetry::{global, trace::{Tracer, TraceError}}; -//! use opentelemetry_jaeger_propagator; -//! -//! #[tokio::main] -//! async fn main() -> Result<(), TraceError> { -//! global::set_text_map_propagator(opentelemetry_jaeger_propagator::Propagator::new()); -//! let tracer = opentelemetry_jaeger::new_agent_pipeline().install_simple()?; -//! -//! tracer.in_span("doing_work", |cx| { -//! // Traced app logic here... -//! }); -//! -//! global::shutdown_tracer_provider(); // export remaining spans -//! -//! Ok(()) -//! } -//! ``` -//! -//! Or if you are running on an async runtime like Tokio and want to report spans in batches -//! ```no_run -//! use opentelemetry::{global, trace::{Tracer, TraceError}}; -//! use opentelemetry_sdk::runtime::Tokio; -//! use opentelemetry_jaeger_propagator; -//! -//! fn main() -> Result<(), TraceError> { -//! global::set_text_map_propagator(opentelemetry_jaeger_propagator::Propagator::new()); -//! let tracer = opentelemetry_jaeger::new_agent_pipeline().install_batch(Tokio)?; -//! -//! tracer.in_span("doing_work", |cx| { -//! // Traced app logic here... -//! }); -//! -//! global::shutdown_tracer_provider(); // export remaining spans -//! -//! Ok(()) -//! } -//! ``` -//! ## Performance -//! -//! For optimal performance, a batch exporter is recommended as the simple exporter -//! will export each span synchronously on drop. You can enable the `rt-tokio`, -//! `rt-tokio-current-thread` or `rt-async-std` features and specify a runtime -//! on the pipeline builder to have a batch exporter configured for you -//! automatically. -//! -//! ```toml -//! [dependencies] -//! opentelemetry_sdk = { version = "*", features = ["rt-tokio"] } -//! opentelemetry-jaeger = { version = "*", features = ["rt-tokio"] } -//! ``` -//! -//! ```no_run -//! # fn main() -> Result<(), opentelemetry::trace::TraceError> { -//! let tracer = opentelemetry_jaeger::new_agent_pipeline() -//! .install_batch(opentelemetry_sdk::runtime::Tokio)?; -//! # Ok(()) -//! # } -//! ``` -//! -//! [`tokio`]: https://tokio.rs -//! [`async-std`]: https://async.rs -//! -//! ## Jaeger Exporter From Environment Variables -//! -//! The jaeger pipeline builder can be configured dynamically via environment -//! variables. All variables are optional, a full list of accepted options can -//! be found in the [jaeger variables spec]. -//! -//! [jaeger variables spec]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md -//! -//! ## Jaeger Collector Example -//! -//! If you want to skip the agent and submit spans directly to a Jaeger collector, -//! you can enable the optional `collector_client` feature for this crate. This -//! example expects a Jaeger collector running on `http://localhost:14268`. -//! -//! ```toml -//! [dependencies] -//! opentelemetry-jaeger = { version = "..", features = ["collector_client", "isahc_collector_client"] } -//! ``` -//! -//! Then you can use the [`with_endpoint`] method to specify the endpoint: -//! -//! [`with_endpoint`]: exporter::config::collector::CollectorPipeline::with_endpoint -//! -//! ```ignore -//! // Note that this requires the `collector_client` feature. -//! // We enabled the `isahc_collector_client` feature for a default isahc http client. -//! // You can also provide your own implementation via .with_http_client() method. -//! use opentelemetry::trace::{Tracer, TraceError}; -//! -//! fn main() -> Result<(), TraceError> { -//! let tracer = opentelemetry_jaeger::new_collector_pipeline() -//! .with_endpoint("http://localhost:14268/api/traces") -//! // optionally set username and password for authentication of the exporter. -//! .with_username("username") -//! .with_password("s3cr3t") -//! .with_isahc() -//! //.with_http_client() provide custom http client implementation -//! .install_batch(opentelemetry_sdk::runtime::Tokio)?; -//! -//! tracer.in_span("doing_work", |cx| { -//! // Traced app logic here... -//! }); -//! -//! Ok(()) -//! } -//! ``` -//! ## Resource, tags and service name -//! In order to export the spans in different format. opentelemetry uses its own -//! model internally. Most of the jaeger spans' concept can be found in this model. -//! The full list of this mapping can be found in [OpenTelemetry to Jaeger Transformation]. -//! -//! The **process tags** in jaeger spans will be mapped as resource in opentelemetry. You can -//! set it through `OTEL_RESOURCE_ATTRIBUTES` environment variable or using [`with_trace_config`]. -//! -//! Note that to avoid copying data multiple times. Jaeger exporter will uses resource stored in [`Exporter`]. -//! -//! The **tags** in jaeger spans will be mapped as attributes in opentelemetry spans. You can -//! set it through [`set_attribute`] method. -//! -//! Each jaeger span requires a **service name**. This will be mapped as a resource with `service.name` key. -//! You can set it using one of the following methods from highest priority to lowest priority. -//! 1. [`with_service_name`]. -//! 2. include a `service.name` key value pairs when configure resource using [`with_trace_config`]. -//! 3. set the service name as `OTEL_SERVICE_NAME` environment variable. -//! 4. set the `service.name` attributes in `OTEL_RESOURCE_ATTRIBUTES`. -//! 5. if the service name is not provided by the above method. `unknown_service` will be used. -//! -//! Based on the service name, we update/append the `service.name` process tags in jaeger spans. -//! -//! [`with_service_name`]: crate::exporter::config::agent::AgentPipeline::with_service_name -//! [`with_trace_config`]: crate::exporter::config::agent::AgentPipeline::with_trace_config -//! [`set_attribute`]: opentelemetry::trace::Span::set_attribute -//! [OpenTelemetry to Jaeger Transformation]:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md -//! -//! ## Kitchen Sink Full Configuration -//! -//! Example showing how to override all configuration options. See the -//! [`CollectorPipeline`] and [`AgentPipeline`] docs for details of each option. -//! -//! [`CollectorPipeline`]: config::collector::CollectorPipeline -//! [`AgentPipeline`]: config::agent::AgentPipeline -//! -//! ### Export to agents -//! ```no_run -//! use opentelemetry::{global, KeyValue, trace::{Tracer, TraceError}}; -//! use opentelemetry_sdk::{trace::{config, RandomIdGenerator, Sampler}, Resource}; -//! use opentelemetry_jaeger_propagator; -//! -//! fn main() -> Result<(), TraceError> { -//! global::set_text_map_propagator(opentelemetry_jaeger_propagator::Propagator::new()); -//! let tracer = opentelemetry_jaeger::new_agent_pipeline() -//! .with_endpoint("localhost:6831") -//! .with_service_name("my_app") -//! .with_max_packet_size(9_216) -//! .with_auto_split_batch(true) -//! .with_instrumentation_library_tags(false) -//! .with_trace_config( -//! config() -//! .with_sampler(Sampler::AlwaysOn) -//! .with_id_generator(RandomIdGenerator::default()) -//! .with_max_events_per_span(64) -//! .with_max_attributes_per_span(16) -//! // resources will translated to tags in jaeger spans -//! .with_resource(Resource::new(vec![KeyValue::new("key", "value"), -//! KeyValue::new("process_key", "process_value")])), -//! ) -//! .install_batch(opentelemetry_sdk::runtime::Tokio)?; -//! -//! tracer.in_span("doing_work", |cx| { -//! // Traced app logic here... -//! }); -//! -//! // export remaining spans. It's optional if you can accept spans loss for the last batch. -//! global::shutdown_tracer_provider(); -//! -//! Ok(()) -//! } -//! ``` -//! -//! ### Export to collectors -//! Note that this example requires `collector_client` and `isahc_collector_client` feature. -//! ```ignore -//! use opentelemetry::{global, KeyValue, trace::{Tracer, TraceError}}; -//! use opentelemetry_sdk::{trace::{config, RandomIdGenerator, Sampler}, Resource}; -//! use opentelemetry_jaeger_propagator; -//! -//! fn main() -> Result<(), TraceError> { -//! global::set_text_map_propagator(opentelemetry_jaeger_propagator::Propagator::new()); -//! let tracer = opentelemetry_jaeger::new_collector_pipeline() -//! .with_endpoint("http://localhost:14250/api/trace") // set collector endpoint -//! .with_service_name("my_app") // the name of the application -//! .with_trace_config( -//! config() -//! .with_sampler(Sampler::AlwaysOn) -//! .with_id_generator(RandomIdGenerator::default()) -//! .with_max_events_per_span(64) -//! .with_max_attributes_per_span(16) -//! .with_max_events_per_span(16) -//! // resources will translated to tags in jaeger spans -//! .with_resource(Resource::new(vec![KeyValue::new("key", "value"), -//! KeyValue::new("process_key", "process_value")])), -//! ) -//! .with_username("username") -//! .with_password("s3cr3t") -//! .with_timeout(std::time::Duration::from_secs(2)) -//! .install_batch(opentelemetry_sdk::runtime::Tokio)?; -//! -//! tracer.in_span("doing_work", |cx| { -//! // Traced app logic here... -//! }); -//! -//! // export remaining spans. It's optional if you can accept spans loss for the last batch. -//! global::shutdown_tracer_provider(); -//! -//! Ok(()) -//! } -//! ``` -//! -//! # Crate Feature Flags -//! -//! The following crate feature flags are available: -//! -//! * `collector_client`: Export span data directly to a Jaeger collector. User MUST provide the http client. -//! -//! * `hyper_collector_client`: Export span data with Jaeger collector backed by a hyper default http client. -//! -//! * `reqwest_collector_client`: Export span data with Jaeger collector backed by a reqwest http client. -//! -//! * `reqwest_blocking_collector_client`: Export span data with Jaeger collector backed by a reqwest blocking http client. -//! -//! * `isahc_collector_client`: Export span data with Jaeger collector backed by a isahc http client. -//! -//! * `wasm_collector_client`: Enable collector in wasm. -//! -//! Support for recording and exporting telemetry asynchronously can be added -//! via the following flags, it extends the [`opentelemetry`] feature: -//! -//! * `rt-tokio`: Enable sending UDP packets to Jaeger agent asynchronously when the tokio -//! [`Multi-Threaded Scheduler`] is used. -//! -//! * `rt-tokio-current-thread`: Enable sending UDP packets to Jaeger agent asynchronously when the -//! tokio [`Current-Thread Scheduler`] is used. -//! -//! * `rt-async-std`: Enable sending UDP packets to Jaeger agent asynchronously when the -//! [`async-std`] runtime is used. -//! -//! [`Multi-Threaded Scheduler`]: https://docs.rs/tokio/latest/tokio/runtime/index.html#multi-thread-scheduler -//! [`Current-Thread Scheduler`]: https://docs.rs/tokio/latest/tokio/runtime/index.html#current-thread-scheduler -//! [`async-std`]: https://async.rs -//! [`opentelemetry`]: https://crates.io/crates/opentelemetry -//! -//! # Supported Rust Versions -//! -//! OpenTelemetry is built against the latest stable release. The minimum -//! supported version is 1.64. The current OpenTelemetry version is not -//! guaranteed to build on Rust versions earlier than the minimum supported -//! version. -//! -//! The current stable Rust compiler and the three most recent minor versions -//! before it will always be supported. For example, if the current stable -//! compiler version is 1.64, the minimum supported version will not be -//! increased past 1.46, three minor versions prior. Increasing the minimum -//! supported compiler version is not considered a semver breaking change as -//! long as doing so complies with this policy. -#![warn( - future_incompatible, - missing_debug_implementations, - missing_docs, - nonstandard_style, - rust_2018_idioms, - unreachable_pub, - unused -)] -#![allow(deprecated)] -#![cfg_attr( - docsrs, - feature(doc_cfg, doc_auto_cfg), - deny(rustdoc::broken_intra_doc_links) -)] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/open-telemetry/opentelemetry-rust/main/assets/logo.svg" -)] -#![cfg_attr(test, deny(warnings))] - -pub use exporter::config; -#[cfg(feature = "collector_client")] -pub use exporter::config::collector::new_collector_pipeline; -#[cfg(feature = "wasm_collector_client")] -pub use exporter::config::collector::new_wasm_collector_pipeline; -pub use exporter::{ - config::agent::new_agent_pipeline, runtime::JaegerTraceRuntime, Error, Exporter, Process, -}; - -mod exporter; - -#[cfg(feature = "integration_test")] -#[doc(hidden)] -pub mod testing; diff --git a/opentelemetry-jaeger/src/testing/jaeger_api_v2.rs b/opentelemetry-jaeger/src/testing/jaeger_api_v2.rs deleted file mode 100644 index 467ef9f2b1..0000000000 --- a/opentelemetry-jaeger/src/testing/jaeger_api_v2.rs +++ /dev/null @@ -1,448 +0,0 @@ -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct KeyValue { - #[prost(string, tag = "1")] - pub key: ::prost::alloc::string::String, - #[prost(enumeration = "ValueType", tag = "2")] - pub v_type: i32, - #[prost(string, tag = "3")] - pub v_str: ::prost::alloc::string::String, - #[prost(bool, tag = "4")] - pub v_bool: bool, - #[prost(int64, tag = "5")] - pub v_int64: i64, - #[prost(double, tag = "6")] - pub v_float64: f64, - #[prost(bytes = "vec", tag = "7")] - pub v_binary: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Log { - #[prost(message, optional, tag = "1")] - pub timestamp: ::core::option::Option<::prost_types::Timestamp>, - #[prost(message, repeated, tag = "2")] - pub fields: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SpanRef { - #[prost(bytes = "vec", tag = "1")] - pub trace_id: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "2")] - pub span_id: ::prost::alloc::vec::Vec, - #[prost(enumeration = "SpanRefType", tag = "3")] - pub ref_type: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Process { - #[prost(string, tag = "1")] - pub service_name: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "2")] - pub tags: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Span { - #[prost(bytes = "vec", tag = "1")] - pub trace_id: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "2")] - pub span_id: ::prost::alloc::vec::Vec, - #[prost(string, tag = "3")] - pub operation_name: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "4")] - pub references: ::prost::alloc::vec::Vec, - #[prost(uint32, tag = "5")] - pub flags: u32, - #[prost(message, optional, tag = "6")] - pub start_time: ::core::option::Option<::prost_types::Timestamp>, - #[prost(message, optional, tag = "7")] - pub duration: ::core::option::Option<::prost_types::Duration>, - #[prost(message, repeated, tag = "8")] - pub tags: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "9")] - pub logs: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "10")] - pub process: ::core::option::Option, - #[prost(string, tag = "11")] - pub process_id: ::prost::alloc::string::String, - #[prost(string, repeated, tag = "12")] - pub warnings: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Trace { - #[prost(message, repeated, tag = "1")] - pub spans: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub process_map: ::prost::alloc::vec::Vec, - #[prost(string, repeated, tag = "3")] - pub warnings: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -/// Nested message and enum types in `Trace`. -pub mod trace { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ProcessMapping { - #[prost(string, tag = "1")] - pub process_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub process: ::core::option::Option, - } -} -/// Note that both Span and Batch may contain a Process. -/// This is different from the Thrift model which was only used -/// for transport, because Proto model is also used by the backend -/// as the domain model, where once a batch is received it is split -/// into individual spans which are all processed independently, -/// and therefore they all need a Process. As far as on-the-wire -/// semantics, both Batch and Spans in the same message may contain -/// their own instances of Process, with span.Process taking priority -/// over batch.Process. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Batch { - #[prost(message, repeated, tag = "1")] - pub spans: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "2")] - pub process: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DependencyLink { - #[prost(string, tag = "1")] - pub parent: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub child: ::prost::alloc::string::String, - #[prost(uint64, tag = "3")] - pub call_count: u64, - #[prost(string, tag = "4")] - pub source: ::prost::alloc::string::String, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ValueType { - String = 0, - Bool = 1, - Int64 = 2, - Float64 = 3, - Binary = 4, -} -impl ValueType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ValueType::String => "STRING", - ValueType::Bool => "BOOL", - ValueType::Int64 => "INT64", - ValueType::Float64 => "FLOAT64", - ValueType::Binary => "BINARY", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "STRING" => Some(Self::String), - "BOOL" => Some(Self::Bool), - "INT64" => Some(Self::Int64), - "FLOAT64" => Some(Self::Float64), - "BINARY" => Some(Self::Binary), - _ => None, - } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum SpanRefType { - ChildOf = 0, - FollowsFrom = 1, -} -impl SpanRefType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - SpanRefType::ChildOf => "CHILD_OF", - SpanRefType::FollowsFrom => "FOLLOWS_FROM", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CHILD_OF" => Some(Self::ChildOf), - "FOLLOWS_FROM" => Some(Self::FollowsFrom), - _ => None, - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetTraceRequest { - #[prost(bytes = "vec", tag = "1")] - pub trace_id: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SpansResponseChunk { - #[prost(message, repeated, tag = "1")] - pub spans: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ArchiveTraceRequest { - #[prost(bytes = "vec", tag = "1")] - pub trace_id: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ArchiveTraceResponse {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TraceQueryParameters { - #[prost(string, tag = "1")] - pub service_name: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub operation_name: ::prost::alloc::string::String, - #[prost(map = "string, string", tag = "3")] - pub tags: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub start_time_min: ::core::option::Option<::prost_types::Timestamp>, - #[prost(message, optional, tag = "5")] - pub start_time_max: ::core::option::Option<::prost_types::Timestamp>, - #[prost(message, optional, tag = "6")] - pub duration_min: ::core::option::Option<::prost_types::Duration>, - #[prost(message, optional, tag = "7")] - pub duration_max: ::core::option::Option<::prost_types::Duration>, - #[prost(int32, tag = "8")] - pub search_depth: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FindTracesRequest { - #[prost(message, optional, tag = "1")] - pub query: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetServicesRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetServicesResponse { - #[prost(string, repeated, tag = "1")] - pub services: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetOperationsRequest { - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub span_kind: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Operation { - #[prost(string, tag = "1")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub span_kind: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetOperationsResponse { - /// deprecated - #[prost(string, repeated, tag = "1")] - pub operation_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub operations: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetDependenciesRequest { - #[prost(message, optional, tag = "1")] - pub start_time: ::core::option::Option<::prost_types::Timestamp>, - #[prost(message, optional, tag = "2")] - pub end_time: ::core::option::Option<::prost_types::Timestamp>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetDependenciesResponse { - #[prost(message, repeated, tag = "1")] - pub dependencies: ::prost::alloc::vec::Vec, -} -/// Generated client implementations. -pub mod query_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct QueryServiceClient { - inner: tonic::client::Grpc, - } - impl QueryServiceClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: std::convert::TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl QueryServiceClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> QueryServiceClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - QueryServiceClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - pub async fn get_trace( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result< - tonic::Response>, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/GetTrace"); - self.inner - .server_streaming(request.into_request(), path, codec) - .await - } - pub async fn archive_trace( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/ArchiveTrace"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn find_traces( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result< - tonic::Response>, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/FindTraces"); - self.inner - .server_streaming(request.into_request(), path, codec) - .await - } - pub async fn get_services( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/GetServices"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_operations( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/GetOperations"); - self.inner.unary(request.into_request(), path, codec).await - } - pub async fn get_dependencies( - &mut self, - request: impl tonic::IntoRequest, - ) -> Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/jaeger.api_v2.QueryService/GetDependencies"); - self.inner.unary(request.into_request(), path, codec).await - } - } -} diff --git a/opentelemetry-jaeger/src/testing/mod.rs b/opentelemetry-jaeger/src/testing/mod.rs deleted file mode 100644 index 36d2c3a222..0000000000 --- a/opentelemetry-jaeger/src/testing/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -#[allow(unused, missing_docs, clippy::derive_partial_eq_without_eq)] -// tonic don't derive Eq. We shouldn't manually change it.)] -pub mod jaeger_api_v2; - -#[allow(missing_docs)] -pub mod jaeger_client { - use crate::testing::jaeger_api_v2::query_service_client::QueryServiceClient; - use crate::testing::jaeger_api_v2::{ - FindTracesRequest, GetServicesRequest, GetTraceRequest, Span as JaegerSpan, - TraceQueryParameters, - }; - use tonic::transport::Channel; - - #[derive(Debug)] - pub struct JaegerTestClient { - query_service_client: QueryServiceClient, - } - - impl JaegerTestClient { - pub fn new(jaeger_url: &'static str) -> JaegerTestClient { - let channel = Channel::from_static(jaeger_url).connect_lazy(); - - JaegerTestClient { - query_service_client: QueryServiceClient::new(channel), - } - } - - /// Check if the jaeger contains the service - pub async fn contain_service(&mut self, service_name: &String) -> bool { - self.query_service_client - .get_services(GetServicesRequest {}) - .await - .unwrap() - .get_ref() - .services - .iter() - .any(|svc_name| *svc_name == *service_name) - } - - /// Find trace by trace id. - /// Note that `trace_id` should be a u128 in hex. - pub async fn get_trace(&mut self, trace_id: String) -> Vec { - let trace_id = u128::from_str_radix(trace_id.as_ref(), 16).expect("invalid trace id"); - let mut resp = self - .query_service_client - .get_trace(GetTraceRequest { - trace_id: trace_id.to_be_bytes().into(), - }) - .await - .unwrap(); - - if let Some(spans) = resp - .get_mut() - .message() - .await - .expect("jaeger returns error") - { - spans.spans - } else { - vec![] - } - } - - /// Find traces belongs the service. - /// It assumes the service exists. - pub async fn find_traces_from_services(&mut self, service_name: &str) -> Vec { - let request = FindTracesRequest { - query: Some(TraceQueryParameters { - service_name: service_name.to_owned(), - ..Default::default() - }), - }; - self.query_service_client - .find_traces(request) - .await - .unwrap() - .get_mut() - .message() - .await - .expect("jaeger returns error") - .unwrap_or_default() - .spans - } - } -} diff --git a/opentelemetry-jaeger/tests/Dockerfile b/opentelemetry-jaeger/tests/Dockerfile deleted file mode 100644 index 0fcabd9b54..0000000000 --- a/opentelemetry-jaeger/tests/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM rust - -WORKDIR /usr/src/opentelemetry -COPY . . diff --git a/opentelemetry-jaeger/tests/docker-compose.yaml b/opentelemetry-jaeger/tests/docker-compose.yaml deleted file mode 100644 index 445ab85fb5..0000000000 --- a/opentelemetry-jaeger/tests/docker-compose.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3" -services: - jaeger: - image: jaegertracing/all-in-one:1 - container_name: opentelemetry-jaeger-integration-test-jaeger - ports: - - "6831:6831/udp" - - "16685:16685" - - "14268:14268" - - "16686:16686" - opentelemetry-jaeger: - build: - context: ../.. - dockerfile: ./opentelemetry-jaeger/tests/Dockerfile - container_name: opentelemetry-jaeger-integration-test-exporter - environment: - OTEL_TEST_JAEGER_AGENT_ENDPOINT: "jaeger:6831" - OTEL_TEST_JAEGER_COLLECTOR_ENDPOINT: "http://jaeger:14268/api/traces" - OTEL_TEST_JAEGER_ENDPOINT: "http://jaeger:16685" - command: [ "cargo", "test", "--package", "opentelemetry-jaeger", "--test", "integration_test", - "--features=integration_test", "tests::integration_test", "--", "--exact", "--ignored" ] - depends_on: - - jaeger diff --git a/opentelemetry-jaeger/tests/integration_test.rs b/opentelemetry-jaeger/tests/integration_test.rs deleted file mode 100644 index 275c130bdc..0000000000 --- a/opentelemetry-jaeger/tests/integration_test.rs +++ /dev/null @@ -1,243 +0,0 @@ -#[allow(deprecated)] -#[cfg(feature = "integration_test")] -mod tests { - use opentelemetry::{ - trace::{Status, TraceContextExt, Tracer}, - KeyValue, - }; - use opentelemetry_jaeger::testing::{ - jaeger_api_v2 as jaeger_api, jaeger_client::JaegerTestClient, - }; - use opentelemetry_sdk::trace::Tracer as SdkTracer; - use std::collections::HashMap; - - const SERVICE_NAME: &str = "opentelemetry_jaeger_integration_test"; - const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION"); - const CRATE_NAME: &str = env!("CARGO_PKG_NAME"); - - // the sample application that will be traced. - // Expect the following span relationship: - // ┌─────────┐ - // │ Step-1 │────────────┐ - // └───┬─────┘ │ - // │ │ - // ┌───┴─────┐ ┌────┴────┐ - // │ Step-2-1│ │ Step-2-2├───────────┐ - // └─────────┘ └────┬────┘ │ - // │ │ - // ┌────┴─────┐ ┌───┴─────┐ - // │ Step-3-1 │ │ Step-3-2│ - // └──────────┘ └─────────┘ - async fn sample_application(tracer: &SdkTracer) { - { - tracer.in_span("step-1", |cx| { - tracer.in_span("step-2-1", |_cx| {}); - tracer.in_span("step-2-2", |_cx| { - tracer.in_span("step-3-1", |cx| { - let span = cx.span(); - span.set_status(Status::error("some err")) - }); - tracer.in_span("step-3-2", |cx| { - cx.span() - .set_attribute(KeyValue::new("tag-3-2-1", "tag-value-3-2-1")) - }) - }); - cx.span() - .add_event("something happened", vec![KeyValue::new("key1", "value1")]); - }); - } - } - - // This tests requires a jaeger agent running on the localhost. - // You can override the agent end point using OTEL_TEST_JAEGER_AGENT_ENDPOINT env var - // You can override the query API endpoint using OTEL_TEST_JAEGER_ENDPOINT env var - // Alternative you can run scripts/integration_tests.sh from project root path. - // - #[test] - #[ignore] // ignore this when running unit tests - #[allow(clippy::type_complexity)] - fn integration_test() { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("cannot start runtime"); - - let agent_endpoint = - option_env!("OTEL_TEST_JAEGER_AGENT_ENDPOINT").unwrap_or("localhost:6831"); - let collector_endpoint = option_env!("OTEL_TEST_JAEGER_COLLECTOR_ENDPOINT") - .unwrap_or("http://localhost:14268/api/traces"); - let query_api_endpoint = - option_env!("OTEL_TEST_JAEGER_ENDPOINT").unwrap_or("http://localhost:16685"); - - let test_cases: Vec<(&str, Box SdkTracer>)> = vec![ - ( - "agent", - Box::new(|| { - opentelemetry_jaeger::new_agent_pipeline() - .with_endpoint(agent_endpoint) - .with_service_name(format!("{}-{}", SERVICE_NAME, "agent")) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .expect("cannot create tracer using default configuration") - }), - ), - ( - "collector_reqwest", - Box::new(|| { - opentelemetry_jaeger::new_collector_pipeline() - .with_endpoint(collector_endpoint) - .with_reqwest() - .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_reqwest")) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .expect("cannot create tracer using default configuration") - }), - ), - ( - "collector_isahc", - Box::new(|| { - opentelemetry_jaeger::new_collector_pipeline() - .with_endpoint(collector_endpoint) - .with_isahc() - .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_isahc")) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .expect("cannot create tracer using default configuration") - }), - ), - ( - "collector_hyper", - Box::new(|| { - opentelemetry_jaeger::new_collector_pipeline() - .with_endpoint(collector_endpoint) - .with_hyper() - .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_hyper")) - .install_batch(opentelemetry_sdk::runtime::Tokio) - .expect("cannot create tracer using default configuration") - }), - ), - ]; - - for (name, build_tracer) in test_cases { - println!("Running test case: {}", name); - - runtime.block_on(async { - let tracer = build_tracer(); - sample_application(&tracer).await; - - tracer.provider().unwrap().force_flush(); - }); - - // assert the results by the jaeger query API - runtime.block_on(async { - // build client - let mut client = JaegerTestClient::new(query_api_endpoint); - let service_name = format!("{}-{}", SERVICE_NAME, name); - assert!( - client.contain_service(&service_name).await, - "jaeger cannot find service with name {}", - service_name - ); - let spans = client.find_traces_from_services(&service_name).await; - assert_eq!(spans.len(), 5); - - for span in spans.iter() { - assert_common_attributes(span, service_name.as_str(), CRATE_NAME, CRATE_VERSION) - } - - // convert to span name/operation name -> span map - let span_map: HashMap = spans - .into_iter() - .map(|spans| (spans.operation_name.clone(), spans)) - .collect(); - - let step_1 = span_map.get("step-1").expect("cannot find step-1 span"); - assert_parent(step_1, None); - assert_eq!(step_1.logs.len(), 1); - - let step_2_1 = span_map.get("step-2-1").expect("cannot find step-2-1 span"); - assert_parent(step_2_1, Some(step_1)); - - let step_2_2 = span_map.get("step-2-2").expect("cannot find step-2-2 span"); - assert_parent(step_2_2, Some(step_1)); - - let step_3_1 = span_map.get("step-3-1").expect("cannot find step-3-1 span"); - assert_parent(step_3_1, Some(step_2_2)); - assert_tags_contains(step_3_1, "otel.status_code", "ERROR"); - assert_tags_contains(step_3_1, "error", "true"); - assert_eq!(step_3_1.flags, 1); - - let step_3_2 = span_map - .get("step-3-2") - .expect("cannot find step 3-2 spans"); - assert_parent(step_3_2, Some(step_2_2)); - assert_tags_contains(step_3_2, "tag-3-2-1", "tag-value-3-2-1"); - }); - } - } - - fn assert_parent(span: &jaeger_api::Span, parent_span: Option<&jaeger_api::Span>) { - let parent = span - .references - .iter() - .filter(|span_ref| span_ref.ref_type == jaeger_api::SpanRefType::ChildOf as i32) - .collect::>(); - if let Some(parent_span) = parent_span { - assert_eq!(parent.len(), 1); - let parent = parent.first().unwrap(); - assert_eq!(parent.span_id, parent_span.span_id); - assert_eq!(parent.trace_id, parent_span.trace_id); - } else { - assert!(parent.is_empty()); - } - } - - fn assert_common_attributes( - span: &jaeger_api::Span, - service_name: T, - library_name: T, - library_version: T, - ) where - T: Into, - { - assert_eq!( - span.process.as_ref().unwrap().service_name, - service_name.into() - ); - let mut library_metadata = span - .tags - .iter() - .filter(|kvs| kvs.key == "otel.library.name" || kvs.key == "otel.library.version") - .collect::>(); - assert_eq!(library_metadata.len(), 2); - if library_metadata.first().unwrap().key != "otel.library.name" { - library_metadata.swap(0, 1) - } - assert_eq!(library_metadata.first().unwrap().v_str, library_name.into()); - assert_eq!( - library_metadata.get(1).unwrap().v_str, - library_version.into() - ); - } - - fn assert_tags_contains(span: &jaeger_api::Span, key: T, value: T) - where - T: Into, - { - let key = key.into(); - let value = value.into(); - assert!(span - .tags - .iter() - .map(|tag| { - (tag.key.clone(), { - match tag.v_type { - 0 => tag.v_str.to_string(), - 1 => tag.v_bool.to_string(), - 2 => tag.v_int64.to_string(), - 3 => tag.v_float64.to_string(), - 4 => std::str::from_utf8(&tag.v_binary).unwrap_or("").into(), - _ => "".to_string(), - } - }) - }) - .any(|(tag_key, tag_value)| tag_key == key.clone() && tag_value == value.clone())); - } -} diff --git a/opentelemetry-jaeger/trace.png b/opentelemetry-jaeger/trace.png deleted file mode 100644 index fedf78c667..0000000000 Binary files a/opentelemetry-jaeger/trace.png and /dev/null differ diff --git a/scripts/lint.sh b/scripts/lint.sh index 13b728f156..2d251b75ac 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -12,7 +12,6 @@ cargo_feature() { if rustup component add clippy; then crates=( "opentelemetry" "opentelemetry-http" - "opentelemetry-jaeger" "opentelemetry-jaeger-propagator" "opentelemetry-appender-log" "opentelemetry-appender-tracing" @@ -40,16 +39,6 @@ if rustup component add clippy; then cargo_feature opentelemetry-otlp "http-proto, reqwest-rustls" cargo_feature opentelemetry-otlp "metrics" - cargo_feature opentelemetry-jaeger "isahc_collector_client" - cargo_feature opentelemetry-jaeger "reqwest_blocking_collector_client" - cargo_feature opentelemetry-jaeger "reqwest_collector_client" - cargo_feature opentelemetry-jaeger "hyper_collector_client" - cargo_feature opentelemetry-jaeger "hyper_tls_collector_client" - cargo_feature opentelemetry-jaeger "collector_client" - cargo_feature opentelemetry-jaeger "wasm_collector_client" - cargo_feature opentelemetry-jaeger "collector_client, wasm_collector_client" - cargo_feature opentelemetry-jaeger "default" - cargo_feature opentelemetry-jaeger-propagator "default" cargo_feature opentelemetry-proto "default" diff --git a/scripts/publish.sh b/scripts/publish.sh index cbe67d7630..e106fec06b 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -9,7 +9,6 @@ packages=( "opentelemetry-proto" "opentelemetry-otlp" "opentelemetry-stdout" - "opentelemetry-jaeger" "opentelemetry-zipkin" "opentelemetry-prometheus" "opentelemetry-appender-log" diff --git a/scripts/test.sh b/scripts/test.sh index 1b7437b1f6..cd02a14994 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -11,5 +11,4 @@ cargo test --manifest-path=opentelemetry/Cargo.toml --no-default-features cargo test --manifest-path=opentelemetry/Cargo.toml --all-features -- --ignored --test-threads=1 cargo test --manifest-path=opentelemetry/Cargo.toml --all-features -cargo test --manifest-path=opentelemetry-jaeger/Cargo.toml --all-features -- --test-threads=1 cargo test --manifest-path=opentelemetry-zipkin/Cargo.toml --all-features