diff --git a/.github/workflows/ci-e2e-all.yml b/.github/workflows/ci-e2e-all.yml new file mode 100644 index 00000000000..fb41a17b5c5 --- /dev/null +++ b/.github/workflows/ci-e2e-all.yml @@ -0,0 +1,42 @@ +name: E2E Tests + +on: + push: + branches: [main] + + pull_request: + branches: [main] + +concurrency: + group: combined-cit-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + badger: + uses: ./.github/workflows/ci-e2e-badger.yaml + + cassandra: + uses: ./.github/workflows/ci-e2e-cassandra.yml + + elasticsearch: + uses: ./.github/workflows/ci-e2e-elasticsearch.yml + + grpc: + uses: ./.github/workflows/ci-e2e-grpc.yml + + kafka: + uses: ./.github/workflows/ci-e2e-kafka.yml + + memory: + uses: ./.github/workflows/ci-e2e-memory.yaml + + opensearch: + uses: ./.github/workflows/ci-e2e-opensearch.yml + + + + + diff --git a/.github/workflows/ci-e2e-badger.yaml b/.github/workflows/ci-e2e-badger.yaml index e4ec18ad83a..5b87cd4e448 100644 --- a/.github/workflows/ci-e2e-badger.yaml +++ b/.github/workflows/ci-e2e-badger.yaml @@ -1,14 +1,10 @@ name: CIT Badger on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-badger-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.github/workflows/ci-e2e-cassandra.yml b/.github/workflows/ci-e2e-cassandra.yml index 3ca6709e012..2e5cb4b561c 100644 --- a/.github/workflows/ci-e2e-cassandra.yml +++ b/.github/workflows/ci-e2e-cassandra.yml @@ -1,14 +1,10 @@ name: CIT Cassandra on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-cassandra-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.github/workflows/ci-e2e-elasticsearch.yml b/.github/workflows/ci-e2e-elasticsearch.yml index e10491e736e..548775f9e97 100644 --- a/.github/workflows/ci-e2e-elasticsearch.yml +++ b/.github/workflows/ci-e2e-elasticsearch.yml @@ -1,14 +1,10 @@ name: CIT Elasticsearch on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-elasticsearch-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.github/workflows/ci-e2e-grpc.yml b/.github/workflows/ci-e2e-grpc.yml index bc2af82f7f1..3d2eb1806d3 100644 --- a/.github/workflows/ci-e2e-grpc.yml +++ b/.github/workflows/ci-e2e-grpc.yml @@ -1,14 +1,10 @@ name: CIT gRPC on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-grpc-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.github/workflows/ci-e2e-kafka.yml b/.github/workflows/ci-e2e-kafka.yml index 162a077470e..d56d0046803 100644 --- a/.github/workflows/ci-e2e-kafka.yml +++ b/.github/workflows/ci-e2e-kafka.yml @@ -1,14 +1,10 @@ name: CIT Kafka on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-kafka-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions @@ -22,7 +18,7 @@ jobs: fail-fast: false matrix: jaeger-version: [v1, v2] # Adjust if there are specific versions of Jaeger - name: Kafka Integration Tests ${{ matrix.jaeger-version }} + name: kafka ${{ matrix.jaeger-version }} steps: - name: Harden Runner uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 diff --git a/.github/workflows/ci-e2e-memory.yaml b/.github/workflows/ci-e2e-memory.yaml index cdb17650e08..3408d459852 100644 --- a/.github/workflows/ci-e2e-memory.yaml +++ b/.github/workflows/ci-e2e-memory.yaml @@ -1,14 +1,10 @@ name: CIT Memory on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-memory-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.github/workflows/ci-e2e-opensearch.yml b/.github/workflows/ci-e2e-opensearch.yml index 63fd77947f2..de98e61e095 100644 --- a/.github/workflows/ci-e2e-opensearch.yml +++ b/.github/workflows/ci-e2e-opensearch.yml @@ -1,14 +1,10 @@ name: CIT OpenSearch on: - push: - branches: [main] - - pull_request: - branches: [main] + workflow_call: concurrency: - group: ${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} + group: cit-opensearch-${{ github.workflow }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }} cancel-in-progress: true # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions diff --git a/.mockery.yaml b/.mockery.yaml index a0f879a5a35..513908625a9 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -76,3 +76,6 @@ packages: github.com/jaegertracing/jaeger/storage_v2/tracestore: config: all: true + github.com/jaegertracing/jaeger/storage_v2/depstore: + config: + all: true diff --git a/CHANGELOG.md b/CHANGELOG.md index d4788ad3e6d..d1bd80a71e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,70 @@ copy from UI changelog +v1.64.0 / v2.1.0 (2024-12-06) +------------------------------- + +### Backend Changes + +#### ⛔ Breaking Changes + +* [metrics][storage] move metrics reader decorator to metrics storage factory ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6287](https://github.com/jaegertracing/jaeger/pull/6287)) +* [v2][storage] move span reader decorator to storage factories ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6280](https://github.com/jaegertracing/jaeger/pull/6280)) + +#### ✨ New Features + +* [v2][storage] implement read path for v2 storage interface ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6170](https://github.com/jaegertracing/jaeger/pull/6170)) +* Create cassandra db schema on session initialization ([@akstron](https://github.com/akstron) in [#5922](https://github.com/jaegertracing/jaeger/pull/5922)) + +#### 🐞 Bug fixes, Minor Improvements + +* Fix password in integration test ([@akstron](https://github.com/akstron) in [#6284](https://github.com/jaegertracing/jaeger/pull/6284)) +* [cassandra] change compaction window default to 2hrs ([@yurishkuro](https://github.com/yurishkuro) in [#6282](https://github.com/jaegertracing/jaeger/pull/6282)) +* Improve telemetry.settings ([@yurishkuro](https://github.com/yurishkuro) in [#6275](https://github.com/jaegertracing/jaeger/pull/6275)) +* [kafka] otel helper instead of tlscfg package ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6270](https://github.com/jaegertracing/jaeger/pull/6270)) +* [refactor] fix package misspelling: telemetery->telemetry ([@yurishkuro](https://github.com/yurishkuro) in [#6269](https://github.com/jaegertracing/jaeger/pull/6269)) +* [prometheus] use otel helper instead of tlscfg package ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6266](https://github.com/jaegertracing/jaeger/pull/6266)) +* [fix] use metrics decorator around metricstorage ([@yurishkuro](https://github.com/yurishkuro) in [#6262](https://github.com/jaegertracing/jaeger/pull/6262)) +* Use real metrics factory instead of nullfactory ([@yurishkuro](https://github.com/yurishkuro) in [#6261](https://github.com/jaegertracing/jaeger/pull/6261)) +* [v2] use only version number for buildinfo ([@yurishkuro](https://github.com/yurishkuro) in [#6260](https://github.com/jaegertracing/jaeger/pull/6260)) +* [refactor] move spm v2 config to cmd/jaeger/ with all other configs ([@yurishkuro](https://github.com/yurishkuro) in [#6256](https://github.com/jaegertracing/jaeger/pull/6256)) +* [es-index-cleaner] use otel helper instead of tlscfg ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6259](https://github.com/jaegertracing/jaeger/pull/6259)) +* [api_v2] change time fields in archivetracerequest to non-nullable ([@rim99](https://github.com/rim99) in [#6251](https://github.com/jaegertracing/jaeger/pull/6251)) +* [es-rollover] use otel helpers for tls config instead of tlscfg ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6238](https://github.com/jaegertracing/jaeger/pull/6238)) +* Enable usestdlibvars linter ([@mmorel-35](https://github.com/mmorel-35) in [#6249](https://github.com/jaegertracing/jaeger/pull/6249)) +* [storage_v1] add time window to gettracerequest ([@rim99](https://github.com/rim99) in [#6244](https://github.com/jaegertracing/jaeger/pull/6244)) +* [fix][query] fix misconfiguration in tls settings from using otel http helper ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6239](https://github.com/jaegertracing/jaeger/pull/6239)) +* Auto-generate gogo annotations for api_v3 ([@yurishkuro](https://github.com/yurishkuro) in [#6233](https://github.com/jaegertracing/jaeger/pull/6233)) +* Use confighttp in expvar extension ([@yurishkuro](https://github.com/yurishkuro) in [#6227](https://github.com/jaegertracing/jaeger/pull/6227)) +* Parameterize listen host and override when in container ([@yurishkuro](https://github.com/yurishkuro) in [#6231](https://github.com/jaegertracing/jaeger/pull/6231)) +* Remove 0.0.0.0 overrides in hotrod ci ([@yurishkuro](https://github.com/yurishkuro) in [#6226](https://github.com/jaegertracing/jaeger/pull/6226)) +* [storage][v2] add reader adapter that just exposes the underlying v1 reader ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6221](https://github.com/jaegertracing/jaeger/pull/6221)) +* Change start/end time in gettrace request to not be pointers ([@yurishkuro](https://github.com/yurishkuro) in [#6218](https://github.com/jaegertracing/jaeger/pull/6218)) +* Pass real meterprovider to components ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6173](https://github.com/jaegertracing/jaeger/pull/6173)) +* [v2] update versions in readme ([@yurishkuro](https://github.com/yurishkuro) in [#6206](https://github.com/jaegertracing/jaeger/pull/6206)) +* Fix: testcreatecollectorproxy unit test failing on go-tip ([@Saumya40-codes](https://github.com/Saumya40-codes) in [#6204](https://github.com/jaegertracing/jaeger/pull/6204)) +* Respect environment variables when creating internal tracer ([@akstron](https://github.com/akstron) in [#6179](https://github.com/jaegertracing/jaeger/pull/6179)) + +#### 🚧 Experimental Features + +* [v2]add script for metrics markdown table ([@vvs-personalstash](https://github.com/vvs-personalstash) in [#5941](https://github.com/jaegertracing/jaeger/pull/5941)) + +#### 👷 CI Improvements + +* Allow using different container runtime ([@rim99](https://github.com/rim99) in [#6247](https://github.com/jaegertracing/jaeger/pull/6247)) +* K8s integration test for hotrod ([@chahatsagarmain](https://github.com/chahatsagarmain) in [#6155](https://github.com/jaegertracing/jaeger/pull/6155)) +* Pass username/password to cassandra docker-compose health check ([@akstron](https://github.com/akstron) in [#6214](https://github.com/jaegertracing/jaeger/pull/6214)) +* [fix][ci] change the prometheus healthcheck endpoint ([@mahadzaryab1](https://github.com/mahadzaryab1) in [#6217](https://github.com/jaegertracing/jaeger/pull/6217)) + +### 📊 UI Changes + +#### 🐞 Bug fixes, Minor Improvements + +* Add new formatting function "add" ([@drewcorlin1](https://github.com/drewcorlin1) in [#2507](https://github.com/jaegertracing/jaeger-ui/pull/2507)) +* Add pad_start link formatting function #2505 ([@drewcorlin1](https://github.com/drewcorlin1) in [#2504](https://github.com/jaegertracing/jaeger-ui/pull/2504)) +* Allow formatting link parameter values as iso date #2487 ([@drewcorlin1](https://github.com/drewcorlin1) in [#2501](https://github.com/jaegertracing/jaeger-ui/pull/2501)) + + v1.63.0 / v2.0.0 (2024-11-10) ------------------------------- diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 8573b0aedd0..69e54775fb7 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -57,13 +57,11 @@ Former maintainers can be reinstated to full maintainer status through the same ## Emeritus Maintainers -Former maintainers are recognized with an honorary _Emeritus Maintainer_ status, and have their names permanently -listed in the README as a form of gratitude for their contributions. +Former maintainers are recognized with an honorary _Emeritus Maintainer_ status, and have their names permanently listed in the [MAINTAINERS](./MAINTAINERS.md#emeritus-maintainers) file as a form of gratitude for their contributions. ## GitHub Project Administration -Maintainers will be added to the GitHub @jaegertracing/jaeger-maintainers team, and made a GitHub maintainer of that team. -They will be given write permission to the Jaeger GitHub repository https://github.com/jaegertracing/jaeger. +Maintainers will be added to the GitHub @jaegertracing/jaeger-maintainers team, and made a GitHub maintainer of that team. They will be given write permission to the Jaeger GitHub repository https://github.com/jaegertracing/jaeger. ## Changes in Governance diff --git a/MAINTAINERS.md b/MAINTAINERS.md index fcc48358467..40afdccf85e 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -5,9 +5,20 @@ The current Maintainers Group for the Jaeger Project consists of: | [@albertteoh](https://github.com/albertteoh) | PackSmith | ALL | | [@jkowall](https://github.com/jkowall) | Aiven | ALL | | [@joe-elliott](https://github.com/joe-elliott) | Grafana Labs | ALL | +| [@mahadzaryab1](https://github.com/mahadzaryab1) | Bloomberg | ALL | | [@pavolloffay](https://github.com/pavolloffay) | RedHat | ALL | | [@yurishkuro](https://github.com/yurishkuro) | Meta | ALL | This list must be kept in sync with the [CNCF Project Maintainers list](https://github.com/cncf/foundation/blob/master/project-maintainers.csv). See [the project Governance](./GOVERNANCE.md) for how maintainers are selected and replaced. + +### Emeritus Maintainers + +We are grateful to our former maintainers for their contributions to the Jaeger project. + +* [@black-adder](https://github.com/black-adder) +* [@jpkrohling](https://github.com/jpkrohling) +* [@objectiser](https://github.com/objectiser) +* [@tiffon](https://github.com/tiffon) +* [@vprithvi](https://github.com/vprithvi) diff --git a/README.md b/README.md index 80a33394621..783edaeb599 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ # Jaeger - a Distributed Tracing System -💥💥💥 Jaeger v2 is coming! Read the [blog post](https://medium.com/jaegertracing/towards-jaeger-v2-moar-opentelemetry-2f8239bee48e) and [try it out](./cmd/jaeger). +💥💥💥 Jaeger v2 is out! Read the [blog post](https://medium.com/jaegertracing/jaeger-v2-released-09a6033d1b10) and [try it out](https://www.jaegertracing.io/docs/latest/getting-started/). ```mermaid graph TD @@ -35,93 +35,16 @@ graph TD end ``` -Jaeger, inspired by [Dapper][dapper] and [OpenZipkin](https://zipkin.io), -is a distributed tracing platform created by [Uber Technologies][ubeross] -and donated to [Cloud Native Computing Foundation](https://cncf.io). -It can be used for monitoring microservices-based distributed systems: +Jaeger is a distributed tracing platform created by [Uber Technologies](https://eng.uber.com/distributed-tracing/) and donated to [Cloud Native Computing Foundation](https://cncf.io). - * Distributed context propagation - * Distributed transaction monitoring - * Root cause analysis - * Service dependency analysis - * Performance / latency optimization +See Jaeger [documentation][doc] for getting started, operational details, and other information. -See also: - - * Jaeger [documentation][doc] for getting started, operational details, and other information. - * Blog post [Evolving Distributed Tracing at Uber](https://eng.uber.com/distributed-tracing/). - * Tutorial / walkthrough [Take Jaeger for a HotROD ride][hotrod-tutorial]. - -Jaeger is hosted by the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) as the 7th top-level project (graduated in October 2019). If you are a company that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details about who's involved and how Jaeger plays a role, read the CNCF [Jaeger incubation announcement](https://www.cncf.io/blog/2017/09/13/cncf-hosts-jaeger/) and [Jaeger graduation announcement](https://www.cncf.io/announcement/2019/10/31/cloud-native-computing-foundation-announces-jaeger-graduation/). +Jaeger is hosted by the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) as the 7th top-level project, graduated in October 2019. See the CNCF [Jaeger incubation announcement](https://www.cncf.io/blog/2017/09/13/cncf-hosts-jaeger/) and [Jaeger graduation announcement](https://www.cncf.io/announcement/2019/10/31/cloud-native-computing-foundation-announces-jaeger-graduation/). ## Get Involved Jaeger is an open source project with open governance. We welcome contributions from the community, and we would love your help to improve and extend the project. Here are [some ideas](https://www.jaegertracing.io/get-involved/) for how to get involved. Many of them do not even require any coding. -## Features - -### High Scalability - -Jaeger backend is designed to have no single points of failure and to scale with the business needs. -For example, any given Jaeger installation at Uber is typically processing several billions of spans per day. - -### Relationship with OpenTelemetry - -The Jaeger and [OpenTelemetry](https://opentelemetry.io) projects have different goals. OpenTelemetry aims to provide APIs and SDKs in multiple languages to allow applications to export various telemetry data out of the process, to any number of metrics and tracing backends. The Jaeger project is primarily the tracing backend that receives tracing telemetry data and provides processing, aggregation, data mining, and visualizations of that data. For more information please refer to a blog post [Jaeger and OpenTelemetry](https://medium.com/jaegertracing/jaeger-and-opentelemetry-1846f701d9f2). - -Jaeger was originally designed to support the [OpenTracing standard](https://opentracing.io/specification/). The terminology is still used in Jaeger UI, but the concepts have direct mapping to the OpenTelemetry data model of traces. - -| Capability | OpenTracing concept | OpenTelemetry concept | -| ------------- | ------------------- | --------------------- | -| Represent traces as directed acyclic graphs (not just trees) | [span references](https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans) | [span links](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span) | -| Strongly typed span attributes | span tags | span attributes | -| Strongly typed events/logs | span logs | span events | - -Jaeger project recommends OpenTelemetry SDKs for instrumentation, instead of [now-deprecated Jaeger SDKs](https://www.jaegertracing.io/docs/latest/client-libraries/#deprecating-jaeger-clients). - -### Multiple storage backends - -Jaeger can be used with a growing a number of storage backends: -* It natively supports two popular open source NoSQL databases as trace storage backends: Cassandra and Elasticsearch. -* It integrates via a gRPC API with other well known databases that have been certified to be Jaeger compliant: [TimescaleDB via Promscale](https://github.com/timescale/promscale), [ClickHouse](https://github.com/jaegertracing/jaeger-clickhouse). -* There is embedded database support using [Badger](https://github.com/dgraph-io/badger) and simple in-memory storage for testing setups. -* ScyllaDB [can be used](https://github.com/jaegertracing/jaeger/blob/main/plugin/storage/scylladb/README.md) as a drop-in replacement for Cassandra since it uses the same data model and query language. -* There are ongoing community experiments using other databases, such as InfluxDB, Amazon DynamoDB, YugabyteDB(YCQL). - -### Modern Web UI - -Jaeger Web UI is implemented in Javascript using popular open source frameworks like React. Several performance -improvements have been released in v1.0 to allow the UI to efficiently deal with large volumes of data and to display -traces with tens of thousands of spans (e.g. we tried a trace with 80,000 spans). - -### Cloud Native Deployment - -Jaeger backend is distributed as a collection of Docker images. The binaries support various configuration methods, -including command line options, environment variables, and configuration files in multiple formats (yaml, toml, etc.). - -The recommended way to deploy Jaeger in a production Kubernetes cluster is via the [Jaeger Operator](https://github.com/jaegertracing/jaeger-operator). - -The Jaeger Operator provides a [CLI to generate](https://github.com/jaegertracing/jaeger-operator#experimental-generate-kubernetes-manifest-file) Kubernetes manifests from the Jaeger CR. -This can be considered as an alternative source over plain Kubernetes manifest files. - -The Jaeger ecosystem also provides a [Helm chart](https://github.com/jaegertracing/helm-charts) as an alternative way to deploy Jaeger. - -### Observability - -All Jaeger backend components expose [Prometheus](https://prometheus.io/) metrics by default (other metrics backends are -also supported). Logs are written to standard out using the structured logging library [zap](https://github.com/uber-go/zap). - -### Security - -Third-party security audits of Jaeger are available in https://github.com/jaegertracing/security-audits. Please see [Issue #1718](https://github.com/jaegertracing/jaeger/issues/1718) for the summary of available security mechanisms in Jaeger. - -### Backwards compatibility with Zipkin - -Although we recommend instrumenting applications with OpenTelemetry, if your organization has already invested in the instrumentation -using Zipkin libraries, you do not have to rewrite all that code. Jaeger provides backwards compatibility with Zipkin -by accepting spans in Zipkin formats (Thrift or JSON v1/v2) over HTTP. Switching from Zipkin backend is just a matter -of routing the traffic from Zipkin libraries to the Jaeger backend. - ## Version Compatibility Guarantees Occasionally, CLI flags can be deprecated due to, for example, usability improvements or new functionality. @@ -151,24 +74,16 @@ Starting with the release of Go 1.21, support for Go versions will be updated as ## Related Repositories -### Documentation - - * Published: https://www.jaegertracing.io/docs/ - * Source: https://github.com/jaegertracing/documentation - -### Instrumentation Libraries - -Jaeger project recommends OpenTelemetry SDKs for instrumentation, instead of Jaeger's native SDKs [that are now deprecated](https://www.jaegertracing.io/docs/latest/client-libraries/#deprecating-jaeger-clients). - -### Deployment - - * [Jaeger Operator for Kubernetes](https://github.com/jaegertracing/jaeger-operator#getting-started) - ### Components * [UI](https://github.com/jaegertracing/jaeger-ui) * [Data model](https://github.com/jaegertracing/jaeger-idl) +### Documentation + + * Published: https://www.jaegertracing.io/docs/ + * Source: https://github.com/jaegertracing/documentation + ## Building From Source See [CONTRIBUTING](./CONTRIBUTING.md). @@ -186,27 +101,11 @@ Thanks to all the people who already contributed! ### Maintainers Rules for becoming a maintainer are defined in the [GOVERNANCE](./GOVERNANCE.md) document. -Below are the official maintainers of the Jaeger project. +The official maintainers of the Jaeger project are listed in the [MAINTAINERS](./MAINTAINERS.md) file. Please use `@jaegertracing/jaeger-maintainers` to tag them on issues / PRs. -* [@albertteoh](https://github.com/albertteoh) -* [@jkowall](https://github.com/jkowall) -* [@joe-elliott](https://github.com/joe-elliott) -* [@pavolloffay](https://github.com/pavolloffay) -* [@yurishkuro](https://github.com/yurishkuro) - Some repositories under [jaegertracing](https://github.com/jaegertracing) org have additional maintainers. -### Emeritus Maintainers - -We are grateful to our former maintainers for their contributions to the Jaeger project. - -* [@black-adder](https://github.com/black-adder) -* [@jpkrohling](https://github.com/jpkrohling) -* [@objectiser](https://github.com/objectiser) -* [@tiffon](https://github.com/tiffon) -* [@vprithvi](https://github.com/vprithvi) - ## Project Status Meetings The Jaeger maintainers and contributors meet regularly on a video call. Everyone is welcome to join, including end users. For meeting details, see https://www.jaegertracing.io/get-in-touch/. @@ -223,6 +122,10 @@ Have questions, suggestions, bug reports? Reach the project community via these * [`jaeger-tracing` mail group](https://groups.google.com/forum/#!forum/jaeger-tracing) * GitHub [issues](https://github.com/jaegertracing/jaeger/issues) and [discussions](https://github.com/jaegertracing/jaeger/discussions) +## Security + +Third-party security audits of Jaeger are available in https://github.com/jaegertracing/security-audits. Please see [Issue #1718](https://github.com/jaegertracing/jaeger/issues/1718) for the summary of available security mechanisms in Jaeger. + ## Adopters Jaeger as a product consists of multiple components. We want to support different types of users, @@ -238,8 +141,6 @@ If you would like to add your organization to the list, please comment on our Copyright (c) The Jaeger Authors. [Apache 2.0 License](./LICENSE). [doc]: https://jaegertracing.io/docs/ -[godoc-img]: https://godoc.org/github.com/jaegertracing/jaeger?status.svg -[godoc]: https://godoc.org/github.com/jaegertracing/jaeger [ci-img]: https://github.com/jaegertracing/jaeger/actions/workflows/ci-unit-tests.yml/badge.svg?branch=main [ci]: https://github.com/jaegertracing/jaeger/actions/workflows/ci-unit-tests.yml?query=branch%3Amain [cov-img]: https://codecov.io/gh/jaegertracing/jaeger/branch/main/graph/badge.svg @@ -256,8 +157,6 @@ Copyright (c) The Jaeger Authors. [Apache 2.0 License](./LICENSE). [artifacthub]: https://artifacthub.io/packages/search?repo=jaegertracing -[dapper]: https://research.google.com/pubs/pub36356.html -[ubeross]: https://uber.github.io [community-badge]: https://img.shields.io/badge/Project+Community-stats-blue.svg [community-stats]: https://all.devstats.cncf.io/d/54/project-health?orgId=1&var-repogroup_name=Jaeger [hotrod-tutorial]: https://medium.com/jaegertracing/take-jaeger-for-a-hotrod-ride-233cf43e46c2 diff --git a/RELEASE.md b/RELEASE.md index f8f67923446..9075e84481c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -78,8 +78,9 @@ Here are the release managers for future versions with the tentative release dat | Version | Release Manager | Tentative release date | |---------|-----------------|------------------------| -| 1.64.0 | @joe-elliott | 4 December 2024 | -| 1.65.0 | @jkowall | 8 January 2025 | -| 1.66.0 | @yurishkuro | 3 February 2025 | -| 1.67.0 | @albertteoh | 5 March 2025 | -| 1.68.0 | @pavolloffay | 5 April 2025 | +| 1.65.0 | @mahadzaryab1 | 8 January 2025 | +| 1.66.0 | @jkowall | 3 February 2025 | +| 1.67.0 | @yurishkuro | 5 March 2025 | +| 1.68.0 | @albertteoh | 5 April 2025 | +| 1.69.0 | @pavolloffay | 7 May 2025 | +| 1.70.0 | @joe-elliott | 5 June 2025 | diff --git a/cmd/all-in-one/main.go b/cmd/all-in-one/main.go index 9b7b89dfba1..7f31b472945 100644 --- a/cmd/all-in-one/main.go +++ b/cmd/all-in-one/main.go @@ -38,13 +38,14 @@ import ( ss "github.com/jaegertracing/jaeger/plugin/sampling/strategyprovider" "github.com/jaegertracing/jaeger/plugin/storage" "github.com/jaegertracing/jaeger/ports" - "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage_v2/depstore" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) // all-in-one/main is a standalone full-stack jaeger backend, backed by a memory store func main() { + flags.PrintV1EOL() setupcontext.SetAllInOne() svc := flags.NewService(ports.CollectorAdminHTTP) @@ -114,7 +115,7 @@ by default uses only in-memory database.`, if err != nil { logger.Fatal("Failed to create span writer", zap.Error(err)) } - dependencyReader, err := storageFactory.CreateDependencyReader() + dependencyReader, err := v2Factory.CreateDependencyReader() if err != nil { logger.Fatal("Failed to create dependency reader", zap.Error(err)) } @@ -148,7 +149,7 @@ by default uses only in-memory database.`, logger.Fatal("Failed to configure query service", zap.Error(err)) } - tm := tenancy.NewManager(&cOpts.GRPC.Tenancy) + tm := tenancy.NewManager(&cOpts.Tenancy) // collector c := collectorApp.New(&collectorApp.CollectorParams{ @@ -218,7 +219,7 @@ func startQuery( qOpts *queryApp.QueryOptions, queryOpts *querysvc.QueryServiceOptions, traceReader tracestore.Reader, - depReader dependencystore.Reader, + depReader depstore.Reader, metricsQueryService querysvc.MetricsQueryService, tm *tenancy.Manager, telset telemetry.Settings, diff --git a/cmd/anonymizer/app/query/query_test.go b/cmd/anonymizer/app/query/query_test.go index 24352622e54..768dbc3c1fb 100644 --- a/cmd/anonymizer/app/query/query_test.go +++ b/cmd/anonymizer/app/query/query_test.go @@ -18,9 +18,9 @@ import ( "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/plugin/metricstore/disabled" "github.com/jaegertracing/jaeger/proto-gen/api_v2" - dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + dependencyStoreMocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) diff --git a/cmd/collector/app/collector.go b/cmd/collector/app/collector.go index 44b1ef47803..c2c5b4a9272 100644 --- a/cmd/collector/app/collector.go +++ b/cmd/collector/app/collector.go @@ -6,7 +6,6 @@ package app import ( "context" "fmt" - "io" "net/http" "time" @@ -47,13 +46,10 @@ type Collector struct { tenancyMgr *tenancy.Manager // state, read only - hServer *http.Server - grpcServer *grpc.Server - otlpReceiver receiver.Traces - zipkinReceiver receiver.Traces - tlsGRPCCertWatcherCloser io.Closer - tlsHTTPCertWatcherCloser io.Closer - tlsZipkinCertWatcherCloser io.Closer + hServer *http.Server + grpcServer *grpc.Server + otlpReceiver receiver.Traces + zipkinReceiver receiver.Traces } // CollectorParams to construct a new Jaeger Collector. @@ -101,26 +97,19 @@ func (c *Collector) Start(options *flags.CollectorOptions) error { c.spanProcessor = handlerBuilder.BuildSpanProcessor(additionalProcessors...) c.spanHandlers = handlerBuilder.BuildHandlers(c.spanProcessor) - grpcServer, err := server.StartGRPCServer(&server.GRPCServerParams{ - HostPort: options.GRPC.HostPort, - Handler: c.spanHandlers.GRPCHandler, - TLSConfig: options.GRPC.TLS, - SamplingProvider: c.samplingProvider, - Logger: c.logger, - MaxReceiveMessageLength: options.GRPC.MaxReceiveMessageLength, - MaxConnectionAge: options.GRPC.MaxConnectionAge, - MaxConnectionAgeGrace: options.GRPC.MaxConnectionAgeGrace, + Handler: c.spanHandlers.GRPCHandler, + SamplingProvider: c.samplingProvider, + Logger: c.logger, + ServerConfig: options.GRPC, }) if err != nil { return fmt.Errorf("could not start gRPC server: %w", err) } c.grpcServer = grpcServer - httpServer, err := server.StartHTTPServer(&server.HTTPServerParams{ - HostPort: options.HTTP.HostPort, + ServerConfig: options.HTTP, Handler: c.spanHandlers.JaegerBatchesHandler, - TLSConfig: options.HTTP.TLS, HealthCheck: c.hCheck, MetricsFactory: c.metricsFactory, SamplingProvider: c.samplingProvider, @@ -131,11 +120,7 @@ func (c *Collector) Start(options *flags.CollectorOptions) error { } c.hServer = httpServer - c.tlsGRPCCertWatcherCloser = &options.GRPC.TLS - c.tlsHTTPCertWatcherCloser = &options.HTTP.TLS - c.tlsZipkinCertWatcherCloser = &options.Zipkin.TLS - - if options.Zipkin.HTTPHostPort == "" { + if options.Zipkin.Endpoint == "" { c.logger.Info("Not listening for Zipkin HTTP traffic, port not configured") } else { zipkinReceiver, err := handler.StartZipkinReceiver(options, c.logger, c.spanProcessor, c.tenancyMgr) @@ -209,17 +194,6 @@ func (c *Collector) Close() error { } } - // watchers actually never return errors from Close - if c.tlsGRPCCertWatcherCloser != nil { - _ = c.tlsGRPCCertWatcherCloser.Close() - } - if c.tlsHTTPCertWatcherCloser != nil { - _ = c.tlsHTTPCertWatcherCloser.Close() - } - if c.tlsZipkinCertWatcherCloser != nil { - _ = c.tlsZipkinCertWatcherCloser.Close() - } - return nil } diff --git a/cmd/collector/app/collector_test.go b/cmd/collector/app/collector_test.go index 35c0576d630..4211f88cbbe 100644 --- a/cmd/collector/app/collector_test.go +++ b/cmd/collector/app/collector_test.go @@ -13,6 +13,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/config/configtls" "go.uber.org/zap" "github.com/jaegertracing/jaeger/cmd/collector/app/flags" @@ -27,13 +31,54 @@ import ( var _ (io.Closer) = (*Collector)(nil) func optionsForEphemeralPorts() *flags.CollectorOptions { - collectorOpts := &flags.CollectorOptions{} - collectorOpts.GRPC.HostPort = ":0" - collectorOpts.HTTP.HostPort = ":0" - collectorOpts.OTLP.Enabled = true - collectorOpts.OTLP.GRPC.HostPort = ":0" - collectorOpts.OTLP.HTTP.HostPort = ":0" - collectorOpts.Zipkin.HTTPHostPort = ":0" + collectorOpts := &flags.CollectorOptions{ + HTTP: confighttp.ServerConfig{ + Endpoint: ":0", + TLSSetting: &configtls.ServerConfig{}, + }, + GRPC: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: ":0", + Transport: confignet.TransportTypeTCP, + }, + Keepalive: &configgrpc.KeepaliveServerConfig{ + ServerParameters: &configgrpc.KeepaliveServerParameters{ + MaxConnectionIdle: 10, + }, + }, + }, + OTLP: struct { + Enabled bool + GRPC configgrpc.ServerConfig + HTTP confighttp.ServerConfig + }{ + Enabled: true, + HTTP: confighttp.ServerConfig{ + Endpoint: ":0", + TLSSetting: &configtls.ServerConfig{}, + }, + GRPC: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: ":0", + Transport: confignet.TransportTypeTCP, + }, + Keepalive: &configgrpc.KeepaliveServerConfig{ + ServerParameters: &configgrpc.KeepaliveServerParameters{ + MaxConnectionIdle: 10, + }, + }, + }, + }, + Zipkin: struct { + confighttp.ServerConfig + KeepAlive bool + }{ + ServerConfig: confighttp.ServerConfig{ + Endpoint: ":0", + }, + }, + Tenancy: tenancy.Options{}, + } return collectorOpts } @@ -112,23 +157,23 @@ func TestCollector_StartErrors(t *testing.T) { var options *flags.CollectorOptions options = optionsForEphemeralPorts() - options.GRPC.HostPort = ":-1" + options.GRPC.NetAddr.Endpoint = ":-1" run("gRPC", options, "could not start gRPC server") options = optionsForEphemeralPorts() - options.HTTP.HostPort = ":-1" + options.HTTP.Endpoint = ":-1" run("HTTP", options, "could not start HTTP server") options = optionsForEphemeralPorts() - options.Zipkin.HTTPHostPort = ":-1" + options.Zipkin.Endpoint = ":-1" run("Zipkin", options, "could not start Zipkin receiver") options = optionsForEphemeralPorts() - options.OTLP.GRPC.HostPort = ":-1" + options.OTLP.GRPC.NetAddr.Endpoint = ":-1" run("OTLP/GRPC", options, "could not start OTLP receiver") options = optionsForEphemeralPorts() - options.OTLP.HTTP.HostPort = ":-1" + options.OTLP.HTTP.Endpoint = ":-1" run("OTLP/HTTP", options, "could not start OTLP receiver") } diff --git a/cmd/collector/app/flags/flags.go b/cmd/collector/app/flags/flags.go index 5c68169c881..2cef1e5f585 100644 --- a/cmd/collector/app/flags/flags.go +++ b/cmd/collector/app/flags/flags.go @@ -10,6 +10,8 @@ import ( "time" "github.com/spf13/viper" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confighttp" "go.uber.org/zap" "github.com/jaegertracing/jaeger/cmd/internal/flags" @@ -63,6 +65,9 @@ var httpServerFlagsCfg = serverFlagsConfig{ tls: tlscfg.ServerFlagsConfig{ Prefix: "collector.http", }, + corsCfg: corscfg.Flags{ + Prefix: "collector.otlp.http", + }, } var otlpServerFlagsCfg = struct { @@ -82,19 +87,20 @@ var otlpServerFlagsCfg = struct { Prefix: "collector.otlp.http", EnableCertReloadInterval: true, }, + corsCfg: corscfg.Flags{ + Prefix: "collector.otlp.http", + }, }, } -var tlsZipkinFlagsConfig = tlscfg.ServerFlagsConfig{ - Prefix: "collector.zipkin", -} - -var corsZipkinFlags = corscfg.Flags{ - Prefix: "collector.zipkin", -} - -var corsOTLPFlags = corscfg.Flags{ - Prefix: "collector.otlp.http", +var zipkinServerFlagsCfg = serverFlagsConfig{ + prefix: "collector.zipkin", + tls: tlscfg.ServerFlagsConfig{ + Prefix: "collector.zipkin", + }, + corsCfg: corscfg.Flags{ + Prefix: "collector.zipkin", + }, } // CollectorOptions holds configuration for collector @@ -106,69 +112,32 @@ type CollectorOptions struct { // NumWorkers is the number of internal workers in a collector NumWorkers int // HTTP section defines options for HTTP server - HTTP HTTPOptions + HTTP confighttp.ServerConfig // GRPC section defines options for gRPC server - GRPC GRPCOptions + GRPC configgrpc.ServerConfig // OTLP section defines options for servers accepting OpenTelemetry OTLP format OTLP struct { Enabled bool - GRPC GRPCOptions - HTTP HTTPOptions + GRPC configgrpc.ServerConfig + HTTP confighttp.ServerConfig } // Zipkin section defines options for Zipkin HTTP server Zipkin struct { - // HTTPHostPort is the host:port address that the Zipkin collector service listens in on for http requests - HTTPHostPort string - // TLS configures secure transport for Zipkin endpoint to collect spans - TLS tlscfg.Options - // CORS allows CORS requests , sets the values for Allowed Headers and Allowed Origins. - CORS corscfg.Options - // KeepAlive configures allow Keep-Alive for Zipkin HTTP server + confighttp.ServerConfig KeepAlive bool } // CollectorTags is the string representing collector tags to append to each and every span CollectorTags map[string]string // SpanSizeMetricsEnabled determines whether to enable metrics based on processed span size SpanSizeMetricsEnabled bool -} -type serverFlagsConfig struct { - prefix string - tls tlscfg.ServerFlagsConfig -} - -// HTTPOptions defines options for an HTTP server -type HTTPOptions struct { - // HostPort is the host:port address that the server listens on - HostPort string - // TLS configures secure transport for HTTP endpoint - TLS tlscfg.Options - // ReadTimeout sets the respective parameter of http.Server - ReadTimeout time.Duration - // ReadHeaderTimeout sets the respective parameter of http.Server - ReadHeaderTimeout time.Duration - // IdleTimeout sets the respective parameter of http.Server - IdleTimeout time.Duration - // CORS allows CORS requests , sets the values for Allowed Headers and Allowed Origins. - CORS corscfg.Options + Tenancy tenancy.Options } -// GRPCOptions defines options for a gRPC server -type GRPCOptions struct { - // HostPort is the host:port address that the collector service listens in on for gRPC requests - HostPort string - // TLS configures secure transport for gRPC endpoint to collect spans - TLS tlscfg.Options - // MaxReceiveMessageLength is the maximum message size receivable by the gRPC Collector. - MaxReceiveMessageLength int - // MaxConnectionAge is a duration for the maximum amount of time a connection may exist. - // See gRPC's keepalive.ServerParameters#MaxConnectionAge. - MaxConnectionAge time.Duration - // MaxConnectionAgeGrace is an additive period after MaxConnectionAge after which the connection will be forcibly closed. - // See gRPC's keepalive.ServerParameters#MaxConnectionAgeGrace. - MaxConnectionAgeGrace time.Duration - // Tenancy configures tenancy for endpoints that collect spans - Tenancy tenancy.Options +type serverFlagsConfig struct { + prefix string + tls tlscfg.ServerFlagsConfig + corsCfg corscfg.Flags } // AddFlags adds flags for CollectorOptions @@ -184,13 +153,13 @@ func AddFlags(flagSet *flag.FlagSet) { flagSet.Bool(flagCollectorOTLPEnabled, true, "Enables OpenTelemetry OTLP receiver on dedicated HTTP and gRPC ports") addHTTPFlags(flagSet, otlpServerFlagsCfg.HTTP, ":4318") - corsOTLPFlags.AddFlags(flagSet) + otlpServerFlagsCfg.HTTP.corsCfg.AddFlags(flagSet) addGRPCFlags(flagSet, otlpServerFlagsCfg.GRPC, ":4317") flagSet.String(flagZipkinHTTPHostPort, "", "The host:port (e.g. 127.0.0.1:9411 or :9411) of the collector's Zipkin server (disabled by default)") flagSet.Bool(flagZipkinKeepAliveEnabled, true, "KeepAlive configures allow Keep-Alive for Zipkin HTTP server (enabled by default)") - tlsZipkinFlagsConfig.AddFlags(flagSet) - corsZipkinFlags.AddFlags(flagSet) + zipkinServerFlagsCfg.tls.AddFlags(flagSet) + zipkinServerFlagsCfg.corsCfg.AddFlags(flagSet) tenancy.AddFlags(flagSet) } @@ -223,67 +192,70 @@ func addGRPCFlags(flagSet *flag.FlagSet, cfg serverFlagsConfig, defaultHostPort cfg.tls.AddFlags(flagSet) } -func (opts *HTTPOptions) initFromViper(v *viper.Viper, _ *zap.Logger, cfg serverFlagsConfig) error { - opts.HostPort = ports.FormatHostPort(v.GetString(cfg.prefix + "." + flagSuffixHostPort)) - opts.IdleTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPIdleTimeout) - opts.ReadTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPReadTimeout) - opts.ReadHeaderTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPReadHeaderTimeout) +func initHTTPFromViper(v *viper.Viper, opts *confighttp.ServerConfig, cfg serverFlagsConfig) error { tlsOpts, err := cfg.tls.InitFromViper(v) if err != nil { return fmt.Errorf("failed to parse HTTP TLS options: %w", err) } - opts.TLS = tlsOpts + opts.TLSSetting = tlsOpts.ToOtelServerConfig() + opts.Endpoint = ports.FormatHostPort(v.GetString(cfg.prefix + "." + flagSuffixHostPort)) + opts.IdleTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPIdleTimeout) + opts.ReadTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPReadTimeout) + opts.ReadHeaderTimeout = v.GetDuration(cfg.prefix + "." + flagSuffixHTTPReadHeaderTimeout) + opts.CORS = cfg.corsCfg.InitFromViper(v) + return nil } -func (opts *GRPCOptions) initFromViper(v *viper.Viper, _ *zap.Logger, cfg serverFlagsConfig) error { - opts.HostPort = ports.FormatHostPort(v.GetString(cfg.prefix + "." + flagSuffixHostPort)) - opts.MaxReceiveMessageLength = v.GetInt(cfg.prefix + "." + flagSuffixGRPCMaxReceiveMessageLength) - opts.MaxConnectionAge = v.GetDuration(cfg.prefix + "." + flagSuffixGRPCMaxConnectionAge) - opts.MaxConnectionAgeGrace = v.GetDuration(cfg.prefix + "." + flagSuffixGRPCMaxConnectionAgeGrace) +func initGRPCFromViper(v *viper.Viper, opts *configgrpc.ServerConfig, cfg serverFlagsConfig) error { tlsOpts, err := cfg.tls.InitFromViper(v) if err != nil { - return fmt.Errorf("failed to parse gRPC TLS options: %w", err) + return fmt.Errorf("failed to parse GRPC TLS options: %w", err) + } + opts.TLSSetting = tlsOpts.ToOtelServerConfig() + opts.NetAddr.Endpoint = ports.FormatHostPort(v.GetString(cfg.prefix + "." + flagSuffixHostPort)) + opts.MaxRecvMsgSizeMiB = v.GetInt(cfg.prefix+"."+flagSuffixGRPCMaxReceiveMessageLength) / (1024 * 1024) + opts.Keepalive = &configgrpc.KeepaliveServerConfig{ + ServerParameters: &configgrpc.KeepaliveServerParameters{ + MaxConnectionAge: v.GetDuration(cfg.prefix + "." + flagSuffixGRPCMaxConnectionAge), + MaxConnectionAgeGrace: v.GetDuration(cfg.prefix + "." + flagSuffixGRPCMaxConnectionAgeGrace), + }, } - opts.TLS = tlsOpts - opts.Tenancy = tenancy.InitFromViper(v) return nil } // InitFromViper initializes CollectorOptions with properties from viper -func (cOpts *CollectorOptions) InitFromViper(v *viper.Viper, logger *zap.Logger) (*CollectorOptions, error) { +func (cOpts *CollectorOptions) InitFromViper(v *viper.Viper, _ *zap.Logger) (*CollectorOptions, error) { cOpts.CollectorTags = flags.ParseJaegerTags(v.GetString(flagCollectorTags)) cOpts.NumWorkers = v.GetInt(flagNumWorkers) cOpts.QueueSize = v.GetUint(flagQueueSize) cOpts.DynQueueSizeMemory = v.GetUint(flagDynQueueSizeMemory) * 1024 * 1024 // we receive in MiB and store in bytes cOpts.SpanSizeMetricsEnabled = v.GetBool(flagSpanSizeMetricsEnabled) + cOpts.Tenancy = tenancy.InitFromViper(v) - if err := cOpts.HTTP.initFromViper(v, logger, httpServerFlagsCfg); err != nil { + if err := initHTTPFromViper(v, &cOpts.HTTP, httpServerFlagsCfg); err != nil { return cOpts, fmt.Errorf("failed to parse HTTP server options: %w", err) } - if err := cOpts.GRPC.initFromViper(v, logger, grpcServerFlagsCfg); err != nil { + if err := initGRPCFromViper(v, &cOpts.GRPC, grpcServerFlagsCfg); err != nil { return cOpts, fmt.Errorf("failed to parse gRPC server options: %w", err) } cOpts.OTLP.Enabled = v.GetBool(flagCollectorOTLPEnabled) - if err := cOpts.OTLP.HTTP.initFromViper(v, logger, otlpServerFlagsCfg.HTTP); err != nil { + + if err := initHTTPFromViper(v, &cOpts.OTLP.HTTP, otlpServerFlagsCfg.HTTP); err != nil { return cOpts, fmt.Errorf("failed to parse OTLP/HTTP server options: %w", err) } - cOpts.OTLP.HTTP.CORS = corsOTLPFlags.InitFromViper(v) - if err := cOpts.OTLP.GRPC.initFromViper(v, logger, otlpServerFlagsCfg.GRPC); err != nil { + if err := initGRPCFromViper(v, &cOpts.OTLP.GRPC, otlpServerFlagsCfg.GRPC); err != nil { return cOpts, fmt.Errorf("failed to parse OTLP/gRPC server options: %w", err) } cOpts.Zipkin.KeepAlive = v.GetBool(flagZipkinKeepAliveEnabled) - cOpts.Zipkin.HTTPHostPort = ports.FormatHostPort(v.GetString(flagZipkinHTTPHostPort)) - tlsZipkin, err := tlsZipkinFlagsConfig.InitFromViper(v) - if err != nil { - return cOpts, fmt.Errorf("failed to parse Zipkin TLS options: %w", err) + + if err := initHTTPFromViper(v, &cOpts.Zipkin.ServerConfig, zipkinServerFlagsCfg); err != nil { + return cOpts, fmt.Errorf("failed to parse Zipkin server options: %w", err) } - cOpts.Zipkin.TLS = tlsZipkin - cOpts.Zipkin.CORS = corsZipkinFlags.InitFromViper(v) return cOpts, nil } diff --git a/cmd/collector/app/flags/flags_test.go b/cmd/collector/app/flags/flags_test.go index 9d261465c09..39727d1bce8 100644 --- a/cmd/collector/app/flags/flags_test.go +++ b/cmd/collector/app/flags/flags_test.go @@ -26,9 +26,9 @@ func TestCollectorOptionsWithFlags_CheckHostPort(t *testing.T) { _, err := c.InitFromViper(v, zap.NewNop()) require.NoError(t, err) - assert.Equal(t, ":5678", c.HTTP.HostPort) - assert.Equal(t, ":1234", c.GRPC.HostPort) - assert.Equal(t, ":3456", c.Zipkin.HTTPHostPort) + assert.Equal(t, ":5678", c.HTTP.Endpoint) + assert.Equal(t, ":1234", c.GRPC.NetAddr.Endpoint) + assert.Equal(t, ":3456", c.Zipkin.Endpoint) } func TestCollectorOptionsWithFlags_CheckFullHostPort(t *testing.T) { @@ -42,9 +42,9 @@ func TestCollectorOptionsWithFlags_CheckFullHostPort(t *testing.T) { _, err := c.InitFromViper(v, zap.NewNop()) require.NoError(t, err) - assert.Equal(t, ":5678", c.HTTP.HostPort) - assert.Equal(t, "127.0.0.1:1234", c.GRPC.HostPort) - assert.Equal(t, "0.0.0.0:3456", c.Zipkin.HTTPHostPort) + assert.Equal(t, ":5678", c.HTTP.Endpoint) + assert.Equal(t, "127.0.0.1:1234", c.GRPC.NetAddr.Endpoint) + assert.Equal(t, "0.0.0.0:3456", c.Zipkin.Endpoint) } func TestCollectorOptionsWithFailedTLSFlags(t *testing.T) { @@ -107,7 +107,7 @@ func TestCollectorOptionsWithFlags_CheckMaxReceiveMessageLength(t *testing.T) { _, err := c.InitFromViper(v, zap.NewNop()) require.NoError(t, err) - assert.Equal(t, 8388608, c.GRPC.MaxReceiveMessageLength) + assert.Equal(t, 8, c.GRPC.MaxRecvMsgSizeMiB) } func TestCollectorOptionsWithFlags_CheckMaxConnectionAge(t *testing.T) { @@ -123,8 +123,8 @@ func TestCollectorOptionsWithFlags_CheckMaxConnectionAge(t *testing.T) { _, err := c.InitFromViper(v, zap.NewNop()) require.NoError(t, err) - assert.Equal(t, 5*time.Minute, c.GRPC.MaxConnectionAge) - assert.Equal(t, time.Minute, c.GRPC.MaxConnectionAgeGrace) + assert.Equal(t, 5*time.Minute, c.GRPC.Keepalive.ServerParameters.MaxConnectionAge) + assert.Equal(t, time.Minute, c.GRPC.Keepalive.ServerParameters.MaxConnectionAgeGrace) assert.Equal(t, 5*time.Minute, c.HTTP.IdleTimeout) assert.Equal(t, 6*time.Minute, c.HTTP.ReadTimeout) assert.Equal(t, 5*time.Second, c.HTTP.ReadHeaderTimeout) @@ -136,7 +136,7 @@ func TestCollectorOptionsWithFlags_CheckNoTenancy(t *testing.T) { command.ParseFlags([]string{}) c.InitFromViper(v, zap.NewNop()) - assert.False(t, c.GRPC.Tenancy.Enabled) + assert.False(t, c.Tenancy.Enabled) } func TestCollectorOptionsWithFlags_CheckSimpleTenancy(t *testing.T) { @@ -147,8 +147,8 @@ func TestCollectorOptionsWithFlags_CheckSimpleTenancy(t *testing.T) { }) c.InitFromViper(v, zap.NewNop()) - assert.True(t, c.GRPC.Tenancy.Enabled) - assert.Equal(t, "x-tenant", c.GRPC.Tenancy.Header) + assert.True(t, c.Tenancy.Enabled) + assert.Equal(t, "x-tenant", c.Tenancy.Header) } func TestCollectorOptionsWithFlags_CheckFullTenancy(t *testing.T) { @@ -161,9 +161,9 @@ func TestCollectorOptionsWithFlags_CheckFullTenancy(t *testing.T) { }) c.InitFromViper(v, zap.NewNop()) - assert.True(t, c.GRPC.Tenancy.Enabled) - assert.Equal(t, "custom-tenant-header", c.GRPC.Tenancy.Header) - assert.Equal(t, []string{"acme", "hardware-store"}, c.GRPC.Tenancy.Tenants) + assert.True(t, c.Tenancy.Enabled) + assert.Equal(t, "custom-tenant-header", c.Tenancy.Header) + assert.Equal(t, []string{"acme", "hardware-store"}, c.Tenancy.Tenants) } func TestCollectorOptionsWithFlags_CheckZipkinKeepAlive(t *testing.T) { diff --git a/cmd/collector/app/handler/otlp_receiver.go b/cmd/collector/app/handler/otlp_receiver.go index fb54d931bf8..1bb2b2a96d9 100644 --- a/cmd/collector/app/handler/otlp_receiver.go +++ b/cmd/collector/app/handler/otlp_receiver.go @@ -10,10 +10,8 @@ import ( otlp2jaeger "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" - "go.opentelemetry.io/collector/config/configgrpc" - "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configtelemetry" - "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/pdata/ptrace" @@ -27,7 +25,6 @@ import ( "github.com/jaegertracing/jaeger/cmd/collector/app/flags" "github.com/jaegertracing/jaeger/cmd/collector/app/processor" - "github.com/jaegertracing/jaeger/pkg/config/tlscfg" "github.com/jaegertracing/jaeger/pkg/tenancy" ) @@ -62,8 +59,9 @@ func startOTLPReceiver( cfg component.Config, nextConsumer consumer.Traces) (receiver.Traces, error), ) (receiver.Traces, error) { otlpReceiverConfig := otlpFactory.CreateDefaultConfig().(*otlpreceiver.Config) - applyGRPCSettings(otlpReceiverConfig.GRPC, &options.OTLP.GRPC) - applyHTTPSettings(otlpReceiverConfig.HTTP.ServerConfig, &options.OTLP.HTTP) + otlpReceiverConfig.GRPC = &options.OTLP.GRPC + otlpReceiverConfig.GRPC.NetAddr.Transport = confignet.TransportTypeTCP + otlpReceiverConfig.HTTP.ServerConfig = &options.OTLP.HTTP statusReporter := func(ev *componentstatus.Event) { // TODO this could be wired into changing healthcheck.HealthCheck logger.Info("OTLP receiver status change", zap.Stringer("status", ev.Status())) @@ -101,54 +99,6 @@ func startOTLPReceiver( return otlpReceiver, nil } -func applyGRPCSettings(cfg *configgrpc.ServerConfig, opts *flags.GRPCOptions) { - if opts.HostPort != "" { - cfg.NetAddr.Endpoint = opts.HostPort - } - if opts.TLS.Enabled { - cfg.TLSSetting = applyTLSSettings(&opts.TLS) - } - if opts.MaxReceiveMessageLength > 0 { - cfg.MaxRecvMsgSizeMiB = int(opts.MaxReceiveMessageLength / (1024 * 1024)) - } - if opts.MaxConnectionAge != 0 || opts.MaxConnectionAgeGrace != 0 { - cfg.Keepalive = &configgrpc.KeepaliveServerConfig{ - ServerParameters: &configgrpc.KeepaliveServerParameters{ - MaxConnectionAge: opts.MaxConnectionAge, - MaxConnectionAgeGrace: opts.MaxConnectionAgeGrace, - }, - } - } -} - -func applyHTTPSettings(cfg *confighttp.ServerConfig, opts *flags.HTTPOptions) { - if opts.HostPort != "" { - cfg.Endpoint = opts.HostPort - } - if opts.TLS.Enabled { - cfg.TLSSetting = applyTLSSettings(&opts.TLS) - } - - cfg.CORS = &confighttp.CORSConfig{ - AllowedOrigins: opts.CORS.AllowedOrigins, - AllowedHeaders: opts.CORS.AllowedHeaders, - } -} - -func applyTLSSettings(opts *tlscfg.Options) *configtls.ServerConfig { - return &configtls.ServerConfig{ - Config: configtls.Config{ - CAFile: opts.CAPath, - CertFile: opts.CertPath, - KeyFile: opts.KeyPath, - MinVersion: opts.MinVersion, - MaxVersion: opts.MaxVersion, - ReloadInterval: opts.ReloadInterval, - }, - ClientCAFile: opts.ClientCAPath, - } -} - func newConsumerDelegate(logger *zap.Logger, spanProcessor processor.SpanProcessor, tm *tenancy.Manager) *consumerDelegate { return &consumerDelegate{ batchConsumer: newBatchConsumer(logger, diff --git a/cmd/collector/app/handler/otlp_receiver_test.go b/cmd/collector/app/handler/otlp_receiver_test.go index 1f18c3d07bb..c0f80de60f2 100644 --- a/cmd/collector/app/handler/otlp_receiver_test.go +++ b/cmd/collector/app/handler/otlp_receiver_test.go @@ -7,11 +7,13 @@ import ( "context" "errors" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" @@ -19,19 +21,28 @@ import ( "go.opentelemetry.io/collector/receiver/otlpreceiver" "github.com/jaegertracing/jaeger/cmd/collector/app/flags" - "github.com/jaegertracing/jaeger/pkg/config/corscfg" - "github.com/jaegertracing/jaeger/pkg/config/tlscfg" "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/pkg/testutils" ) func optionsWithPorts(port string) *flags.CollectorOptions { - opts := &flags.CollectorOptions{} - opts.OTLP.GRPC = flags.GRPCOptions{ - HostPort: port, - } - opts.OTLP.HTTP = flags.HTTPOptions{ - HostPort: port, + opts := &flags.CollectorOptions{ + OTLP: struct { + Enabled bool + GRPC configgrpc.ServerConfig + HTTP confighttp.ServerConfig + }{ + Enabled: true, + HTTP: confighttp.ServerConfig{ + Endpoint: port, + }, + GRPC: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: port, + Transport: confignet.TransportTypeTCP, + }, + }, + }, } return opts } @@ -128,80 +139,3 @@ func TestOtelHost(t *testing.T) { assert.Nil(t, host.GetExtensions()) assert.Nil(t, host.GetExporters()) } - -func TestApplyOTLPGRPCServerSettings(t *testing.T) { - otlpFactory := otlpreceiver.NewFactory() - otlpReceiverConfig := otlpFactory.CreateDefaultConfig().(*otlpreceiver.Config) - - grpcOpts := &flags.GRPCOptions{ - HostPort: ":54321", - MaxReceiveMessageLength: 42 * 1024 * 1024, - MaxConnectionAge: 33 * time.Second, - MaxConnectionAgeGrace: 37 * time.Second, - TLS: tlscfg.Options{ - Enabled: true, - CAPath: "ca", - CertPath: "cert", - KeyPath: "key", - ClientCAPath: "clientca", - MinVersion: "1.1", - MaxVersion: "1.3", - ReloadInterval: 24 * time.Hour, - }, - } - applyGRPCSettings(otlpReceiverConfig.GRPC, grpcOpts) - out := otlpReceiverConfig.GRPC - assert.Equal(t, ":54321", out.NetAddr.Endpoint) - assert.EqualValues(t, 42, out.MaxRecvMsgSizeMiB) - require.NotNil(t, out.Keepalive) - require.NotNil(t, out.Keepalive.ServerParameters) - assert.Equal(t, 33*time.Second, out.Keepalive.ServerParameters.MaxConnectionAge) - assert.Equal(t, 37*time.Second, out.Keepalive.ServerParameters.MaxConnectionAgeGrace) - require.NotNil(t, out.TLSSetting) - assert.Equal(t, "ca", out.TLSSetting.CAFile) - assert.Equal(t, "cert", out.TLSSetting.CertFile) - assert.Equal(t, "key", out.TLSSetting.KeyFile) - assert.Equal(t, "clientca", out.TLSSetting.ClientCAFile) - assert.Equal(t, "1.1", out.TLSSetting.MinVersion) - assert.Equal(t, "1.3", out.TLSSetting.MaxVersion) - assert.Equal(t, 24*time.Hour, out.TLSSetting.ReloadInterval) -} - -func TestApplyOTLPHTTPServerSettings(t *testing.T) { - otlpFactory := otlpreceiver.NewFactory() - otlpReceiverConfig := otlpFactory.CreateDefaultConfig().(*otlpreceiver.Config) - - httpOpts := &flags.HTTPOptions{ - HostPort: ":12345", - TLS: tlscfg.Options{ - Enabled: true, - CAPath: "ca", - CertPath: "cert", - KeyPath: "key", - ClientCAPath: "clientca", - MinVersion: "1.1", - MaxVersion: "1.3", - ReloadInterval: 24 * time.Hour, - }, - CORS: corscfg.Options{ - AllowedOrigins: []string{"http://example.domain.com", "http://*.domain.com"}, - AllowedHeaders: []string{"Content-Type", "Accept", "X-Requested-With"}, - }, - } - - applyHTTPSettings(otlpReceiverConfig.HTTP.ServerConfig, httpOpts) - - out := otlpReceiverConfig.HTTP - - assert.Equal(t, ":12345", out.Endpoint) - require.NotNil(t, out.TLSSetting) - assert.Equal(t, "ca", out.TLSSetting.CAFile) - assert.Equal(t, "cert", out.TLSSetting.CertFile) - assert.Equal(t, "key", out.TLSSetting.KeyFile) - assert.Equal(t, "clientca", out.TLSSetting.ClientCAFile) - assert.Equal(t, "1.1", out.TLSSetting.MinVersion) - assert.Equal(t, "1.3", out.TLSSetting.MaxVersion) - assert.Equal(t, 24*time.Hour, out.TLSSetting.ReloadInterval) - assert.Equal(t, []string{"Content-Type", "Accept", "X-Requested-With"}, out.CORS.AllowedHeaders) - assert.Equal(t, []string{"http://example.domain.com", "http://*.domain.com"}, out.CORS.AllowedOrigins) -} diff --git a/cmd/collector/app/handler/zipkin_receiver.go b/cmd/collector/app/handler/zipkin_receiver.go index 983ee4bd2a5..b7fc18619e3 100644 --- a/cmd/collector/app/handler/zipkin_receiver.go +++ b/cmd/collector/app/handler/zipkin_receiver.go @@ -56,12 +56,7 @@ func startZipkinReceiver( cfg component.Config, nextConsumer consumer.Traces) (receiver.Traces, error), ) (receiver.Traces, error) { receiverConfig := zipkinFactory.CreateDefaultConfig().(*zipkinreceiver.Config) - applyHTTPSettings(&receiverConfig.ServerConfig, &flags.HTTPOptions{ - HostPort: options.Zipkin.HTTPHostPort, - TLS: options.Zipkin.TLS, - CORS: options.HTTP.CORS, - // TODO keepAlive not supported? - }) + receiverConfig.ServerConfig = options.Zipkin.ServerConfig receiverSettings := receiver.Settings{ TelemetrySettings: component.TelemetrySettings{ Logger: logger, diff --git a/cmd/collector/app/handler/zipkin_receiver_test.go b/cmd/collector/app/handler/zipkin_receiver_test.go index 584dbc56cda..d6ad98c4319 100644 --- a/cmd/collector/app/handler/zipkin_receiver_test.go +++ b/cmd/collector/app/handler/zipkin_receiver_test.go @@ -37,7 +37,7 @@ func TestZipkinReceiver(t *testing.T) { tm := &tenancy.Manager{} opts := &flags.CollectorOptions{} - opts.Zipkin.HTTPHostPort = ":11911" + opts.Zipkin.Endpoint = ":11911" rec, err := StartZipkinReceiver(opts, logger, spanProcessor, tm) require.NoError(t, err) @@ -138,7 +138,7 @@ func TestStartZipkinReceiver_Error(t *testing.T) { tm := &tenancy.Manager{} opts := &flags.CollectorOptions{} - opts.Zipkin.HTTPHostPort = ":-1" + opts.Zipkin.Endpoint = ":-1" _, err := StartZipkinReceiver(opts, logger, spanProcessor, tm) require.ErrorContains(t, err, "could not start Zipkin receiver") diff --git a/cmd/collector/app/handler/zipkin_receiver_tls_test.go b/cmd/collector/app/handler/zipkin_receiver_tls_test.go index 060327360a6..108a1023150 100644 --- a/cmd/collector/app/handler/zipkin_receiver_tls_test.go +++ b/cmd/collector/app/handler/zipkin_receiver_tls_test.go @@ -13,10 +13,9 @@ import ( "time" "github.com/stretchr/testify/require" - "go.uber.org/zap" + "go.opentelemetry.io/collector/config/configtls" "github.com/jaegertracing/jaeger/cmd/collector/app/flags" - "github.com/jaegertracing/jaeger/pkg/config/tlscfg" "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/ports" @@ -26,21 +25,21 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { const testCertKeyLocation = "../../../../pkg/config/tlscfg/testdata" testCases := []struct { name string - serverTLS tlscfg.Options - clientTLS tlscfg.Options + serverTLS configtls.ServerConfig + clientTLS configtls.ClientConfig expectTLSClientErr bool expectZipkinClientErr bool expectServerFail bool }{ { name: "should fail with TLS client to untrusted TLS server", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", + serverTLS: configtls.ServerConfig{ + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, + clientTLS: configtls.ClientConfig{ ServerName: "example.com", }, expectTLSClientErr: true, @@ -49,14 +48,16 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { }, { name: "should fail with TLS client to trusted TLS server with incorrect hostname", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", + serverTLS: configtls.ServerConfig{ + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + }, ServerName: "nonEmpty", }, expectTLSClientErr: true, @@ -65,14 +66,16 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { }, { name: "should pass with TLS client to trusted TLS server with correct hostname", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", + serverTLS: configtls.ServerConfig{ + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + }, ServerName: "example.com", }, expectTLSClientErr: false, @@ -81,74 +84,82 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { }, { name: "should fail with TLS client without cert to trusted TLS server requiring cert", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", - ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", + serverTLS: configtls.ServerConfig{ + ClientCAFile: testCertKeyLocation + "/example-CA-cert.pem", + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + }, ServerName: "example.com", }, expectTLSClientErr: false, - expectServerFail: false, expectZipkinClientErr: true, + expectServerFail: false, }, { name: "should pass with TLS client with cert to trusted TLS server requiring cert", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", - ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", + serverTLS: configtls.ServerConfig{ + ClientCAFile: testCertKeyLocation + "/example-CA-cert.pem", + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + CertFile: testCertKeyLocation + "/example-client-cert.pem", + KeyFile: testCertKeyLocation + "/example-client-key.pem", + }, ServerName: "example.com", - CertPath: testCertKeyLocation + "/example-client-cert.pem", - KeyPath: testCertKeyLocation + "/example-client-key.pem", }, expectTLSClientErr: false, - expectServerFail: false, expectZipkinClientErr: false, + expectServerFail: false, }, { - name: "should fail with TLS client without cert to trusted TLS server requiring cert from a different CA", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", - ClientCAPath: testCertKeyLocation + "/wrong-CA-cert.pem", // NB: wrong CA + name: "should fail with TLS client without cert to trusted TLS server requiring cert from different CA", + serverTLS: configtls.ServerConfig{ + ClientCAFile: testCertKeyLocation + "/wrong-CA-cert.pem", + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + CertFile: testCertKeyLocation + "/example-client-cert.pem", + KeyFile: testCertKeyLocation + "/example-client-key.pem", + }, ServerName: "example.com", - CertPath: testCertKeyLocation + "/example-client-cert.pem", - KeyPath: testCertKeyLocation + "/example-client-key.pem", }, expectTLSClientErr: false, - expectServerFail: false, expectZipkinClientErr: true, + expectServerFail: false, }, { name: "should fail with TLS client with cert to trusted TLS server with incorrect TLS min", - serverTLS: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", - ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", - MinVersion: "1.5", + serverTLS: configtls.ServerConfig{ + ClientCAFile: testCertKeyLocation + "/example-CA-cert.pem", + Config: configtls.Config{ + CertFile: testCertKeyLocation + "/example-server-cert.pem", + KeyFile: testCertKeyLocation + "/example-server-key.pem", + MinVersion: "1.5", + }, }, - clientTLS: tlscfg.Options{ - Enabled: true, - CAPath: testCertKeyLocation + "/example-CA-cert.pem", + clientTLS: configtls.ClientConfig{ + Config: configtls.Config{ + CAFile: testCertKeyLocation + "/example-CA-cert.pem", + CertFile: testCertKeyLocation + "/example-client-cert.pem", + KeyFile: testCertKeyLocation + "/example-client-key.pem", + }, ServerName: "example.com", - CertPath: testCertKeyLocation + "/example-client-cert.pem", - KeyPath: testCertKeyLocation + "/example-client-key.pem", }, expectTLSClientErr: true, expectServerFail: true, @@ -163,9 +174,8 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { tm := &tenancy.Manager{} opts := &flags.CollectorOptions{} - opts.Zipkin.HTTPHostPort = ports.PortToHostPort(ports.CollectorZipkin) - opts.Zipkin.TLS = test.serverTLS - defer test.serverTLS.Close() + opts.Zipkin.Endpoint = ports.PortToHostPort(ports.CollectorZipkin) + opts.Zipkin.TLSSetting = &test.serverTLS server, err := StartZipkinReceiver(opts, logger, spanProcessor, tm) if test.expectServerFail { @@ -177,8 +187,7 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { require.NoError(t, server.Shutdown(context.Background())) }() - clientTLSCfg, err0 := test.clientTLS.Config(zap.NewNop()) - defer test.clientTLS.Close() + clientTLSCfg, err0 := test.clientTLS.LoadTLSConfig(context.Background()) require.NoError(t, err0) dialer := &net.Dialer{Timeout: 2 * time.Second} conn, clientError := tls.DialWithDialer(dialer, "tcp", fmt.Sprintf("localhost:%d", ports.CollectorZipkin), clientTLSCfg) @@ -197,7 +206,6 @@ func TestSpanCollectorZipkinTLS(t *testing.T) { } response, requestError := client.Post(fmt.Sprintf("https://localhost:%d", ports.CollectorZipkin), "", nil) - if test.expectZipkinClientErr { require.Error(t, requestError) } else { diff --git a/cmd/collector/app/server/grpc.go b/cmd/collector/app/server/grpc.go index a740fe5b8fe..dbdedce6f26 100644 --- a/cmd/collector/app/server/grpc.go +++ b/cmd/collector/app/server/grpc.go @@ -4,36 +4,32 @@ package server import ( + "context" "fmt" "net" - "time" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" "go.uber.org/zap" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" "github.com/jaegertracing/jaeger/cmd/collector/app/handler" "github.com/jaegertracing/jaeger/cmd/collector/app/sampling" "github.com/jaegertracing/jaeger/cmd/collector/app/sampling/samplingstrategy" - "github.com/jaegertracing/jaeger/pkg/config/tlscfg" + "github.com/jaegertracing/jaeger/pkg/telemetry" "github.com/jaegertracing/jaeger/proto-gen/api_v2" ) // GRPCServerParams to construct a new Jaeger Collector gRPC Server type GRPCServerParams struct { - TLSConfig tlscfg.Options - HostPort string - Handler *handler.GRPCHandler - SamplingProvider samplingstrategy.Provider - Logger *zap.Logger - OnError func(error) - MaxReceiveMessageLength int - MaxConnectionAge time.Duration - MaxConnectionAgeGrace time.Duration + configgrpc.ServerConfig + Handler *handler.GRPCHandler + SamplingProvider samplingstrategy.Provider + Logger *zap.Logger + OnError func(error) // Set by the server to indicate the actual host:port of the server. HostPortActual string @@ -42,31 +38,17 @@ type GRPCServerParams struct { // StartGRPCServer based on the given parameters func StartGRPCServer(params *GRPCServerParams) (*grpc.Server, error) { var server *grpc.Server - var grpcOpts []grpc.ServerOption - - if params.MaxReceiveMessageLength > 0 { - grpcOpts = append(grpcOpts, grpc.MaxRecvMsgSize(params.MaxReceiveMessageLength)) - } - grpcOpts = append(grpcOpts, grpc.KeepaliveParams(keepalive.ServerParameters{ - MaxConnectionAge: params.MaxConnectionAge, - MaxConnectionAgeGrace: params.MaxConnectionAgeGrace, - })) - - if params.TLSConfig.Enabled { - // user requested a server with TLS, setup creds - tlsCfg, err := params.TLSConfig.Config(params.Logger) - if err != nil { - return nil, err - } - - creds := credentials.NewTLS(tlsCfg) - grpcOpts = append(grpcOpts, grpc.Creds(creds)) + var grpcOpts []configgrpc.ToServerOption + params.NetAddr.Transport = confignet.TransportTypeTCP + server, err := params.ToServer(context.Background(), nil, + telemetry.NoopSettings().ToOtelComponent(), + grpcOpts...) + if err != nil { + return nil, err } - - server = grpc.NewServer(grpcOpts...) reflection.Register(server) - listener, err := net.Listen("tcp", params.HostPort) + listener, err := params.NetAddr.Listen(context.Background()) if err != nil { return nil, fmt.Errorf("failed to listen on gRPC port: %w", err) } diff --git a/cmd/collector/app/server/grpc_test.go b/cmd/collector/app/server/grpc_test.go index 19594ebcfa7..3ac6351d628 100644 --- a/cmd/collector/app/server/grpc_test.go +++ b/cmd/collector/app/server/grpc_test.go @@ -10,6 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" @@ -28,7 +30,12 @@ import ( func TestFailToListen(t *testing.T) { logger, _ := zap.NewDevelopment() server, err := StartGRPCServer(&GRPCServerParams{ - HostPort: ":-1", + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: ":-1", + Transport: confignet.TransportTypeTCP, + }, + }, Handler: handler.NewGRPCHandler(logger, &mockSpanProcessor{}, &tenancy.Manager{}), SamplingProvider: &mockSamplingProvider{}, Logger: logger, @@ -63,10 +70,15 @@ func TestFailServe(t *testing.T) { func TestSpanCollector(t *testing.T) { logger, _ := zap.NewDevelopment() params := &GRPCServerParams{ - Handler: handler.NewGRPCHandler(logger, &mockSpanProcessor{}, &tenancy.Manager{}), - SamplingProvider: &mockSamplingProvider{}, - Logger: logger, - MaxReceiveMessageLength: 1024 * 1024, + Handler: handler.NewGRPCHandler(logger, &mockSpanProcessor{}, &tenancy.Manager{}), + SamplingProvider: &mockSamplingProvider{}, + Logger: logger, + ServerConfig: configgrpc.ServerConfig{ + MaxRecvMsgSizeMiB: 2, + NetAddr: confignet.AddrConfig{ + Transport: confignet.TransportTypeTCP, + }, + }, } server, err := StartGRPCServer(params) @@ -87,21 +99,26 @@ func TestSpanCollector(t *testing.T) { func TestCollectorStartWithTLS(t *testing.T) { logger, _ := zap.NewDevelopment() + opts := tlscfg.Options{ + Enabled: true, + CertPath: testCertKeyLocation + "/example-server-cert.pem", + KeyPath: testCertKeyLocation + "/example-server-key.pem", + ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", + } params := &GRPCServerParams{ Handler: handler.NewGRPCHandler(logger, &mockSpanProcessor{}, &tenancy.Manager{}), SamplingProvider: &mockSamplingProvider{}, Logger: logger, - TLSConfig: tlscfg.Options{ - Enabled: true, - CertPath: testCertKeyLocation + "/example-server-cert.pem", - KeyPath: testCertKeyLocation + "/example-server-key.pem", - ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Transport: confignet.TransportTypeTCP, + }, + TLSSetting: opts.ToOtelServerConfig(), }, } server, err := StartGRPCServer(params) require.NoError(t, err) defer server.Stop() - defer params.TLSConfig.Close() } func TestCollectorReflection(t *testing.T) { @@ -110,6 +127,11 @@ func TestCollectorReflection(t *testing.T) { Handler: handler.NewGRPCHandler(logger, &mockSpanProcessor{}, &tenancy.Manager{}), SamplingProvider: &mockSamplingProvider{}, Logger: logger, + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Transport: confignet.TransportTypeTCP, + }, + }, } server, err := StartGRPCServer(params) diff --git a/cmd/collector/app/server/http.go b/cmd/collector/app/server/http.go index c519e6df495..15385bb9320 100644 --- a/cmd/collector/app/server/http.go +++ b/cmd/collector/app/server/http.go @@ -4,63 +4,47 @@ package server import ( + "context" "net" "net/http" - "time" "github.com/gorilla/mux" + "go.opentelemetry.io/collector/config/confighttp" "go.uber.org/zap" "go.uber.org/zap/zapcore" "github.com/jaegertracing/jaeger/cmd/collector/app/handler" "github.com/jaegertracing/jaeger/cmd/collector/app/sampling/samplingstrategy" clientcfgHandler "github.com/jaegertracing/jaeger/pkg/clientcfg/clientcfghttp" - "github.com/jaegertracing/jaeger/pkg/config/tlscfg" "github.com/jaegertracing/jaeger/pkg/healthcheck" "github.com/jaegertracing/jaeger/pkg/httpmetrics" "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/pkg/recoveryhandler" + "github.com/jaegertracing/jaeger/pkg/telemetry" ) // HTTPServerParams to construct a new Jaeger Collector HTTP Server type HTTPServerParams struct { - TLSConfig tlscfg.Options - HostPort string + confighttp.ServerConfig Handler handler.JaegerBatchesHandler SamplingProvider samplingstrategy.Provider MetricsFactory metrics.Factory HealthCheck *healthcheck.HealthCheck Logger *zap.Logger - - // ReadTimeout sets the respective parameter of http.Server - ReadTimeout time.Duration - // ReadHeaderTimeout sets the respective parameter of http.Server - ReadHeaderTimeout time.Duration - // IdleTimeout sets the respective parameter of http.Server - IdleTimeout time.Duration } // StartHTTPServer based on the given parameters func StartHTTPServer(params *HTTPServerParams) (*http.Server, error) { - params.Logger.Info("Starting jaeger-collector HTTP server", zap.String("http host-port", params.HostPort)) - - errorLog, _ := zap.NewStdLogAt(params.Logger, zapcore.ErrorLevel) - server := &http.Server{ - Addr: params.HostPort, - ReadTimeout: params.ReadTimeout, - ReadHeaderTimeout: params.ReadHeaderTimeout, - IdleTimeout: params.IdleTimeout, - ErrorLog: errorLog, - } - if params.TLSConfig.Enabled { - tlsCfg, err := params.TLSConfig.Config(params.Logger) // This checks if the certificates are correctly provided - if err != nil { - return nil, err - } - server.TLSConfig = tlsCfg + params.Logger.Info("Starting jaeger-collector HTTP server", zap.String("host-port", params.Endpoint)) + listener, err := params.ToListener(context.Background()) + if err != nil { + return nil, err } + errorLog, _ := zap.NewStdLogAt(params.Logger, zapcore.ErrorLevel) + server, err := params.ToServer(context.Background(), nil, telemetry.NoopSettings().ToOtelComponent(), + nil) - listener, err := net.Listen("tcp", params.HostPort) + server.ErrorLog = errorLog if err != nil { return nil, err } @@ -89,12 +73,7 @@ func serveHTTP(server *http.Server, listener net.Listener, params *HTTPServerPar recoveryHandler := recoveryhandler.NewRecoveryHandler(params.Logger, true) server.Handler = httpmetrics.Wrap(recoveryHandler(r), params.MetricsFactory, params.Logger) go func() { - var err error - if params.TLSConfig.Enabled { - err = server.ServeTLS(listener, "", "") - } else { - err = server.Serve(listener) - } + err := server.Serve(listener) if err != nil { if err != http.ErrServerClosed { params.Logger.Error("Could not start HTTP collector", zap.Error(err)) diff --git a/cmd/collector/app/server/http_test.go b/cmd/collector/app/server/http_test.go index 46184bd8b89..24c00b94e54 100644 --- a/cmd/collector/app/server/http_test.go +++ b/cmd/collector/app/server/http_test.go @@ -4,17 +4,20 @@ package server import ( + "context" "crypto/tls" "fmt" "net" "net/http" - "net/http/httptest" "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configtls" "go.uber.org/zap" "github.com/jaegertracing/jaeger/cmd/collector/app/handler" @@ -30,8 +33,10 @@ var testCertKeyLocation = "../../../../pkg/config/tlscfg/testdata" func TestFailToListenHTTP(t *testing.T) { logger, _ := zap.NewDevelopment() server, err := StartHTTPServer(&HTTPServerParams{ - HostPort: ":-1", - Logger: logger, + ServerConfig: confighttp.ServerConfig{ + Endpoint: ":-1", + }, + Logger: logger, }) assert.Nil(t, server) require.EqualError(t, err, "listen tcp: address -1: invalid port") @@ -39,22 +44,23 @@ func TestFailToListenHTTP(t *testing.T) { func TestCreateTLSHTTPServerError(t *testing.T) { logger, _ := zap.NewDevelopment() - tlsCfg := tlscfg.Options{ - Enabled: true, - CertPath: "invalid/path", - KeyPath: "invalid/path", - ClientCAPath: "invalid/path", - } params := &HTTPServerParams{ - HostPort: fmt.Sprintf(":%d", ports.CollectorHTTP), + ServerConfig: confighttp.ServerConfig{ + Endpoint: ":0", + TLSSetting: &configtls.ServerConfig{ + Config: configtls.Config{ + CertFile: "invalid/path", + KeyFile: "invalid/path", + CAFile: "invalid/path", + }, + }, + }, HealthCheck: healthcheck.New(), Logger: logger, - TLSConfig: tlsCfg, } _, err := StartHTTPServer(params) require.Error(t, err) - defer params.TLSConfig.Close() } func TestSpanCollectorHTTP(t *testing.T) { @@ -69,11 +75,15 @@ func TestSpanCollectorHTTP(t *testing.T) { Logger: logger, } - server := httptest.NewServer(nil) - - serveHTTP(server.Config, server.Listener, params) + server, _ := params.ToServer(context.Background(), nil, component.TelemetrySettings{}, nil) + listener, _ := params.ToListener(context.Background()) - response, err := http.Post(server.URL, "", nil) + serveHTTP(server, listener, params) + addr := listener.Addr().String() + host, port, err := net.SplitHostPort(addr) + require.NoError(t, err) + url := fmt.Sprintf("http://%s:%s", host, port) + response, err := http.Post(url, "", nil) require.NoError(t, err) assert.NotNil(t, response) defer response.Body.Close() @@ -188,15 +198,16 @@ func TestSpanCollectorHTTPS(t *testing.T) { mFact := metricstest.NewFactory(time.Hour) defer mFact.Backend.Stop() params := &HTTPServerParams{ - HostPort: fmt.Sprintf(":%d", ports.CollectorHTTP), + ServerConfig: confighttp.ServerConfig{ + Endpoint: fmt.Sprintf(":%d", ports.CollectorHTTP), + TLSSetting: test.TLS.ToOtelServerConfig(), + }, Handler: handler.NewJaegerSpanHandler(logger, &mockSpanProcessor{}), SamplingProvider: &mockSamplingProvider{}, MetricsFactory: mFact, HealthCheck: healthcheck.New(), Logger: logger, - TLSConfig: test.TLS, } - defer params.TLSConfig.Close() server, err := StartHTTPServer(params) require.NoError(t, err) @@ -204,8 +215,7 @@ func TestSpanCollectorHTTPS(t *testing.T) { require.NoError(t, server.Close()) }() - clientTLSCfg, err0 := test.clientTLS.Config(logger) - defer test.clientTLS.Close() + clientTLSCfg, err0 := test.clientTLS.ToOtelClientConfig().LoadTLSConfig(context.Background()) require.NoError(t, err0) dialer := &net.Dialer{Timeout: 2 * time.Second} conn, clientError := tls.DialWithDialer(dialer, "tcp", "localhost:"+strconv.Itoa(ports.CollectorHTTP), clientTLSCfg) @@ -250,15 +260,17 @@ func TestStartHTTPServerParams(t *testing.T) { mFact := metricstest.NewFactory(time.Hour) defer mFact.Stop() params := &HTTPServerParams{ - HostPort: fmt.Sprintf(":%d", ports.CollectorHTTP), - Handler: handler.NewJaegerSpanHandler(logger, &mockSpanProcessor{}), - SamplingProvider: &mockSamplingProvider{}, - MetricsFactory: mFact, - HealthCheck: healthcheck.New(), - Logger: logger, - IdleTimeout: 5 * time.Minute, - ReadTimeout: 6 * time.Minute, - ReadHeaderTimeout: 7 * time.Second, + ServerConfig: confighttp.ServerConfig{ + Endpoint: fmt.Sprintf(":%d", ports.CollectorHTTP), + IdleTimeout: 5 * time.Minute, + ReadTimeout: 6 * time.Minute, + ReadHeaderTimeout: 7 * time.Second, + }, + Handler: handler.NewJaegerSpanHandler(logger, &mockSpanProcessor{}), + SamplingProvider: &mockSamplingProvider{}, + MetricsFactory: mFact, + HealthCheck: healthcheck.New(), + Logger: logger, } server, err := StartHTTPServer(params) diff --git a/cmd/collector/main.go b/cmd/collector/main.go index 86f26d1cb84..29303cecdbb 100644 --- a/cmd/collector/main.go +++ b/cmd/collector/main.go @@ -35,6 +35,7 @@ import ( const serviceName = "jaeger-collector" func main() { + cmdFlags.PrintV1EOL() svc := cmdFlags.NewService(ports.CollectorAdminHTTP) storageFactory, err := storage.NewFactory(storage.FactoryConfigFromEnvAndCLI(os.Args, os.Stderr)) @@ -94,7 +95,7 @@ func main() { if err != nil { logger.Fatal("Failed to initialize collector", zap.Error(err)) } - tm := tenancy.NewManager(&collectorOpts.GRPC.Tenancy) + tm := tenancy.NewManager(&collectorOpts.Tenancy) collector := app.New(&app.CollectorParams{ ServiceName: serviceName, diff --git a/cmd/ingester/app/flags_test.go b/cmd/ingester/app/flags_test.go index d390b57481f..65ce83a6b7b 100644 --- a/cmd/ingester/app/flags_test.go +++ b/cmd/ingester/app/flags_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/configtls" "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/kafka/auth" @@ -66,12 +67,18 @@ func TestTLSFlags(t *testing.T) { expected: auth.AuthenticationConfig{Authentication: "kerberos", Kerberos: kerb, PlainText: plain}, }, { - flags: []string{"--kafka.consumer.authentication=tls"}, - expected: auth.AuthenticationConfig{Authentication: "tls", Kerberos: kerb, PlainText: plain}, - }, - { - flags: []string{"--kafka.consumer.authentication=tls", "--kafka.consumer.tls.enabled=false"}, - expected: auth.AuthenticationConfig{Authentication: "tls", Kerberos: kerb, PlainText: plain}, + flags: []string{"--kafka.consumer.authentication=tls"}, + expected: auth.AuthenticationConfig{ + Authentication: "tls", + Kerberos: kerb, + // TODO this test is unclear - if tls.enabled != true, why is it not tls.Insecure=true? + TLS: configtls.ClientConfig{ + Config: configtls.Config{ + IncludeSystemCACertsPool: true, + }, + }, + PlainText: plain, + }, }, } diff --git a/cmd/ingester/main.go b/cmd/ingester/main.go index efc08cea61f..4500b997311 100644 --- a/cmd/ingester/main.go +++ b/cmd/ingester/main.go @@ -30,6 +30,7 @@ import ( ) func main() { + flags.PrintV1EOL() svc := flags.NewService(ports.IngesterAdminHTTP) storageFactory, err := storage.NewFactory(storage.FactoryConfigFromEnvAndCLI(os.Args, os.Stderr)) diff --git a/cmd/internal/flags/service.go b/cmd/internal/flags/service.go index 7a276d59d18..a076cebc19b 100644 --- a/cmd/internal/flags/service.go +++ b/cmd/internal/flags/service.go @@ -42,6 +42,30 @@ type Service struct { signalsChannel chan os.Signal } +func PrintV1EOL() { + println(` +******************************************************************************* + +🛑 WARNING: End-of-life Notice for Jaeger v1 + +You are currently running a v1 version of Jaeger, which is deprecated and will +reach end-of-life on December 31st, 2025. This means there will be no further +development, bug fixes, or security patches for v1 after this date. + +We strongly recommend migrating to Jaeger v2 for continued support and access +to new features. + +For detailed migration instructions, please refer to the official Jaeger +documentation: https://www.jaegertracing.io/docs/latest/migration/ + +Tracking issue: https://github.com/jaegertracing/jaeger/issues/6321 + +🛑 WARNING: End-of-life Notice for Jaeger v1 + +******************************************************************************* +`) +} + // NewService creates a new Service. func NewService(adminPort int) *Service { signalsChannel := make(chan os.Signal, 1) diff --git a/cmd/jaeger/internal/exporters/storageexporter/exporter.go b/cmd/jaeger/internal/exporters/storageexporter/exporter.go index 3fbeab79b43..4b2dee9e0fc 100644 --- a/cmd/jaeger/internal/exporters/storageexporter/exporter.go +++ b/cmd/jaeger/internal/exporters/storageexporter/exporter.go @@ -34,7 +34,7 @@ func newExporter(config *Config, otel component.TelemetrySettings) *storageExpor } func (exp *storageExporter) start(_ context.Context, host component.Host) error { - f, err := jaegerstorage.GetStorageFactoryV2(exp.config.TraceStorage, host) + f, err := jaegerstorage.GetTraceStoreFactory(exp.config.TraceStorage, host) if err != nil { return fmt.Errorf("cannot find storage factory: %w", err) } diff --git a/cmd/jaeger/internal/extension/jaegerquery/server.go b/cmd/jaeger/internal/extension/jaegerquery/server.go index 29f836e9c89..5f578c3f2de 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/server.go +++ b/cmd/jaeger/internal/extension/jaegerquery/server.go @@ -21,6 +21,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/plugin/metricstore/disabled" "github.com/jaegertracing/jaeger/storage/metricstore" + "github.com/jaegertracing/jaeger/storage_v2/depstore" ) var ( @@ -71,23 +72,20 @@ func (s *server) Start(ctx context.Context, host component.Host) error { telset.Metrics = telset.Metrics. Namespace(metrics.NSOptions{Name: "jaeger"}). Namespace(metrics.NSOptions{Name: "query"}) - - // TODO currently v1 is still needed because of dependency storage - v1Factory, err := jaegerstorage.GetStorageFactory(s.config.Storage.TracesPrimary, host) + tf, err := jaegerstorage.GetTraceStoreFactory(s.config.Storage.TracesPrimary, host) if err != nil { - return fmt.Errorf("cannot find v1 factory for primary storage %s: %w", s.config.Storage.TracesPrimary, err) + return fmt.Errorf("cannot find factory for trace storage %s: %w", s.config.Storage.TracesPrimary, err) } - f, err := jaegerstorage.GetStorageFactoryV2(s.config.Storage.TracesPrimary, host) - if err != nil { - return fmt.Errorf("cannot find v2 factory for primary storage %s: %w", s.config.Storage.TracesPrimary, err) - } - - traceReader, err := f.CreateTraceReader() + traceReader, err := tf.CreateTraceReader() if err != nil { return fmt.Errorf("cannot create trace reader: %w", err) } - depReader, err := v1Factory.CreateDependencyReader() + df, ok := tf.(depstore.Factory) + if !ok { + return fmt.Errorf("cannot find factory for dependency storage %s: %w", s.config.Storage.TracesPrimary, err) + } + depReader, err := df.CreateDependencyReader() if err != nil { return fmt.Errorf("cannot create dependencies reader: %w", err) } diff --git a/cmd/jaeger/internal/extension/jaegerquery/server_test.go b/cmd/jaeger/internal/extension/jaegerquery/server_test.go index 70e60d78768..696b691c938 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/server_test.go +++ b/cmd/jaeger/internal/extension/jaegerquery/server_test.go @@ -150,7 +150,7 @@ func TestServerStart(t *testing.T) { TracesPrimary: "need-factory-error", }, }, - expectedErr: "cannot find v1 factory for primary storage", + expectedErr: "cannot find factory for trace storage", }, { name: "span reader error", diff --git a/cmd/jaeger/internal/extension/jaegerstorage/extension.go b/cmd/jaeger/internal/extension/jaegerstorage/extension.go index 7ac99e15a29..c1dd68b01b7 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/extension.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/extension.go @@ -74,7 +74,7 @@ func GetMetricStorageFactory(name string, host component.Host) (storage.MetricSt return mf, nil } -func GetStorageFactoryV2(name string, host component.Host) (tracestore.Factory, error) { +func GetTraceStoreFactory(name string, host component.Host) (tracestore.Factory, error) { f, err := GetStorageFactory(name, host) if err != nil { return nil, err diff --git a/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go b/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go index 6213c912765..8623703ad83 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go @@ -100,7 +100,7 @@ func TestStorageFactoryBadShutdownError(t *testing.T) { func TestGetFactoryV2Error(t *testing.T) { host := componenttest.NewNopHost() - _, err := GetStorageFactoryV2("something", host) + _, err := GetTraceStoreFactory("something", host) require.ErrorContains(t, err, "cannot find extension") } @@ -112,7 +112,7 @@ func TestGetFactory(t *testing.T) { require.NoError(t, err) require.NotNil(t, f) - f2, err := GetStorageFactoryV2(name, host) + f2, err := GetTraceStoreFactory(name, host) require.NoError(t, err) require.NotNil(t, f2) diff --git a/cmd/query/app/apiv3/grpc_handler_test.go b/cmd/query/app/apiv3/grpc_handler_test.go index b14f1c01abf..6534df23fe6 100644 --- a/cmd/query/app/apiv3/grpc_handler_test.go +++ b/cmd/query/app/apiv3/grpc_handler_test.go @@ -20,9 +20,9 @@ import ( "github.com/jaegertracing/jaeger/cmd/query/app/querysvc" "github.com/jaegertracing/jaeger/model" _ "github.com/jaegertracing/jaeger/pkg/gogocodec" // force gogo codec registration - dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + dependencyStoreMocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) diff --git a/cmd/query/app/apiv3/http_gateway_test.go b/cmd/query/app/apiv3/http_gateway_test.go index 5f742a0522f..f0abbeb3307 100644 --- a/cmd/query/app/apiv3/http_gateway_test.go +++ b/cmd/query/app/apiv3/http_gateway_test.go @@ -22,9 +22,9 @@ import ( "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/pkg/jtracer" "github.com/jaegertracing/jaeger/pkg/testutils" - dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + dependencyStoreMocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) diff --git a/cmd/query/app/grpc_handler.go b/cmd/query/app/grpc_handler.go index 64669ed3e4e..7cbeab083cb 100644 --- a/cmd/query/app/grpc_handler.go +++ b/cmd/query/app/grpc_handler.go @@ -223,7 +223,7 @@ func (g *GRPCHandler) GetDependencies(ctx context.Context, r *api_v2.GetDependen return nil, status.Errorf(codes.InvalidArgument, "StartTime and EndTime must be initialized.") } - dependencies, err := g.queryService.GetDependencies(ctx, startTime, endTime.Sub(startTime)) + dependencies, err := g.queryService.GetDependencies(ctx, endTime, endTime.Sub(startTime)) if err != nil { g.logger.Error("failed to fetch dependencies", zap.Error(err)) return nil, status.Errorf(codes.Internal, "failed to fetch dependencies: %v", err) diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index 55dcf2affa7..a5c59638031 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -28,11 +28,12 @@ import ( "github.com/jaegertracing/jaeger/plugin/metricstore/disabled" "github.com/jaegertracing/jaeger/proto-gen/api_v2" "github.com/jaegertracing/jaeger/proto-gen/api_v2/metrics" - depsmocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" "github.com/jaegertracing/jaeger/storage/metricstore" metricsmocks "github.com/jaegertracing/jaeger/storage/metricstore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + "github.com/jaegertracing/jaeger/storage_v2/depstore" + depsmocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) @@ -513,8 +514,10 @@ func TestGetDependenciesSuccessGRPC(t *testing.T) { endTs := time.Now().UTC() server.depReader.On("GetDependencies", mock.Anything, // context.Context - endTs.Add(time.Duration(-1)*defaultDependencyLookbackDuration), - defaultDependencyLookbackDuration, + depstore.QueryParameters{ + StartTime: endTs.Add(-defaultDependencyLookbackDuration), + EndTime: endTs, + }, ).Return(expectedDependencies, nil).Times(1) res, err := client.GetDependencies(context.Background(), &api_v2.GetDependenciesRequest{ @@ -529,11 +532,13 @@ func TestGetDependenciesSuccessGRPC(t *testing.T) { func TestGetDependenciesFailureGRPC(t *testing.T) { withServerAndClient(t, func(server *grpcServer, client *grpcClient) { endTs := time.Now().UTC() - server.depReader.On( - "GetDependencies", + server.depReader.On("GetDependencies", mock.Anything, // context.Context - endTs.Add(time.Duration(-1)*defaultDependencyLookbackDuration), - defaultDependencyLookbackDuration).Return(nil, errStorageGRPC).Times(1) + depstore.QueryParameters{ + StartTime: endTs.Add(-defaultDependencyLookbackDuration), + EndTime: endTs, + }, + ).Return(nil, errStorageGRPC).Times(1) _, err := client.GetDependencies(context.Background(), &api_v2.GetDependenciesRequest{ StartTime: endTs.Add(time.Duration(-1) * defaultDependencyLookbackDuration), diff --git a/cmd/query/app/handler_deps_test.go b/cmd/query/app/handler_deps_test.go index ff71efe62cf..e24799c00ce 100644 --- a/cmd/query/app/handler_deps_test.go +++ b/cmd/query/app/handler_deps_test.go @@ -15,6 +15,7 @@ import ( "github.com/jaegertracing/jaeger/model" ui "github.com/jaegertracing/jaeger/model/json" + "github.com/jaegertracing/jaeger/storage_v2/depstore" ) func TestDeduplicateDependencies(t *testing.T) { @@ -304,8 +305,10 @@ func TestGetDependenciesSuccess(t *testing.T) { endTs := time.Unix(0, 1476374248550*millisToNanosMultiplier) ts.dependencyReader.On("GetDependencies", mock.Anything, // context - endTs, - defaultDependencyLookbackDuration, + depstore.QueryParameters{ + StartTime: endTs.Add(-defaultDependencyLookbackDuration), + EndTime: endTs, + }, ).Return(expectedDependencies, nil).Times(1) var response structuredResponse @@ -324,8 +327,11 @@ func TestGetDependenciesCassandraFailure(t *testing.T) { endTs := time.Unix(0, 1476374248550*millisToNanosMultiplier) ts.dependencyReader.On("GetDependencies", mock.Anything, // context - endTs, - defaultDependencyLookbackDuration).Return(nil, errStorage).Times(1) + depstore.QueryParameters{ + StartTime: endTs.Add(-defaultDependencyLookbackDuration), + EndTime: endTs, + }, + ).Return(nil, errStorage).Times(1) var response structuredResponse err := getJSON(ts.server.URL+"/api/dependencies?endTs=1476374248550&service=testing", &response) diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index dfa54f6701a..511495193c3 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -38,10 +38,10 @@ import ( "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/plugin/metricstore/disabled" "github.com/jaegertracing/jaeger/proto-gen/api_v2/metrics" - depsmocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" metricsmocks "github.com/jaegertracing/jaeger/storage/metricstore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + depsmocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index f627c3c8344..1a34cd1e408 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -13,8 +13,8 @@ import ( "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/model/adjuster" "github.com/jaegertracing/jaeger/storage" - "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" + "github.com/jaegertracing/jaeger/storage_v2/depstore" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) @@ -43,12 +43,12 @@ type StorageCapabilities struct { // QueryService contains span utils required by the query-service. type QueryService struct { traceReader tracestore.Reader - dependencyReader dependencystore.Reader + dependencyReader depstore.Reader options QueryServiceOptions } // NewQueryService returns a new QueryService. -func NewQueryService(traceReader tracestore.Reader, dependencyReader dependencystore.Reader, options QueryServiceOptions) *QueryService { +func NewQueryService(traceReader tracestore.Reader, dependencyReader depstore.Reader, options QueryServiceOptions) *QueryService { qsvc := &QueryService{ traceReader: traceReader, dependencyReader: dependencyReader, @@ -134,7 +134,10 @@ func (qs QueryService) Adjust(trace *model.Trace) (*model.Trace, error) { // GetDependencies implements dependencystore.Reader.GetDependencies func (qs QueryService) GetDependencies(ctx context.Context, endTs time.Time, lookback time.Duration) ([]model.DependencyLink, error) { - return qs.dependencyReader.GetDependencies(ctx, endTs, lookback) + return qs.dependencyReader.GetDependencies(ctx, depstore.QueryParameters{ + StartTime: endTs.Add(-lookback), + EndTime: endTs, + }) } // GetCapabilities returns the features supported by the query service. diff --git a/cmd/query/app/querysvc/query_service_test.go b/cmd/query/app/querysvc/query_service_test.go index 3a9f906d2b5..9cfd8ec6212 100644 --- a/cmd/query/app/querysvc/query_service_test.go +++ b/cmd/query/app/querysvc/query_service_test.go @@ -22,9 +22,10 @@ import ( "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/storage" "github.com/jaegertracing/jaeger/storage/dependencystore" - depsmocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + "github.com/jaegertracing/jaeger/storage_v2/depstore" + depsmocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) @@ -345,8 +346,10 @@ func TestGetDependencies(t *testing.T) { tqs.depsReader.On( "GetDependencies", mock.Anything, // context.Context - endTs, - defaultDependencyLookbackDuration).Return(expectedDependencies, nil).Times(1) + depstore.QueryParameters{ + StartTime: endTs.Add(-defaultDependencyLookbackDuration), + EndTime: endTs, + }).Return(expectedDependencies, nil).Times(1) actualDependencies, err := tqs.queryService.GetDependencies(context.Background(), time.Unix(0, 1476374248550*millisToNanosMultiplier), defaultDependencyLookbackDuration) require.NoError(t, err) diff --git a/cmd/query/app/server_test.go b/cmd/query/app/server_test.go index 51db8aeb239..fc2c0d298f0 100644 --- a/cmd/query/app/server_test.go +++ b/cmd/query/app/server_test.go @@ -39,8 +39,8 @@ import ( "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/ports" "github.com/jaegertracing/jaeger/proto-gen/api_v2" - depsmocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + depsmocks "github.com/jaegertracing/jaeger/storage_v2/depstore/mocks" "github.com/jaegertracing/jaeger/storage_v2/factoryadapter" ) diff --git a/cmd/query/main.go b/cmd/query/main.go index 5d32b5db10f..1b8b353a7ae 100644 --- a/cmd/query/main.go +++ b/cmd/query/main.go @@ -36,6 +36,7 @@ import ( ) func main() { + flags.PrintV1EOL() svc := flags.NewService(ports.QueryAdminHTTP) storageFactory, err := storage.NewFactory(storage.FactoryConfigFromEnvAndCLI(os.Args, os.Stderr)) @@ -96,7 +97,7 @@ func main() { if err != nil { logger.Fatal("Failed to create trace reader", zap.Error(err)) } - dependencyReader, err := storageFactory.CreateDependencyReader() + dependencyReader, err := v2Factory.CreateDependencyReader() if err != nil { logger.Fatal("Failed to create dependency reader", zap.Error(err)) } diff --git a/go.mod b/go.mod index 003fc057822..656614e68cd 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 github.com/kr/pretty v0.3.1 github.com/olivere/elastic v6.2.37+incompatible github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.115.0 @@ -262,7 +262,7 @@ require ( go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.30.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/text v0.21.0 // indirect gonum.org/v1/gonum v0.15.1 // indirect diff --git a/go.sum b/go.sum index 308f93da133..332af178994 100644 --- a/go.sum +++ b/go.sum @@ -248,8 +248,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= @@ -786,8 +786,8 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/jaeger-ui b/jaeger-ui index a0458053c53..c5cd17bf979 160000 --- a/jaeger-ui +++ b/jaeger-ui @@ -1 +1 @@ -Subproject commit a0458053c53bb18ba36a42867c06b0803d8fafaf +Subproject commit c5cd17bf979ba454da761f660fde08a1f309aee9 diff --git a/model/ids.go b/model/ids.go index 27c7d3846b0..5bf93dc43be 100644 --- a/model/ids.go +++ b/model/ids.go @@ -12,6 +12,7 @@ import ( "strconv" "github.com/gogo/protobuf/jsonpb" + "go.opentelemetry.io/collector/pdata/pcommon" ) const ( @@ -145,6 +146,23 @@ func (t *TraceID) UnmarshalJSON(data []byte) error { return t.Unmarshal(b) } +// ToOTELTraceID converts the TraceID to OTEL's representation of a trace identitfier. +// This was taken from +// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/internal/coreinternal/idutils/big_endian_converter.go. +func (t *TraceID) ToOTELTraceID() pcommon.TraceID { + traceID := [16]byte{} + binary.BigEndian.PutUint64(traceID[:8], t.High) + binary.BigEndian.PutUint64(traceID[8:], t.Low) + return traceID +} + +func TraceIDFromOTEL(traceID pcommon.TraceID) TraceID { + return TraceID{ + High: binary.BigEndian.Uint64(traceID[:traceIDShortBytesLen]), + Low: binary.BigEndian.Uint64(traceID[traceIDShortBytesLen:]), + } +} + // ------- SpanID ------- // NewSpanID creates a new SpanID from a 64bit unsigned int. diff --git a/model/ids_test.go b/model/ids_test.go index ba490236bb6..40c6f801a5c 100644 --- a/model/ids_test.go +++ b/model/ids_test.go @@ -12,6 +12,7 @@ import ( "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/pdata/pcommon" "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/model/prototest" @@ -117,3 +118,22 @@ func TestTraceIDFromBytes(t *testing.T) { assert.Equal(t, test.expected, traceID) } } + +func TestToOTELTraceID(t *testing.T) { + modelTraceID := model.TraceID{ + Low: 3, + High: 2, + } + otelTraceID := modelTraceID.ToOTELTraceID() + expected := []byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3} + require.Equal(t, pcommon.TraceID(expected), otelTraceID) +} + +func TestTraceIDFromOTEL(t *testing.T) { + otelTraceID := pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}) + expected := model.TraceID{ + Low: 3, + High: 2, + } + require.Equal(t, expected, model.TraceIDFromOTEL(otelTraceID)) +} diff --git a/pkg/cassandra/config/config.go b/pkg/cassandra/config/config.go index d5e499a2523..9cec5128c4f 100644 --- a/pkg/cassandra/config/config.go +++ b/pkg/cassandra/config/config.go @@ -68,6 +68,8 @@ type Schema struct { ReplicationFactor int `mapstructure:"replication_factor" valid:"optional"` // CompactionWindow is the size of the window for TimeWindowCompactionStrategy. // All SSTables within that window are grouped together into one SSTable. + // Ideally, operators should select a compaction window size that produces approximately less than 50 windows. + // For example, if writing with a 90 day TTL, a 3 day window would be a reasonable choice. CompactionWindow time.Duration `mapstructure:"compaction_window" valid:"optional"` } diff --git a/pkg/config/corscfg/flags.go b/pkg/config/corscfg/flags.go index c58b6b44bc4..892e177d7f7 100644 --- a/pkg/config/corscfg/flags.go +++ b/pkg/config/corscfg/flags.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/spf13/viper" + "go.opentelemetry.io/collector/config/confighttp" ) const ( @@ -25,8 +26,8 @@ func (c Flags) AddFlags(flags *flag.FlagSet) { flags.String(c.Prefix+corsAllowedOrigins, "", "Comma-separated CORS allowed origins. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin") } -func (c Flags) InitFromViper(v *viper.Viper) Options { - var p Options +func (c Flags) InitFromViper(v *viper.Viper) *confighttp.CORSConfig { + var p confighttp.CORSConfig allowedHeaders := v.GetString(c.Prefix + corsAllowedHeaders) allowedOrigins := v.GetString(c.Prefix + corsAllowedOrigins) @@ -34,5 +35,5 @@ func (c Flags) InitFromViper(v *viper.Viper) Options { p.AllowedOrigins = strings.Split(strings.ReplaceAll(allowedOrigins, " ", ""), ",") p.AllowedHeaders = strings.Split(strings.ReplaceAll(allowedHeaders, " ", ""), ",") - return p + return &p } diff --git a/pkg/config/corscfg/flags_test.go b/pkg/config/corscfg/flags_test.go index 4ddb292e1fe..2ca108b6c2b 100644 --- a/pkg/config/corscfg/flags_test.go +++ b/pkg/config/corscfg/flags_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/confighttp" "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/testutils" @@ -31,10 +32,10 @@ func TestCORSFlags(t *testing.T) { corsOpts := flagCfg.InitFromViper(v) fmt.Println(corsOpts) - assert.Equal(t, Options{ + assert.Equal(t, confighttp.CORSConfig{ AllowedHeaders: []string{"Content-Type", "Accept", "X-Requested-With"}, AllowedOrigins: []string{"http://example.domain.com", "http://*.domain.com"}, - }, corsOpts) + }, *corsOpts) }) } diff --git a/pkg/config/corscfg/options.go b/pkg/config/corscfg/options.go deleted file mode 100644 index 9dd1f7ffd5a..00000000000 --- a/pkg/config/corscfg/options.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2023 The Jaeger Authors. -// SPDX-License-Identifier: Apache-2.0 - -package corscfg - -type Options struct { - AllowedOrigins []string - AllowedHeaders []string -} diff --git a/pkg/config/tlscfg/options.go b/pkg/config/tlscfg/options.go index 4604313e157..c67dcb2b2ef 100644 --- a/pkg/config/tlscfg/options.go +++ b/pkg/config/tlscfg/options.go @@ -139,6 +139,10 @@ func (o *Options) ToOtelClientConfig() configtls.ClientConfig { MinVersion: o.MinVersion, MaxVersion: o.MaxVersion, ReloadInterval: o.ReloadInterval, + + // when no truststore given, use SystemCertPool + // https://github.com/jaegertracing/jaeger/issues/6334 + IncludeSystemCACertsPool: o.Enabled && (len(o.CAPath) == 0), }, } } diff --git a/pkg/kafka/auth/config_test.go b/pkg/kafka/auth/config_test.go index f5354c67d2f..56d248a7e4a 100644 --- a/pkg/kafka/auth/config_test.go +++ b/pkg/kafka/auth/config_test.go @@ -37,20 +37,18 @@ func Test_InitFromViper(t *testing.T) { "--kafka.auth.kerberos.keytab-file=/path/to/keytab", "--kafka.auth.kerberos.disable-fast-negotiation=true", "--kafka.auth.tls.enabled=false", + "--kafka.auth.tls.ca=/not/allowed/if/tls/is/disabled", "--kafka.auth.plaintext.username=user", "--kafka.auth.plaintext.password=password", "--kafka.auth.plaintext.mechanism=SCRAM-SHA-256", - "--kafka.auth.tls.ca=failing", }) authConfig := &AuthenticationConfig{} err := authConfig.InitFromViper(configPrefix, v) - require.EqualError(t, err, "failed to process Kafka TLS options: kafka.auth.tls.* options cannot be used when kafka.auth.tls.enabled is false") + require.ErrorContains(t, err, "kafka.auth.tls.* options cannot be used when kafka.auth.tls.enabled is false") - command.ParseFlags([]string{"--kafka.auth.tls.ca="}) - v.BindPFlags(command.Flags()) - err = authConfig.InitFromViper(configPrefix, v) - require.NoError(t, err) + command.ParseFlags([]string{"--kafka.auth.tls.ca="}) // incrementally update authConfig + require.NoError(t, authConfig.InitFromViper(configPrefix, v)) expectedConfig := &AuthenticationConfig{ Authentication: "tls", @@ -64,7 +62,11 @@ func Test_InitFromViper(t *testing.T) { KeyTabPath: "/path/to/keytab", DisablePAFXFast: true, }, - TLS: configtls.ClientConfig{}, + TLS: configtls.ClientConfig{ + Config: configtls.Config{ + IncludeSystemCACertsPool: true, + }, + }, PlainText: PlainTextConfig{ Username: "user", Password: "password", diff --git a/pkg/telemetry/settings.go b/pkg/telemetry/settings.go index 1f76b38e107..5b58fd7583d 100644 --- a/pkg/telemetry/settings.go +++ b/pkg/telemetry/settings.go @@ -70,3 +70,11 @@ func FromOtelComponent(telset component.TelemetrySettings, host component.Host) Host: host, } } + +func (s Settings) ToOtelComponent() component.TelemetrySettings { + return component.TelemetrySettings{ + Logger: s.Logger, + MeterProvider: s.MeterProvider, + TracerProvider: s.TracerProvider, + } +} diff --git a/pkg/testutils/leakcheck.go b/pkg/testutils/leakcheck.go index df59dc0cc04..fd03e0f7c21 100644 --- a/pkg/testutils/leakcheck.go +++ b/pkg/testutils/leakcheck.go @@ -23,6 +23,17 @@ func IgnoreOpenCensusWorkerLeak() goleak.Option { return goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start") } +// IgnoreGoMetricsMeterLeak prevents the leak created by go-metrics which is +// used by Sarama (Kafka Client) in Jaeger v1. This reason of this leak is +// not Jaeger but the go-metrics used by Samara. +// See these issues for the context +// - https://github.com/IBM/sarama/issues/1321 +// - https://github.com/IBM/sarama/issues/1340 +// - https://github.com/IBM/sarama/issues/2832 +func IgnoreGoMetricsMeterLeak() goleak.Option { + return goleak.IgnoreTopFunction("github.com/rcrowley/go-metrics.(*meterArbiter).tick") +} + // VerifyGoLeaks verifies that unit tests do not leak any goroutines. // It should be called in TestMain. func VerifyGoLeaks(m *testing.M) { @@ -36,5 +47,5 @@ func VerifyGoLeaks(m *testing.M) { // // defer testutils.VerifyGoLeaksOnce(t) func VerifyGoLeaksOnce(t *testing.T) { - goleak.VerifyNone(t, IgnoreGlogFlushDaemonLeak(), IgnoreOpenCensusWorkerLeak()) + goleak.VerifyNone(t, IgnoreGlogFlushDaemonLeak(), IgnoreOpenCensusWorkerLeak(), IgnoreGoMetricsMeterLeak()) } diff --git a/plugin/storage/integration/cassandra_test.go b/plugin/storage/integration/cassandra_test.go index 39b3bf18c34..41d67c94544 100644 --- a/plugin/storage/integration/cassandra_test.go +++ b/plugin/storage/integration/cassandra_test.go @@ -9,12 +9,14 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest" "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/metrics" + "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/plugin/storage/cassandra" "github.com/jaegertracing/jaeger/storage/dependencystore" ) @@ -47,6 +49,9 @@ func (*CassandraStorageIntegration) initializeCassandraFactory(t *testing.T, fla require.NoError(t, command.ParseFlags(flags)) f.InitFromViper(v, logger) require.NoError(t, f.Initialize(metrics.NullFactory, logger)) + t.Cleanup(func() { + assert.NoError(t, f.Close()) + }) return f } @@ -78,9 +83,6 @@ func (s *CassandraStorageIntegration) initializeCassandra(t *testing.T) { s.SamplingStore, err = f.CreateSamplingStore(0) require.NoError(t, err) s.initializeDependencyReaderAndWriter(t, f) - t.Cleanup(func() { - require.NoError(t, f.Close()) - }) } func (s *CassandraStorageIntegration) initializeDependencyReaderAndWriter(t *testing.T, f *cassandra.Factory) { @@ -99,6 +101,9 @@ func (s *CassandraStorageIntegration) initializeDependencyReaderAndWriter(t *tes func TestCassandraStorage(t *testing.T) { SkipUnlessEnv(t, "cassandra") + t.Cleanup(func() { + testutils.VerifyGoLeaksOnce(t) + }) s := newCassandraStorageIntegration() s.initializeCassandra(t) s.RunAll(t) diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index ef3528baf65..987f49057b1 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/Shopify/sarama" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest" @@ -20,6 +21,7 @@ import ( "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/kafka/consumer" "github.com/jaegertracing/jaeger/pkg/metrics" + "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/plugin/storage/kafka" "github.com/jaegertracing/jaeger/plugin/storage/memory" "github.com/jaegertracing/jaeger/storage/spanstore" @@ -53,10 +55,11 @@ func (s *KafkaIntegrationTestSuite) initialize(t *testing.T) { f.InitFromViper(v, logger) err = f.Initialize(metrics.NullFactory, logger) require.NoError(t, err) - + t.Cleanup(func() { + assert.NoError(t, f.Close()) + }) spanWriter, err := f.CreateSpanWriter() require.NoError(t, err) - v, command = config.Viperize(app.AddFlags) err = command.ParseFlags([]string{ "--kafka.consumer.topic", @@ -82,6 +85,9 @@ func (s *KafkaIntegrationTestSuite) initialize(t *testing.T) { traceStore := memory.NewStore() spanConsumer, err := builder.CreateConsumer(logger, metrics.NullFactory, traceStore, options) require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, spanConsumer.Close()) + }) spanConsumer.Start() s.SpanWriter = spanWriter @@ -120,6 +126,9 @@ func (*ingester) FindTraceIDs(context.Context, *spanstore.TraceQueryParameters) func TestKafkaStorage(t *testing.T) { SkipUnlessEnv(t, "kafka") + t.Cleanup(func() { + testutils.VerifyGoLeaksOnce(t) + }) s := &KafkaIntegrationTestSuite{} s.initialize(t) t.Run("GetTrace", s.testGetTrace) diff --git a/plugin/storage/kafka/options_test.go b/plugin/storage/kafka/options_test.go index cb41caac0a3..c02823fc89c 100644 --- a/plugin/storage/kafka/options_test.go +++ b/plugin/storage/kafka/options_test.go @@ -184,12 +184,31 @@ func TestTLSFlags(t *testing.T) { expected: auth.AuthenticationConfig{Authentication: "kerberos", Kerberos: kerb, TLS: configtls.ClientConfig{}, PlainText: plain}, }, { - flags: []string{"--kafka.producer.authentication=tls"}, - expected: auth.AuthenticationConfig{Authentication: "tls", Kerberos: kerb, TLS: configtls.ClientConfig{}, PlainText: plain}, + flags: []string{"--kafka.producer.authentication=tls"}, + expected: auth.AuthenticationConfig{ + Authentication: "tls", + Kerberos: kerb, + TLS: configtls.ClientConfig{ + Config: configtls.Config{ + IncludeSystemCACertsPool: true, + }, + }, + PlainText: plain, + }, }, { - flags: []string{"--kafka.producer.authentication=tls", "--kafka.producer.tls.enabled=false"}, - expected: auth.AuthenticationConfig{Authentication: "tls", Kerberos: kerb, TLS: configtls.ClientConfig{}, PlainText: plain}, + flags: []string{"--kafka.producer.authentication=tls", "--kafka.producer.tls.enabled=false"}, + expected: auth.AuthenticationConfig{ + Authentication: "tls", + Kerberos: kerb, + // TODO this test is unclear - if tls.enabled=false, why is it not tls.Insecure=true? + TLS: configtls.ClientConfig{ + Config: configtls.Config{ + IncludeSystemCACertsPool: true, + }, + }, + PlainText: plain, + }, }, } diff --git a/storage_v2/depstore/factory.go b/storage_v2/depstore/factory.go new file mode 100644 index 00000000000..b6818a0adfb --- /dev/null +++ b/storage_v2/depstore/factory.go @@ -0,0 +1,8 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package depstore + +type Factory interface { + CreateDependencyReader() (Reader, error) +} diff --git a/storage_v2/depstore/mocks/Factory.go b/storage_v2/depstore/mocks/Factory.go new file mode 100644 index 00000000000..7fed1659c69 --- /dev/null +++ b/storage_v2/depstore/mocks/Factory.go @@ -0,0 +1,62 @@ +// Copyright (c) The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 +// +// Run 'make generate-mocks' to regenerate. + +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + depstore "github.com/jaegertracing/jaeger/storage_v2/depstore" + mock "github.com/stretchr/testify/mock" +) + +// Factory is an autogenerated mock type for the Factory type +type Factory struct { + mock.Mock +} + +// CreateDependencyReader provides a mock function with no fields +func (_m *Factory) CreateDependencyReader() (depstore.Reader, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for CreateDependencyReader") + } + + var r0 depstore.Reader + var r1 error + if rf, ok := ret.Get(0).(func() (depstore.Reader, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() depstore.Reader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(depstore.Reader) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewFactory creates a new instance of Factory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFactory(t interface { + mock.TestingT + Cleanup(func()) +}) *Factory { + mock := &Factory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/storage_v2/depstore/mocks/Reader.go b/storage_v2/depstore/mocks/Reader.go new file mode 100644 index 00000000000..b997a3d3036 --- /dev/null +++ b/storage_v2/depstore/mocks/Reader.go @@ -0,0 +1,66 @@ +// Copyright (c) The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 +// +// Run 'make generate-mocks' to regenerate. + +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + + depstore "github.com/jaegertracing/jaeger/storage_v2/depstore" + mock "github.com/stretchr/testify/mock" + + model "github.com/jaegertracing/jaeger/model" +) + +// Reader is an autogenerated mock type for the Reader type +type Reader struct { + mock.Mock +} + +// GetDependencies provides a mock function with given fields: ctx, query +func (_m *Reader) GetDependencies(ctx context.Context, query depstore.QueryParameters) ([]model.DependencyLink, error) { + ret := _m.Called(ctx, query) + + if len(ret) == 0 { + panic("no return value specified for GetDependencies") + } + + var r0 []model.DependencyLink + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, depstore.QueryParameters) ([]model.DependencyLink, error)); ok { + return rf(ctx, query) + } + if rf, ok := ret.Get(0).(func(context.Context, depstore.QueryParameters) []model.DependencyLink); ok { + r0 = rf(ctx, query) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]model.DependencyLink) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, depstore.QueryParameters) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewReader creates a new instance of Reader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewReader(t interface { + mock.TestingT + Cleanup(func()) +}) *Reader { + mock := &Reader{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/storage_v2/depstore/package_test.go b/storage_v2/depstore/package_test.go new file mode 100644 index 00000000000..bb0d70c2b01 --- /dev/null +++ b/storage_v2/depstore/package_test.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package depstore + +import ( + "testing" + + "github.com/jaegertracing/jaeger/pkg/testutils" +) + +func TestMain(m *testing.M) { + testutils.VerifyGoLeaks(m) +} diff --git a/storage_v2/depstore/reader.go b/storage_v2/depstore/reader.go new file mode 100644 index 00000000000..436dfb62187 --- /dev/null +++ b/storage_v2/depstore/reader.go @@ -0,0 +1,22 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package depstore + +import ( + "context" + "time" + + "github.com/jaegertracing/jaeger/model" +) + +// QueryParameters contains the parameters that can be used to query dependencies. +type QueryParameters struct { + StartTime time.Time + EndTime time.Time +} + +// Reader can load service dependencies from storage. +type Reader interface { + GetDependencies(ctx context.Context, query QueryParameters) ([]model.DependencyLink, error) +} diff --git a/storage_v2/factory.go b/storage_v2/factory.go deleted file mode 100644 index e7515549e05..00000000000 --- a/storage_v2/factory.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2024 The Jaeger Authors. -// SPDX-License-Identifier: Apache-2.0 - -package storage_v2 - -import ( - "context" -) - -// Factory is a general factory interface to be reused across different storage factories. -// It lives within the OTEL collector extension component's lifecycle. -// The Initialize and Close functions supposed to be called from the -// OTEL component's Start and Shutdown functions. -type FactoryBase interface { - // Initialize performs internal initialization of the factory, - // such as opening connections to the backend store. - Initialize(ctx context.Context) error - - // Close closes the resources held by the factory - Close(ctx context.Context) error -} diff --git a/storage_v2/factoryadapter/factory.go b/storage_v2/factoryadapter/factory.go index 56356a70262..1eaaea146ed 100644 --- a/storage_v2/factoryadapter/factory.go +++ b/storage_v2/factoryadapter/factory.go @@ -8,6 +8,7 @@ import ( "io" storage_v1 "github.com/jaegertracing/jaeger/storage" + "github.com/jaegertracing/jaeger/storage_v2/depstore" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) @@ -15,7 +16,7 @@ type Factory struct { ss storage_v1.Factory } -func NewFactory(ss storage_v1.Factory) tracestore.Factory { +func NewFactory(ss storage_v1.Factory) *Factory { return &Factory{ ss: ss, } @@ -51,3 +52,12 @@ func (f *Factory) CreateTraceWriter() (tracestore.Writer, error) { } return NewTraceWriter(spanWriter), nil } + +// CreateDependencyReader implements depstore.Factory. +func (f *Factory) CreateDependencyReader() (depstore.Reader, error) { + dr, err := f.ss.CreateDependencyReader() + if err != nil { + return nil, err + } + return NewDependencyReader(dr), nil +} diff --git a/storage_v2/factoryadapter/factory_test.go b/storage_v2/factoryadapter/factory_test.go index a8e2819ce0f..d8794adf327 100644 --- a/storage_v2/factoryadapter/factory_test.go +++ b/storage_v2/factoryadapter/factory_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/jaegertracing/jaeger/plugin/storage/grpc" + dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" factoryMocks "github.com/jaegertracing/jaeger/storage/mocks" spanstoreMocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" ) @@ -71,3 +72,24 @@ func TestAdapterCreateTraceWriter(t *testing.T) { _, err := f.CreateTraceWriter() require.NoError(t, err) } + +func TestAdapterCreateDependencyReader(t *testing.T) { + f1 := new(factoryMocks.Factory) + f1.On("CreateDependencyReader").Return(new(dependencyStoreMocks.Reader), nil) + + f := NewFactory(f1) + r, err := f.CreateDependencyReader() + require.NoError(t, err) + require.NotNil(t, r) +} + +func TestAdapterCreateDependencyReaderError(t *testing.T) { + f1 := new(factoryMocks.Factory) + testErr := errors.New("test error") + f1.On("CreateDependencyReader").Return(nil, testErr) + + f := NewFactory(f1) + r, err := f.CreateDependencyReader() + require.ErrorIs(t, err, testErr) + require.Nil(t, r) +} diff --git a/storage_v2/factoryadapter/reader.go b/storage_v2/factoryadapter/reader.go index 2bc5e0b5936..85ebddab7e9 100644 --- a/storage_v2/factoryadapter/reader.go +++ b/storage_v2/factoryadapter/reader.go @@ -7,10 +7,14 @@ import ( "context" "errors" + model2otel "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "github.com/jaegertracing/jaeger/model" + "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" + "github.com/jaegertracing/jaeger/storage_v2/depstore" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) @@ -33,22 +37,79 @@ func NewTraceReader(spanReader spanstore.Reader) *TraceReader { } } -func (*TraceReader) GetTrace(_ context.Context, _ pcommon.TraceID) (ptrace.Traces, error) { - panic("not implemented") +func (tr *TraceReader) GetTrace(ctx context.Context, traceID pcommon.TraceID) (ptrace.Traces, error) { + t, err := tr.spanReader.GetTrace(ctx, model.TraceIDFromOTEL(traceID)) + if err != nil { + return ptrace.NewTraces(), err + } + batch := &model.Batch{Spans: t.GetSpans()} + return model2otel.ProtoToTraces([]*model.Batch{batch}) +} + +func (tr *TraceReader) GetServices(ctx context.Context) ([]string, error) { + return tr.spanReader.GetServices(ctx) +} + +func (tr *TraceReader) GetOperations(ctx context.Context, query tracestore.OperationQueryParameters) ([]tracestore.Operation, error) { + o, err := tr.spanReader.GetOperations(ctx, spanstore.OperationQueryParameters{ + ServiceName: query.ServiceName, + SpanKind: query.SpanKind, + }) + if err != nil || o == nil { + return nil, err + } + operations := []tracestore.Operation{} + for _, operation := range o { + operations = append(operations, tracestore.Operation{ + Name: operation.Name, + SpanKind: operation.SpanKind, + }) + } + return operations, nil } -func (*TraceReader) GetServices(_ context.Context) ([]string, error) { - panic("not implemented") +func (tr *TraceReader) FindTraces( + ctx context.Context, + query tracestore.TraceQueryParameters, +) ([]ptrace.Traces, error) { + t, err := tr.spanReader.FindTraces(ctx, query.ToSpanStoreQueryParameters()) + if err != nil || t == nil { + return nil, err + } + otelTraces := []ptrace.Traces{} + for _, trace := range t { + batch := &model.Batch{Spans: trace.GetSpans()} + otelTrace, _ := model2otel.ProtoToTraces([]*model.Batch{batch}) + otelTraces = append(otelTraces, otelTrace) + } + return otelTraces, nil } -func (*TraceReader) GetOperations(_ context.Context, _ tracestore.OperationQueryParameters) ([]tracestore.Operation, error) { - panic("not implemented") +func (tr *TraceReader) FindTraceIDs(ctx context.Context, query tracestore.TraceQueryParameters) ([]pcommon.TraceID, error) { + t, err := tr.spanReader.FindTraceIDs(ctx, query.ToSpanStoreQueryParameters()) + if err != nil || t == nil { + return nil, err + } + traceIDs := []pcommon.TraceID{} + for _, traceID := range t { + traceIDs = append(traceIDs, traceID.ToOTELTraceID()) + } + return traceIDs, nil } -func (*TraceReader) FindTraces(_ context.Context, _ tracestore.TraceQueryParameters) ([]ptrace.Traces, error) { - panic("not implemented") +type DependencyReader struct { + reader dependencystore.Reader +} + +func NewDependencyReader(reader dependencystore.Reader) *DependencyReader { + return &DependencyReader{ + reader: reader, + } } -func (*TraceReader) FindTraceIDs(_ context.Context, _ tracestore.TraceQueryParameters) ([]pcommon.TraceID, error) { - panic("not implemented") +func (dr *DependencyReader) GetDependencies( + ctx context.Context, + query depstore.QueryParameters, +) ([]model.DependencyLink, error) { + return dr.reader.GetDependencies(ctx, query.EndTime, query.EndTime.Sub(query.StartTime)) } diff --git a/storage_v2/factoryadapter/reader_test.go b/storage_v2/factoryadapter/reader_test.go index 85c245f7a70..0559f7e5d94 100644 --- a/storage_v2/factoryadapter/reader_test.go +++ b/storage_v2/factoryadapter/reader_test.go @@ -5,13 +5,21 @@ package factoryadapter import ( "context" + "errors" "testing" + "time" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/plugin/storage/memory" + dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" + "github.com/jaegertracing/jaeger/storage/spanstore" + spanStoreMocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" + "github.com/jaegertracing/jaeger/storage_v2/depstore" "github.com/jaegertracing/jaeger/storage_v2/tracestore" ) @@ -53,51 +61,344 @@ func TestGetV1Reader_Error(t *testing.T) { require.ErrorIs(t, err, errV1ReaderNotAvailable) } -func TestTraceReader_GetTracePanics(t *testing.T) { - memstore := memory.NewStore() +func TestTraceReader_GetTraceDelegatesSuccessResponse(t *testing.T) { + sr := new(spanStoreMocks.Reader) + modelTrace := &model.Trace{ + Spans: []*model.Span{ + { + TraceID: model.NewTraceID(2, 3), + SpanID: model.SpanID(1), + OperationName: "operation-a", + }, + { + TraceID: model.NewTraceID(2, 3), + SpanID: model.SpanID(2), + OperationName: "operation-b", + }, + }, + } + sr.On("GetTrace", mock.Anything, model.NewTraceID(2, 3)).Return(modelTrace, nil) traceReader := &TraceReader{ - spanReader: memstore, + spanReader: sr, } - require.Panics(t, func() { traceReader.GetTrace(context.Background(), pcommon.NewTraceIDEmpty()) }) + trace, err := traceReader.GetTrace( + context.Background(), + pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}), + ) + require.NoError(t, err) + traceSpans := trace.ResourceSpans().At(0).ScopeSpans().At(0).Spans() + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}, traceSpans.At(0).TraceID()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 1}, traceSpans.At(0).SpanID()) + require.Equal(t, "operation-a", traceSpans.At(0).Name()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}, traceSpans.At(1).TraceID()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 2}, traceSpans.At(1).SpanID()) + require.Equal(t, "operation-b", traceSpans.At(1).Name()) } -func TestTraceReader_GetServicesPanics(t *testing.T) { - memstore := memory.NewStore() +func TestTraceReader_GetTraceErrorResponse(t *testing.T) { + sr := new(spanStoreMocks.Reader) + testErr := errors.New("test error") + sr.On("GetTrace", mock.Anything, mock.Anything).Return(nil, testErr) traceReader := &TraceReader{ - spanReader: memstore, + spanReader: sr, } - require.Panics(t, func() { traceReader.GetServices(context.Background()) }) + trace, err := traceReader.GetTrace( + context.Background(), + pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}), + ) + require.ErrorIs(t, err, testErr) + require.Equal(t, ptrace.NewTraces(), trace) } -func TestTraceReader_GetOperationsPanics(t *testing.T) { - memstore := memory.NewStore() +func TestTraceReader_GetServicesDelegatesToSpanReader(t *testing.T) { + sr := new(spanStoreMocks.Reader) + expectedServices := []string{"service-a", "service-b"} + sr.On("GetServices", mock.Anything).Return(expectedServices, nil) traceReader := &TraceReader{ - spanReader: memstore, + spanReader: sr, } - require.Panics( - t, - func() { traceReader.GetOperations(context.Background(), tracestore.OperationQueryParameters{}) }, - ) + services, err := traceReader.GetServices(context.Background()) + require.NoError(t, err) + require.Equal(t, expectedServices, services) } -func TestTraceReader_FindTracesPanics(t *testing.T) { - memstore := memory.NewStore() - traceReader := &TraceReader{ - spanReader: memstore, +func TestTraceReader_GetOperationsDelegatesResponse(t *testing.T) { + tests := []struct { + name string + operations []spanstore.Operation + expectedOperations []tracestore.Operation + err error + }{ + { + name: "successful response", + operations: []spanstore.Operation{ + { + Name: "operation-a", + SpanKind: "server", + }, + { + Name: "operation-b", + SpanKind: "server", + }, + }, + expectedOperations: []tracestore.Operation{ + { + Name: "operation-a", + SpanKind: "server", + }, + { + Name: "operation-b", + SpanKind: "server", + }, + }, + }, + { + name: "nil response", + operations: nil, + expectedOperations: nil, + }, + { + name: "empty response", + operations: []spanstore.Operation{}, + expectedOperations: []tracestore.Operation{}, + }, + { + name: "error response", + operations: nil, + expectedOperations: nil, + err: errors.New("test error"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + sr := new(spanStoreMocks.Reader) + sr.On("GetOperations", + mock.Anything, + spanstore.OperationQueryParameters{ + ServiceName: "service-a", + SpanKind: "server", + }).Return(test.operations, test.err) + traceReader := &TraceReader{ + spanReader: sr, + } + operations, err := traceReader.GetOperations( + context.Background(), + tracestore.OperationQueryParameters{ + ServiceName: "service-a", + SpanKind: "server", + }) + require.ErrorIs(t, err, test.err) + require.Equal(t, test.expectedOperations, operations) + }) } - require.Panics( - t, - func() { traceReader.FindTraces(context.Background(), tracestore.TraceQueryParameters{}) }, - ) } -func TestTraceReader_FindTraceIDsPanics(t *testing.T) { - memstore := memory.NewStore() +func TestTraceReader_FindTracesDelegatesSuccessResponse(t *testing.T) { + modelTraces := []*model.Trace{ + { + Spans: []*model.Span{ + { + TraceID: model.NewTraceID(2, 3), + SpanID: model.SpanID(1), + OperationName: "operation-a", + }, + { + TraceID: model.NewTraceID(4, 5), + SpanID: model.SpanID(2), + OperationName: "operation-b", + }, + }, + }, + { + Spans: []*model.Span{ + { + TraceID: model.NewTraceID(6, 7), + SpanID: model.SpanID(3), + OperationName: "operation-c", + }, + }, + }, + } + sr := new(spanStoreMocks.Reader) + now := time.Now() + sr.On( + "FindTraces", + mock.Anything, + &spanstore.TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + }, + ).Return(modelTraces, nil) traceReader := &TraceReader{ - spanReader: memstore, + spanReader: sr, } - require.Panics( - t, - func() { traceReader.FindTraceIDs(context.Background(), tracestore.TraceQueryParameters{}) }, + traces, err := traceReader.FindTraces( + context.Background(), + tracestore.TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + }, ) + require.NoError(t, err) + require.Len(t, traces, len(modelTraces)) + traceASpans := traces[0].ResourceSpans().At(0).ScopeSpans().At(0).Spans() + traceBSpans := traces[1].ResourceSpans().At(0).ScopeSpans().At(0).Spans() + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}, traceASpans.At(0).TraceID()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 1}, traceASpans.At(0).SpanID()) + require.Equal(t, "operation-a", traceASpans.At(0).Name()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5}, traceASpans.At(1).TraceID()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 2}, traceASpans.At(1).SpanID()) + require.Equal(t, "operation-b", traceASpans.At(1).Name()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7}, traceBSpans.At(0).TraceID()) + require.EqualValues(t, []byte{0, 0, 0, 0, 0, 0, 0, 3}, traceBSpans.At(0).SpanID()) + require.Equal(t, "operation-c", traceBSpans.At(0).Name()) +} + +func TestTraceReader_FindTracesEdgeCases(t *testing.T) { + tests := []struct { + name string + modelTraces []*model.Trace + expectedTraces []ptrace.Traces + err error + }{ + { + name: "nil response", + modelTraces: nil, + expectedTraces: nil, + }, + { + name: "empty response", + modelTraces: []*model.Trace{}, + expectedTraces: []ptrace.Traces{}, + }, + { + name: "error response", + modelTraces: nil, + expectedTraces: nil, + err: errors.New("test error"), + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + sr := new(spanStoreMocks.Reader) + sr.On( + "FindTraces", + mock.Anything, + mock.Anything, + ).Return(test.modelTraces, test.err) + traceReader := &TraceReader{ + spanReader: sr, + } + traces, err := traceReader.FindTraces( + context.Background(), + tracestore.TraceQueryParameters{}, + ) + require.ErrorIs(t, err, test.err) + require.Equal(t, test.expectedTraces, traces) + }) + } +} + +func TestTraceReader_FindTraceIDsDelegatesResponse(t *testing.T) { + tests := []struct { + name string + modelTraceIDs []model.TraceID + expectedTraceIDs []pcommon.TraceID + err error + }{ + { + name: "successful response", + modelTraceIDs: []model.TraceID{ + {Low: 3, High: 2}, + {Low: 4, High: 3}, + }, + expectedTraceIDs: []pcommon.TraceID{ + pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}), + pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4}), + }, + }, + { + name: "empty response", + modelTraceIDs: []model.TraceID{}, + expectedTraceIDs: []pcommon.TraceID{}, + }, + { + name: "nil response", + modelTraceIDs: nil, + expectedTraceIDs: nil, + }, + { + name: "error response", + modelTraceIDs: nil, + expectedTraceIDs: nil, + err: errors.New("test error"), + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + sr := new(spanStoreMocks.Reader) + now := time.Now() + sr.On( + "FindTraceIDs", + mock.Anything, + &spanstore.TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + }, + ).Return(test.modelTraceIDs, test.err) + traceReader := &TraceReader{ + spanReader: sr, + } + traceIDs, err := traceReader.FindTraceIDs( + context.Background(), + tracestore.TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + }, + ) + require.ErrorIs(t, err, test.err) + require.Equal(t, test.expectedTraceIDs, traceIDs) + }) + } +} + +func TestDependencyReader_GetDependencies(t *testing.T) { + end := time.Now() + start := end.Add(-1 * time.Minute) + query := depstore.QueryParameters{ + StartTime: start, + EndTime: end, + } + expectedDeps := []model.DependencyLink{{Parent: "parent", Child: "child", CallCount: 12}} + mr := new(dependencyStoreMocks.Reader) + mr.On("GetDependencies", mock.Anything, end, time.Minute).Return(expectedDeps, nil) + dr := NewDependencyReader(mr) + deps, err := dr.GetDependencies(context.Background(), query) + require.NoError(t, err) + require.Equal(t, expectedDeps, deps) } diff --git a/storage_v2/tracestore/factory.go b/storage_v2/tracestore/factory.go index 0f670946562..bf081f0fb45 100644 --- a/storage_v2/tracestore/factory.go +++ b/storage_v2/tracestore/factory.go @@ -3,15 +3,9 @@ package tracestore -import ( - "github.com/jaegertracing/jaeger/storage_v2" -) - // Factory defines an interface for a factory that can create implementations of // different span storage components. type Factory interface { - storage_v2.FactoryBase - // CreateTraceReader creates a spanstore.Reader. CreateTraceReader() (Reader, error) diff --git a/storage_v2/tracestore/mocks/Factory.go b/storage_v2/tracestore/mocks/Factory.go index 922d57ae2c4..095cac10d0f 100644 --- a/storage_v2/tracestore/mocks/Factory.go +++ b/storage_v2/tracestore/mocks/Factory.go @@ -8,8 +8,6 @@ package mocks import ( - context "context" - tracestore "github.com/jaegertracing/jaeger/storage_v2/tracestore" mock "github.com/stretchr/testify/mock" ) @@ -19,24 +17,6 @@ type Factory struct { mock.Mock } -// Close provides a mock function with given fields: ctx -func (_m *Factory) Close(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // CreateTraceReader provides a mock function with no fields func (_m *Factory) CreateTraceReader() (tracestore.Reader, error) { ret := _m.Called() @@ -97,24 +77,6 @@ func (_m *Factory) CreateTraceWriter() (tracestore.Writer, error) { return r0, r1 } -// Initialize provides a mock function with given fields: ctx -func (_m *Factory) Initialize(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Initialize") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // NewFactory creates a new instance of Factory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFactory(t interface { diff --git a/storage_v2/tracestore/reader.go b/storage_v2/tracestore/reader.go index 9a60a7bc77b..487758700c8 100644 --- a/storage_v2/tracestore/reader.go +++ b/storage_v2/tracestore/reader.go @@ -58,6 +58,19 @@ type TraceQueryParameters struct { NumTraces int } +func (t *TraceQueryParameters) ToSpanStoreQueryParameters() *spanstore.TraceQueryParameters { + return &spanstore.TraceQueryParameters{ + ServiceName: t.ServiceName, + OperationName: t.OperationName, + Tags: t.Tags, + StartTimeMin: t.StartTimeMin, + StartTimeMax: t.StartTimeMax, + DurationMin: t.DurationMin, + DurationMax: t.DurationMax, + NumTraces: t.NumTraces, + } +} + // OperationQueryParameters contains parameters of query operations, empty spanKind means get operations for all kinds of span. type OperationQueryParameters struct { ServiceName string diff --git a/storage_v2/tracestore/reader_test.go b/storage_v2/tracestore/reader_test.go new file mode 100644 index 00000000000..16f558c9877 --- /dev/null +++ b/storage_v2/tracestore/reader_test.go @@ -0,0 +1,38 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package tracestore + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +func TestToSpanStoreQueryParameters(t *testing.T) { + now := time.Now() + query := &TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + } + expected := &spanstore.TraceQueryParameters{ + ServiceName: "service", + OperationName: "operation", + Tags: map[string]string{"tag-a": "val-a"}, + StartTimeMin: now, + StartTimeMax: now.Add(time.Minute), + DurationMin: time.Minute, + DurationMax: time.Hour, + NumTraces: 10, + } + require.Equal(t, expected, query.ToSpanStoreQueryParameters()) +}