diff --git a/.github/workflows/ci-e2e-spm.yml b/.github/workflows/ci-e2e-spm.yml index 8f58de52f91..eb987af1ba7 100644 --- a/.github/workflows/ci-e2e-spm.yml +++ b/.github/workflows/ci-e2e-spm.yml @@ -18,6 +18,14 @@ permissions: jobs: spm: runs-on: ubuntu-latest + strategy: + matrix: + mode: + - name: v1 + binary: all-in-one + - name: v2 + binary: jaeger + steps: - name: Harden Runner uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 @@ -38,11 +46,6 @@ jobs: - name: Setup Node.js version uses: ./.github/actions/setup-node.js - - - name: Temporary - only run the build - run: - cd docker-compose/monitor && make build - + - name: Run SPM Test - run: ./scripts/spm-integration-test.sh - + run: bash scripts/spm-integration-test.sh -b ${{ matrix.mode.binary }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e42ec99dae..73127e0511c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,11 @@ run `make changelog` to generate content #### ⛔ Breaking Changes +* The OTEL Collector upgrade brought in a change where OTLP receivers started listening on `localhost` instead of `0.0.0.0` as before. As a result, when running in container environment the endpoints are likely unreachable from other containers (Issue [#5737](https://github.com/jaegertracing/jaeger/issues/5737)). The fix will be available in the next release. Meanwhile, the workaround is to instruct Jaeger to listen on `0.0.0.0`, as in [this fix](https://github.com/jaegertracing/jaeger/pull/5734/files#diff-299f817cc4ab077ddb763f1e6a023d9d042d714e2fd3736cc40af3f218d44f1eR15): +``` + - COLLECTOR_OTLP_GRPC_HOST_PORT=0.0.0.0:4317 + - COLLECTOR_OTLP_HTTP_HOST_PORT=0.0.0.0:4318 +``` * Update opentelemetry-go to v1.28.0 and refactor references to semantic conventions ([@renovate-bot](https://github.com/renovate-bot) in [#5698](https://github.com/jaegertracing/jaeger/pull/5698)) #### ✨ New Features diff --git a/README.md b/README.md index a306942b4dc..80a33394621 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ [![Slack chat][slack-img]](#get-in-touch) -[![Project+Community stats][community-badge]][community-stats] [![Unit Tests][ci-img]][ci] [![Coverage Status][cov-img]][cov] +[![Project+Community stats][community-badge]][community-stats] [![FOSSA Status][fossa-img]][fossa] [![OpenSSF Scorecard][openssf-img]][openssf] [![OpenSSF Best Practices][openssf-bp-img]][openssf-bp] @@ -16,6 +16,8 @@ # 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). + ```mermaid graph TD SDK["OpenTelemetry SDK"] --> |HTTP or gRPC| COLLECTOR diff --git a/cmd/all-in-one/all_in_one_test.go b/cmd/all-in-one/all_in_one_test.go index 95b7ea9bac8..afb80ec6f53 100644 --- a/cmd/all-in-one/all_in_one_test.go +++ b/cmd/all-in-one/all_in_one_test.go @@ -89,6 +89,7 @@ func healthCheck(t *testing.T) { } func httpGet(t *testing.T, url string) (*http.Response, []byte) { + t.Logf("Executing HTTP GET %s", url) req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) req.Close = true // avoid persistent connections which leak goroutines diff --git a/cmd/jaeger/README.md b/cmd/jaeger/README.md index 81cf5961a24..5677dc240db 100644 --- a/cmd/jaeger/README.md +++ b/cmd/jaeger/README.md @@ -3,8 +3,50 @@ This is experimental Jaeger V2 based on OpenTelemetry collector. See https://github.com/jaegertracing/jaeger/issues/4843. +Read the [blog post](https://medium.com/jaegertracing/towards-jaeger-v2-moar-opentelemetry-2f8239bee48e). + +Tracking issue: https://github.com/jaegertracing/jaeger/issues/4843. + +```mermaid +flowchart LR + Receiver1 --> Processor + Receiver2 --> Processor + Receiver3 --> Processor + Processor --> Exporter + + Exporter --> Database + Database --> Query[Query + UI] + + subgraph Pipeline + Receiver1[OTLP Receiver] + Receiver2[Jaeger Proto Receiver] + Receiver3[Zipkin Receiver] + Processor[Batch + Processor] + Exporter[Jaeger + Storage + Exporter] + end + + subgraph JaegerStorageExension[Jaeger Storage Ext] + Database[(Storage)] + end + subgraph JaegerQueryExtension[Jaeger Query Ext] + Query + end +``` + +## Try it out + +* Download `docker-compose-v2.yml` from https://github.com/jaegertracing/jaeger/blob/main/examples/hotrod/docker-compose-v2.yml +* Optional: find the latest Jaeger version (see https://www.jaegertracing.io/download/) and pass it via environment variable `JAEGER_VERSION`. Otherwise `docker compose` will use the `latest` tag, which is fine for the first time you download the images, but once they are in your local registry the `latest` tag is never updated and you may be running stale (and possibly incompatible) verions of Jaeger and the HotROD app. +* Run Jaeger backend and HotROD demo, e.g.: + * `JAEGER_VERSION=1.59 docker compose -f path-to-yml-file-v2 up` +* Access Jaeger UI at http://localhost:16686 and HotROD app at http://localhost:8080 +* Shutdown / cleanup with `docker compose -f path-to-yml-file down` + ## Compatibility ### Service Name Sanitizer -In v1, there was a `serviceNameSanitizer` that sanitized the service names in span annotations using a source of truth alias to service cache. This functionality has been removed in v2. If your implementation relies on this sanitizer, you will need to find a different way to integrate this functionality, such as implementing a custom processor. \ No newline at end of file +In v1, there was a `serviceNameSanitizer` that sanitized the service names in span annotations using a source of truth alias to service cache. This functionality has been removed in v2. If your implementation relies on this sanitizer, you will need to find a different way to integrate this functionality, such as implementing a custom processor. diff --git a/cmd/jaeger/collector-with-kafka.yaml b/cmd/jaeger/collector-with-kafka.yaml new file mode 100644 index 00000000000..fb16234bc8c --- /dev/null +++ b/cmd/jaeger/collector-with-kafka.yaml @@ -0,0 +1,28 @@ +service: + pipelines: + traces: + receivers: [otlp, jaeger] + processors: [batch] + exporters: [kafka] + +receivers: + otlp: + protocols: + grpc: + http: + jaeger: + protocols: + grpc: + thrift_binary: + thrift_compact: + thrift_http: + +processors: + batch: + +exporters: + kafka: + brokers: + - localhost:9092 + topic: "jaeger-spans" + encoding: otlp_proto diff --git a/cmd/jaeger/ingester-remote-storage.yaml b/cmd/jaeger/ingester-remote-storage.yaml new file mode 100644 index 00000000000..2f200c6533a --- /dev/null +++ b/cmd/jaeger/ingester-remote-storage.yaml @@ -0,0 +1,37 @@ +service: + extensions: [jaeger_storage, jaeger_query] + pipelines: + traces: + receivers: [kafka] + processors: [batch] + exporters: [jaeger_storage_exporter] + telemetry: + metrics: + address: 0.0.0.0:8889 + logs: + level: debug + +extensions: + jaeger_query: + trace_storage: some_storage + + jaeger_storage: + backends: + some_storage: + memory: + max_traces: 100000 + +receivers: + kafka: + brokers: + - localhost:9092 + topic: "jaeger-spans" + encoding: otlp_proto + initial_offset: earliest + +processors: + batch: + +exporters: + jaeger_storage_exporter: + trace_storage: some_storage diff --git a/cmd/jaeger/internal/all-in-one.yaml b/cmd/jaeger/internal/all-in-one.yaml index 2e99217191f..a81add4475b 100644 --- a/cmd/jaeger/internal/all-in-one.yaml +++ b/cmd/jaeger/internal/all-in-one.yaml @@ -5,6 +5,13 @@ service: receivers: [otlp, jaeger, zipkin] processors: [batch] exporters: [jaeger_storage_exporter] + telemetry: + resource: + service.name: jaeger + metrics: + level: detailed + # TODO Initialize telemetery tracer once OTEL released new feature. + # https://github.com/open-telemetry/opentelemetry-collector/issues/10663 extensions: jaeger_query: diff --git a/cmd/jaeger/internal/components.go b/cmd/jaeger/internal/components.go index f7161ffef22..7a615785b4d 100644 --- a/cmd/jaeger/internal/components.go +++ b/cmd/jaeger/internal/components.go @@ -6,6 +6,7 @@ package internal import ( "github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kafkareceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver" @@ -90,6 +91,7 @@ func (b builders) build() (otelcol.Factories, error) { // add-ons storageexporter.NewFactory(), // generic exporter to Jaeger v1 spanstore.SpanWriter kafkaexporter.NewFactory(), + prometheusexporter.NewFactory(), // elasticsearch.NewFactory(), ) if err != nil { diff --git a/cmd/jaeger/internal/exporters/storageexporter/exporter_test.go b/cmd/jaeger/internal/exporters/storageexporter/exporter_test.go index cfe7a2b1e50..54dedab391e 100644 --- a/cmd/jaeger/internal/exporters/storageexporter/exporter_test.go +++ b/cmd/jaeger/internal/exporters/storageexporter/exporter_test.go @@ -39,10 +39,13 @@ import ( ) type mockStorageExt struct { - name string - factory *factoryMocks.Factory + name string + factory *factoryMocks.Factory + metricsFactory *factoryMocks.MetricsFactory } +var _ jaegerstorage.Extension = (*mockStorageExt)(nil) + func (*mockStorageExt) Start(context.Context, component.Host) error { panic("not implemented") } @@ -51,13 +54,20 @@ func (*mockStorageExt) Shutdown(context.Context) error { panic("not implemented") } -func (m *mockStorageExt) Factory(name string) (storage.Factory, bool) { +func (m *mockStorageExt) TraceStorageFactory(name string) (storage.Factory, bool) { if m.name == name { return m.factory, true } return nil, false } +func (m *mockStorageExt) MetricStorageFactory(name string) (storage.MetricsFactory, bool) { + if m.name == name { + return m.metricsFactory, true + } + return nil, false +} + func TestExporterConfigError(t *testing.T) { config := createDefaultConfig().(*Config) err := config.Validate() diff --git a/cmd/jaeger/internal/extension/jaegerquery/config.go b/cmd/jaeger/internal/extension/jaegerquery/config.go index ec5de1bb69c..9abaf0c1a64 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/config.go +++ b/cmd/jaeger/internal/extension/jaegerquery/config.go @@ -18,14 +18,12 @@ var _ component.ConfigValidator = (*Config)(nil) // Config represents the configuration for jaeger-query, type Config struct { queryApp.QueryOptionsBase `mapstructure:",squash"` - - TraceStoragePrimary string `valid:"required" mapstructure:"trace_storage"` - TraceStorageArchive string `valid:"optional" mapstructure:"trace_storage_archive"` - - HTTP confighttp.ServerConfig `mapstructure:",squash"` - GRPC configgrpc.ServerConfig `mapstructure:",squash"` - - Tenancy tenancy.Options `mapstructure:"multi_tenancy"` + TraceStoragePrimary string `valid:"required" mapstructure:"trace_storage"` + TraceStorageArchive string `valid:"optional" mapstructure:"trace_storage_archive"` + MetricStorage string `valid:"optional" mapstructure:"metric_storage"` + HTTP confighttp.ServerConfig `mapstructure:",squash"` + GRPC configgrpc.ServerConfig `mapstructure:",squash"` + Tenancy tenancy.Options `mapstructure:"multi_tenancy"` } func (cfg *Config) Validate() error { diff --git a/cmd/jaeger/internal/extension/jaegerquery/server.go b/cmd/jaeger/internal/extension/jaegerquery/server.go index d4dfa53715d..7fa249a976c 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/server.go +++ b/cmd/jaeger/internal/extension/jaegerquery/server.go @@ -14,10 +14,14 @@ import ( "github.com/jaegertracing/jaeger/cmd/jaeger/internal/extension/jaegerstorage" queryApp "github.com/jaegertracing/jaeger/cmd/query/app" "github.com/jaegertracing/jaeger/cmd/query/app/querysvc" + "github.com/jaegertracing/jaeger/internal/metrics/otelmetrics" "github.com/jaegertracing/jaeger/pkg/jtracer" + "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/pkg/telemetery" "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/plugin/metrics/disabled" + "github.com/jaegertracing/jaeger/storage/metricsstore" + storageMetrics "github.com/jaegertracing/jaeger/storage/spanstore/metrics" ) var ( @@ -45,6 +49,8 @@ func (*server) Dependencies() []component.ID { } func (s *server) Start(_ context.Context, host component.Host) error { + mf := otelmetrics.NewFactory(s.telset.MeterProvider) + queryMetricsFactory := mf.Namespace(metrics.NSOptions{Name: "query"}) f, err := jaegerstorage.GetStorageFactory(s.config.TraceStoragePrimary, host) if err != nil { return fmt.Errorf("cannot find primary storage %s: %w", s.config.TraceStoragePrimary, err) @@ -54,8 +60,8 @@ func (s *server) Start(_ context.Context, host component.Host) error { if err != nil { return fmt.Errorf("cannot create span reader: %w", err) } - // TODO - // spanReader = storageMetrics.NewReadMetricsDecorator(spanReader, baseFactory.Namespace(metrics.NSOptions{Name: "query"})) + + spanReader = storageMetrics.NewReadMetricsDecorator(spanReader, queryMetricsFactory) depReader, err := f.CreateDependencyReader() if err != nil { @@ -67,7 +73,12 @@ func (s *server) Start(_ context.Context, host component.Host) error { return err } qs := querysvc.NewQueryService(spanReader, depReader, opts) - metricsQueryService, _ := disabled.NewMetricsReader() + + mqs, err := s.createMetricReader(host) + if err != nil { + return err + } + tm := tenancy.NewManager(&s.config.Tenancy) // TODO OTel-collector does not initialize the tracer currently @@ -81,6 +92,7 @@ func (s *server) Start(_ context.Context, host component.Host) error { telset := telemetery.Setting{ Logger: s.telset.Logger, TracerProvider: tracerProvider.OTEL, + Metrics: queryMetricsFactory, ReportStatus: s.telset.ReportStatus, } @@ -89,7 +101,7 @@ func (s *server) Start(_ context.Context, host component.Host) error { s.server, err = queryApp.NewServer( // TODO propagate healthcheck updates up to the collector's runtime qs, - metricsQueryService, + mqs, s.makeQueryOptions(), tm, telset, @@ -122,6 +134,24 @@ func (s *server) addArchiveStorage(opts *querysvc.QueryServiceOptions, host comp return nil } +func (s *server) createMetricReader(host component.Host) (metricsstore.Reader, error) { + if s.config.MetricStorage == "" { + s.telset.Logger.Info("Metric storage not configured") + return disabled.NewMetricsReader() + } + + mf, err := jaegerstorage.GetMetricsFactory(s.config.MetricStorage, host) + if err != nil { + return nil, fmt.Errorf("cannot find metrics storage factory: %w", err) + } + + metricsReader, err := mf.CreateMetricsReader() + if err != nil { + return nil, fmt.Errorf("cannot create metrics reader %w", err) + } + return metricsReader, err +} + func (s *server) makeQueryOptions() *queryApp.QueryOptions { return &queryApp.QueryOptions{ QueryOptionsBase: s.config.QueryOptionsBase, diff --git a/cmd/jaeger/internal/extension/jaegerquery/server_test.go b/cmd/jaeger/internal/extension/jaegerquery/server_test.go index 6ba3e963c5c..986033e133f 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/server_test.go +++ b/cmd/jaeger/internal/extension/jaegerquery/server_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" + noopMeter "go.opentelemetry.io/otel/metric/noop" "go.uber.org/zap" "go.uber.org/zap/zaptest" @@ -26,6 +27,8 @@ import ( "github.com/jaegertracing/jaeger/storage" "github.com/jaegertracing/jaeger/storage/dependencystore" depsmocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" + "github.com/jaegertracing/jaeger/storage/metricsstore" + metricsstoremocks "github.com/jaegertracing/jaeger/storage/metricsstore/mocks" "github.com/jaegertracing/jaeger/storage/spanstore" spanstoremocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" ) @@ -62,17 +65,43 @@ func (ff fakeFactory) Initialize(metrics.Factory, *zap.Logger) error { return nil } +type fakeMetricsFactory struct { + name string +} + +// Initialize implements storage.MetricsFactory. +func (fmf fakeMetricsFactory) Initialize(*zap.Logger) error { + if fmf.name == "need-initialize-error" { + return fmt.Errorf("test-error") + } + return nil +} + +func (fmf fakeMetricsFactory) CreateMetricsReader() (metricsstore.Reader, error) { + if fmf.name == "need-metrics-reader-error" { + return nil, fmt.Errorf("test-error") + } + return &metricsstoremocks.Reader{}, nil +} + type fakeStorageExt struct{} var _ jaegerstorage.Extension = (*fakeStorageExt)(nil) -func (fakeStorageExt) Factory(name string) (storage.Factory, bool) { +func (fakeStorageExt) TraceStorageFactory(name string) (storage.Factory, bool) { if name == "need-factory-error" { return nil, false } return fakeFactory{name: name}, true } +func (fakeStorageExt) MetricStorageFactory(name string) (storage.MetricsFactory, bool) { + if name == "need-factory-error" { + return nil, false + } + return fakeMetricsFactory{name: name}, true +} + func (fakeStorageExt) Start(context.Context, component.Host) error { return nil } @@ -105,6 +134,7 @@ func TestServerStart(t *testing.T) { config: &Config{ TraceStorageArchive: "jaeger_storage", TraceStoragePrimary: "jaeger_storage", + MetricStorage: "jaeger_metrics_storage", }, }, { @@ -136,13 +166,30 @@ func TestServerStart(t *testing.T) { }, expectedErr: "cannot find archive storage factory", }, + { + name: "metrics storage error", + config: &Config{ + MetricStorage: "need-factory-error", + TraceStoragePrimary: "jaeger_storage", + }, + expectedErr: "cannot find metrics storage factory", + }, + { + name: " metrics reader error", + config: &Config{ + MetricStorage: "need-metrics-reader-error", + TraceStoragePrimary: "jaeger_storage", + }, + expectedErr: "cannot create metrics reader", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { telemetrySettings := component.TelemetrySettings{ - Logger: zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())), - ReportStatus: func(*component.StatusEvent) {}, + Logger: zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())), + MeterProvider: noopMeter.NewMeterProvider(), + ReportStatus: func(*component.StatusEvent) {}, } tt.config.HTTP.Endpoint = ":0" tt.config.GRPC.NetAddr.Endpoint = ":0" @@ -242,3 +289,51 @@ func TestServerAddArchiveStorage(t *testing.T) { }) } } + +func TestServerAddMetricsStorage(t *testing.T) { + host := componenttest.NewNopHost() + + tests := []struct { + name string + config *Config + extension component.Component + expectedOutput string + expectedErr string + }{ + { + name: "Metrics storage unset", + config: &Config{}, + expectedOutput: `{"level":"info","msg":"Metric storage not configured"}` + "\n", + expectedErr: "", + }, + { + name: "Metrics storage set", + config: &Config{ + MetricStorage: "random-value", + }, + expectedOutput: "", + expectedErr: "cannot find metrics storage factory: cannot find extension", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + logger, buf := testutils.NewLogger() + telemetrySettings := component.TelemetrySettings{ + Logger: logger, + } + server := newServer(tt.config, telemetrySettings) + if tt.extension != nil { + host = storagetest.NewStorageHost().WithExtension(jaegerstorage.ID, tt.extension) + } + _, err := server.createMetricReader(host) + if tt.expectedErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tt.expectedErr) + } + + assert.Contains(t, buf.String(), tt.expectedOutput) + }) + } +} diff --git a/cmd/jaeger/internal/extension/jaegerstorage/config.go b/cmd/jaeger/internal/extension/jaegerstorage/config.go index 42d4630d29d..98d19d08270 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/config.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/config.go @@ -13,6 +13,8 @@ import ( casCfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" esCfg "github.com/jaegertracing/jaeger/pkg/es/config" + promCfg "github.com/jaegertracing/jaeger/pkg/prometheus/config" + "github.com/jaegertracing/jaeger/plugin/metrics/prometheus" "github.com/jaegertracing/jaeger/plugin/storage/badger" "github.com/jaegertracing/jaeger/plugin/storage/cassandra" "github.com/jaegertracing/jaeger/plugin/storage/es" @@ -23,6 +25,7 @@ import ( var ( _ component.ConfigValidator = (*Config)(nil) _ confmap.Unmarshaler = (*Backend)(nil) + _ confmap.Unmarshaler = (*MetricBackends)(nil) ) // Config contains configuration(s) for jaeger trace storage. @@ -31,7 +34,8 @@ var ( // We tried to alias this type directly to a map, but conf did not populated it correctly. // Note also that the Backend struct has a custom unmarshaler. type Config struct { - Backends map[string]Backend `mapstructure:"backends"` + Backends map[string]Backend `mapstructure:"backends"` + MetricBackends map[string]MetricBackends `mapstructure:"metric_backends"` } type Backend struct { @@ -43,6 +47,10 @@ type Backend struct { Opensearch *esCfg.Configuration `mapstructure:"opensearch"` } +type MetricBackends struct { + Prometheus *promCfg.Configuration `mapstructure:"prometheus"` +} + // Unmarshal implements confmap.Unmarshaler. This allows us to provide // defaults for different configs. It cannot be done in createDefaultConfig() // because at that time we don't know which backends the user wants to use. @@ -98,3 +106,12 @@ func (cfg *Config) Validate() error { } return nil } + +func (cfg *MetricBackends) Unmarshal(conf *confmap.Conf) error { + // apply defaults + if conf.IsSet("prometheus") { + v := prometheus.DefaultConfig() + cfg.Prometheus = &v + } + return conf.Unmarshal(cfg) +} diff --git a/cmd/jaeger/internal/extension/jaegerstorage/config_test.go b/cmd/jaeger/internal/extension/jaegerstorage/config_test.go index 3f4dd8cd74b..1b2718c4cda 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/config_test.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/config_test.go @@ -107,3 +107,14 @@ backends: require.NoError(t, conf.Unmarshal(cfg)) assert.NotEmpty(t, cfg.Backends["some_storage"].Opensearch.Servers) } + +func TestConfigDefaultPrometheus(t *testing.T) { + conf := loadConf(t, ` +metric_backends: + some_metrics_storage: + prometheus: +`) + cfg := createDefaultConfig().(*Config) + require.NoError(t, conf.Unmarshal(cfg)) + assert.NotEmpty(t, cfg.MetricBackends["some_metrics_storage"].Prometheus.ServerURL) +} diff --git a/cmd/jaeger/internal/extension/jaegerstorage/extension.go b/cmd/jaeger/internal/extension/jaegerstorage/extension.go index 4f2e618d327..5e8d1061349 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/extension.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/extension.go @@ -14,6 +14,7 @@ import ( "github.com/jaegertracing/jaeger/cmd/jaeger/internal/extension/jaegerstorage/factoryadapter" "github.com/jaegertracing/jaeger/internal/metrics/otelmetrics" + "github.com/jaegertracing/jaeger/plugin/metrics/prometheus" "github.com/jaegertracing/jaeger/plugin/storage/badger" "github.com/jaegertracing/jaeger/plugin/storage/cassandra" "github.com/jaegertracing/jaeger/plugin/storage/es" @@ -27,38 +28,47 @@ var _ Extension = (*storageExt)(nil) type Extension interface { extension.Extension - Factory(name string) (storage.Factory, bool) + TraceStorageFactory(name string) (storage.Factory, bool) + MetricStorageFactory(name string) (storage.MetricsFactory, bool) } type storageExt struct { - config *Config - telset component.TelemetrySettings - factories map[string]storage.Factory + config *Config + telset component.TelemetrySettings + factories map[string]storage.Factory + metricsFactories map[string]storage.MetricsFactory } // GetStorageFactory locates the extension in Host and retrieves a storage factory from it with the given name. func GetStorageFactory(name string, host component.Host) (storage.Factory, error) { - var comp component.Component - for id, ext := range host.GetExtensions() { - if id.Type() == componentType { - comp = ext - break - } + ext, err := findExtension(host) + if err != nil { + return nil, err } - if comp == nil { + f, ok := ext.TraceStorageFactory(name) + if !ok { return nil, fmt.Errorf( - "cannot find extension '%s' (make sure it's defined earlier in the config)", - componentType, + "cannot find definition of storage '%s' in the configuration for extension '%s'", + name, componentType, ) } - f, ok := comp.(Extension).Factory(name) + return f, nil +} + +// GetMetricsFactory locates the extension in Host and retrieves a metrics factory from it with the given name. +func GetMetricsFactory(name string, host component.Host) (storage.MetricsFactory, error) { + ext, err := findExtension(host) + if err != nil { + return nil, err + } + mf, ok := ext.MetricStorageFactory(name) if !ok { return nil, fmt.Errorf( - "cannot find definition of storage '%s' in the configuration for extension '%s'", + "cannot find metric storage '%s' declared by '%s' extension", name, componentType, ) } - return f, nil + return mf, nil } func GetStorageFactoryV2(name string, host component.Host) (spanstore.Factory, error) { @@ -70,11 +80,34 @@ func GetStorageFactoryV2(name string, host component.Host) (spanstore.Factory, e return factoryadapter.NewFactory(f), nil } +func findExtension(host component.Host) (Extension, error) { + var id component.ID + var comp component.Component + for i, ext := range host.GetExtensions() { + if i.Type() == componentType { + id, comp = i, ext + break + } + } + if comp == nil { + return nil, fmt.Errorf( + "cannot find extension '%s' (make sure it's defined earlier in the config)", + componentType, + ) + } + ext, ok := comp.(Extension) + if !ok { + return nil, fmt.Errorf("extension '%s' is not of expected type '%s'", id, componentType) + } + return ext, nil +} + func newStorageExt(config *Config, telset component.TelemetrySettings) *storageExt { return &storageExt{ - config: config, - telset: telset, - factories: make(map[string]storage.Factory), + config: config, + telset: telset, + factories: make(map[string]storage.Factory), + metricsFactories: make(map[string]storage.MetricsFactory), } } @@ -104,6 +137,20 @@ func (s *storageExt) Start(_ context.Context, _ component.Host) error { } s.factories[storageName] = factory } + + for metricStorageName, cfg := range s.config.MetricBackends { + s.telset.Logger.Sugar().Infof("Initializing metrics storage '%s'", metricStorageName) + var metricsFactory storage.MetricsFactory + var err error + if cfg.Prometheus != nil { + metricsFactory, err = prometheus.NewFactoryWithConfig(*cfg.Prometheus, s.telset.Logger) + } + if err != nil { + return fmt.Errorf("failed to initialize metrics storage '%s': %w", metricStorageName, err) + } + s.metricsFactories[metricStorageName] = metricsFactory + } + return nil } @@ -120,7 +167,12 @@ func (s *storageExt) Shutdown(context.Context) error { return errors.Join(errs...) } -func (s *storageExt) Factory(name string) (storage.Factory, bool) { +func (s *storageExt) TraceStorageFactory(name string) (storage.Factory, bool) { f, ok := s.factories[name] return f, ok } + +func (s *storageExt) MetricStorageFactory(name string) (storage.MetricsFactory, bool) { + mf, ok := s.metricsFactories[name] + return mf, ok +} diff --git a/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go b/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go index b05ef36474a..472b160fb13 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/extension_test.go @@ -23,6 +23,7 @@ import ( esCfg "github.com/jaegertracing/jaeger/pkg/es/config" "github.com/jaegertracing/jaeger/pkg/metrics" + promCfg "github.com/jaegertracing/jaeger/pkg/prometheus/config" "github.com/jaegertracing/jaeger/plugin/storage/badger" "github.com/jaegertracing/jaeger/plugin/storage/cassandra" "github.com/jaegertracing/jaeger/plugin/storage/grpc" @@ -62,11 +63,28 @@ func TestStorageFactoryBadHostError(t *testing.T) { } func TestStorageFactoryBadNameError(t *testing.T) { - host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, "foo")) + host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, "foo", "")) _, err := GetStorageFactory("bar", host) require.ErrorContains(t, err, "cannot find definition of storage 'bar'") } +func TestMetricsFactoryBadHostError(t *testing.T) { + _, err := GetMetricsFactory("something", componenttest.NewNopHost()) + require.ErrorContains(t, err, "cannot find extension") +} + +func TestMetricsFactoryBadNameError(t *testing.T) { + host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, "", "foo")) + _, err := GetMetricsFactory("bar", host) + require.ErrorContains(t, err, "cannot find metric storage 'bar'") +} + +func TestStorageExtensionType(t *testing.T) { + host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, "", "foo")) + _, err := findExtension(host) + require.NoError(t, err) +} + func TestStorageFactoryBadShutdownError(t *testing.T) { shutdownError := fmt.Errorf("shutdown error") ext := storageExt{ @@ -86,7 +104,8 @@ func TestGetFactoryV2Error(t *testing.T) { func TestGetFactory(t *testing.T) { const name = "foo" - host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, name)) + const metricname = "bar" + host := storagetest.NewStorageHost().WithExtension(ID, startStorageExtension(t, name, metricname)) f, err := GetStorageFactory(name, host) require.NoError(t, err) require.NotNil(t, f) @@ -94,6 +113,10 @@ func TestGetFactory(t *testing.T) { f2, err := GetStorageFactoryV2(name, host) require.NoError(t, err) require.NotNil(t, f2) + + f3, err := GetMetricsFactory(metricname, host) + require.NoError(t, err) + require.NotNil(t, f3) } func TestBadger(t *testing.T) { @@ -132,6 +155,22 @@ func TestGRPC(t *testing.T) { require.NoError(t, ext.Shutdown(ctx)) } +func TestPrometheus(t *testing.T) { + ext := makeStorageExtenion(t, &Config{ + MetricBackends: map[string]MetricBackends{ + "foo": { + Prometheus: &promCfg.Configuration{ + ServerURL: "localhost:12345", + }, + }, + }, + }) + ctx := context.Background() + err := ext.Start(ctx, componenttest.NewNopHost()) + require.NoError(t, err) + require.NoError(t, ext.Shutdown(ctx)) +} + func TestStartError(t *testing.T) { ext := makeStorageExtenion(t, &Config{ Backends: map[string]Backend{ @@ -143,6 +182,18 @@ func TestStartError(t *testing.T) { require.ErrorContains(t, err, "empty configuration") } +func TestMetricsStorageStartError(t *testing.T) { + ext := makeStorageExtenion(t, &Config{ + MetricBackends: map[string]MetricBackends{ + "foo": { + Prometheus: &promCfg.Configuration{}, + }, + }, + }) + err := ext.Start(context.Background(), componenttest.NewNopHost()) + require.ErrorContains(t, err, "failed to initialize metrics storage 'foo'") +} + func testElasticsearchOrOpensearch(t *testing.T, cfg Backend) { ext := makeStorageExtenion(t, &Config{ Backends: map[string]Backend{ @@ -222,7 +273,7 @@ func makeStorageExtenion(t *testing.T, config *Config) component.Component { return ext } -func startStorageExtension(t *testing.T, memstoreName string) component.Component { +func startStorageExtension(t *testing.T, memstoreName string, promstoreName string) component.Component { config := &Config{ Backends: map[string]Backend{ memstoreName: { @@ -231,6 +282,13 @@ func startStorageExtension(t *testing.T, memstoreName string) component.Componen }, }, }, + MetricBackends: map[string]MetricBackends{ + promstoreName: { + Prometheus: &promCfg.Configuration{ + ServerURL: "localhost:12345", + }, + }, + }, } require.NoError(t, config.Validate()) diff --git a/cmd/jaeger/internal/integration/README.md b/cmd/jaeger/internal/integration/README.md index 3c97bfddbd0..9237aac4dcf 100644 --- a/cmd/jaeger/internal/integration/README.md +++ b/cmd/jaeger/internal/integration/README.md @@ -63,6 +63,56 @@ flowchart LR end ``` +## Kafka Integration + +The primary difference between the Kafka integration tests and other integration tests lies in the flow of data. In the standard tests, spans are written by the SpanWriter, sent through an RPC_client directly to a receiver, then to an exporter, and written to a storage backend. Spans are read by the SpanReader, which queries the jaeger_query process accessing the storage backend. In contrast, the Kafka tests introduce Kafka as an intermediary. Spans go from the SpanWriter through an RPC_client to an OTLP receiver in the Jaeger Collector, exported to Kafka, received by the Jaeger Ingester, and then stored. For details, see the [Architecture](#KafkaArchitecture) section below. + + +## Kafka Architecture + +``` mermaid +flowchart LR + Test -->|writeSpan| SpanWriter + SpanWriter --> RPCW[RPC_client] + RPCW --> OTLP_Receiver[Receiver] + OTLP_Receiver --> CollectorExporter[Kafka Exporter] + CollectorExporter --> Kafka[Kafka] + Kafka --> IngesterReceiver[Kafka Receiver] + IngesterReceiver --> IngesterExporter[Exporter] + IngesterExporter --> StorageBackend[(In-Memory Store)] + Test -->|readSpan| SpanReader + SpanReader --> RPCR[RPC_client] + RPCR --> QueryProcess[jaeger_query] + StorageCleaner -->|purge| StorageBackend + QueryProcess --> StorageBackend + + + subgraph Integration_Test_Executable + Test + SpanWriter + SpanReader + RPCW + RPCR + end + + subgraph Jaeger Collector + OTLP_Receiver + CollectorExporter + end + + subgraph Jaeger Ingester + IngesterReceiver + IngesterExporter + QueryProcess + StorageBackend + StorageCleaner[Storage Cleaner Extension] + end + + subgraph Kafka + Topic + end +``` + ## Running tests locally All integration tests can be run locally. diff --git a/cmd/jaeger/internal/integration/badger_test.go b/cmd/jaeger/internal/integration/badger_test.go index a0fe00f669a..b5c62d5c21a 100644 --- a/cmd/jaeger/internal/integration/badger_test.go +++ b/cmd/jaeger/internal/integration/badger_test.go @@ -24,8 +24,5 @@ func TestBadgerStorage(t *testing.T) { }, } s.e2eInitialize(t, "badger") - t.Cleanup(func() { - s.e2eCleanUp(t) - }) s.RunAll(t) } diff --git a/cmd/jaeger/internal/integration/cassandra_test.go b/cmd/jaeger/internal/integration/cassandra_test.go index 0ac74c13149..a78f66b3ec9 100644 --- a/cmd/jaeger/internal/integration/cassandra_test.go +++ b/cmd/jaeger/internal/integration/cassandra_test.go @@ -22,8 +22,5 @@ func TestCassandraStorage(t *testing.T) { }, } s.e2eInitialize(t, "cassandra") - t.Cleanup(func() { - s.e2eCleanUp(t) - }) s.RunSpanStoreTests(t) } diff --git a/cmd/jaeger/internal/integration/e2e_integration.go b/cmd/jaeger/internal/integration/e2e_integration.go index 670b7b576d4..4bf341a2a8f 100644 --- a/cmd/jaeger/internal/integration/e2e_integration.go +++ b/cmd/jaeger/internal/integration/e2e_integration.go @@ -37,6 +37,7 @@ const otlpPort = 4317 // - At last, clean up anything declared in its own test functions. // (e.g. close remote-storage) type E2EStorageIntegration struct { + SkipStorageCleaner bool integration.StorageIntegration ConfigFile string } @@ -46,7 +47,10 @@ type E2EStorageIntegration struct { // This function should be called before any of the tests start. func (s *E2EStorageIntegration) e2eInitialize(t *testing.T, storage string) { logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) - configFile := createStorageCleanerConfig(t, s.ConfigFile, storage) + configFile := s.ConfigFile + if !s.SkipStorageCleaner { + configFile = createStorageCleanerConfig(t, s.ConfigFile, storage) + } t.Logf("Starting Jaeger-v2 in the background with config file %s", configFile) outFile, err := os.OpenFile( @@ -93,19 +97,27 @@ func (s *E2EStorageIntegration) e2eInitialize(t *testing.T, storage string) { }, 30*time.Second, 500*time.Millisecond, "Jaeger-v2 did not start") t.Log("Jaeger-v2 is ready") t.Cleanup(func() { - require.NoError(t, cmd.Process.Kill()) + if err := cmd.Process.Kill(); err != nil { + t.Errorf("Failed to kill Jaeger-v2 process: %v", err) + } if t.Failed() { // A Github Actions special annotation to create a foldable section // in the Github runner output. // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines fmt.Println("::group::🚧 🚧 🚧 Jaeger-v2 binary logs") outLogs, err := os.ReadFile(outFile.Name()) - require.NoError(t, err) - fmt.Printf("🚧 🚧 🚧 Jaeger-v2 output logs:\n%s", outLogs) + if err != nil { + t.Errorf("Failed to read output logs: %v", err) + } else { + fmt.Printf("🚧 🚧 🚧 Jaeger-v2 output logs:\n%s", outLogs) + } errLogs, err := os.ReadFile(errFile.Name()) - require.NoError(t, err) - fmt.Printf("🚧 🚧 🚧 Jaeger-v2 error logs:\n%s", errLogs) + if err != nil { + t.Errorf("Failed to read error logs: %v", err) + } else { + fmt.Printf("🚧 🚧 🚧 Jaeger-v2 error logs:\n%s", errLogs) + } // End of Github Actions foldable section annotation. fmt.Println("::endgroup::") } @@ -115,6 +127,11 @@ func (s *E2EStorageIntegration) e2eInitialize(t *testing.T, storage string) { require.NoError(t, err) s.SpanReader, err = createSpanReader(logger, ports.QueryGRPC) require.NoError(t, err) + + t.Cleanup(func() { + // Call e2eCleanUp to close the SpanReader and SpanWriter gRPC connection. + s.e2eCleanUp(t) + }) } // e2eCleanUp closes the SpanReader and SpanWriter gRPC connection. diff --git a/cmd/jaeger/internal/integration/elasticsearch_test.go b/cmd/jaeger/internal/integration/elasticsearch_test.go index 2c78bfdb7af..844c4866321 100644 --- a/cmd/jaeger/internal/integration/elasticsearch_test.go +++ b/cmd/jaeger/internal/integration/elasticsearch_test.go @@ -21,8 +21,5 @@ func TestElasticsearchStorage(t *testing.T) { }, } s.e2eInitialize(t, "elasticsearch") - t.Cleanup(func() { - s.e2eCleanUp(t) - }) s.RunSpanStoreTests(t) } diff --git a/cmd/jaeger/internal/integration/grpc_test.go b/cmd/jaeger/internal/integration/grpc_test.go index b33b7b002a0..cd12984bc62 100644 --- a/cmd/jaeger/internal/integration/grpc_test.go +++ b/cmd/jaeger/internal/integration/grpc_test.go @@ -36,7 +36,6 @@ func TestGRPCStorage(t *testing.T) { s.initialize(t) s.e2eInitialize(t, "grpc") t.Cleanup(func() { - s.e2eCleanUp(t) s.remoteStorage.Close(t) }) s.RunSpanStoreTests(t) diff --git a/cmd/jaeger/internal/integration/kafka_test.go b/cmd/jaeger/internal/integration/kafka_test.go new file mode 100644 index 00000000000..099bddba3e1 --- /dev/null +++ b/cmd/jaeger/internal/integration/kafka_test.go @@ -0,0 +1,40 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package integration + +import ( + "testing" + + "github.com/jaegertracing/jaeger/plugin/storage/integration" +) + +func TestKafkaStorage(t *testing.T) { + integration.SkipUnlessEnv(t, "kafka") + + collectorConfig := "../../collector-with-kafka.yaml" + ingesterConfig := "../../ingester-remote-storage.yaml" + + collector := &E2EStorageIntegration{ + SkipStorageCleaner: true, + ConfigFile: collectorConfig, + } + + // Initialize and start the collector + collector.e2eInitialize(t, "kafka") + + ingester := &E2EStorageIntegration{ + ConfigFile: ingesterConfig, + StorageIntegration: integration.StorageIntegration{ + CleanUp: purge, + GetDependenciesReturnsSource: true, + SkipArchiveTest: true, + }, + } + + // Initialize and start the ingester + ingester.e2eInitialize(t, "kafka") + + // Run the span store tests + ingester.RunSpanStoreTests(t) +} diff --git a/cmd/jaeger/internal/integration/memory_test.go b/cmd/jaeger/internal/integration/memory_test.go index a2592b04a38..81f0bfa94fb 100644 --- a/cmd/jaeger/internal/integration/memory_test.go +++ b/cmd/jaeger/internal/integration/memory_test.go @@ -20,8 +20,5 @@ func TestMemoryStorage(t *testing.T) { }, } s.e2eInitialize(t, "memory") - t.Cleanup(func() { - s.e2eCleanUp(t) - }) s.RunAll(t) } diff --git a/cmd/jaeger/internal/integration/opensearch_test.go b/cmd/jaeger/internal/integration/opensearch_test.go index 909c0be6510..f164bfcda26 100644 --- a/cmd/jaeger/internal/integration/opensearch_test.go +++ b/cmd/jaeger/internal/integration/opensearch_test.go @@ -20,8 +20,5 @@ func TestOpenSearchStorage(t *testing.T) { }, } s.e2eInitialize(t, "opensearch") - t.Cleanup(func() { - s.e2eCleanUp(t) - }) s.RunSpanStoreTests(t) } diff --git a/cmd/jaeger/internal/integration/storagecleaner/extension_test.go b/cmd/jaeger/internal/integration/storagecleaner/extension_test.go index 6f1290cf0b9..4c130fdc245 100644 --- a/cmd/jaeger/internal/integration/storagecleaner/extension_test.go +++ b/cmd/jaeger/internal/integration/storagecleaner/extension_test.go @@ -37,8 +37,9 @@ func (f *PurgerFactory) Purge(_ context.Context) error { } type mockStorageExt struct { - name string - factory storage.Factory + name string + factory storage.Factory + metricsFactory storage.MetricsFactory } func (*mockStorageExt) Start(context.Context, component.Host) error { @@ -49,13 +50,20 @@ func (*mockStorageExt) Shutdown(context.Context) error { panic("not implemented") } -func (m *mockStorageExt) Factory(name string) (storage.Factory, bool) { +func (m *mockStorageExt) TraceStorageFactory(name string) (storage.Factory, bool) { if m.name == name { return m.factory, true } return nil, false } +func (m *mockStorageExt) MetricStorageFactory(name string) (storage.MetricsFactory, bool) { + if m.name == name { + return m.metricsFactory, true + } + return nil, false +} + func TestStorageCleanerExtension(t *testing.T) { tests := []struct { name string diff --git a/cmd/query/app/querysvc/query_service.go b/cmd/query/app/querysvc/query_service.go index 2144928acb2..06ec79d94a4 100644 --- a/cmd/query/app/querysvc/query_service.go +++ b/cmd/query/app/querysvc/query_service.go @@ -44,6 +44,7 @@ type QueryServiceOptions struct { // StorageCapabilities is a feature flag for query service type StorageCapabilities struct { ArchiveStorage bool `json:"archiveStorage"` + // TODO: Maybe add metrics Storage here // SupportRegex bool // SupportTagFilter bool } diff --git a/docker-compose/monitor/Makefile b/docker-compose/monitor/Makefile index f6628dffd3b..e5d53688124 100644 --- a/docker-compose/monitor/Makefile +++ b/docker-compose/monitor/Makefile @@ -1,22 +1,30 @@ +BINARY ?= all-in-one # Default value uses v1 binary + .PHONY: build build: clean-jaeger - cd ../../ && make build-all-in-one-linux + cd ../../ && make build-$(BINARY) GOOS=linux cd ../../ && make create-baseimg PLATFORMS=linux/$(shell go env GOARCH) cd ../../ && docker buildx build --target release \ - --tag jaegertracing/all-in-one:dev \ + --tag jaegertracing/$(BINARY):dev \ --build-arg base_image=localhost:5000/baseimg_alpine:latest \ --build-arg debug_image=not-used \ --build-arg TARGETARCH=$(shell go env GOARCH) \ --load \ - cmd/all-in-one + cmd/$(BINARY) # starts up the system required for SPM using the latest otel image and a development jaeger image. # Note: the jaeger "dev" image can be built with "make build". .PHONY: dev dev: export JAEGER_IMAGE_TAG = dev -dev: +dev: docker compose -f docker-compose.yml up $(DOCKER_COMPOSE_ARGS) +.PHONY: dev-v2 +dev-v2: export JAEGER_IMAGE_TAG = dev +dev-v2: export BINARY = jaeger +dev-v2: build + docker compose -f docker-compose-v2.yml up $(DOCKER_COMPOSE_ARGS) + .PHONY: clean-jaeger clean-jaeger: # Also cleans up intermediate cached containers. diff --git a/docker-compose/monitor/docker-compose-v2.yml b/docker-compose/monitor/docker-compose-v2.yml new file mode 100644 index 00000000000..5bddd2cc658 --- /dev/null +++ b/docker-compose/monitor/docker-compose-v2.yml @@ -0,0 +1,51 @@ +version: "3.5" +services: + jaeger: + networks: + backend: + # This is the host name used in Prometheus scrape configuration. + aliases: [spm_metrics_source] + image: jaegertracing/jaeger:${JAEGER_IMAGE_TAG:-latest} + volumes: + - "./jaeger-ui.json:/etc/jaeger/jaeger-ui.json" # Do we need this for v2 ? Seems to be running without this. + - "./jaeger-v2-config.yml:/etc/jaeger/config.yml" + command: ["--config", "/etc/jaeger/config.yml"] + ports: + - "16686:16686" + - "8889:8889" + + microsim: + networks: + - backend + image: yurishkuro/microsim:v0.4.1 + command: "-d 24h -s 500ms" + environment: + - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://jaeger:4318/v1/traces + depends_on: + - jaeger + + prometheus: + networks: + - backend + image: prom/prometheus:latest + volumes: + - "./prometheus.yml:/etc/prometheus/prometheus.yml" + ports: + - "9090:9090" + + grafana: + networks: + - backend + image: grafana/grafana:latest + volumes: + - ./grafana.ini:/etc/grafana/grafana.ini + - ./datasource.yml:/etc/grafana/provisioning/datasources/datasource.yaml + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + ports: + - 3000:3000 + +networks: + backend: diff --git a/docker-compose/monitor/docker-compose.yml b/docker-compose/monitor/docker-compose.yml index 61e9170148c..3f288201eb9 100644 --- a/docker-compose/monitor/docker-compose.yml +++ b/docker-compose/monitor/docker-compose.yml @@ -17,15 +17,21 @@ services: - PROMETHEUS_QUERY_NORMALIZE_DURATION=true ports: - "16686:16686" + otel_collector: networks: - - backend + backend: + # This is the host name used in Prometheus scrape configuration. + aliases: [spm_metrics_source] image: otel/opentelemetry-collector-contrib:${OTEL_IMAGE_TAG:-0.89.0} volumes: - ${OTEL_CONFIG_SRC:-./otel-collector-config-connector.yml}:/etc/otelcol/otel-collector-config.yml command: --config /etc/otelcol/otel-collector-config.yml depends_on: - jaeger + ports: + - "8889:8889" + microsim: networks: - backend @@ -36,6 +42,7 @@ services: - OTEL_EXPORTER_OTLP_INSECURE=true depends_on: - otel_collector + prometheus: networks: - backend @@ -44,6 +51,7 @@ services: - "./prometheus.yml:/etc/prometheus/prometheus.yml" ports: - "9090:9090" + grafana: networks: - backend @@ -56,7 +64,7 @@ services: - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin - GF_AUTH_DISABLE_LOGIN_FORM=true ports: - - 3000:3000 + - "3000:3000" networks: backend: diff --git a/docker-compose/monitor/jaeger-v2-config.yml b/docker-compose/monitor/jaeger-v2-config.yml new file mode 100644 index 00000000000..bc7160c5bb8 --- /dev/null +++ b/docker-compose/monitor/jaeger-v2-config.yml @@ -0,0 +1,48 @@ +service: + extensions: [jaeger_storage, jaeger_query] + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [jaeger_storage_exporter, spanmetrics] + metrics/spanmetrics: + receivers: [spanmetrics] + exporters: [prometheus] + telemetry: + logs: + level: DEBUG + +extensions: + jaeger_query: + trace_storage: some_storage + metric_storage: some_metrics_storage + jaeger_storage: + backends: + some_storage: + memory: + max_traces: 100000 + metric_backends: + some_metrics_storage: + prometheus: + endpoint: http://prometheus:9090 + normalize_calls: true + normalize_duration: true + +connectors: + spanmetrics: + +receivers: + otlp: + protocols: + grpc: + http: + endpoint: "0.0.0.0:4318" + +processors: + batch: + +exporters: + jaeger_storage_exporter: + trace_storage: some_storage + prometheus: + endpoint: "0.0.0.0:8889" diff --git a/docker-compose/monitor/otel-collector-config-connector.yml b/docker-compose/monitor/otel-collector-config-connector.yml index 038f5f86c29..72d577d4321 100644 --- a/docker-compose/monitor/otel-collector-config-connector.yml +++ b/docker-compose/monitor/otel-collector-config-connector.yml @@ -1,9 +1,4 @@ receivers: - jaeger: - protocols: - thrift_http: - endpoint: "0.0.0.0:14278" - otlp: protocols: grpc: @@ -27,11 +22,12 @@ processors: service: pipelines: traces: - receivers: [otlp, jaeger] + receivers: [otlp] processors: [batch] exporters: [spanmetrics, otlp] - # The exporter name in this pipeline must match the spanmetrics.metrics_exporter name. - # The receiver is just a dummy and never used; added to pass validation requiring at least one receiver in a pipeline. + + # The metrics pipeline receives generated span metrics from 'spanmetrics' connector + # and pushes to Prometheus exporter, which makes them available for scraping on :8889. metrics/spanmetrics: receivers: [spanmetrics] exporters: [prometheus] diff --git a/docker-compose/monitor/prometheus.yml b/docker-compose/monitor/prometheus.yml index 4dfa620887f..5ca0a6293cc 100644 --- a/docker-compose/monitor/prometheus.yml +++ b/docker-compose/monitor/prometheus.yml @@ -6,4 +6,4 @@ global: scrape_configs: - job_name: aggregated-trace-metrics static_configs: - - targets: ['otel_collector:8889'] + - targets: ['spm_metrics_source:8889'] diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index 1910e9b4870..3e0a3b38400 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -1,6 +1,6 @@ -FROM alpine:3.20.1 AS cert +FROM alpine:3.20.2 AS cert RUN apk add --update --no-cache ca-certificates mailcap -FROM alpine:3.20.1 +FROM alpine:3.20.2 COPY --from=cert /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=cert /etc/mime.types /etc/mime.types diff --git a/examples/hotrod/README.md b/examples/hotrod/README.md index f69fb49099b..44d6565ccb2 100644 --- a/examples/hotrod/README.md +++ b/examples/hotrod/README.md @@ -19,6 +19,8 @@ As of Jaeger v1.42.0 this application was upgraded to use the OpenTelemetry SDK ## Running +💥💥💥 Try it with Jaeger v2! See [cmd/jaeger](../../cmd/jaeger). + ### Run everything via `docker compose` * Download `docker-compose.yml` from https://github.com/jaegertracing/jaeger/blob/main/examples/hotrod/docker-compose.yml diff --git a/examples/hotrod/docker-compose-v2.yml b/examples/hotrod/docker-compose-v2.yml new file mode 100644 index 00000000000..062cfe7703e --- /dev/null +++ b/examples/hotrod/docker-compose-v2.yml @@ -0,0 +1,35 @@ +version: '3.7' +# To run a specific version of Jaeger, use environment variable, e.g.: +# JAEGER_VERSION=1.52 docker compose up + +services: + jaeger: + image: ${REGISTRY:-}jaegertracing/jaeger:${JAEGER_VERSION:-latest} + command: ["--feature-gates=-component.UseLocalHostAsDefaultHost"] + ports: + - "16686:16686" + - "4317:4317" + - "4318:4318" + environment: + - LOG_LEVEL=debug + networks: + - jaeger-example + + hotrod: + image: ${REGISTRY:-}jaegertracing/example-hotrod:${JAEGER_VERSION:-latest} + # To run the latest trunk build, find the tag at Docker Hub and use the line below + # https://hub.docker.com/r/jaegertracing/example-hotrod-snapshot/tags + #image: jaegertracing/example-hotrod-snapshot:0ab8f2fcb12ff0d10830c1ee3bb52b745522db6c + ports: + - "8080:8080" + - "8083:8083" + command: ["all"] + environment: + - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318 + networks: + - jaeger-example + depends_on: + - jaeger + +networks: + jaeger-example: diff --git a/go.mod b/go.mod index cf46248a6d2..62ec869cbe0 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/olivere/elastic v6.2.37+incompatible github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.105.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.105.0 + github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.105.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage v0.105.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.105.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.105.0 @@ -93,6 +94,8 @@ require ( ) require ( + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.105.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.105.0 // indirect go.opentelemetry.io/collector/internal/globalgates v0.105.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.105.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.105.0 // indirect @@ -103,7 +106,7 @@ require ( require ( github.com/IBM/sarama v1.43.2 // indirect - github.com/aws/aws-sdk-go v1.53.11 // indirect + github.com/aws/aws-sdk-go v1.53.16 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index 6128a76429a..5269dcc2d67 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,50 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= +cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0/go.mod h1:QyiQdW4f4/BIfB8ZutZ2s+28RAgfa/pT+zS++ZHyM1I= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U+0KMqAA0KcU= +github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/IBM/sarama v1.43.2 h1:HABeEqRUh32z8yzY2hGB/j8mHSzC/HA9zlEjqFNCzSw= github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMdXFQ= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Shopify/sarama v1.33.0 h1:2K4mB9M4fo46sAM7t6QTsmSO8dLX1OqznLM7vn3OjZ8= github.com/Shopify/sarama v1.33.0/go.mod h1:lYO7LwEBkE0iAeTl94UfPSrDaavFzSFlmn+5isARATQ= github.com/Shopify/toxiproxy/v2 v2.3.0 h1:62YkpiP4bzdhKMH+6uC5E95y608k3zDwdzuBMsnn3uQ= github.com/Shopify/toxiproxy/v2 v2.3.0/go.mod h1:KvQTtB6RjCJY4zqNJn7C7JDFgsG5uoHYDirfUfpIm0c= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/apache/thrift v0.20.0 h1:631+KvYbsBZxmuJjYwhezVsrfc/TbqtZV4QcxOX1fOI= github.com/apache/thrift v0.20.0/go.mod h1:hOk1BQqcp2OLzGsyVXdfMk7YFlMxK3aoEVhjD06QhB8= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.53.11 h1:KcmduYvX15rRqt4ZU/7jKkmDxU/G87LJ9MUI0yQJh00= -github.com/aws/aws-sdk-go v1.53.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.53.16 h1:8oZjKQO/ml1WLUZw5hvF7pvYjPf8o9f57Wldoy/q9Qc= +github.com/aws/aws-sdk-go v1.53.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= @@ -33,6 +61,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw= +github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -43,12 +73,24 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= +github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/digitalocean/godo v1.117.0 h1:WVlTe09melDYTd7VCVyvHcNWbgB+uI1O115+5LOtdSw= +github.com/digitalocean/godo v1.117.0/go.mod h1:Vk0vpCot2HOAJwc5WE8wljZGtJ3ZtWIc8MQ8rF38sdo= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU= +github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -63,10 +105,18 @@ github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHo github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= github.com/elastic/go-elasticsearch/v8 v8.14.0 h1:1ywU8WFReLLcxE1WJqii3hTtbPUE2hc38ZK/j4mMFow= github.com/elastic/go-elasticsearch/v8 v8.14.0/go.mod h1:WRvnlGkSuZyp83M2U8El/LGXpCjYLrvlkSgkAH4O5I4= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -80,6 +130,10 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -89,15 +143,27 @@ github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= +github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= +github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g= +github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gocql/gocql v1.6.0 h1:IdFdOTbnpbd0pDhl4REKQDM+Q0SzKXQ1Yh+YZZ8T/qU= github.com/gocql/gocql v1.6.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= @@ -123,6 +189,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -134,10 +202,22 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= +github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/gophercloud/gophercloud v1.12.0 h1:Jrz16vPAL93l80q16fp8NplrTCp93y7rZh2P3Q4Yq7g= +github.com/gophercloud/gophercloud v1.12.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -145,17 +225,35 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +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/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= +github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= +github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -167,9 +265,19 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/nomad/api v0.0.0-20240604134157-e73d8bb1140d h1:KHq+mAzWSkumj4PDoXc5VZbycPGcmYu8tohgVLQ6SIc= +github.com/hashicorp/nomad/api v0.0.0-20240604134157-e73d8bb1140d/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hetznercloud/hcloud-go/v2 v2.9.0 h1:s0N6R7Zoi2DPfMtUF5o9VeUBzTtHVY6MIkHOQnfu/AY= +github.com/hetznercloud/hcloud-go/v2 v2.9.0/go.mod h1:qtW/TuU7Bs16ibXl/ktJarWqU2LwHr7eGlwoilHxtgg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= +github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -206,6 +314,8 @@ github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPgh github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM= github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -215,20 +325,34 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lightstep/go-expohisto v1.0.0 h1:UPtTS1rGdtehbbAF7o/dhkWLTDI73UifG8LbfQI7cA4= github.com/lightstep/go-expohisto v1.0.0/go.mod h1:xDXD0++Mu2FOaItXtdDfksfgxfV0z1TMPa+e/EUd0cs= +github.com/linode/linodego v1.35.0 h1:rIhUeCHBLEDlkoRnOTwzSGzljQ3ksXwLxacmXnrV+Do= +github.com/linode/linodego v1.35.0/go.mod h1:JxuhOEAMfSxun6RU5/MgTKH2GGTmFrhKRj3wL1NFin0= github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY= github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -258,6 +382,8 @@ github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsc github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.105.0/go.mod h1:45iX3DRsbK2XlbHzEWtIvud56FE2XdC7crKIne4DUaU= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.105.0 h1:HcFHS9xNt2nI9yphhvvgWekr9zsP2jVi8IQUckAxCUk= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.105.0/go.mod h1:DB9+mDKgg/nO+vZca48EWvCTcOjHyjOeJKAbP+WfPXU= +github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.105.0 h1:L3zHDcjdhyvZatjv0jGAR9ShWYY4a9sDCBcdxCxdKcU= +github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.105.0/go.mod h1:plLxFSlZzwEa06qc/1pVH1EQISsnSsMX9PwXYKEB/sg= github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage v0.105.0 h1:HmimWATFFNI8o6n52DXTS2EjFRa6aETNqmA3MBGAxSI= github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage v0.105.0/go.mod h1:DoCIQkjzSFD/rRq9rsI4kzYKcHRn6B7g7txILM18dHQ= github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.105.0 h1:kHHL4A9wL6TxM2sIUEXUpFXGPxrW7u002FJK+majI0s= @@ -272,28 +398,42 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.105.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.105.0/go.mod h1:hzu5KvOYEH5W9OpVc+iRXUAvj7GHcLyyR4qjIH+hOhQ= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.105.0 h1:hs7TaJClEAhHrj71XcaYqlYnIOpOYQgoHqhnnBNrOK8= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.105.0/go.mod h1:ehzaiDdkrww7l1Stvse5GCOAsAZOpFcgeIbB/2PqFs4= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.105.0 h1:wKujcXESoQPBWIxYIET7YP6lN2idX8oZRsNl8iWXum0= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.105.0/go.mod h1:n9awPzI+erPm8NB8yL/UusWvF5P741BbHv5bcWYMXrc= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/azure v0.105.0 h1:PfbW/oTNBNOCzantcwnGXMuc+qhMSUhdcWnfO0qXEhs= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/azure v0.105.0/go.mod h1:NZsH4m+WpkVKuUYK6Te0Z012jjhfmVcVL3M1W/0Hw4w= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.105.0 h1:EIMptO6ZZeP734nBLxNVftrWA+OEGtgsxarNH7rao2A= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.105.0/go.mod h1:/2F91Hsx7RAn/FENz/7MRbHBkBYQ/uX6t4tYJfyeBfM= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.105.0 h1:hKpdsx8wzn/wA3hAavSEVKLUBfkYkpfXpudT+VUxucA= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.105.0/go.mod h1:1Tq47AVtrvxnohU1Is3EV/zv2ifPwdRSW735xG+zvFU= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.105.0 h1:60worMGZbZFw6djolg/CVExX6DPQoXgfM4pmdZj2b7E= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.105.0/go.mod h1:Nhq0L1GhTdyl/Td94xCiys0kJMO9lOsezhYRXz0MTvQ= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.105.0 h1:KGvKn2n/tV5aG3JlryEgXnnSVnY0O6YFWGOY72OI8MY= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.105.0/go.mod h1:NKh0a5RFTHnvxRRmjlV96ZzSc5xZrHr1yPRWxskjBB0= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kafkareceiver v0.105.0 h1:JADJYzFGjD3c7eVKYYAHxMFE9rBtMTEPM/4t8C8ww3Q= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kafkareceiver v0.105.0/go.mod h1:rGyiKbLfQyHk5Q+ZSGs4wH8kb2J+SbIlEiytjB/cDdI= +github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.105.0 h1:s2kcmrILHXgutAl3Slol4xlDUMJTYjEU7kppk3DkZ2s= +github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.105.0/go.mod h1:gBmEBZB1odOni3kBpY+EbOBcXOK3tDu2eoqegdSeXtY= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.105.0 h1:JLYDrRk4oJB5CZY49Q1AhvpN8Tnl8faPG0CqpnDOFIw= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.105.0/go.mod h1:73LyO27uXzwtEZrSq/7b1wi5FG9aHx6TUVcCDaxJ5mw= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/ovh/go-ovh v1.5.1 h1:P8O+7H+NQuFK9P/j4sFW5C0fvSS2DnHYGPwdVCp45wI= +github.com/ovh/go-ovh v1.5.1/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -311,8 +451,12 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/prometheus v0.53.0 h1:vOnhpUKrDv954jnVBvhG/ZQJ3kqscnKI+Hbdwo2tAhc= +github.com/prometheus/prometheus v0.53.0/go.mod h1:RZDkzs+ShMBDkAPQkLEaLBXpjmDcjhNxU2drUVPgKUU= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/relvacode/iso8601 v1.4.0 h1:GsInVSEJfkYuirYFxa80nMLbH2aydgZpIf52gYZXUJs= @@ -330,6 +474,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 h1:yGAraK1uUjlhSXgNMIy8o/J4LFNcy7yeipBqt9N9mVg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckySQL64= github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -382,6 +528,8 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMW github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= +github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -570,6 +718,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -631,6 +781,8 @@ golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -639,6 +791,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -652,6 +806,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -662,6 +818,8 @@ gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.183.0 h1:PNMeRDwo1pJdgNcFQ9GstuLe/noWKIc89pRWRLMvLwE= +google.golang.org/api v0.183.0/go.mod h1:q43adC5/pHoSZTx5h2mSmdF7NcyfW9JuDyIOJAgS9ZQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -715,4 +873,22 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/discovery/grpcresolver/grpc_resolver_test.go b/pkg/discovery/grpcresolver/grpc_resolver_test.go index 9256570cc6f..1843281dfe0 100644 --- a/pkg/discovery/grpcresolver/grpc_resolver_test.go +++ b/pkg/discovery/grpcresolver/grpc_resolver_test.go @@ -88,6 +88,9 @@ func makeSureConnectionsUp(t *testing.T, count int, testc grpc_testing.TestServi for si := 0; si < count; si++ { connected := false for i := 0; i < 3000; i++ { // 3000 * 10ms = 30s + if i != 0 { + time.Sleep(time.Millisecond * 10) + } _, err := testc.EmptyCall(context.Background(), &grpc_testing.Empty{}, grpc.Peer(&p)) if err != nil { continue @@ -98,7 +101,6 @@ func makeSureConnectionsUp(t *testing.T, count int, testc grpc_testing.TestServi t.Logf("connected to peer #%d (%v) on iteration %d", si, p.Addr, i) break } - time.Sleep(time.Millisecond * 10) } assert.True(t, connected, "Connection #%d was still not up. Connections so far: %+v", si, addrs) } diff --git a/pkg/prometheus/config/config.go b/pkg/prometheus/config/config.go index 122b831dea1..54ee6ea9398 100644 --- a/pkg/prometheus/config/config.go +++ b/pkg/prometheus/config/config.go @@ -17,19 +17,27 @@ package config import ( "time" + "github.com/asaskevich/govalidator" + "github.com/jaegertracing/jaeger/pkg/config/tlscfg" ) // Configuration describes the options to customize the storage behavior. type Configuration struct { - ServerURL string - ConnectTimeout time.Duration - TLS tlscfg.Options - TokenFilePath string - TokenOverrideFromContext bool - - MetricNamespace string - LatencyUnit string - NormalizeCalls bool - NormalizeDuration bool + ServerURL string `valid:"required" mapstructure:"endpoint"` + ConnectTimeout time.Duration `mapstructure:"connect_timeout"` + TLS tlscfg.Options + + TokenFilePath string `mapstructure:"token_file_path"` + TokenOverrideFromContext bool `mapstructure:"token_override_from_context"` + + MetricNamespace string `mapstructure:"metric_namespace"` + LatencyUnit string `mapstructure:"latency_unit"` + NormalizeCalls bool `mapstructure:"normalize_calls"` + NormalizeDuration bool `mapstructure:"normalize_duration"` +} + +func (c *Configuration) Validate() error { + _, err := govalidator.ValidateStruct(c) + return err } diff --git a/pkg/prometheus/config/empty_test.go b/pkg/prometheus/config/config_test.go similarity index 74% rename from pkg/prometheus/config/empty_test.go rename to pkg/prometheus/config/config_test.go index 2b7fcf4a4b8..d49f95c1141 100644 --- a/pkg/prometheus/config/empty_test.go +++ b/pkg/prometheus/config/config_test.go @@ -17,9 +17,22 @@ package config import ( "testing" + "github.com/stretchr/testify/require" + "github.com/jaegertracing/jaeger/pkg/testutils" ) +func TestValidate(t *testing.T) { + cfg := Configuration{ + ServerURL: "localhost:1234", + } + err := cfg.Validate() + require.NoError(t, err) + cfg = Configuration{} + err = cfg.Validate() + require.Error(t, err) +} + func TestMain(m *testing.M) { testutils.VerifyGoLeaks(m) } diff --git a/plugin/metrics/prometheus/factory.go b/plugin/metrics/prometheus/factory.go index a806942eb46..48fe906196e 100644 --- a/plugin/metrics/prometheus/factory.go +++ b/plugin/metrics/prometheus/factory.go @@ -22,6 +22,7 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" + "github.com/jaegertracing/jaeger/pkg/prometheus/config" "github.com/jaegertracing/jaeger/plugin" prometheusstore "github.com/jaegertracing/jaeger/plugin/metrics/prometheus/metricsstore" "github.com/jaegertracing/jaeger/storage/metricsstore" @@ -66,3 +67,18 @@ func (f *Factory) Initialize(logger *zap.Logger) error { func (f *Factory) CreateMetricsReader() (metricsstore.Reader, error) { return prometheusstore.NewMetricsReader(f.options.Configuration, f.logger, f.tracer) } + +func NewFactoryWithConfig( + cfg config.Configuration, + logger *zap.Logger, +) (*Factory, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + f := NewFactory() + f.options = &Options{ + Configuration: cfg, + } + f.Initialize(logger) + return f, nil +} diff --git a/plugin/metrics/prometheus/factory_test.go b/plugin/metrics/prometheus/factory_test.go index bd49eca32d5..cc677fb7f61 100644 --- a/plugin/metrics/prometheus/factory_test.go +++ b/plugin/metrics/prometheus/factory_test.go @@ -24,6 +24,7 @@ import ( "go.uber.org/zap" "github.com/jaegertracing/jaeger/pkg/config" + promCfg "github.com/jaegertracing/jaeger/pkg/prometheus/config" "github.com/jaegertracing/jaeger/pkg/testutils" "github.com/jaegertracing/jaeger/storage" ) @@ -134,6 +135,20 @@ func TestFailedTLSOptions(t *testing.T) { t.Errorf("f.InitFromViper did not panic") } +func TestEmptyFactoryConfig(t *testing.T) { + cfg := promCfg.Configuration{} + _, err := NewFactoryWithConfig(cfg, zap.NewNop()) + require.Error(t, err) +} + +func TestFactoryConfig(t *testing.T) { + cfg := promCfg.Configuration{ + ServerURL: "localhost:1234", + } + _, err := NewFactoryWithConfig(cfg, zap.NewNop()) + require.NoError(t, err) +} + func TestMain(m *testing.M) { testutils.VerifyGoLeaks(m) } diff --git a/plugin/metrics/prometheus/options.go b/plugin/metrics/prometheus/options.go index 80cf09e3070..2b4bd221a94 100644 --- a/plugin/metrics/prometheus/options.go +++ b/plugin/metrics/prometheus/options.go @@ -55,9 +55,8 @@ type Options struct { config.Configuration `mapstructure:",squash"` } -// NewOptions creates a new Options struct. -func NewOptions() *Options { - defaultConfig := config.Configuration{ +func DefaultConfig() config.Configuration { + return config.Configuration{ ServerURL: defaultServerURL, ConnectTimeout: defaultConnectTimeout, @@ -66,9 +65,12 @@ func NewOptions() *Options { NormalizeCalls: defaultNormalizeCalls, NormalizeDuration: defaultNormalizeCalls, } +} +// NewOptions creates a new Options struct. +func NewOptions() *Options { return &Options{ - Configuration: defaultConfig, + Configuration: DefaultConfig(), } } diff --git a/plugin/storage/integration/integration.go b/plugin/storage/integration/integration.go index f9ca020c41d..8ed6d905b83 100644 --- a/plugin/storage/integration/integration.go +++ b/plugin/storage/integration/integration.go @@ -49,7 +49,7 @@ var fixtures embed.FS // - in those functions it instantiates and populates this struct // - it then calls RunAll. // -// Some implementations may declate multuple tests, with different settings, +// Some implementations may declare multiple tests, with different settings, // and RunAll() under different conditions. type StorageIntegration struct { SpanWriter spanstore.Writer diff --git a/scripts/compare_metrics.py b/scripts/compare_metrics.py new file mode 100644 index 00000000000..98f0af80bd6 --- /dev/null +++ b/scripts/compare_metrics.py @@ -0,0 +1,62 @@ +# Run the following commands first to create the JSON files: +# Run V1 Binary +# prom2json http://localhost:14269/metrics > V1_Metrics.json +# Run V2 Binary +# prom2json http://localhost:8888/metrics > V2_Metrics.json + +import json + +# Load the JSON files +v1_metrics_path = "./V1_Metrics.json" +v2_metrics_path = "./V2_Metrics.json" + +with open(v1_metrics_path, 'r') as file: + v1_metrics = json.load(file) + +with open(v2_metrics_path, 'r') as file: + v2_metrics = json.load(file) + +# Extract names and labels of the metrics +def extract_metrics_with_labels(metrics): + result = {} + for metric in metrics: + name = metric['name'] + labels = {} + if 'metrics' in metric and 'labels' in metric['metrics'][0]: + labels = metric['metrics'][0]['labels'] + result[name] = labels + return result + +v1_metrics_with_labels = extract_metrics_with_labels(v1_metrics) +v2_metrics_with_labels = extract_metrics_with_labels(v2_metrics) + +# Compare the metrics names and labels +common_metrics = {} +v1_only_metrics = {} +v2_only_metrics = {} + +for name, labels in v1_metrics_with_labels.items(): + if name in v2_metrics_with_labels: + if labels == v2_metrics_with_labels[name]: + common_metrics[name] = labels + else: + v1_only_metrics[name] = labels + else: + v1_only_metrics[name] = labels + +for name, labels in v2_metrics_with_labels.items(): + if name not in v1_metrics_with_labels: + v2_only_metrics[name] = labels + +differences = { + "common_metrics": common_metrics, + "v1_only_metrics": v1_only_metrics, + "v2_only_metrics": v2_only_metrics +} + +# Write the differences to a new JSON file +differences_path = "./differences.json" +with open(differences_path, 'w') as file: + json.dump(differences, file, indent=4) + +print(f"Differences written to {differences_path}") \ No newline at end of file diff --git a/scripts/spm-integration-test.sh b/scripts/spm-integration-test.sh index 61e99911206..b9cf9204a8a 100755 --- a/scripts/spm-integration-test.sh +++ b/scripts/spm-integration-test.sh @@ -2,8 +2,34 @@ set -euf -o pipefail +print_help() { + echo "Usage: $0 [-b binary]" + echo "-b: Which binary to build: 'all-in-one' (default) or 'jaeger' (v2)" + echo "-h: Print help" + exit 1 +} + +BINARY='all-in-one' compose_file=docker-compose/monitor/docker-compose.yml -timeout=300 + +while getopts "b:h" opt; do + case "${opt}" in + b) + BINARY=${OPTARG} + ;; + *) + print_help + ;; + esac +done + +set -x + +if [ "$BINARY" == "jaeger" ]; then + compose_file=docker-compose/monitor/docker-compose-v2.yml +fi + +timeout=600 end_time=$((SECONDS + timeout)) success="false" @@ -12,7 +38,7 @@ check_service_health() { local url=$2 echo "Checking health of service: $service_name at $url" - local wait_seconds=10 + local wait_seconds=3 local curl_params=( --silent --output @@ -39,7 +65,7 @@ wait_for_services() { check_service_health "Jaeger" "http://localhost:16686" check_service_health "Prometheus" "http://localhost:9090/graph" # Grafana is not actually important for the functional test, - # but it at least validates that the docker-compose file is correct. + # but we still validate that the docker-compose file is correct. check_service_health "Grafana" "http://localhost:3000" } @@ -63,9 +89,9 @@ validate_service_metrics() { echo "Metric datapoints found for service '$service': " "${metric_points[@]}" # Check that atleast some values are non-zero after the threshold local non_zero_count=0 - local expected_non_zero_count=3 + local expected_non_zero_count=4 local zero_count=0 - local expected_max_zero_count=3 + local expected_max_zero_count=4 for value in "${metric_points[@]}"; do if [[ $(echo "$value > 0.0" | bc) == "1" ]]; then non_zero_count=$((non_zero_count + 1)) @@ -79,7 +105,7 @@ validate_service_metrics() { fi done if [ $non_zero_count -lt $expected_non_zero_count ]; then - echo "⏳ Expecting at least 3 non-zero data points" + echo "⏳ Expecting at least 4 non-zero data points" return 1 fi return 0 @@ -122,7 +148,11 @@ teardown_services() { } main() { - (cd docker-compose/monitor && make build && make dev DOCKER_COMPOSE_ARGS="-d") + if [ "$BINARY" == "jaeger" ]; then + (cd docker-compose/monitor && make build BINARY="$BINARY" && make dev-v2 DOCKER_COMPOSE_ARGS="-d") + else + (cd docker-compose/monitor && make build BINARY="$BINARY" && make dev DOCKER_COMPOSE_ARGS="-d") + fi wait_for_services check_spm success="true"