diff --git a/.codecov.yml b/.codecov.yml index c6449f90d71..bb9bed99e54 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -23,9 +23,7 @@ coverage: project: default: enabled: yes - # Temporarily lower threshold below 95% - # Tacked in https://github.com/jaegertracing/jaeger/issues/5194 - target: 94.4% + target: 95% patch: default: enabled: yes diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c518e5fc8f0..329a54799eb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -18,9 +18,6 @@ updates: otel-instrumentation: patterns: - "go.opentelemetry.io/contrib/instrumentation/*" - hashicorp: - patterns: - - "github.com/hashicorp/*" - package-ecosystem: "github-actions" directory: "/" diff --git a/.github/workflows/ci-elasticsearch.yml b/.github/workflows/ci-elasticsearch.yml index 6c2175c8971..a87e511b785 100644 --- a/.github/workflows/ci-elasticsearch.yml +++ b/.github/workflows/ci-elasticsearch.yml @@ -21,12 +21,6 @@ jobs: strategy: matrix: version: - - major: 5.x - image: 5.6.16 - distribution: elasticsearch - - major: 6.x - image: 6.8.18 - distribution: elasticsearch - major: 7.x image: 7.14.0 distribution: elasticsearch diff --git a/.github/workflows/ci-lint-checks.yaml b/.github/workflows/ci-lint-checks.yaml index 616495c67b0..c6efb1411cc 100644 --- a/.github/workflows/ci-lint-checks.yaml +++ b/.github/workflows/ci-lint-checks.yaml @@ -14,7 +14,7 @@ concurrency: # See https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions permissions: # added using https://github.com/step-security/secure-workflows contents: read - + jobs: lint: runs-on: ubuntu-latest @@ -30,11 +30,14 @@ jobs: with: go-version: 1.22.x + - name: Print Jaeger version + run: make echo-version + - name: Install tools run: make install-test-tools - name: Lint run: make lint - + - name: Ensure PR is not on main branch - uses: ./.github/actions/block-pr-not-on-main \ No newline at end of file + uses: ./.github/actions/block-pr-not-on-main diff --git a/.github/workflows/ci-unit-tests.yml b/.github/workflows/ci-unit-tests.yml index b23bf0e44ff..7be1d1929f9 100644 --- a/.github/workflows/ci-unit-tests.yml +++ b/.github/workflows/ci-unit-tests.yml @@ -32,6 +32,10 @@ jobs: go-version: 1.22.x cache-dependency-path: ./go.sum + # download dependencies separately to keep unit test step's output cleaner + - name: go mod download + run: go mod download + - name: Install test deps # even though the same target runs from test-ci, running it separately makes for cleaner log in GH workflow run: make install-test-tools diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 97323a31371..e9ecaf44277 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -24,4 +24,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@5bbc3ba658137598168acb2ab73b21c432dd411b # v4.2.5 + uses: actions/dependency-review-action@0c155c5e8556a497adf53f2c18edabf945ed8e70 # v4.3.2 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 86b617092e1..0a9bf0698f1 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,7 +42,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 with: results_file: results.sarif results_format: sarif diff --git a/.gitignore b/.gitignore index 63cd11b81bd..73b86d9b398 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ cover.html vendor/ examples/hotrod/hotrod examples/hotrod/hotrod-* -examples/memstore-plugin/memstore-plugin cmd/all-in-one/all-in-one-* cmd/agent/agent cmd/agent/agent-* diff --git a/Makefile b/Makefile index 863b0c66718..7055dad4630 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,9 @@ IMPORT_LOG=.import.log COLORIZE ?= | $(SED) 's/PASS/✅ PASS/g' | $(SED) 's/FAIL/❌ FAIL/g' | $(SED) 's/SKIP/🔕 SKIP/g' GIT_SHA=$(shell git rev-parse HEAD) -GIT_CLOSEST_TAG=$(shell git describe --abbrev=0 --tags) +GIT_SHALLOW_CLONE := $(shell git rev-parse --is-shallow-repository) +# Some of GitHub Actions workflows do a shallow checkout without tags. This avoids logging warnings from git. +GIT_CLOSEST_TAG=$(shell if [ "$(GIT_SHALLOW_CLONE)" = "false" ]; then git describe --abbrev=0 --tags; else echo 0.0.0; fi) ifneq ($(GIT_CLOSEST_TAG),$(shell echo ${GIT_CLOSEST_TAG} | grep -E "$(semver_regex)")) $(warning GIT_CLOSEST_TAG=$(GIT_CLOSEST_TAG) is not in the semver format $(semver_regex)) endif @@ -91,9 +93,15 @@ include Makefile.Crossdock.mk .PHONY: test-and-lint test-and-lint: test fmt lint +.PHONY: echo-version +echo-version: + @echo "GIT_CLOSEST_TAG=$(GIT_CLOSEST_TAG)" + +.PHONY: echo-all-pkgs echo-all-pkgs: @echo $(ALL_PKGS) | tr ' ' '\n' | sort +.PHONY: echo-all-srcs echo-all-srcs: @echo $(ALL_SRC) | tr ' ' '\n' | sort @@ -139,7 +147,6 @@ badger-storage-integration-test: .PHONY: grpc-storage-integration-test grpc-storage-integration-test: - (cd examples/memstore-plugin/ && go build .) STORAGE=grpc $(MAKE) storage-integration-test # this test assumes STORAGE environment variable is set to elasticsearch|opensearch @@ -475,10 +482,6 @@ generate-mocks: install-tools $(MOCKERY) --all --dir ./storage/spanstore/ --output ./storage/spanstore/mocks $(MOCKERY) --all --dir ./proto-gen/storage_v1/ --output ./proto-gen/storage_v1/mocks -.PHONY: echo-version -echo-version: - @echo $(GIT_CLOSEST_TAG) - .PHONY: certs certs: cd pkg/config/tlscfg/testdata && ./gen-certs.sh diff --git a/cmd/agent/app/reporter/grpc/collector_proxy_test.go b/cmd/agent/app/reporter/grpc/collector_proxy_test.go index c6cf803420f..4d717c809d2 100644 --- a/cmd/agent/app/reporter/grpc/collector_proxy_test.go +++ b/cmd/agent/app/reporter/grpc/collector_proxy_test.go @@ -18,6 +18,7 @@ import ( "context" "io" "net" + "sync" "testing" "time" @@ -35,15 +36,13 @@ var _ io.Closer = (*ProxyBuilder)(nil) func TestMultipleCollectors(t *testing.T) { spanHandler1 := &mockSpanHandler{} - s1, addr1 := initializeGRPCTestServer(t, func(s *grpc.Server) { + _, addr1 := initializeGRPCTestServer(t, func(s *grpc.Server) { api_v2.RegisterCollectorServiceServer(s, spanHandler1) }) - defer s1.Stop() spanHandler2 := &mockSpanHandler{} - s2, addr2 := initializeGRPCTestServer(t, func(s *grpc.Server) { + _, addr2 := initializeGRPCTestServer(t, func(s *grpc.Server) { api_v2.RegisterCollectorServiceServer(s, spanHandler2) }) - defer s2.Stop() mFactory := metricstest.NewFactory(time.Microsecond) defer mFactory.Stop() @@ -79,8 +78,15 @@ func initializeGRPCTestServer(t *testing.T, beforeServe func(server *grpc.Server lis, err := net.Listen("tcp", "localhost:0") require.NoError(t, err) beforeServe(server) + var wg sync.WaitGroup + wg.Add(1) go func() { require.NoError(t, server.Serve(lis)) + wg.Done() }() + t.Cleanup(func() { + server.Stop() + wg.Wait() + }) return server, lis.Addr() } diff --git a/cmd/esmapping-generator/app/renderer/render_test.go b/cmd/esmapping-generator/app/renderer/render_test.go index b971d800d87..e8245b24696 100644 --- a/cmd/esmapping-generator/app/renderer/render_test.go +++ b/cmd/esmapping-generator/app/renderer/render_test.go @@ -56,14 +56,6 @@ func Test_getMappingAsString(t *testing.T) { name: "ES version 7", args: app.Options{Mapping: "jaeger-span", EsVersion: 7, Shards: 5, Replicas: 1, IndexPrefix: "test", UseILM: "true", ILMPolicyName: "jaeger-test-policy"}, want: "ES version 7", }, - { - name: "ES version 6", args: app.Options{Mapping: "jaeger-span", EsVersion: 6, Shards: 5, Replicas: 1, IndexPrefix: "test", UseILM: "false", ILMPolicyName: "jaeger-test-policy"}, - want: "ES version 6", - }, - { - name: "Parse Error version 6", args: app.Options{Mapping: "jaeger-span", EsVersion: 6, Shards: 5, Replicas: 1, IndexPrefix: "test", UseILM: "false", ILMPolicyName: "jaeger-test-policy"}, - wantErr: errors.New("parse error"), - }, { name: "Parse Error version 7", args: app.Options{Mapping: "jaeger-span", EsVersion: 7, Shards: 5, Replicas: 1, IndexPrefix: "test", UseILM: "true", ILMPolicyName: "jaeger-test-policy"}, wantErr: errors.New("parse error"), diff --git a/cmd/jaeger/config-remote-storage.yaml b/cmd/jaeger/config-remote-storage.yaml index 0da873500bd..98a438bd779 100644 --- a/cmd/jaeger/config-remote-storage.yaml +++ b/cmd/jaeger/config-remote-storage.yaml @@ -14,8 +14,10 @@ extensions: jaeger_storage: grpc: external-storage: - server: localhost:17271 - connection-timeout: 5s + endpoint: localhost:17271 + timeout: 5s + tls: + insecure: true receivers: otlp: diff --git a/cmd/jaeger/internal/exporters/storageexporter/factory.go b/cmd/jaeger/internal/exporters/storageexporter/factory.go index 10a54959964..2638a949dbe 100644 --- a/cmd/jaeger/internal/exporters/storageexporter/factory.go +++ b/cmd/jaeger/internal/exporters/storageexporter/factory.go @@ -40,7 +40,7 @@ func createTracesExporter(ctx context.Context, set exporter.CreateSettings, conf exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), // Disable Timeout/RetryOnFailure and SendingQueue exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}), - exporterhelper.WithRetry(configretry.NewDefaultBackOffConfig()), + exporterhelper.WithRetry(configretry.BackOffConfig{Enabled: false}), exporterhelper.WithQueue(exporterhelper.QueueSettings{Enabled: false}), exporterhelper.WithStart(ex.start), exporterhelper.WithShutdown(ex.close), diff --git a/cmd/jaeger/internal/extension/jaegerquery/server_test.go b/cmd/jaeger/internal/extension/jaegerquery/server_test.go index e6800a79aa8..91a8360fd5d 100644 --- a/cmd/jaeger/internal/extension/jaegerquery/server_test.go +++ b/cmd/jaeger/internal/extension/jaegerquery/server_test.go @@ -101,7 +101,7 @@ func (storageHost) GetExporters() map[component.DataType]map[component.ID]compon func TestServerDependencies(t *testing.T) { expectedDependencies := []component.ID{jaegerstorage.ID} telemetrySettings := component.TelemetrySettings{ - Logger: zaptest.NewLogger(t), + Logger: zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())), } server := newServer(createDefaultConfig().(*Config), telemetrySettings) @@ -160,7 +160,7 @@ func TestServerStart(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { telemetrySettings := component.TelemetrySettings{ - Logger: zaptest.NewLogger(t), + Logger: zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())), } server := newServer(tt.config, telemetrySettings) err := server.Start(context.Background(), host) diff --git a/cmd/jaeger/internal/extension/jaegerstorage/config.go b/cmd/jaeger/internal/extension/jaegerstorage/config.go index 542c5a6437a..1e6128cda93 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/config.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/config.go @@ -18,7 +18,7 @@ import ( type Config struct { Memory map[string]memoryCfg.Configuration `mapstructure:"memory"` Badger map[string]badgerCfg.NamespaceConfig `mapstructure:"badger"` - GRPC map[string]grpcCfg.Configuration `mapstructure:"grpc"` + GRPC map[string]grpcCfg.ConfigV2 `mapstructure:"grpc"` Opensearch map[string]esCfg.Configuration `mapstructure:"opensearch"` Elasticsearch map[string]esCfg.Configuration `mapstructure:"elasticsearch"` Cassandra map[string]cassandra.Options `mapstructure:"cassandra"` diff --git a/cmd/jaeger/internal/extension/jaegerstorage/extension.go b/cmd/jaeger/internal/extension/jaegerstorage/extension.go index a5442b82ff1..23709c00d3b 100644 --- a/cmd/jaeger/internal/extension/jaegerstorage/extension.go +++ b/cmd/jaeger/internal/extension/jaegerstorage/extension.go @@ -117,7 +117,7 @@ func (s *storageExt) Start(ctx context.Context, host component.Host) error { cfg: s.config.Badger, builder: badger.NewFactoryWithConfig, } - grpcStarter := &starter[grpcCfg.Configuration, *grpc.Factory]{ + grpcStarter := &starter[grpcCfg.ConfigV2, *grpc.Factory]{ ext: s, storageKind: "grpc", cfg: s.config.GRPC, diff --git a/cmd/jaeger/internal/integration/badger_test.go b/cmd/jaeger/internal/integration/badger_test.go index c57eb7fdeb9..a0fe00f669a 100644 --- a/cmd/jaeger/internal/integration/badger_test.go +++ b/cmd/jaeger/internal/integration/badger_test.go @@ -15,7 +15,6 @@ func TestBadgerStorage(t *testing.T) { s := &E2EStorageIntegration{ ConfigFile: "../../config-badger.yaml", StorageIntegration: integration.StorageIntegration{ - SkipBinaryAttrs: true, SkipArchiveTest: true, CleanUp: purge, diff --git a/cmd/jaeger/internal/integration/cassandra_test.go b/cmd/jaeger/internal/integration/cassandra_test.go index f04cb335ee7..0ac74c13149 100644 --- a/cmd/jaeger/internal/integration/cassandra_test.go +++ b/cmd/jaeger/internal/integration/cassandra_test.go @@ -17,7 +17,6 @@ func TestCassandraStorage(t *testing.T) { CleanUp: purge, GetDependenciesReturnsSource: true, SkipArchiveTest: true, - SkipBinaryAttrs: true, SkipList: integration.CassandraSkippedTests, }, diff --git a/cmd/jaeger/internal/integration/e2e_integration.go b/cmd/jaeger/internal/integration/e2e_integration.go index c140f7d1c3a..be8c9a9c00a 100644 --- a/cmd/jaeger/internal/integration/e2e_integration.go +++ b/cmd/jaeger/internal/integration/e2e_integration.go @@ -45,7 +45,7 @@ type E2EStorageIntegration struct { // it also initialize the SpanWriter and SpanReader below. // 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.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) configFile := createStorageCleanerConfig(t, s.ConfigFile, storage) t.Logf("Starting Jaeger-v2 in the background with config file %s", configFile) @@ -98,14 +98,14 @@ func (s *E2EStorageIntegration) e2eInitialize(t *testing.T, storage string) { // 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") + 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) + 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) + fmt.Printf("🚧 🚧 🚧 Jaeger-v2 error logs:\n%s", errLogs) // End of Github Actions foldable section annotation. fmt.Println("::endgroup::") } @@ -113,7 +113,7 @@ func (s *E2EStorageIntegration) e2eInitialize(t *testing.T, storage string) { s.SpanWriter, err = createSpanWriter(logger, otlpPort) require.NoError(t, err) - s.SpanReader, err = createSpanReader(ports.QueryGRPC) + s.SpanReader, err = createSpanReader(logger, ports.QueryGRPC) require.NoError(t, err) } diff --git a/cmd/jaeger/internal/integration/es_test.go b/cmd/jaeger/internal/integration/es_test.go index 840cda5d2f2..92b9f0c79e0 100644 --- a/cmd/jaeger/internal/integration/es_test.go +++ b/cmd/jaeger/internal/integration/es_test.go @@ -17,7 +17,6 @@ func TestESStorage(t *testing.T) { StorageIntegration: integration.StorageIntegration{ CleanUp: purge, Fixtures: integration.LoadAndParseQueryTestCases(t, "fixtures/queries_es.json"), - SkipBinaryAttrs: true, GetOperationsMissingSpanKind: true, }, } diff --git a/cmd/jaeger/internal/integration/grpc_test.go b/cmd/jaeger/internal/integration/grpc_test.go index 79f1f85f7fa..b33b7b002a0 100644 --- a/cmd/jaeger/internal/integration/grpc_test.go +++ b/cmd/jaeger/internal/integration/grpc_test.go @@ -30,9 +30,6 @@ func TestGRPCStorage(t *testing.T) { s := &GRPCStorageIntegration{ E2EStorageIntegration: E2EStorageIntegration{ ConfigFile: "../../config-remote-storage.yaml", - StorageIntegration: integration.StorageIntegration{ - SkipBinaryAttrs: true, - }, }, } s.CleanUp = s.cleanUp diff --git a/cmd/jaeger/internal/integration/os_test.go b/cmd/jaeger/internal/integration/os_test.go index 944afe56fe1..a5d3e945214 100644 --- a/cmd/jaeger/internal/integration/os_test.go +++ b/cmd/jaeger/internal/integration/os_test.go @@ -16,7 +16,6 @@ func TestOSStorage(t *testing.T) { StorageIntegration: integration.StorageIntegration{ CleanUp: purge, Fixtures: integration.LoadAndParseQueryTestCases(t, "fixtures/queries_es.json"), - SkipBinaryAttrs: true, GetOperationsMissingSpanKind: true, }, } diff --git a/cmd/jaeger/internal/integration/span_reader.go b/cmd/jaeger/internal/integration/span_reader.go index 9d2d61b9658..eb878836133 100644 --- a/cmd/jaeger/internal/integration/span_reader.go +++ b/cmd/jaeger/internal/integration/span_reader.go @@ -10,8 +10,8 @@ import ( "io" "math" "strings" - "time" + "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" @@ -29,31 +29,31 @@ var ( // SpanReader retrieve span data from Jaeger-v2 query with api_v2.QueryServiceClient. type spanReader struct { + logger *zap.Logger clientConn *grpc.ClientConn client api_v2.QueryServiceClient } -func createSpanReader(port int) (*spanReader, error) { +func createSpanReader(logger *zap.Logger, port int) (*spanReader, error) { + logger.Info("Creating the span reader", zap.Int("port", port)) opts := []grpc.DialOption{ - grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()), } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - cc, err := grpc.DialContext(ctx, ports.PortToHostPort(port), opts...) + cc, err := grpc.NewClient(ports.PortToHostPort(port), opts...) if err != nil { return nil, err } return &spanReader{ + logger: logger, clientConn: cc, client: api_v2.NewQueryServiceClient(cc), }, nil } func (r *spanReader) Close() error { + r.logger.Info("Closing the span writer") return r.clientConn.Close() } @@ -82,7 +82,9 @@ func (r *spanReader) GetTrace(ctx context.Context, traceID model.TraceID) (*mode for i := range received.Spans { spans = append(spans, &received.Spans[i]) } + // r.logger.Info(fmt.Sprintf("GetTrace received %d spans (total %d)", len(received.Spans), len(spans))) } + r.logger.Info(fmt.Sprintf("GetTraces received a total of %d spans", len(spans))) return &model.Trace{ Spans: spans, @@ -94,6 +96,7 @@ func (r *spanReader) GetServices(ctx context.Context) ([]string, error) { if err != nil { return []string{}, err } + r.logger.Info(fmt.Sprintf("Received %d services", len(res.Services))) return res.Services, nil } @@ -106,6 +109,7 @@ func (r *spanReader) GetOperations(ctx context.Context, query spanstore.Operatio if err != nil { return operations, err } + r.logger.Info(fmt.Sprintf("Received %d operations", len(res.Operations))) for _, operation := range res.Operations { operations = append(operations, spanstore.Operation{ @@ -138,6 +142,7 @@ func (r *spanReader) FindTraces(ctx context.Context, query *spanstore.TraceQuery return traces, err } + totalSpans := 0 spanMaps := map[string][]*model.Span{} for received, err := stream.Recv(); !errors.Is(err, io.EOF); received, err = stream.Recv() { if err != nil { @@ -150,7 +155,10 @@ func (r *spanReader) FindTraces(ctx context.Context, query *spanstore.TraceQuery } spanMaps[traceID] = append(spanMaps[traceID], &received.Spans[i]) } + totalSpans += len(received.Spans) + r.logger.Info(fmt.Sprintf("FindTraces received %d spans (total %d)", len(received.Spans), totalSpans)) } + r.logger.Info(fmt.Sprintf("FindTraces received a total of %d spans", totalSpans)) for _, spans := range spanMaps { traces = append(traces, &model.Trace{ diff --git a/cmd/jaeger/internal/integration/span_writer.go b/cmd/jaeger/internal/integration/span_writer.go index 426301eee98..60c817cdf0e 100644 --- a/cmd/jaeger/internal/integration/span_writer.go +++ b/cmd/jaeger/internal/integration/span_writer.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "io" + "time" jaeger2otlp "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger" "go.opentelemetry.io/collector/component/componenttest" @@ -27,13 +28,18 @@ var ( // SpanWriter utilizes the OTLP exporter to send span data to the Jaeger-v2 receiver type spanWriter struct { + logger *zap.Logger exporter exporter.Traces } func createSpanWriter(logger *zap.Logger, port int) (*spanWriter, error) { + logger.Info("Creating the span writer", zap.Int("port", port)) + factory := otlpexporter.NewFactory() cfg := factory.CreateDefaultConfig().(*otlpexporter.Config) cfg.Endpoint = fmt.Sprintf("localhost:%d", port) + cfg.Timeout = 30 * time.Second + cfg.RetryConfig.Enabled = false cfg.QueueConfig.Enabled = false cfg.TLSSetting = configtls.ClientConfig{ Insecure: true, @@ -51,11 +57,13 @@ func createSpanWriter(logger *zap.Logger, port int) (*spanWriter, error) { } return &spanWriter{ + logger: logger, exporter: exporter, }, nil } func (w *spanWriter) Close() error { + w.logger.Info("Closing the span writer") return w.exporter.Shutdown(context.Background()) } diff --git a/cmd/query/app/grpc_handler_test.go b/cmd/query/app/grpc_handler_test.go index 72c524f79af..bec65d371b3 100644 --- a/cmd/query/app/grpc_handler_test.go +++ b/cmd/query/app/grpc_handler_test.go @@ -174,10 +174,7 @@ func newGRPCServer(t *testing.T, q *querysvc.QueryService, mq querysvc.MetricsQu } func newGRPCClient(t *testing.T, addr string) *grpcClient { - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - // TODO: Need to replace grpc.DialContext with grpc.NewClient and pass test - conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) return &grpcClient{ diff --git a/cmd/query/app/server.go b/cmd/query/app/server.go index 9c34bc26018..719f3957778 100644 --- a/cmd/query/app/server.go +++ b/cmd/query/app/server.go @@ -308,7 +308,7 @@ func (s *Server) Start() error { if err != nil && !errors.Is(err, http.ErrServerClosed) && !errors.Is(err, cmux.ErrListenerClosed) && !errors.Is(err, cmux.ErrServerClosed) { s.logger.Error("Could not start HTTP server", zap.Error(err)) } - + s.logger.Info("HTTP server stopped", zap.Int("port", httpPort), zap.String("addr", s.queryOptions.HTTPHostPort)) s.healthCheck.Set(healthcheck.Unavailable) s.bgFinished.Done() }() @@ -321,6 +321,7 @@ func (s *Server) Start() error { if err := s.grpcServer.Serve(s.grpcConn); err != nil { s.logger.Error("Could not start GRPC server", zap.Error(err)) } + s.logger.Info("GRPC server stopped", zap.Int("port", grpcPort), zap.String("addr", s.queryOptions.GRPCHostPort)) s.healthCheck.Set(healthcheck.Unavailable) s.bgFinished.Done() }() diff --git a/cmd/query/app/server_test.go b/cmd/query/app/server_test.go index 4a08c7b4f29..cd6ab915b1e 100644 --- a/cmd/query/app/server_test.go +++ b/cmd/query/app/server_test.go @@ -27,6 +27,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap" + "go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest/observer" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -66,7 +67,7 @@ func TestCreateTLSServerSinglePortError(t *testing.T) { ClientCAPath: testCertKeyLocation + "/example-CA-cert.pem", } - _, err := NewServer(zap.NewNop(), healthcheck.New(), &querysvc.QueryService{}, nil, + _, err := NewServer(zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, &QueryOptions{HTTPHostPort: ":8080", GRPCHostPort: ":8080", TLSGRPC: tlsCfg, TLSHTTP: tlsCfg}, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.Error(t, err) @@ -80,7 +81,7 @@ func TestCreateTLSGrpcServerError(t *testing.T) { ClientCAPath: "invalid/path", } - _, err := NewServer(zap.NewNop(), healthcheck.New(), &querysvc.QueryService{}, nil, + _, err := NewServer(zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, &QueryOptions{HTTPHostPort: ":8080", GRPCHostPort: ":8081", TLSGRPC: tlsCfg}, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.Error(t, err) @@ -94,7 +95,7 @@ func TestCreateTLSHttpServerError(t *testing.T) { ClientCAPath: "invalid/path", } - _, err := NewServer(zap.NewNop(), healthcheck.New(), &querysvc.QueryService{}, nil, + _, err := NewServer(zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, &QueryOptions{HTTPHostPort: ":8080", GRPCHostPort: ":8081", TLSHTTP: tlsCfg}, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.Error(t, err) @@ -283,6 +284,27 @@ var testCases = []struct { }, } +type fakeQueryService struct { + qs *querysvc.QueryService + spanReader *spanstoremocks.Reader + dependencyReader *depsmocks.Reader + expectedServices []string +} + +func makeQuerySvc() *fakeQueryService { + spanReader := &spanstoremocks.Reader{} + dependencyReader := &depsmocks.Reader{} + expectedServices := []string{"test"} + spanReader.On("GetServices", mock.AnythingOfType("*context.valueCtx")).Return(expectedServices, nil) + qs := querysvc.NewQueryService(spanReader, dependencyReader, querysvc.QueryServiceOptions{}) + return &fakeQueryService{ + qs: qs, + spanReader: spanReader, + dependencyReader: dependencyReader, + expectedServices: expectedServices, + } +} + func TestServerHTTPTLS(t *testing.T) { testlen := len(testCases) @@ -331,29 +353,25 @@ func TestServerHTTPTLS(t *testing.T) { }, } flagsSvc := flags.NewService(ports.QueryAdminHTTP) - flagsSvc.Logger = zap.NewNop() + flagsSvc.Logger = zaptest.NewLogger(t) - spanReader := &spanstoremocks.Reader{} - dependencyReader := &depsmocks.Reader{} - expectedServices := []string{"test"} - spanReader.On("GetServices", mock.AnythingOfType("*context.valueCtx")).Return(expectedServices, nil) - - querySvc := querysvc.NewQueryService(spanReader, dependencyReader, querysvc.QueryServiceOptions{}) - server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc, + querySvc := makeQuerySvc() + server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc.qs, nil, serverOptions, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.NoError(t, err) require.NoError(t, server.Start()) + t.Cleanup(func() { + require.NoError(t, server.Close()) + }) var clientError error var clientClose func() error var clientTLSCfg *tls.Config if serverOptions.TLSHTTP.Enabled { - var err0 error - - clientTLSCfg, err0 = test.clientTLS.Config(zap.NewNop()) + clientTLSCfg, err0 = test.clientTLS.Config(flagsSvc.Logger) defer test.clientTLS.Close() require.NoError(t, err0) @@ -390,8 +408,7 @@ func TestServerHTTPTLS(t *testing.T) { TLSClientConfig: clientTLSCfg, }, } - readMock := spanReader - readMock.On("FindTraces", mock.AnythingOfType("*context.valueCtx"), mock.AnythingOfType("*spanstore.TraceQueryParameters")).Return([]*model.Trace{mockTrace}, nil).Once() + querySvc.spanReader.On("FindTraces", mock.Anything, mock.Anything).Return([]*model.Trace{mockTrace}, nil).Once() queryString := "/api/traces?service=service&start=0&end=0&operation=operation&limit=200&minDuration=20ms" req, err := http.NewRequest(http.MethodGet, "https://localhost:"+fmt.Sprintf("%d", ports.QueryHTTP)+queryString, nil) require.NoError(t, err) @@ -408,24 +425,18 @@ func TestServerHTTPTLS(t *testing.T) { require.NoError(t, err2) } } - server.Close() - assert.Equal(t, healthcheck.Unavailable, flagsSvc.HC().Get()) }) } } func newGRPCClientWithTLS(t *testing.T, addr string, creds credentials.TransportCredentials) *grpcClient { - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() var conn *grpc.ClientConn var err error if creds != nil { - // TODO: Need to replace grpc.DialContext with grpc.NewClient and pass test - conn, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(creds)) + conn, err = grpc.NewClient(addr, grpc.WithTransportCredentials(creds)) } else { - // TODO: Need to replace grpc.DialContext with grpc.NewClient and pass test - conn, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err = grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) } require.NoError(t, err) @@ -481,56 +492,54 @@ func TestServerGRPCTLS(t *testing.T) { }, } flagsSvc := flags.NewService(ports.QueryAdminHTTP) - flagsSvc.Logger = zap.NewNop() - - spanReader := &spanstoremocks.Reader{} - dependencyReader := &depsmocks.Reader{} - expectedServices := []string{"test"} - spanReader.On("GetServices", mock.AnythingOfType("*context.valueCtx")).Return(expectedServices, nil) + flagsSvc.Logger = zaptest.NewLogger(t) - querySvc := querysvc.NewQueryService(spanReader, dependencyReader, querysvc.QueryServiceOptions{}) - server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc, + querySvc := makeQuerySvc() + server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc.qs, nil, serverOptions, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.NoError(t, err) require.NoError(t, server.Start()) + t.Cleanup(func() { + require.NoError(t, server.Close()) + }) - var clientError error var client *grpcClient - if serverOptions.TLSGRPC.Enabled { - clientTLSCfg, err0 := test.clientTLS.Config(zap.NewNop()) + clientTLSCfg, err0 := test.clientTLS.Config(flagsSvc.Logger) require.NoError(t, err0) defer test.clientTLS.Close() creds := credentials.NewTLS(clientTLSCfg) client = newGRPCClientWithTLS(t, ports.PortToHostPort(ports.QueryGRPC), creds) - } else { client = newGRPCClientWithTLS(t, ports.PortToHostPort(ports.QueryGRPC), nil) } + t.Cleanup(func() { + require.NoError(t, client.conn.Close()) + }) - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + // using generous timeout since grpc.NewClient no longer does a handshake. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() + flagsSvc.Logger.Info("calling client.GetServices()") res, clientError := client.GetServices(ctx, &api_v2.GetServicesRequest{}) + flagsSvc.Logger.Info("returned from GetServices()") if test.expectClientError { require.Error(t, clientError) } else { require.NoError(t, clientError) - assert.Equal(t, expectedServices, res.Services) + assert.Equal(t, querySvc.expectedServices, res.Services) } - require.NoError(t, client.conn.Close()) - server.Close() - assert.Equal(t, healthcheck.Unavailable, flagsSvc.HC().Get()) }) } } func TestServerBadHostPort(t *testing.T) { - _, err := NewServer(zap.NewNop(), healthcheck.New(), &querysvc.QueryService{}, nil, + _, err := NewServer(zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, &QueryOptions{ - HTTPHostPort: "8080", + HTTPHostPort: "8080", // bad string, not :port GRPCHostPort: "127.0.0.1:8081", QueryOptionsBase: QueryOptionsBase{ BearerTokenPropagation: true, @@ -538,12 +547,12 @@ func TestServerBadHostPort(t *testing.T) { }, tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) - require.Error(t, err) - _, err = NewServer(zap.NewNop(), healthcheck.New(), &querysvc.QueryService{}, nil, + + _, err = NewServer(zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, &QueryOptions{ HTTPHostPort: "127.0.0.1:8081", - GRPCHostPort: "9123", + GRPCHostPort: "9123", // bad string, not :port QueryOptionsBase: QueryOptionsBase{ BearerTokenPropagation: true, }, @@ -571,7 +580,7 @@ func TestServerInUseHostPort(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { server, err := NewServer( - zap.NewNop(), + zaptest.NewLogger(t), healthcheck.New(), &querysvc.QueryService{}, nil, @@ -586,10 +595,7 @@ func TestServerInUseHostPort(t *testing.T) { jtracer.NoOp(), ) require.NoError(t, err) - - err = server.Start() - require.Error(t, err) - + require.Error(t, server.Start()) server.Close() }) } @@ -597,15 +603,10 @@ func TestServerInUseHostPort(t *testing.T) { func TestServerSinglePort(t *testing.T) { flagsSvc := flags.NewService(ports.QueryAdminHTTP) - flagsSvc.Logger = zap.NewNop() + flagsSvc.Logger = zaptest.NewLogger(t) hostPort := ports.GetAddressFromCLIOptions(ports.QueryHTTP, "") - spanReader := &spanstoremocks.Reader{} - dependencyReader := &depsmocks.Reader{} - expectedServices := []string{"test"} - spanReader.On("GetServices", mock.AnythingOfType("*context.valueCtx")).Return(expectedServices, nil) - - querySvc := querysvc.NewQueryService(spanReader, dependencyReader, querysvc.QueryServiceOptions{}) - server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc, nil, + querySvc := makeQuerySvc() + server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc.qs, nil, &QueryOptions{ GRPCHostPort: hostPort, HTTPHostPort: hostPort, @@ -617,19 +618,22 @@ func TestServerSinglePort(t *testing.T) { jtracer.NoOp()) require.NoError(t, err) require.NoError(t, server.Start()) + t.Cleanup(func() { + require.NoError(t, server.Close()) + }) client := newGRPCClient(t, hostPort) - defer client.conn.Close() + t.Cleanup(func() { + require.NoError(t, client.conn.Close()) + }) - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + // using generous timeout since grpc.NewClient no longer does a handshake. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() res, err := client.GetServices(ctx, &api_v2.GetServicesRequest{}) require.NoError(t, err) - assert.Equal(t, expectedServices, res.Services) - - server.Close() - assert.Equal(t, healthcheck.Unavailable, flagsSvc.HC().Get()) + assert.Equal(t, querySvc.expectedServices, res.Services) } func TestServerGracefulExit(t *testing.T) { @@ -641,20 +645,27 @@ func TestServerGracefulExit(t *testing.T) { flagsSvc.Logger = zap.New(zapCore) hostPort := ports.PortToHostPort(ports.QueryAdminHTTP) - querySvc := &querysvc.QueryService{} - tracer := jtracer.NoOp() - - server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc, nil, + querySvc := makeQuerySvc() + server, err := NewServer(flagsSvc.Logger, flagsSvc.HC(), querySvc.qs, nil, &QueryOptions{GRPCHostPort: hostPort, HTTPHostPort: hostPort}, - tenancy.NewManager(&tenancy.Options{}), tracer) + tenancy.NewManager(&tenancy.Options{}), jtracer.NoOp()) require.NoError(t, err) require.NoError(t, server.Start()) // Wait for servers to come up before we can call .Close() - // TODO Find a way to wait only as long as necessary. Unconditional sleep slows down the tests. - time.Sleep(1 * time.Second) - server.Close() + { + client := newGRPCClient(t, hostPort) + t.Cleanup(func() { + require.NoError(t, client.conn.Close()) + }) + // using generous timeout since grpc.NewClient no longer does a handshake. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + _, err := client.GetServices(ctx, &api_v2.GetServicesRequest{}) + require.NoError(t, err) + } + server.Close() for _, logEntry := range logs.All() { assert.NotEqual(t, zap.ErrorLevel, logEntry.Level, "Error log found on server exit: %v", logEntry) @@ -724,15 +735,15 @@ func TestServerHTTPTenancy(t *testing.T) { }, } tenancyMgr := tenancy.NewManager(&serverOptions.Tenancy) - - spanReader := &spanstoremocks.Reader{} - dependencyReader := &depsmocks.Reader{} - - querySvc := querysvc.NewQueryService(spanReader, dependencyReader, querysvc.QueryServiceOptions{}) - server, err := NewServer(zap.NewNop(), healthcheck.New(), querySvc, + querySvc := makeQuerySvc() + querySvc.spanReader.On("FindTraces", mock.Anything, mock.Anything).Return([]*model.Trace{mockTrace}, nil).Once() + server, err := NewServer(zaptest.NewLogger(t), healthcheck.New(), querySvc.qs, nil, serverOptions, tenancyMgr, jtracer.NoOp()) require.NoError(t, err) require.NoError(t, server.Start()) + t.Cleanup(func() { + require.NoError(t, server.Close()) + }) for _, test := range testCases { t.Run(test.name, func(t *testing.T) { @@ -766,5 +777,4 @@ func TestServerHTTPTenancy(t *testing.T) { } }) } - server.Close() } diff --git a/cmd/remote-storage/app/server.go b/cmd/remote-storage/app/server.go index ecc29f0ff9b..a79187ca471 100644 --- a/cmd/remote-storage/app/server.go +++ b/cmd/remote-storage/app/server.go @@ -22,6 +22,7 @@ import ( "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health" "google.golang.org/grpc/reflection" "github.com/jaegertracing/jaeger/cmd/query/app/querysvc" @@ -115,8 +116,9 @@ func createGRPCServer(opts *Options, tm *tenancy.Manager, handler *shared.GRPCHa } server := grpc.NewServer(grpcOpts...) + healthServer := health.NewServer() reflection.Register(server) - handler.Register(server) + handler.Register(server, healthServer) return server, nil } diff --git a/crossdock/jaeger-docker-compose.yml b/crossdock/jaeger-docker-compose.yml index fefc3714864..877b752e355 100644 --- a/crossdock/jaeger-docker-compose.yml +++ b/crossdock/jaeger-docker-compose.yml @@ -22,7 +22,7 @@ services: - "14250" - "9411:9411" environment: - - SPAN_STORAGE_TYPE=grpc-plugin + - SPAN_STORAGE_TYPE=grpc - LOG_LEVEL=debug restart: on-failure depends_on: @@ -37,7 +37,7 @@ services: - "16686:16686" - "16687" environment: - - SPAN_STORAGE_TYPE=grpc-plugin + - SPAN_STORAGE_TYPE=grpc restart: on-failure depends_on: - jaeger-remote-storage diff --git a/docker-compose/kafka/docker-compose.yml b/docker-compose/kafka/docker-compose.yml index 02922cd95a4..d927e8661c3 100644 --- a/docker-compose/kafka/docker-compose.yml +++ b/docker-compose/kafka/docker-compose.yml @@ -72,7 +72,7 @@ services: - "--grpc-storage.server=jaeger-remote-storage:17271" - "--log-level=debug" environment: - - SPAN_STORAGE_TYPE=grpc-plugin + - SPAN_STORAGE_TYPE=grpc - KAFKA_CONSUMER_BROKERS=kafka:9092 healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:14270/ || exit 1"] @@ -117,7 +117,7 @@ services: - "--grpc-storage.server=jaeger-remote-storage:17271" - "--log-level=debug" environment: - - SPAN_STORAGE_TYPE=grpc-plugin + - SPAN_STORAGE_TYPE=grpc - JAEGER_AGENT_HOST=jaeger-agent ports: - "16686:16686" diff --git a/docker/Makefile b/docker/Makefile index 237bb8c5306..dfb72662a7d 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,7 +1,4 @@ VERSION := 1.0.0 -ROOT_IMAGE ?= alpine:3.16 -CERT_IMAGE := $(ROOT_IMAGE) -GOLANG_IMAGE := golang:1.22-alpine DOCKER_REGISTRY ?= localhost:5000 BASE_IMAGE ?= $(DOCKER_REGISTRY)/baseimg_alpine:latest @@ -12,14 +9,11 @@ create-baseimg-debugimg: create-baseimg create-debugimg create-baseimg: prepare-docker-buildx docker buildx build -t $(BASE_IMAGE) --push \ - --build-arg root_image=$(ROOT_IMAGE) \ - --build-arg cert_image=$(CERT_IMAGE) \ --platform=$(PLATFORMS) \ docker/base create-debugimg: prepare-docker-buildx docker buildx build -t $(DEBUG_IMAGE) --push \ - --build-arg golang_image=$(GOLANG_IMAGE) \ --platform=$(PLATFORMS) \ docker/debug diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index 6fa10c92bd1..4dd96acf1ed 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -1,9 +1,6 @@ -ARG cert_image -ARG root_image - -FROM $cert_image AS cert +FROM alpine:3.19.1 AS cert RUN apk add --update --no-cache ca-certificates mailcap -FROM $root_image +FROM alpine:3.19.1 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/docker/debug/Dockerfile b/docker/debug/Dockerfile index b8e4ddc005d..40a7179ceea 100644 --- a/docker/debug/Dockerfile +++ b/docker/debug/Dockerfile @@ -1,6 +1,4 @@ -ARG golang_image - -FROM $golang_image AS build +FROM golang:1.22-alpine AS build ARG TARGETARCH ENV GOPATH /go RUN apk add --update --no-cache ca-certificates make git build-base mailcap @@ -12,7 +10,7 @@ RUN if [[ "$TARGETARCH" == "s390x" || "$TARGETARCH" == "ppc64le" ]] ; then \ go install github.com/go-delve/delve/cmd/dlv@latest; \ fi -FROM $golang_image +FROM golang:1.22-alpine COPY --from=build /go/bin/dlv /go/bin/dlv COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=build /etc/mime.types /etc/mime.types diff --git a/examples/memstore-plugin/README.md b/examples/memstore-plugin/README.md deleted file mode 100644 index 566e85c0978..00000000000 --- a/examples/memstore-plugin/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# memstore-plugin - -This package builds a binary that can be used as an example of a sidecar storage plugin. - -Note that Jaeger now supports remote storages via gRPC API, so using plugins is discouraged. -For example, `memorystore` can be used as a remote backend (https://github.com/jaegertracing/jaeger/issues/3835). diff --git a/examples/memstore-plugin/main.go b/examples/memstore-plugin/main.go deleted file mode 100644 index 097fdfcc17c..00000000000 --- a/examples/memstore-plugin/main.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2018 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "fmt" - "strings" - - "github.com/hashicorp/go-plugin" - "github.com/spf13/viper" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" - googleGRPC "google.golang.org/grpc" - - "github.com/jaegertracing/jaeger/pkg/jtracer" - "github.com/jaegertracing/jaeger/plugin/storage/grpc" - grpcMemory "github.com/jaegertracing/jaeger/plugin/storage/grpc/memory" - "github.com/jaegertracing/jaeger/plugin/storage/grpc/shared" - "github.com/jaegertracing/jaeger/plugin/storage/memory" -) - -const ( - serviceName = "mem-store" -) - -var configPath string - -func main() { - flag.StringVar(&configPath, "config", "", "A path to the plugin's configuration file") - flag.Parse() - - v := viper.New() - v.AutomaticEnv() - v.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_")) - - if configPath != "" { - v.SetConfigFile(configPath) - if err := v.ReadInConfig(); err != nil { - panic(err) - } - } - - opts := memory.Options{} - opts.InitFromViper(v) - - tracer, err := jtracer.New(serviceName) - if err != nil { - panic(fmt.Errorf("failed to initialize tracer: %w", err)) - } - defer tracer.Close(context.Background()) - - memStorePlugin := grpcMemory.NewStoragePlugin(memory.NewStore(), memory.NewStore()) - service := &shared.PluginServices{ - Store: memStorePlugin, - ArchiveStore: memStorePlugin, - } - if v.GetBool("enable_streaming_writer") { - service.StreamingSpanWriter = memStorePlugin - } - grpc.ServeWithGRPCServer(service, func(options []googleGRPC.ServerOption) *googleGRPC.Server { - return plugin.DefaultGRPCServer([]googleGRPC.ServerOption{ - googleGRPC.StatsHandler(otelgrpc.NewServerHandler(otelgrpc.WithTracerProvider(tracer.OTEL))), - }) - }) -} diff --git a/go.mod b/go.mod index a7aa6e776f7..37f1728d533 100644 --- a/go.mod +++ b/go.mod @@ -22,8 +22,6 @@ require ( github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 - github.com/hashicorp/go-hclog v1.6.3 - github.com/hashicorp/go-plugin v1.6.0 github.com/kr/pretty v0.3.1 github.com/olivere/elastic v6.2.37+incompatible github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.100.0 @@ -77,9 +75,9 @@ require ( go.uber.org/automaxprocs v1.5.3 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 - golang.org/x/net v0.24.0 + golang.org/x/net v0.25.0 golang.org/x/sys v0.20.0 - google.golang.org/grpc v1.63.2 + google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.34.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -100,7 +98,6 @@ require ( github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/elastic/elastic-transport-go/v8 v8.5.0 // indirect - github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -120,7 +117,6 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect @@ -139,16 +135,12 @@ require ( github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mostynb/go-grpc-compression v1.2.2 // indirect - github.com/oklog/run v1.1.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage v0.100.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.100.0 // indirect @@ -219,11 +211,11 @@ require ( go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.22.0 // indirect + golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/text v0.15.0 // indirect gonum.org/v1/gonum v0.15.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index e76f001ea49..a6fefe83c13 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,6 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bsm/sarama-cluster v2.1.13+incompatible h1:bqU3gMJbWZVxLZ9PGWVKP05yOmFXUlfw61RBwuE3PYU= github.com/bsm/sarama-cluster v2.1.13+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM= -github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= -github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -81,9 +79,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF 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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -181,12 +176,8 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMW 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-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-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-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= -github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= 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= @@ -196,8 +187,6 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 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/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -216,8 +205,6 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= -github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -261,20 +248,9 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V 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.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 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= @@ -293,8 +269,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= -github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U= github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -431,7 +405,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -613,8 +586,8 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -654,8 +627,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= @@ -681,8 +654,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -690,17 +661,12 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -715,8 +681,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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= @@ -750,10 +716,8 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -763,8 +727,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/config/tlscfg/options.go b/pkg/config/tlscfg/options.go index 2707887831d..68739e2470b 100644 --- a/pkg/config/tlscfg/options.go +++ b/pkg/config/tlscfg/options.go @@ -23,6 +23,7 @@ import ( "path/filepath" "time" + "go.opentelemetry.io/collector/config/configtls" "go.uber.org/zap" ) @@ -135,6 +136,23 @@ func (p Options) loadCertPool() (*x509.CertPool, error) { return certPool, nil } +func (o *Options) ToOtelClientConfig() configtls.ClientConfig { + return configtls.ClientConfig{ + Insecure: !o.Enabled, + InsecureSkipVerify: o.SkipHostVerify, + ServerName: o.ServerName, + Config: configtls.Config{ + CAFile: o.CAPath, + CertFile: o.CertPath, + KeyFile: o.KeyPath, + CipherSuites: o.CipherSuites, + MinVersion: o.MinVersion, + MaxVersion: o.MaxVersion, + ReloadInterval: o.ReloadInterval, + }, + } +} + func addCertToPool(caPath string, certPool *x509.CertPool) error { caPEM, err := os.ReadFile(filepath.Clean(caPath)) if err != nil { diff --git a/pkg/config/tlscfg/options_test.go b/pkg/config/tlscfg/options_test.go index 81d146c5210..44ad205fdc0 100644 --- a/pkg/config/tlscfg/options_test.go +++ b/pkg/config/tlscfg/options_test.go @@ -20,9 +20,11 @@ import ( "fmt" "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/configtls" "go.uber.org/zap" ) @@ -186,3 +188,57 @@ func TestOptionsToConfig(t *testing.T) { }) } } + +func TestToOtelClientConfig(t *testing.T) { + testCases := []struct { + name string + options Options + expected configtls.ClientConfig + }{ + { + name: "insecure", + options: Options{ + Enabled: false, + }, + expected: configtls.ClientConfig{ + Insecure: true, + }, + }, + { + name: "secure with skip host verify", + options: Options{ + Enabled: true, + SkipHostVerify: true, + ServerName: "example.com", + CAPath: "path/to/ca.pem", + CertPath: "path/to/cert.pem", + KeyPath: "path/to/key.pem", + CipherSuites: []string{"TLS_RSA_WITH_AES_128_CBC_SHA"}, + MinVersion: "1.2", + MaxVersion: "1.3", + ReloadInterval: 24 * time.Hour, + }, + expected: configtls.ClientConfig{ + Insecure: false, + InsecureSkipVerify: true, + ServerName: "example.com", + Config: configtls.Config{ + CAFile: "path/to/ca.pem", + CertFile: "path/to/cert.pem", + KeyFile: "path/to/key.pem", + CipherSuites: []string{"TLS_RSA_WITH_AES_128_CBC_SHA"}, + MinVersion: "1.2", + MaxVersion: "1.3", + ReloadInterval: 24 * time.Hour, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := tc.options.ToOtelClientConfig() + assert.Equal(t, tc.expected, actual) + }) + } +} diff --git a/plugin/storage/es/dependencystore/storage_test.go b/plugin/storage/es/dependencystore/storage_test.go index 91d3e152186..a147535bbbf 100644 --- a/plugin/storage/es/dependencystore/storage_test.go +++ b/plugin/storage/es/dependencystore/storage_test.go @@ -97,10 +97,6 @@ func TestWriteDependencies(t *testing.T) { expectedError string esVersion uint }{ - { - expectedError: "", - esVersion: 6, - }, { expectedError: "", esVersion: 7, diff --git a/plugin/storage/es/factory_test.go b/plugin/storage/es/factory_test.go index a7ac2ad5b6c..a79e2942a19 100644 --- a/plugin/storage/es/factory_test.go +++ b/plugin/storage/es/factory_test.go @@ -253,6 +253,7 @@ func TestArchiveEnabled(t *testing.T) { f.newClientFn = (&mockClientBuilder{}).NewClient err := f.Initialize(metrics.NullFactory, zap.NewNop()) require.NoError(t, err) + defer f.Close() // Ensure resources are cleaned up if initialization is successful w, err := f.CreateArchiveSpanWriter() require.NoError(t, err) assert.NotNil(t, w) diff --git a/plugin/storage/es/mappings/fixtures/jaeger-dependencies.json b/plugin/storage/es/mappings/fixtures/jaeger-dependencies.json deleted file mode 100644 index 42659ac9d03..00000000000 --- a/plugin/storage/es/mappings/fixtures/jaeger-dependencies.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "template": "*jaeger-dependencies-*", - "settings":{ - "index.number_of_shards": 3, - "index.number_of_replicas": 3, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true - }, - "mappings":{} -} diff --git a/plugin/storage/es/mappings/fixtures/jaeger-sampling.json b/plugin/storage/es/mappings/fixtures/jaeger-sampling.json deleted file mode 100644 index 87304011017..00000000000 --- a/plugin/storage/es/mappings/fixtures/jaeger-sampling.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "template": "*jaeger-sampling-*", - "settings":{ - "index.number_of_shards": 3, - "index.number_of_replicas": 3, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true - }, - "mappings":{} -} diff --git a/plugin/storage/es/mappings/fixtures/jaeger-service.json b/plugin/storage/es/mappings/fixtures/jaeger-service.json deleted file mode 100644 index 9ba447775ed..00000000000 --- a/plugin/storage/es/mappings/fixtures/jaeger-service.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "template": "*jaeger-service-*", - "settings":{ - "index.number_of_shards": 3, - "index.number_of_replicas": 3, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true, - "index.mapper.dynamic":false - }, - "mappings":{ - "_default_":{ - "_all":{ - "enabled":false - }, - "dynamic_templates":[ - { - "span_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"tag.*" - } - }, - { - "process_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"process.tag.*" - } - } - ] - }, - "service":{ - "properties":{ - "serviceName":{ - "type":"keyword", - "ignore_above":256 - }, - "operationName":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } -} diff --git a/plugin/storage/es/mappings/fixtures/jaeger-span.json b/plugin/storage/es/mappings/fixtures/jaeger-span.json deleted file mode 100644 index e7a89878009..00000000000 --- a/plugin/storage/es/mappings/fixtures/jaeger-span.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "template": "*jaeger-span-*", - "settings":{ - "index.number_of_shards": 3, - "index.number_of_replicas": 3, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true, - "index.mapper.dynamic":false - }, - "mappings":{ - "_default_":{ - "_all":{ - "enabled":false - }, - "dynamic_templates":[ - { - "span_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"tag.*" - } - }, - { - "process_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"process.tag.*" - } - } - ] - }, - "span":{ - "properties":{ - "traceID":{ - "type":"keyword", - "ignore_above":256 - }, - "parentSpanID":{ - "type":"keyword", - "ignore_above":256 - }, - "spanID":{ - "type":"keyword", - "ignore_above":256 - }, - "operationName":{ - "type":"keyword", - "ignore_above":256 - }, - "startTime":{ - "type":"long" - }, - "startTimeMillis":{ - "type":"date", - "format":"epoch_millis" - }, - "duration":{ - "type":"long" - }, - "flags":{ - "type":"integer" - }, - "logs":{ - "type":"nested", - "dynamic":false, - "properties":{ - "timestamp":{ - "type":"long" - }, - "fields":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - }, - "process":{ - "properties":{ - "serviceName":{ - "type":"keyword", - "ignore_above":256 - }, - "tag":{ - "type":"object" - }, - "tags":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - }, - "references":{ - "type":"nested", - "dynamic":false, - "properties":{ - "refType":{ - "type":"keyword", - "ignore_above":256 - }, - "traceID":{ - "type":"keyword", - "ignore_above":256 - }, - "spanID":{ - "type":"keyword", - "ignore_above":256 - } - } - }, - "tag":{ - "type":"object" - }, - "tags":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - } - } -} diff --git a/plugin/storage/es/mappings/jaeger-dependencies.json b/plugin/storage/es/mappings/jaeger-dependencies.json deleted file mode 100644 index cdfa62d9547..00000000000 --- a/plugin/storage/es/mappings/jaeger-dependencies.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "template": "*jaeger-dependencies-*", - "settings":{ - "index.number_of_shards": {{ .Shards }}, - "index.number_of_replicas": {{ .Replicas }}, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true - }, - "mappings":{} -} diff --git a/plugin/storage/es/mappings/jaeger-sampling.json b/plugin/storage/es/mappings/jaeger-sampling.json deleted file mode 100644 index 458d490a357..00000000000 --- a/plugin/storage/es/mappings/jaeger-sampling.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "template": "*jaeger-sampling-*", - "settings":{ - "index.number_of_shards": {{ .Shards }}, - "index.number_of_replicas": {{ .Replicas }}, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":false - }, - "mappings":{} -} diff --git a/plugin/storage/es/mappings/jaeger-service.json b/plugin/storage/es/mappings/jaeger-service.json deleted file mode 100644 index 1adb8e0bf38..00000000000 --- a/plugin/storage/es/mappings/jaeger-service.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "template": "*jaeger-service-*", - "settings":{ - "index.number_of_shards": {{ .Shards }}, - "index.number_of_replicas": {{ .Replicas }}, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true, - "index.mapper.dynamic":false - }, - "mappings":{ - "_default_":{ - "_all":{ - "enabled":false - }, - "dynamic_templates":[ - { - "span_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"tag.*" - } - }, - { - "process_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"process.tag.*" - } - } - ] - }, - "service":{ - "properties":{ - "serviceName":{ - "type":"keyword", - "ignore_above":256 - }, - "operationName":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } -} diff --git a/plugin/storage/es/mappings/jaeger-span.json b/plugin/storage/es/mappings/jaeger-span.json deleted file mode 100644 index 3c73f923c4c..00000000000 --- a/plugin/storage/es/mappings/jaeger-span.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "template": "*jaeger-span-*", - "settings":{ - "index.number_of_shards": {{ .Shards }}, - "index.number_of_replicas": {{ .Replicas }}, - "index.mapping.nested_fields.limit":50, - "index.requests.cache.enable":true, - "index.mapper.dynamic":false - }, - "mappings":{ - "_default_":{ - "_all":{ - "enabled":false - }, - "dynamic_templates":[ - { - "span_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"tag.*" - } - }, - { - "process_tags_map":{ - "mapping":{ - "type":"keyword", - "ignore_above":256 - }, - "path_match":"process.tag.*" - } - } - ] - }, - "span":{ - "properties":{ - "traceID":{ - "type":"keyword", - "ignore_above":256 - }, - "parentSpanID":{ - "type":"keyword", - "ignore_above":256 - }, - "spanID":{ - "type":"keyword", - "ignore_above":256 - }, - "operationName":{ - "type":"keyword", - "ignore_above":256 - }, - "startTime":{ - "type":"long" - }, - "startTimeMillis":{ - "type":"date", - "format":"epoch_millis" - }, - "duration":{ - "type":"long" - }, - "flags":{ - "type":"integer" - }, - "logs":{ - "type":"nested", - "dynamic":false, - "properties":{ - "timestamp":{ - "type":"long" - }, - "fields":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - }, - "process":{ - "properties":{ - "serviceName":{ - "type":"keyword", - "ignore_above":256 - }, - "tag":{ - "type":"object" - }, - "tags":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - }, - "references":{ - "type":"nested", - "dynamic":false, - "properties":{ - "refType":{ - "type":"keyword", - "ignore_above":256 - }, - "traceID":{ - "type":"keyword", - "ignore_above":256 - }, - "spanID":{ - "type":"keyword", - "ignore_above":256 - } - } - }, - "tag":{ - "type":"object" - }, - "tags":{ - "type":"nested", - "dynamic":false, - "properties":{ - "key":{ - "type":"keyword", - "ignore_above":256 - }, - "value":{ - "type":"keyword", - "ignore_above":256 - }, - "tagType":{ - "type":"keyword", - "ignore_above":256 - } - } - } - } - } - } -} diff --git a/plugin/storage/es/mappings/mapping.go b/plugin/storage/es/mappings/mapping.go index 5da255f8838..d5a42180f3e 100644 --- a/plugin/storage/es/mappings/mapping.go +++ b/plugin/storage/es/mappings/mapping.go @@ -46,10 +46,8 @@ type MappingBuilder struct { func (mb *MappingBuilder) GetMapping(mapping string) (string, error) { if mb.EsVersion == 8 { return mb.fixMapping(mapping + "-8.json") - } else if mb.EsVersion == 7 { - return mb.fixMapping(mapping + "-7.json") } - return mb.fixMapping(mapping + ".json") + return mb.fixMapping(mapping + "-7.json") } // GetSpanServiceMappings returns span and service mappings diff --git a/plugin/storage/es/mappings/mapping_test.go b/plugin/storage/es/mappings/mapping_test.go index 167c6893d1b..efa56c335bf 100644 --- a/plugin/storage/es/mappings/mapping_test.go +++ b/plugin/storage/es/mappings/mapping_test.go @@ -42,13 +42,10 @@ func TestMappingBuilder_GetMapping(t *testing.T) { }{ {mapping: "jaeger-span", esVersion: 8}, {mapping: "jaeger-span", esVersion: 7}, - {mapping: "jaeger-span", esVersion: 6}, {mapping: "jaeger-service", esVersion: 8}, {mapping: "jaeger-service", esVersion: 7}, - {mapping: "jaeger-service", esVersion: 6}, {mapping: "jaeger-dependencies", esVersion: 8}, {mapping: "jaeger-dependencies", esVersion: 7}, - {mapping: "jaeger-dependencies", esVersion: 6}, } for _, tt := range tests { t.Run(tt.mapping, func(t *testing.T) { @@ -67,10 +64,7 @@ func TestMappingBuilder_GetMapping(t *testing.T) { got, err := mb.GetMapping(tt.mapping) require.NoError(t, err) var wantbytes []byte - fileSuffix := "" - if tt.esVersion >= 7 { - fileSuffix = fmt.Sprintf("-%d", tt.esVersion) - } + fileSuffix := fmt.Sprintf("-%d", tt.esVersion) wantbytes, err = FIXTURES.ReadFile("fixtures/" + tt.mapping + fileSuffix + ".json") require.NoError(t, err) want := string(wantbytes) @@ -83,13 +77,10 @@ func TestMappingBuilder_loadMapping(t *testing.T) { tests := []struct { name string }{ - {name: "jaeger-span.json"}, {name: "jaeger-span-7.json"}, {name: "jaeger-span-8.json"}, - {name: "jaeger-service.json"}, {name: "jaeger-service-7.json"}, {name: "jaeger-service-8.json"}, - {name: "jaeger-dependencies.json"}, {name: "jaeger-dependencies-7.json"}, {name: "jaeger-dependencies-8.json"}, } @@ -219,65 +210,6 @@ func TestMappingBuilder_GetSpanServiceMappings(t *testing.T) { }, err: "template load error", }, - - { - name: "ES Version < 7", - args: args{ - shards: 3, - replicas: 3, - esVersion: 6, - indexPrefix: "test", - useILM: true, - ilmPolicyName: "jaeger-test-policy", - }, - mockNewTextTemplateBuilder: func() es.TemplateBuilder { - tb := mocks.TemplateBuilder{} - ta := mocks.TemplateApplier{} - ta.On("Execute", mock.Anything, mock.Anything).Return(nil) - tb.On("Parse", mock.Anything).Return(&ta, nil) - return &tb - }, - err: "", - }, - { - name: "ES Version < 7 Service Error", - args: args{ - shards: 3, - replicas: 3, - esVersion: 6, - indexPrefix: "test", - useILM: true, - ilmPolicyName: "jaeger-test-policy", - }, - mockNewTextTemplateBuilder: func() es.TemplateBuilder { - tb := mocks.TemplateBuilder{} - ta := mocks.TemplateApplier{} - ta.On("Execute", mock.Anything, mock.Anything).Return(nil).Once() - ta.On("Execute", mock.Anything, mock.Anything).Return(errors.New("template load error")).Once() - tb.On("Parse", mock.Anything).Return(&ta, nil) - return &tb - }, - err: "template load error", - }, - { - name: "ES Version < 7 Span Error", - args: args{ - shards: 3, - replicas: 3, - esVersion: 6, - indexPrefix: "test", - useILM: true, - ilmPolicyName: "jaeger-test-policy", - }, - mockNewTextTemplateBuilder: func() es.TemplateBuilder { - tb := mocks.TemplateBuilder{} - ta := mocks.TemplateApplier{} - ta.On("Execute", mock.Anything, mock.Anything).Return(errors.New("template load error")) - tb.On("Parse", mock.Anything).Return(&ta, nil) - return &tb - }, - err: "template load error", - }, { name: "ES Version 7 Span Error", args: args{ diff --git a/plugin/storage/factory.go b/plugin/storage/factory.go index c8ab75d7ec6..b9ed0e76c52 100644 --- a/plugin/storage/factory.go +++ b/plugin/storage/factory.go @@ -44,7 +44,8 @@ const ( elasticsearchStorageType = "elasticsearch" memoryStorageType = "memory" kafkaStorageType = "kafka" - grpcPluginStorageType = "grpc-plugin" + grpcStorageType = "grpc" + grpcPluginDeprecated = "grpc-plugin" badgerStorageType = "badger" blackholeStorageType = "blackhole" @@ -67,7 +68,7 @@ var AllStorageTypes = []string{ kafkaStorageType, badgerStorageType, blackholeStorageType, - grpcPluginStorageType, + grpcStorageType, } // AllSamplingStorageTypes returns all storage backends that implement adaptive sampling @@ -135,7 +136,7 @@ func (f *Factory) getFactoryOfType(factoryType string) (storage.Factory, error) return kafka.NewFactory(), nil case badgerStorageType: return badger.NewFactory(), nil - case grpcPluginStorageType: + case grpcStorageType: return grpc.NewFactory(), nil case blackholeStorageType: return blackhole.NewFactory(), nil diff --git a/plugin/storage/factory_config.go b/plugin/storage/factory_config.go index 06b6833290b..1d8a0748d8f 100644 --- a/plugin/storage/factory_config.go +++ b/plugin/storage/factory_config.go @@ -53,7 +53,7 @@ type FactoryConfig struct { // * `memory` - built-in // * `kafka` - built-in // * `blackhole` - built-in -// * `plugin` - loads a dynamic plugin that implements storage.Factory interface (not supported at the moment) +// * `grpc` - build-in // // For backwards compatibility it also parses the args looking for deprecated --span-storage.type flag. // If found, it writes a deprecation warning to the log. @@ -66,6 +66,13 @@ func FactoryConfigFromEnvAndCLI(args []string, log io.Writer) FactoryConfig { if spanStorageType == "" { spanStorageType = cassandraStorageType } + if spanStorageType == grpcPluginDeprecated { + fmt.Fprintf(log, + "WARNING: `%s` storage type is deprecated and will be remove from v1.60. Use `%s`.\n\n", + grpcPluginDeprecated, grpcStorageType, + ) + spanStorageType = grpcStorageType + } spanWriterTypes := strings.Split(spanStorageType, ",") if len(spanWriterTypes) > 1 { fmt.Fprintf(log, diff --git a/plugin/storage/grpc/README.md b/plugin/storage/grpc/README.md index 1fee18db23a..86f1f41602f 100644 --- a/plugin/storage/grpc/README.md +++ b/plugin/storage/grpc/README.md @@ -1,23 +1,22 @@ -gRPC Storage Plugins -==================== +gRPC Remote Storage Plugins +=========================== -Update (Jan 2022): as of Jaeger v1.30, the gRPC storage extension can be implemented as a remote gRPC server, in addition to the gRPC plugin architecture described below. The remote server needs to implement the same `storage_v1` gRPC interfaces defined in `plugin/storage/grpc/proto/`. +Update (May 2024): as of v1.58, Jaeger will no longer support grpc-sidecar plugin model. Only gRPC Remote Storage API is suppored. -gRPC Storage Plugins currently use the [Hashicorp go-plugin](https://github.com/hashicorp/go-plugin). This requires the -implementer of a plugin to develop the "server" side of the go-plugin system. At a high level this looks like: +In order to support an ecosystem of different backend storage implementations, Jaeger supports a gRPC-based Remote Strorage API. The custom backend storage solutions need to implement `storage_v1` gRPC interfaces defined in `plugin/storage/grpc/proto/`. ``` +----------------------------------+ +-----------------------------+ | | | | -| +-------------+ | unix-socket | +-------------+ | +| +-------------+ | gRPC | +-------------+ | | | | | | | | | -| jaeger-component | grpc-client +----------------------> grpc-server | plugin-impl | +| jaeger-component | grpc-client +----------------------> grpc-server | custom impl | | | | | | | | | | +-------------+ | | +-------------+ | | | | | +----------------------------------+ +-----------------------------+ - parent process child sub-process + Jaeger official components Custom backend implementation ``` Implementing a plugin @@ -25,9 +24,9 @@ Implementing a plugin Although the instructions below are limited to Go, plugins can be implemented any language. Languages other than Go would implement a gRPC server using the `storage_v1` proto interfaces. The `proto` file can be found in `plugin/storage/grpc/proto/`. -To generate the bindings for your language you would use `protoc` with the appropriate `xx_out=` flag. This is detailed +To generate the bindings for your language you would use `protoc` with the appropriate `xx_out=` flag. This is detailed in the [protobuf documentation](https://developers.google.com/protocol-buffers/docs/tutorials) and you can see an example of -how it is done for Go in the top level Jaeger `Makefile`. +how it is done for Go in the top level Jaeger `Makefile`. The easiest way to generate the gRPC storage plugin bindings is to use [Docker Protobuf](https://github.com/jaegertracing/docker-protobuf/) which is a lightweight `protoc` Docker image containing the dependencies needed to generate code for multiple languages. For example, one can generate bindings for C# on Windows with Docker for Windows using the following steps: 1. First clone the Jaeger github repo to a folder (e.g. `c:\source\repos\jaeger`): @@ -40,79 +39,23 @@ $ git clone https://github.com/jaegertracing/jaeger.git c:\source\repos\jaeger ``` $ git submodule update --init --recursive ``` -3. Then execute the following Docker command which mounts the local directory `c:\source\repos\jaeger` to the directory `/jaeger` in the Docker container and then executes the `jaegertracing/protobuf:0.2.0` command. This will create a file called `Storage.cs` in your local Windows folder `c:\source\repos\jaeger\code` containing the gRPC Storage Plugin bindings. +3. Then execute the following Docker command which mounts the local directory `c:\source\repos\jaeger` to the directory `/jaeger` in the Docker container and then executes the `jaegertracing/protobuf:0.2.0` command. This will create a file called `Storage.cs` in your local Windows folder `c:\source\repos\jaeger\code` containing the gRPC Storage API bindings. ``` $ docker run --rm -u 1000 -v/c/source/repos/jaeger:/jaeger -w/jaeger \ jaegertracing/protobuf:0.2.0 "-I/jaeger -Iidl/proto/api_v2 -I/usr/include/github.com/gogo/protobuf -Iplugin/storage/grpc/proto --csharp_out=/jaeger/code plugin/storage/grpc/proto/storage.proto" ``` -There are instructions on implementing a `go-plugin` server for non-Go languages in the -[go-plugin non-go guide](https://github.com/hashicorp/go-plugin/blob/master/docs/guide-plugin-write-non-go.md). -Take note of the required [health check service](https://github.com/hashicorp/go-plugin/blob/master/docs/guide-plugin-write-non-go.md#3-add-the-grpc-health-checking-service). - -A Go plugin is a standalone application which calls `grpc.Serve(&pluginServices)` in its `main` function, where the `grpc` package -is `github.com/jaegertracing/jaeger/plugin/storage/grpc`. - -```go - package main - - import ( - "flag" - "github.com/jaegertracing/jaeger/plugin/storage/grpc" - ) - - func main() { - var configPath string - flag.StringVar(&configPath, "config", "", "A path to the plugin's configuration file") - flag.Parse() - - plugin := myStoragePlugin{} - - grpc.Serve(&shared.PluginServices{ - Store: plugin, - ArchiveStore: plugin, - }) - } -``` - -Note that `grpc.Serve` is called as the final part of the main. This should be called after you have carried out any necessary -setup for your plugin, as once running Jaeger may start calling to read/write spans straight away. You could defer -setup until the first read/write but that could make the first operation slow and also lead to racing behaviours. - -A plugin must implement the StoragePlugin interface of: - -```go -type StoragePlugin interface { - SpanReader() spanstore.Reader - SpanWriter() spanstore.Writer - DependencyReader() dependencystore.Reader -} -``` - -As your plugin will be dependent on the protobuf implementation within Jaeger you will likely need to `vendor` your -dependencies, you can also use `go.mod` to achieve the same goal of pinning your plugin to a Jaeger point in time. +An example of a Go binary that implements Remote Storage API can be found in `cmd/remote-storage`. That specific binary does not implement a custom backend, instead it supports the same backend implementations as available directly in Jaeger, but it makes them accessible via a Remote Storage API (and is being used in the integration tests). -A simple plugin which uses the memstore storage implementation can be found in the `examples` directory of the top level -of the Jaeger project. +The API consists of several gRPC services: + * `SpanReaderPlugin` - used for querying the data + * `SpanWriterPlugin` - used for writing data + * (optional) `StreamingSpanWriterPlugin` - allows more efficient transmission + * (optional) `ArchiveSpanWriterPlugin` and `ArchiveSpanReaderPlugin` - to support archiving storage + * (optional) `DependenciesReaderPlugin` - for reading service dependencies + * (optional) `PluginCapabilities` - can be interrogated to find out which services an implementation supports -To support archive storage a plugin must implement the ArchiveStoragePlugin interface of: - -```go -type ArchiveStoragePlugin interface { - ArchiveSpanReader() spanstore.Reader - ArchiveSpanWriter() spanstore.Writer -} -``` - -If you don't plan to implement archive storage simply do not fill `ArchiveStore` property of `shared.PluginServices`: - -```go -grpc.Serve(&shared.PluginServices{ - Store: plugin, -}) -``` - -The plugin framework supports writing spans via gRPC stream, instead of unary messages. Streaming writes can improve throughput and decrease CPU load (see benchmarks in Issue #3636). The plugin needs to implement `StreamingSpanWriter` interface and indicate support via the `streamingSpanWriter` flag in the `Capabilities` response. +The API supports writing spans via gRPC stream, instead of unary messages. Streaming writes can improve throughput and decrease CPU load (see benchmarks in Issue #3636). The backend needs to implement `StreamingSpanWriterPlugin` service and indicate support via the `streamingSpanWriter` flag in the `Capabilities` response. Note that using the streaming spanWriter may make the collector's `save_by_svr` metric inaccurate, in which case users will need to pay attention to the metrics provided by the plugin. @@ -141,72 +84,15 @@ func TestJaegerStorageIntegration(t *testing.T) { ``` For more details, refer to one of the following implementations. -1. [grpc-plugin](https://github.com/jaegertracing/jaeger/blob/cbceceb1e0cc308cdf0226b1fa19b9c531a3a2d3/plugin/storage/integration/grpc_test.go#L189-L203) -2. [jaeger-clickhouse](https://github.com/jaegertracing/jaeger-clickhouse/blob/798c568c1e1a345536f35692fca71196a796811e/integration/grpc_test.go#L88-L107) -3. [Timescale DB via Promscale](https://github.com/timescale/promscale/blob/ccde8accf5205450891e805e23566d9a11dbf8d3/pkg/tests/end_to_end_tests/jaeger_store_integration_test.go#L79-L97) - -Running with a plugin ---------------------- -A plugin can be run using the `all-in-one` application within the top level `cmd` package of the Jaeger project. To do this -an environment variable must be set to tell the `all-in-one` application to use the gRPC plugin storage: -`export SPAN_STORAGE_TYPE="grpc-plugin"` - -Once this has been set then there are two command line flags that can be used to configure the plugin. The first is -`--grpc-storage-plugin.binary` which is required and is the path to the plugin **binary**. The second is -`--grpc-storage-plugin.configuration-file` which is optional and is the path to the configuration file which will be -provided to your plugin as a command line flag. This command line flag is `config`, as can be seen in the code sample -above. An example invocation would be: - -``` -./all-in-one --grpc-storage-plugin.binary=/path/to/my/plugin --grpc-storage-plugin.configuration-file=/path/to/my/config -``` - -As well as passing configuration values via the command line through the configuration file it is also possible to use -environment variables. When you invoke `all-in-one` any environment variables that have been set will also be accessible -from within your plugin, this is useful if using Docker. - -Logging -------- -In order for Jaeger to include the log output from your plugin you need to use `hclog` (`"github.com/hashicorp/go-hclog"`). -The plugin framework will only include any log output created at the `WARN` or above levels. If you log output in this -way before calling `grpc.Serve` then it will still be included in the Jaeger output. - -An example logger instantiation could look like: - - ``` -logger := hclog.New(&hclog.LoggerOptions{ - Level: hclog.Warn, - Name: "my-jaeger-plugin", - JSONFormat: true, -}) -``` - -There are more logger options that can be used with `hclog` listed on [godoc](https://godoc.org/github.com/hashicorp/go-hclog#LoggerOptions). - -Note: Setting the `Output` option to `os.Stdout` can confuse the `go-plugin` framework and lead it to consider the plugin -errored. +1. [jaeger-clickhouse](https://github.com/jaegertracing/jaeger-clickhouse/blob/798c568c1e1a345536f35692fca71196a796811e/integration/grpc_test.go#L88-L107) +2. [Timescale DB via Promscale](https://github.com/timescale/promscale/blob/ccde8accf5205450891e805e23566d9a11dbf8d3/pkg/tests/end_to_end_tests/jaeger_store_integration_test.go#L79-L97) Tracing ------- -When `grpc-plugin` is used, it will be running as a separated process, thus context propagation is necessary for inter-process scenarios. - -In order to get complete traces containing both `jaeger-component`(s) and the `grpc-plugin`, developers should enable tracing at server-side. -Thus, we can leverage gRPC interceptors, - -```golang -grpc.ServeWithGRPCServer(&shared.PluginServices{ - Store: memStorePlugin, - ArchiveStore: memStorePlugin, -}, func(options []googleGRPC.ServerOption) *googleGRPC.Server { - return plugin.DefaultGRPCServer([]googleGRPC.ServerOption{ - grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(tracerProvider))), - grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(tracerProvider))), - }) -}) -``` +Jaeger requests to the backend implementation will include standard OTEL tracing headers. The implementation may choose to participate in those traces to allow end to end visibility of Jaeger's own operations (typically only enabled for read requests, +as tracing write requests results in traces for traces and may cause infinite loops). -Refer to `example/memstore-plugin` for more details. Bearer token propagation from the UI ------------------------------------ diff --git a/plugin/storage/grpc/config/config.go b/plugin/storage/grpc/config/config.go index c22e9f9d6f1..33b274a8873 100644 --- a/plugin/storage/grpc/config/config.go +++ b/plugin/storage/grpc/config/config.go @@ -1,7 +1,7 @@ // Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. +// you may not use this file ex cept in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 @@ -17,114 +17,88 @@ package config import ( "context" "fmt" - "os/exec" "time" - "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-plugin" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" "github.com/jaegertracing/jaeger/pkg/config/tlscfg" "github.com/jaegertracing/jaeger/pkg/tenancy" "github.com/jaegertracing/jaeger/plugin/storage/grpc/shared" ) -var pluginHealthCheckInterval = time.Second * 60 - // Configuration describes the options to customize the storage behavior. type Configuration struct { - PluginBinary string `yaml:"binary" mapstructure:"binary"` - PluginConfigurationFile string `yaml:"configuration-file" mapstructure:"configuration_file"` - PluginLogLevel string `yaml:"log-level" mapstructure:"log_level"` - RemoteServerAddr string `yaml:"server" mapstructure:"server"` - RemoteTLS tlscfg.Options - RemoteConnectTimeout time.Duration `yaml:"connection-timeout" mapstructure:"connection-timeout"` - TenancyOpts tenancy.Options - - pluginHealthCheck *time.Ticker - pluginHealthCheckDone chan bool - pluginRPCClient plugin.ClientProtocol - remoteConn *grpc.ClientConn + RemoteServerAddr string `yaml:"server" mapstructure:"server"` + RemoteTLS tlscfg.Options + RemoteConnectTimeout time.Duration `yaml:"connection-timeout" mapstructure:"connection-timeout"` + TenancyOpts tenancy.Options } -// ClientPluginServices defines services plugin can expose and its capabilities -type ClientPluginServices struct { - shared.PluginServices - Capabilities shared.PluginCapabilities - killPluginClient func() +type ConfigV2 struct { + Tenancy tenancy.Options `mapstructure:"multi_tenancy"` + configgrpc.ClientConfig `mapstructure:",squash"` + exporterhelper.TimeoutSettings `mapstructure:",squash"` } -func (c *ClientPluginServices) Close() error { - if c.killPluginClient != nil { - c.killPluginClient() +func (c *Configuration) TranslateToConfigV2() *ConfigV2 { + return &ConfigV2{ + ClientConfig: configgrpc.ClientConfig{ + Endpoint: c.RemoteServerAddr, + TLSSetting: c.RemoteTLS.ToOtelClientConfig(), + }, + TimeoutSettings: exporterhelper.TimeoutSettings{ + Timeout: c.RemoteConnectTimeout, + }, } - return nil -} - -// PluginBuilder is used to create storage plugins. Implemented by Configuration. -type PluginBuilder interface { - Build(logger *zap.Logger, tracerProvider trace.TracerProvider) (*ClientPluginServices, error) - Close() error } -// Build instantiates a PluginServices -func (c *Configuration) Build(logger *zap.Logger, tracerProvider trace.TracerProvider) (*ClientPluginServices, error) { - if c.PluginBinary != "" { - return c.buildPlugin(logger, tracerProvider) - } else { - return c.buildRemote(logger, tracerProvider) - } +// ClientPluginServices defines services plugin can expose and its capabilities +type ClientPluginServices struct { + shared.PluginServices + Capabilities shared.PluginCapabilities + remoteConn *grpc.ClientConn } -func (c *Configuration) Close() error { - if c.pluginHealthCheck != nil { - c.pluginHealthCheck.Stop() - c.pluginHealthCheckDone <- true +// TODO move this to factory.go +func (c *ConfigV2) Build(logger *zap.Logger, tracerProvider trace.TracerProvider) (*ClientPluginServices, error) { + telset := component.TelemetrySettings{ + Logger: logger, + TracerProvider: tracerProvider, } - if c.remoteConn != nil { - c.remoteConn.Close() + newClientFn := func(opts ...grpc.DialOption) (conn *grpc.ClientConn, err error) { + return c.ToClientConn(context.Background(), componenttest.NewNopHost(), telset, opts...) } - - return c.RemoteTLS.Close() + return newRemoteStorage(c, telset, newClientFn) } -func (c *Configuration) buildRemote(logger *zap.Logger, tracerProvider trace.TracerProvider) (*ClientPluginServices, error) { +type newClientFn func(opts ...grpc.DialOption) (*grpc.ClientConn, error) + +func newRemoteStorage(c *ConfigV2, telset component.TelemetrySettings, newClient newClientFn) (*ClientPluginServices, error) { opts := []grpc.DialOption{ - grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(tracerProvider))), - grpc.WithBlock(), + grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(telset.TracerProvider))), } - if c.RemoteTLS.Enabled { - tlsCfg, err := c.RemoteTLS.Config(logger) - if err != nil { - return nil, err - } - creds := credentials.NewTLS(tlsCfg) - opts = append(opts, grpc.WithTransportCredentials(creds)) - } else { - opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + if c.Auth != nil { + return nil, fmt.Errorf("authenticator is not supported") } - ctx, cancel := context.WithTimeout(context.Background(), c.RemoteConnectTimeout) - defer cancel() - - tenancyMgr := tenancy.NewManager(&c.TenancyOpts) + tenancyMgr := tenancy.NewManager(&c.Tenancy) if tenancyMgr.Enabled { opts = append(opts, grpc.WithUnaryInterceptor(tenancy.NewClientUnaryInterceptor(tenancyMgr))) opts = append(opts, grpc.WithStreamInterceptor(tenancy.NewClientStreamInterceptor(tenancyMgr))) } - var err error - // TODO: Need to replace grpc.DialContext with grpc.NewClient and pass test - c.remoteConn, err = grpc.DialContext(ctx, c.RemoteServerAddr, opts...) + + remoteConn, err := newClient(opts...) if err != nil { - return nil, fmt.Errorf("error connecting to remote storage: %w", err) + return nil, fmt.Errorf("error creating remote storage client: %w", err) } - - grpcClient := shared.NewGRPCClient(c.remoteConn) + grpcClient := shared.NewGRPCClient(remoteConn) return &ClientPluginServices{ PluginServices: shared.PluginServices{ Store: grpcClient, @@ -132,99 +106,13 @@ func (c *Configuration) buildRemote(logger *zap.Logger, tracerProvider trace.Tra StreamingSpanWriter: grpcClient, }, Capabilities: grpcClient, + remoteConn: remoteConn, }, nil } -func (c *Configuration) buildPlugin(logger *zap.Logger, tracerProvider trace.TracerProvider) (*ClientPluginServices, error) { - opts := []grpc.DialOption{ - grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(tracerProvider))), - } - - tenancyMgr := tenancy.NewManager(&c.TenancyOpts) - if tenancyMgr.Enabled { - opts = append(opts, grpc.WithUnaryInterceptor(tenancy.NewClientUnaryInterceptor(tenancyMgr))) - opts = append(opts, grpc.WithStreamInterceptor(tenancy.NewClientStreamInterceptor(tenancyMgr))) - } - - // #nosec G204 - cmd := exec.Command(c.PluginBinary, "--config", c.PluginConfigurationFile) - client := plugin.NewClient(&plugin.ClientConfig{ - HandshakeConfig: shared.Handshake, - VersionedPlugins: map[int]plugin.PluginSet{ - 1: shared.PluginMap, - }, - Cmd: cmd, - AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, - Logger: hclog.New(&hclog.LoggerOptions{ - Level: hclog.LevelFromString(c.PluginLogLevel), - }), - GRPCDialOptions: opts, - }) - - rpcClient, err := client.Client() - if err != nil { - return nil, fmt.Errorf("error attempting to connect to plugin rpc client: %w", err) - } - - raw, err := rpcClient.Dispense(shared.StoragePluginIdentifier) - if err != nil { - return nil, fmt.Errorf("unable to retrieve storage plugin instance: %w", err) - } - - // in practice, the type of `raw` is *shared.grpcClient, and type casts below cannot fail - storagePlugin, ok := raw.(shared.StoragePlugin) - if !ok { - return nil, fmt.Errorf("unable to cast %T to shared.StoragePlugin for plugin \"%s\"", - raw, shared.StoragePluginIdentifier) - } - archiveStoragePlugin, ok := raw.(shared.ArchiveStoragePlugin) - if !ok { - return nil, fmt.Errorf("unable to cast %T to shared.ArchiveStoragePlugin for plugin \"%s\"", - raw, shared.StoragePluginIdentifier) - } - streamingSpanWriterPlugin, ok := raw.(shared.StreamingSpanWriterPlugin) - if !ok { - return nil, fmt.Errorf("unable to cast %T to shared.StreamingSpanWriterPlugin for plugin \"%s\"", - raw, shared.StoragePluginIdentifier) - } - capabilities, ok := raw.(shared.PluginCapabilities) - if !ok { - return nil, fmt.Errorf("unable to cast %T to shared.PluginCapabilities for plugin \"%s\"", - raw, shared.StoragePluginIdentifier) - } - - if err := c.startPluginHealthCheck(rpcClient, logger); err != nil { - return nil, fmt.Errorf("initial plugin health check failed: %w", err) +func (c *ClientPluginServices) Close() error { + if c.remoteConn != nil { + return c.remoteConn.Close() } - - return &ClientPluginServices{ - PluginServices: shared.PluginServices{ - Store: storagePlugin, - ArchiveStore: archiveStoragePlugin, - StreamingSpanWriter: streamingSpanWriterPlugin, - }, - Capabilities: capabilities, - killPluginClient: client.Kill, - }, nil -} - -func (c *Configuration) startPluginHealthCheck(rpcClient plugin.ClientProtocol, logger *zap.Logger) error { - c.pluginRPCClient = rpcClient - c.pluginHealthCheckDone = make(chan bool) - c.pluginHealthCheck = time.NewTicker(pluginHealthCheckInterval) - - go func() { - for { - select { - case <-c.pluginHealthCheckDone: - return - case <-c.pluginHealthCheck.C: - if err := c.pluginRPCClient.Ping(); err != nil { - logger.Fatal("plugin health check failed", zap.Error(err)) - } - } - } - }() - - return c.pluginRPCClient.Ping() + return nil } diff --git a/plugin/storage/grpc/config/config_test.go b/plugin/storage/grpc/config/config_test.go new file mode 100644 index 00000000000..dc6bf298ac9 --- /dev/null +++ b/plugin/storage/grpc/config/config_test.go @@ -0,0 +1,24 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package config + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "google.golang.org/grpc" +) + +func TestBuildRemoteNewClientError(t *testing.T) { + // this is a silly test to verify handling of error from grpc.NewClient, which cannot be induced via params. + c := &ConfigV2{} + newClientFn := func(opts ...grpc.DialOption) (conn *grpc.ClientConn, err error) { + return nil, errors.New("test error") + } + _, err := newRemoteStorage(c, component.TelemetrySettings{}, newClientFn) + require.Error(t, err) + require.Contains(t, err.Error(), "error creating remote storage client") +} diff --git a/plugin/storage/grpc/factory.go b/plugin/storage/grpc/factory.go index e5ae279541d..fd39208f750 100644 --- a/plugin/storage/grpc/factory.go +++ b/plugin/storage/grpc/factory.go @@ -28,7 +28,6 @@ import ( "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/plugin" "github.com/jaegertracing/jaeger/plugin/storage/grpc/config" - "github.com/jaegertracing/jaeger/plugin/storage/grpc/shared" "github.com/jaegertracing/jaeger/storage" "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" @@ -43,19 +42,14 @@ var ( // interface comformance checks // Factory implements storage.Factory and creates storage components backed by a storage plugin. type Factory struct { - options Options metricsFactory metrics.Factory logger *zap.Logger tracerProvider trace.TracerProvider - builder config.PluginBuilder + configV1 config.Configuration + configV2 *config.ConfigV2 - store shared.StoragePlugin - archiveStore shared.ArchiveStoragePlugin - streamingSpanWriter shared.StreamingSpanWriterPlugin - capabilities shared.PluginCapabilities - - servicesCloser io.Closer + services *config.ClientPluginServices } // NewFactory creates a new Factory. @@ -65,14 +59,13 @@ func NewFactory() *Factory { // NewFactoryWithConfig is used from jaeger(v2). func NewFactoryWithConfig( - cfg config.Configuration, + cfg config.ConfigV2, metricsFactory metrics.Factory, logger *zap.Logger, ) (*Factory, error) { f := NewFactory() - f.configureFromOptions(Options{Configuration: cfg}) - err := f.Initialize(metricsFactory, logger) - if err != nil { + f.configV2 = &cfg + if err := f.Initialize(metricsFactory, logger); err != nil { return nil, err } return f, nil @@ -80,21 +73,14 @@ func NewFactoryWithConfig( // AddFlags implements plugin.Configurable func (f *Factory) AddFlags(flagSet *flag.FlagSet) { - f.options.AddFlags(flagSet) + v1AddFlags(flagSet) } // InitFromViper implements plugin.Configurable func (f *Factory) InitFromViper(v *viper.Viper, logger *zap.Logger) { - if err := f.options.InitFromViper(v); err != nil { + if err := v1InitFromViper(&f.configV1, v); err != nil { logger.Fatal("unable to initialize gRPC storage factory", zap.Error(err)) } - f.builder = &f.options.Configuration -} - -// configureFromOptions initializes factory from options -func (f *Factory) configureFromOptions(opts Options) { - f.options = opts - f.builder = &f.options.Configuration } // Initialize implements storage.Factory @@ -102,76 +88,75 @@ func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) f.metricsFactory, f.logger = metricsFactory, logger f.tracerProvider = otel.GetTracerProvider() - services, err := f.builder.Build(logger, f.tracerProvider) - if err != nil { - return fmt.Errorf("grpc-plugin builder failed to create a store: %w", err) + if f.configV2 == nil { + f.configV2 = f.configV1.TranslateToConfigV2() } - f.store = services.Store - f.archiveStore = services.ArchiveStore - f.capabilities = services.Capabilities - f.streamingSpanWriter = services.StreamingSpanWriter - f.servicesCloser = services - logger.Info("External plugin storage configuration", zap.Any("configuration", f.options.Configuration)) + var err error + f.services, err = f.configV2.Build(logger, f.tracerProvider) + if err != nil { + return fmt.Errorf("grpc storage builder failed to create a store: %w", err) + } + logger.Info("Remote storage configuration", zap.Any("configuration", f.configV2)) return nil } // CreateSpanReader implements storage.Factory func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { - return f.store.SpanReader(), nil + return f.services.Store.SpanReader(), nil } // CreateSpanWriter implements storage.Factory func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { - if f.capabilities != nil && f.streamingSpanWriter != nil { - if capabilities, err := f.capabilities.Capabilities(); err == nil && capabilities.StreamingSpanWriter { - return f.streamingSpanWriter.StreamingSpanWriter(), nil + if f.services.Capabilities != nil && f.services.StreamingSpanWriter != nil { + if capabilities, err := f.services.Capabilities.Capabilities(); err == nil && capabilities.StreamingSpanWriter { + return f.services.StreamingSpanWriter.StreamingSpanWriter(), nil } } - return f.store.SpanWriter(), nil + return f.services.Store.SpanWriter(), nil } // CreateDependencyReader implements storage.Factory func (f *Factory) CreateDependencyReader() (dependencystore.Reader, error) { - return f.store.DependencyReader(), nil + return f.services.Store.DependencyReader(), nil } // CreateArchiveSpanReader implements storage.ArchiveFactory func (f *Factory) CreateArchiveSpanReader() (spanstore.Reader, error) { - if f.capabilities == nil { + if f.services.Capabilities == nil { return nil, storage.ErrArchiveStorageNotSupported } - capabilities, err := f.capabilities.Capabilities() + capabilities, err := f.services.Capabilities.Capabilities() if err != nil { return nil, err } if capabilities == nil || !capabilities.ArchiveSpanReader { return nil, storage.ErrArchiveStorageNotSupported } - return f.archiveStore.ArchiveSpanReader(), nil + return f.services.ArchiveStore.ArchiveSpanReader(), nil } // CreateArchiveSpanWriter implements storage.ArchiveFactory func (f *Factory) CreateArchiveSpanWriter() (spanstore.Writer, error) { - if f.capabilities == nil { + if f.services.Capabilities == nil { return nil, storage.ErrArchiveStorageNotSupported } - capabilities, err := f.capabilities.Capabilities() + capabilities, err := f.services.Capabilities.Capabilities() if err != nil { return nil, err } if capabilities == nil || !capabilities.ArchiveSpanWriter { return nil, storage.ErrArchiveStorageNotSupported } - return f.archiveStore.ArchiveSpanWriter(), nil + return f.services.ArchiveStore.ArchiveSpanWriter(), nil } // Close closes the resources held by the factory func (f *Factory) Close() error { - errs := []error{} - if f.servicesCloser != nil { - errs = append(errs, f.servicesCloser.Close()) + var errs []error + if f.services != nil { + errs = append(errs, f.services.Close()) } - errs = append(errs, f.builder.Close()) + errs = append(errs, f.configV1.RemoteTLS.Close()) return errors.Join(errs...) } diff --git a/plugin/storage/grpc/factory_test.go b/plugin/storage/grpc/factory_test.go index 2dae30fe202..dfc32f40612 100644 --- a/plugin/storage/grpc/factory_test.go +++ b/plugin/storage/grpc/factory_test.go @@ -15,6 +15,7 @@ package grpc import ( + "context" "errors" "log" "net" @@ -23,8 +24,11 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/collector/config/configauth" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/exporter/exporterhelper" "go.uber.org/zap" "google.golang.org/grpc" @@ -40,118 +44,112 @@ import ( spanStoreMocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" ) -type mockPluginBuilder struct { - plugin *mockPlugin - writerType string - err error +type store struct { + reader spanstore.Reader + writer spanstore.Writer + deps dependencystore.Reader } -func (b *mockPluginBuilder) Build(logger *zap.Logger, tracer trace.TracerProvider) (*grpcConfig.ClientPluginServices, error) { - if b.err != nil { - return nil, b.err - } - - services := &grpcConfig.ClientPluginServices{ - PluginServices: shared.PluginServices{ - Store: b.plugin, - ArchiveStore: b.plugin, - }, - } - if b.writerType == "streaming" { - services.PluginServices.StreamingSpanWriter = b.plugin - } - if b.plugin.capabilities != nil { - services.Capabilities = b.plugin - } - - return services, nil +func (s *store) SpanReader() spanstore.Reader { + return s.reader } -func (b *mockPluginBuilder) Close() error { - return nil +func (s *store) SpanWriter() spanstore.Writer { + return s.writer } -type mockPlugin struct { - spanReader spanstore.Reader - spanWriter spanstore.Writer - archiveReader spanstore.Reader - archiveWriter spanstore.Writer - streamingSpanWriter spanstore.Writer - capabilities shared.PluginCapabilities - dependencyReader dependencystore.Reader +func (s *store) ArchiveSpanReader() spanstore.Reader { + return s.reader } -func (mp *mockPlugin) Capabilities() (*shared.Capabilities, error) { - return mp.capabilities.Capabilities() +func (s *store) ArchiveSpanWriter() spanstore.Writer { + return s.writer } -func (mp *mockPlugin) ArchiveSpanReader() spanstore.Reader { - return mp.archiveReader +func (s *store) DependencyReader() dependencystore.Reader { + return s.deps } -func (mp *mockPlugin) ArchiveSpanWriter() spanstore.Writer { - return mp.archiveWriter +func (s *store) StreamingSpanWriter() spanstore.Writer { + return s.writer } -func (mp *mockPlugin) SpanReader() spanstore.Reader { - return mp.spanReader +func makeMockServices() *grpcConfig.ClientPluginServices { + return &grpcConfig.ClientPluginServices{ + PluginServices: shared.PluginServices{ + Store: &store{ + writer: new(spanStoreMocks.Writer), + reader: new(spanStoreMocks.Reader), + deps: new(dependencyStoreMocks.Reader), + }, + ArchiveStore: &store{ + writer: new(spanStoreMocks.Writer), + reader: new(spanStoreMocks.Reader), + }, + StreamingSpanWriter: &store{ + writer: new(spanStoreMocks.Writer), + }, + }, + Capabilities: new(mocks.PluginCapabilities), + } } -func (mp *mockPlugin) SpanWriter() spanstore.Writer { - return mp.spanWriter -} +func makeFactory(t *testing.T) *Factory { + f := NewFactory() + f.InitFromViper(viper.New(), zap.NewNop()) + require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) -func (mp *mockPlugin) StreamingSpanWriter() spanstore.Writer { - return mp.streamingSpanWriter -} + keepServices := f.services + t.Cleanup(func() { + keepServices.Close() + f.Close() + }) -func (mp *mockPlugin) DependencyReader() dependencystore.Reader { - return mp.dependencyReader + f.services = makeMockServices() + return f } -func TestGRPCStorageFactory(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) - - // after InitFromViper, f.builder points to a real plugin builder that will fail in unit tests, - // so we override it with a mock. - f.builder = &mockPluginBuilder{ - err: errors.New("made-up error"), - } - err := f.Initialize(metrics.NullFactory, zap.NewNop()) - require.Error(t, err) - assert.Contains(t, err.Error(), "made-up error") - - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - spanWriter: new(spanStoreMocks.Writer), - spanReader: new(spanStoreMocks.Reader), - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - capabilities: new(mocks.PluginCapabilities), - dependencyReader: new(dependencyStoreMocks.Reader), +func TestNewFactoryError(t *testing.T) { + cfg := &grpcConfig.ConfigV2{ + ClientConfig: configgrpc.ClientConfig{ + // non-empty Auth is currently not supported + Auth: &configauth.Authentication{}, }, } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + t.Run("with_config", func(t *testing.T) { + _, err := NewFactoryWithConfig(*cfg, metrics.NullFactory, zap.NewNop()) + require.Error(t, err) + assert.Contains(t, err.Error(), "authenticator") + }) + + t.Run("viper", func(t *testing.T) { + f := NewFactory() + f.InitFromViper(viper.New(), zap.NewNop()) + f.configV2 = cfg + err := f.Initialize(metrics.NullFactory, zap.NewNop()) + require.Error(t, err) + assert.Contains(t, err.Error(), "authenticator") + }) +} + +func TestInitFactory(t *testing.T) { + f := makeFactory(t) + f.services.Capabilities = nil - assert.NotNil(t, f.store) reader, err := f.CreateSpanReader() require.NoError(t, err) - assert.Equal(t, f.store.SpanReader(), reader) + assert.Equal(t, f.services.Store.SpanReader(), reader) + writer, err := f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) + assert.Equal(t, f.services.Store.SpanWriter(), writer) + depReader, err := f.CreateDependencyReader() require.NoError(t, err) - assert.Equal(t, f.store.DependencyReader(), depReader) + assert.Equal(t, f.services.Store.DependencyReader(), depReader) } func TestGRPCStorageFactoryWithConfig(t *testing.T) { - cfg := grpcConfig.Configuration{} - _, err := NewFactoryWithConfig(cfg, metrics.NullFactory, zap.NewNop()) - require.ErrorContains(t, err, "grpc-plugin builder failed to create a store: error connecting to remote storage") - lis, err := net.Listen("tcp", ":0") require.NoError(t, err, "failed to listen") @@ -163,19 +161,23 @@ func TestGRPCStorageFactoryWithConfig(t *testing.T) { }() defer s.Stop() - cfg.RemoteServerAddr = lis.Addr().String() - cfg.RemoteConnectTimeout = 1 * time.Second + cfg := grpcConfig.ConfigV2{ + ClientConfig: configgrpc.ClientConfig{ + Endpoint: lis.Addr().String(), + }, + TimeoutSettings: exporterhelper.TimeoutSettings{ + Timeout: 1 * time.Second, + }, + } f, err := NewFactoryWithConfig(cfg, metrics.NullFactory, zap.NewNop()) require.NoError(t, err) require.NoError(t, f.Close()) } func TestGRPCStorageFactory_Capabilities(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) + f := makeFactory(t) - capabilities := new(mocks.PluginCapabilities) + capabilities := f.services.Capabilities.(*mocks.PluginCapabilities) capabilities.On("Capabilities"). Return(&shared.Capabilities{ ArchiveSpanReader: true, @@ -183,53 +185,30 @@ func TestGRPCStorageFactory_Capabilities(t *testing.T) { StreamingSpanWriter: true, }, nil).Times(3) - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - capabilities: capabilities, - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - streamingSpanWriter: new(spanStoreMocks.Writer), - }, - writerType: "streaming", - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) - - assert.NotNil(t, f.store) reader, err := f.CreateArchiveSpanReader() require.NoError(t, err) assert.NotNil(t, reader) + writer, err := f.CreateArchiveSpanWriter() require.NoError(t, err) assert.NotNil(t, writer) + writer, err = f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.streamingSpanWriter.StreamingSpanWriter(), writer) + assert.NotNil(t, writer) } func TestGRPCStorageFactory_CapabilitiesDisabled(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) + f := makeFactory(t) - capabilities := new(mocks.PluginCapabilities) + capabilities := f.services.Capabilities.(*mocks.PluginCapabilities) capabilities.On("Capabilities"). Return(&shared.Capabilities{ ArchiveSpanReader: false, ArchiveSpanWriter: false, StreamingSpanWriter: false, - }, nil) - - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - capabilities: capabilities, - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - spanWriter: new(spanStoreMocks.Writer), - }, - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + }, nil).Times(3) - assert.NotNil(t, f.store) reader, err := f.CreateArchiveSpanReader() require.EqualError(t, err, storage.ErrArchiveStorageNotSupported.Error()) assert.Nil(t, reader) @@ -238,30 +217,16 @@ func TestGRPCStorageFactory_CapabilitiesDisabled(t *testing.T) { assert.Nil(t, writer) writer, err = f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) + assert.NotNil(t, writer, "regular span writer is available") } func TestGRPCStorageFactory_CapabilitiesError(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) + f := makeFactory(t) - capabilities := new(mocks.PluginCapabilities) + capabilities := f.services.Capabilities.(*mocks.PluginCapabilities) customError := errors.New("made-up error") - capabilities.On("Capabilities"). - Return(nil, customError) - - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - capabilities: capabilities, - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - spanWriter: new(spanStoreMocks.Writer), - }, - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + capabilities.On("Capabilities").Return(nil, customError) - assert.NotNil(t, f.store) reader, err := f.CreateArchiveSpanReader() require.EqualError(t, err, customError.Error()) assert.Nil(t, reader) @@ -270,24 +235,13 @@ func TestGRPCStorageFactory_CapabilitiesError(t *testing.T) { assert.Nil(t, writer) writer, err = f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) + assert.NotNil(t, writer, "regular span writer is available") } func TestGRPCStorageFactory_CapabilitiesNil(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) - - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - spanWriter: new(spanStoreMocks.Writer), - }, - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + f := makeFactory(t) + f.services.Capabilities = nil - assert.NotNil(t, f.store) reader, err := f.CreateArchiveSpanReader() assert.Equal(t, err, storage.ErrArchiveStorageNotSupported) assert.Nil(t, reader) @@ -296,82 +250,70 @@ func TestGRPCStorageFactory_CapabilitiesNil(t *testing.T) { assert.Nil(t, writer) writer, err = f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) + assert.NotNil(t, writer, "regular span writer is available") } -func TestWithConfiguration(t *testing.T) { +func TestWithCLIFlags(t *testing.T) { f := NewFactory() v, command := config.Viperize(f.AddFlags) err := command.ParseFlags([]string{ - "--grpc-storage-plugin.log-level=debug", - "--grpc-storage-plugin.binary=noop-grpc-plugin", - "--grpc-storage-plugin.configuration-file=config.json", + "--grpc-storage.server=foo:1234", }) require.NoError(t, err) f.InitFromViper(v, zap.NewNop()) - assert.Equal(t, "noop-grpc-plugin", f.options.Configuration.PluginBinary) - assert.Equal(t, "config.json", f.options.Configuration.PluginConfigurationFile) - assert.Equal(t, "debug", f.options.Configuration.PluginLogLevel) + assert.Equal(t, "foo:1234", f.configV1.RemoteServerAddr) require.NoError(t, f.Close()) } -func TestConfigureFromOptions(t *testing.T) { - f := Factory{} - o := Options{ - Configuration: grpcConfig.Configuration{ - PluginLogLevel: "info", - }, - } - f.configureFromOptions(o) - assert.Equal(t, o, f.options) - assert.Equal(t, &o.Configuration, f.builder) -} - func TestStreamingSpanWriterFactory_CapabilitiesNil(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) + f := makeFactory(t) + + f.services.Capabilities = nil + mockWriter := f.services.Store.SpanWriter().(*spanStoreMocks.Writer) + mockWriter.On("WriteSpan", mock.Anything, mock.Anything).Return(errors.New("not streaming writer")) + mockWriter2 := f.services.StreamingSpanWriter.StreamingSpanWriter().(*spanStoreMocks.Writer) + mockWriter2.On("WriteSpan", mock.Anything, mock.Anything).Return(errors.New("I am streaming writer")) - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - spanWriter: new(spanStoreMocks.Writer), - }, - writerType: "streaming", - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) writer, err := f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) + err = writer.WriteSpan(context.Background(), nil) + require.Error(t, err) + require.Contains(t, err.Error(), "not streaming writer") } func TestStreamingSpanWriterFactory_Capabilities(t *testing.T) { - f := NewFactory() - v := viper.New() - f.InitFromViper(v, zap.NewNop()) + f := makeFactory(t) - capabilities := new(mocks.PluginCapabilities) + capabilities := f.services.Capabilities.(*mocks.PluginCapabilities) customError := errors.New("made-up error") - capabilities.On("Capabilities"). - Return(nil, customError).Once(). - On("Capabilities").Return(&shared.Capabilities{}, nil).Once() - - f.builder = &mockPluginBuilder{ - plugin: &mockPlugin{ - archiveWriter: new(spanStoreMocks.Writer), - archiveReader: new(spanStoreMocks.Reader), - spanWriter: new(spanStoreMocks.Writer), - capabilities: capabilities, - }, - writerType: "streaming", - } - require.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + capabilities. + // return error on the first call + On("Capabilities").Return(nil, customError).Once(). + // then return false on the second call + On("Capabilities").Return(&shared.Capabilities{}, nil).Once(). + // then return true on the second call + On("Capabilities").Return(&shared.Capabilities{StreamingSpanWriter: true}, nil).Once() + + mockWriter := f.services.Store.SpanWriter().(*spanStoreMocks.Writer) + mockWriter.On("WriteSpan", mock.Anything, mock.Anything).Return(errors.New("not streaming writer")) + mockWriter2 := f.services.StreamingSpanWriter.StreamingSpanWriter().(*spanStoreMocks.Writer) + mockWriter2.On("WriteSpan", mock.Anything, mock.Anything).Return(errors.New("I am streaming writer")) + writer, err := f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) // get unary writer when Capabilities return error + err = writer.WriteSpan(context.Background(), nil) + require.Error(t, err) + require.Contains(t, err.Error(), "not streaming writer", "unary writer when Capabilities return error") + + writer, err = f.CreateSpanWriter() + require.NoError(t, err) + err = writer.WriteSpan(context.Background(), nil) + require.Error(t, err) + require.Contains(t, err.Error(), "not streaming writer", "unary writer when Capabilities return false") writer, err = f.CreateSpanWriter() require.NoError(t, err) - assert.Equal(t, f.store.SpanWriter(), writer) // get unary writer when Capabilities return false + err = writer.WriteSpan(context.Background(), nil) + require.Error(t, err) + require.Contains(t, err.Error(), "I am streaming writer", "streaming writer when Capabilities return true") } diff --git a/plugin/storage/grpc/grpc.go b/plugin/storage/grpc/grpc.go deleted file mode 100644 index 09ffffcd399..00000000000 --- a/plugin/storage/grpc/grpc.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2019 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpc - -import ( - "github.com/hashicorp/go-plugin" - "google.golang.org/grpc" - - "github.com/jaegertracing/jaeger/plugin/storage/grpc/shared" -) - -// Serve creates a plugin configuration using the implementation of StoragePlugin and then serves it. -func Serve(services *shared.PluginServices) { - ServeWithGRPCServer(services, plugin.DefaultGRPCServer) -} - -// ServeWithGRPCServer creates a plugin configuration using the implementation of StoragePlugin and -// function to create grpcServer, and then serves it. -func ServeWithGRPCServer(services *shared.PluginServices, grpcServer func([]grpc.ServerOption) *grpc.Server, -) { - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: shared.Handshake, - VersionedPlugins: map[int]plugin.PluginSet{ - 1: map[string]plugin.Plugin{ - shared.StoragePluginIdentifier: &shared.StorageGRPCPlugin{ - Impl: services.Store, - ArchiveImpl: services.ArchiveStore, - StreamImpl: services.StreamingSpanWriter, - }, - }, - }, - GRPCServer: grpcServer, - }) -} diff --git a/plugin/storage/grpc/memory/plugin.go b/plugin/storage/grpc/memory/plugin.go deleted file mode 100644 index bda596e9684..00000000000 --- a/plugin/storage/grpc/memory/plugin.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2020 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package memory - -import ( - "github.com/jaegertracing/jaeger/plugin/storage/grpc/shared" - "github.com/jaegertracing/jaeger/plugin/storage/memory" - "github.com/jaegertracing/jaeger/storage/dependencystore" - "github.com/jaegertracing/jaeger/storage/spanstore" -) - -var ( - _ shared.StoragePlugin = (*storagePlugin)(nil) - _ shared.ArchiveStoragePlugin = (*storagePlugin)(nil) - _ shared.StreamingSpanWriterPlugin = (*storagePlugin)(nil) -) - -type storagePlugin struct { - store *memory.Store - archiveStore *memory.Store -} - -func NewStoragePlugin(mainStore *memory.Store, archiveStore *memory.Store) *storagePlugin { - return &storagePlugin{store: mainStore, archiveStore: archiveStore} -} - -func (ns *storagePlugin) DependencyReader() dependencystore.Reader { - return ns.store -} - -func (ns *storagePlugin) SpanReader() spanstore.Reader { - return ns.store -} - -func (ns *storagePlugin) SpanWriter() spanstore.Writer { - return ns.store -} - -func (ns *storagePlugin) StreamingSpanWriter() spanstore.Writer { - return ns.store -} - -func (ns *storagePlugin) ArchiveSpanReader() spanstore.Reader { - return ns.archiveStore -} - -func (ns *storagePlugin) ArchiveSpanWriter() spanstore.Writer { - return ns.archiveStore -} diff --git a/plugin/storage/grpc/memory/plugin_test.go b/plugin/storage/grpc/memory/plugin_test.go deleted file mode 100644 index 7f9501ce29a..00000000000 --- a/plugin/storage/grpc/memory/plugin_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2019 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package memory - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/jaegertracing/jaeger/pkg/testutils" - "github.com/jaegertracing/jaeger/plugin/storage/memory" -) - -func TestPluginUsesMemoryStorage(t *testing.T) { - mainStorage := memory.NewStore() - archiveStorage := memory.NewStore() - - memStorePlugin := NewStoragePlugin(mainStorage, archiveStorage) - - assert.Equal(t, mainStorage, memStorePlugin.DependencyReader()) - assert.Equal(t, mainStorage, memStorePlugin.SpanReader()) - assert.Equal(t, mainStorage, memStorePlugin.SpanWriter()) - assert.Equal(t, mainStorage, memStorePlugin.StreamingSpanWriter()) - assert.Equal(t, archiveStorage, memStorePlugin.ArchiveSpanReader()) - assert.Equal(t, archiveStorage, memStorePlugin.ArchiveSpanWriter()) -} - -func TestMain(m *testing.M) { - testutils.VerifyGoLeaks(m) -} diff --git a/plugin/storage/grpc/options.go b/plugin/storage/grpc/options.go index b3b8d9210b2..b70290baf23 100644 --- a/plugin/storage/grpc/options.go +++ b/plugin/storage/grpc/options.go @@ -17,7 +17,6 @@ package grpc import ( "flag" "fmt" - "log" "time" "github.com/spf13/viper" @@ -28,24 +27,12 @@ import ( ) const ( - pluginBinary = "grpc-storage-plugin.binary" - pluginConfigurationFile = "grpc-storage-plugin.configuration-file" - pluginLogLevel = "grpc-storage-plugin.log-level" remotePrefix = "grpc-storage" remoteServer = remotePrefix + ".server" remoteConnectionTimeout = remotePrefix + ".connection-timeout" - defaultPluginLogLevel = "warn" defaultConnectionTimeout = time.Duration(5 * time.Second) - - deprecatedSidecar = "(deprecated, will be removed after 2024-03-01) " ) -// Options contains GRPC plugins configs and provides the ability -// to bind them to command line flags -type Options struct { - Configuration config.Configuration `mapstructure:",squash"` -} - func tlsFlagsConfig() tlscfg.ClientFlagsConfig { return tlscfg.ClientFlagsConfig{ Prefix: remotePrefix, @@ -53,31 +40,21 @@ func tlsFlagsConfig() tlscfg.ClientFlagsConfig { } // AddFlags adds flags for Options -func (opt *Options) AddFlags(flagSet *flag.FlagSet) { +func v1AddFlags(flagSet *flag.FlagSet) { tlsFlagsConfig().AddFlags(flagSet) - flagSet.String(pluginBinary, "", deprecatedSidecar+"The location of the plugin binary") - flagSet.String(pluginConfigurationFile, "", deprecatedSidecar+"A path pointing to the plugin's configuration file, made available to the plugin with the --config arg") - flagSet.String(pluginLogLevel, defaultPluginLogLevel, "Set the log level of the plugin's logger") flagSet.String(remoteServer, "", "The remote storage gRPC server address as host:port") flagSet.Duration(remoteConnectionTimeout, defaultConnectionTimeout, "The remote storage gRPC server connection timeout") } -// InitFromViper initializes Options with properties from viper -func (opt *Options) InitFromViper(v *viper.Viper) error { - opt.Configuration.PluginBinary = v.GetString(pluginBinary) - opt.Configuration.PluginConfigurationFile = v.GetString(pluginConfigurationFile) - opt.Configuration.PluginLogLevel = v.GetString(pluginLogLevel) - opt.Configuration.RemoteServerAddr = v.GetString(remoteServer) +func v1InitFromViper(cfg *config.Configuration, v *viper.Viper) error { + cfg.RemoteServerAddr = v.GetString(remoteServer) var err error - opt.Configuration.RemoteTLS, err = tlsFlagsConfig().InitFromViper(v) + cfg.RemoteTLS, err = tlsFlagsConfig().InitFromViper(v) if err != nil { return fmt.Errorf("failed to parse gRPC storage TLS options: %w", err) } - opt.Configuration.RemoteConnectTimeout = v.GetDuration(remoteConnectionTimeout) - opt.Configuration.TenancyOpts = tenancy.InitFromViper(v) - if opt.Configuration.PluginBinary != "" { - log.Printf(deprecatedSidecar + "using sidecar model of grpc-plugin storage, please upgrade to 'remote' gRPC storage. https://github.com/jaegertracing/jaeger/issues/4647") - } + cfg.RemoteConnectTimeout = v.GetDuration(remoteConnectionTimeout) + cfg.TenancyOpts = tenancy.InitFromViper(v) return nil } diff --git a/plugin/storage/grpc/options_test.go b/plugin/storage/grpc/options_test.go index a72bb9eeb81..4d1670e97c2 100644 --- a/plugin/storage/grpc/options_test.go +++ b/plugin/storage/grpc/options_test.go @@ -23,70 +23,65 @@ import ( "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/tenancy" + grpccfg "github.com/jaegertracing/jaeger/plugin/storage/grpc/config" ) func TestOptionsWithFlags(t *testing.T) { - opts := &Options{} - v, command := config.Viperize(opts.AddFlags, tenancy.AddFlags) + v, command := config.Viperize(v1AddFlags, tenancy.AddFlags) err := command.ParseFlags([]string{ - "--grpc-storage-plugin.binary=noop-grpc-plugin", - "--grpc-storage-plugin.configuration-file=config.json", - "--grpc-storage-plugin.log-level=debug", + "--grpc-storage.server=foo:12345", "--multi-tenancy.header=x-scope-orgid", }) require.NoError(t, err) - opts.InitFromViper(v) + var cfg grpccfg.Configuration + require.NoError(t, v1InitFromViper(&cfg, v)) - assert.Equal(t, "noop-grpc-plugin", opts.Configuration.PluginBinary) - assert.Equal(t, "config.json", opts.Configuration.PluginConfigurationFile) - assert.Equal(t, "debug", opts.Configuration.PluginLogLevel) - assert.False(t, opts.Configuration.TenancyOpts.Enabled) - assert.Equal(t, "x-scope-orgid", opts.Configuration.TenancyOpts.Header) + assert.Equal(t, "foo:12345", cfg.RemoteServerAddr) + assert.False(t, cfg.TenancyOpts.Enabled) + assert.Equal(t, "x-scope-orgid", cfg.TenancyOpts.Header) } func TestRemoteOptionsWithFlags(t *testing.T) { - opts := &Options{} - v, command := config.Viperize(opts.AddFlags) + v, command := config.Viperize(v1AddFlags) err := command.ParseFlags([]string{ "--grpc-storage.server=localhost:2001", "--grpc-storage.tls.enabled=true", "--grpc-storage.connection-timeout=60s", }) require.NoError(t, err) - opts.InitFromViper(v) + var cfg grpccfg.Configuration + require.NoError(t, v1InitFromViper(&cfg, v)) - assert.Equal(t, "", opts.Configuration.PluginBinary) - assert.Equal(t, "localhost:2001", opts.Configuration.RemoteServerAddr) - assert.True(t, opts.Configuration.RemoteTLS.Enabled) - assert.Equal(t, 60*time.Second, opts.Configuration.RemoteConnectTimeout) + assert.Equal(t, "localhost:2001", cfg.RemoteServerAddr) + assert.True(t, cfg.RemoteTLS.Enabled) + assert.Equal(t, 60*time.Second, cfg.RemoteConnectTimeout) } func TestRemoteOptionsNoTLSWithFlags(t *testing.T) { - opts := &Options{} - v, command := config.Viperize(opts.AddFlags) + v, command := config.Viperize(v1AddFlags) err := command.ParseFlags([]string{ "--grpc-storage.server=localhost:2001", "--grpc-storage.tls.enabled=false", "--grpc-storage.connection-timeout=60s", }) require.NoError(t, err) - opts.InitFromViper(v) + var cfg grpccfg.Configuration + require.NoError(t, v1InitFromViper(&cfg, v)) - assert.Equal(t, "", opts.Configuration.PluginBinary) - assert.Equal(t, "localhost:2001", opts.Configuration.RemoteServerAddr) - assert.False(t, opts.Configuration.RemoteTLS.Enabled) - assert.Equal(t, 60*time.Second, opts.Configuration.RemoteConnectTimeout) + assert.Equal(t, "localhost:2001", cfg.RemoteServerAddr) + assert.False(t, cfg.RemoteTLS.Enabled) + assert.Equal(t, 60*time.Second, cfg.RemoteConnectTimeout) } func TestFailedTLSFlags(t *testing.T) { - opts := &Options{} - v, command := config.Viperize(opts.AddFlags) + v, command := config.Viperize(v1AddFlags) err := command.ParseFlags([]string{ "--grpc-storage.tls.enabled=false", "--grpc-storage.tls.cert=blah", // invalid unless tls.enabled=true }) require.NoError(t, err) - err = opts.InitFromViper(v) + var cfg grpccfg.Configuration + err = v1InitFromViper(&cfg, v) require.Error(t, err) assert.Contains(t, err.Error(), "failed to parse gRPC storage TLS options") } diff --git a/plugin/storage/grpc/shared/grpc_client.go b/plugin/storage/grpc/shared/grpc_client.go index 9b24b6c18eb..cb8693f950b 100644 --- a/plugin/storage/grpc/shared/grpc_client.go +++ b/plugin/storage/grpc/shared/grpc_client.go @@ -28,6 +28,7 @@ import ( "github.com/jaegertracing/jaeger/model" "github.com/jaegertracing/jaeger/pkg/bearertoken" + _ "github.com/jaegertracing/jaeger/pkg/gogocodec" // force gogo codec registration "github.com/jaegertracing/jaeger/proto-gen/storage_v1" "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" diff --git a/plugin/storage/grpc/shared/grpc_handler.go b/plugin/storage/grpc/shared/grpc_handler.go index 98f27a53540..794bbf7e6e8 100644 --- a/plugin/storage/grpc/shared/grpc_handler.go +++ b/plugin/storage/grpc/shared/grpc_handler.go @@ -22,9 +22,12 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/status" "github.com/jaegertracing/jaeger/model" + _ "github.com/jaegertracing/jaeger/pkg/gogocodec" // force gogo codec registration "github.com/jaegertracing/jaeger/proto-gen/storage_v1" "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" @@ -83,7 +86,7 @@ func NewGRPCHandlerWithPlugins( } // Register registers the server as gRPC methods handler. -func (s *GRPCHandler) Register(ss *grpc.Server) error { +func (s *GRPCHandler) Register(ss *grpc.Server, hs *health.Server) error { storage_v1.RegisterSpanReaderPluginServer(ss, s) storage_v1.RegisterSpanWriterPluginServer(ss, s) storage_v1.RegisterArchiveSpanReaderPluginServer(ss, s) @@ -91,6 +94,16 @@ func (s *GRPCHandler) Register(ss *grpc.Server) error { storage_v1.RegisterPluginCapabilitiesServer(ss, s) storage_v1.RegisterDependenciesReaderPluginServer(ss, s) storage_v1.RegisterStreamingSpanWriterPluginServer(ss, s) + + hs.SetServingStatus("jaeger.storage.v1.SpanReaderPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.SpanWriterPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.ArchiveSpanReaderPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.ArchiveSpanWriterPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.PluginCapabilities", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.DependenciesReaderPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + hs.SetServingStatus("jaeger.storage.v1.StreamingSpanWriterPlugin", grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(ss, hs) + return nil } diff --git a/plugin/storage/grpc/shared/interface.go b/plugin/storage/grpc/shared/interface.go index c6345a29b82..ac3e5275d3e 100644 --- a/plugin/storage/grpc/shared/interface.go +++ b/plugin/storage/grpc/shared/interface.go @@ -15,26 +15,10 @@ package shared import ( - "github.com/hashicorp/go-plugin" - "github.com/jaegertracing/jaeger/storage/dependencystore" "github.com/jaegertracing/jaeger/storage/spanstore" ) -// StoragePluginIdentifier is the identifier that is shared by plugin and host. -const StoragePluginIdentifier = "storage_plugin" - -// Handshake is a common handshake that is shared by plugin and host. -var Handshake = plugin.HandshakeConfig{ - MagicCookieKey: "STORAGE_PLUGIN", - MagicCookieValue: "jaeger", -} - -// PluginMap is the map of plugins we can dispense. -var PluginMap = map[string]plugin.Plugin{ - StoragePluginIdentifier: &StorageGRPCPlugin{}, -} - // StoragePlugin is the interface we're exposing as a plugin. type StoragePlugin interface { SpanReader() spanstore.Reader diff --git a/plugin/storage/grpc/shared/plugin.go b/plugin/storage/grpc/shared/plugin.go deleted file mode 100644 index b4a3fabf93e..00000000000 --- a/plugin/storage/grpc/shared/plugin.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shared - -import ( - "context" - - "github.com/hashicorp/go-plugin" - "google.golang.org/grpc" - - _ "github.com/jaegertracing/jaeger/pkg/gogocodec" // force gogo codec registration -) - -// Ensure plugin.GRPCPlugin API match. -var _ plugin.GRPCPlugin = (*StorageGRPCPlugin)(nil) - -// StorageGRPCPlugin is the implementation of plugin.GRPCPlugin. -type StorageGRPCPlugin struct { - plugin.Plugin - - // Concrete implementation, This is only used for plugins that are written in Go. - Impl StoragePlugin - ArchiveImpl ArchiveStoragePlugin - StreamImpl StreamingSpanWriterPlugin -} - -// RegisterHandlers registers the plugin with the server -func (p *StorageGRPCPlugin) RegisterHandlers(s *grpc.Server) error { - handler := NewGRPCHandlerWithPlugins(p.Impl, p.ArchiveImpl, p.StreamImpl) - return handler.Register(s) -} - -// GRPCServer implements plugin.GRPCPlugin. It is used by go-plugin to create a grpc plugin server. -func (p *StorageGRPCPlugin) GRPCServer(_ *plugin.GRPCBroker, s *grpc.Server) error { - return p.RegisterHandlers(s) -} - -// GRPCClient implements plugin.GRPCPlugin. It is used by go-plugin to create a grpc plugin client. -func (*StorageGRPCPlugin) GRPCClient(_ context.Context, _ *plugin.GRPCBroker, conn *grpc.ClientConn) (interface{}, error) { - return NewGRPCClient(conn), nil -} diff --git a/plugin/storage/grpc/shared/plugin_test.go b/plugin/storage/grpc/shared/plugin_test.go deleted file mode 100644 index 3f143b773d4..00000000000 --- a/plugin/storage/grpc/shared/plugin_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2024 The Jaeger Authors. -// SPDX-License-Identifier: Apache-2.0 - -package shared - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - - "github.com/jaegertracing/jaeger/storage/dependencystore" - dependencyStoreMocks "github.com/jaegertracing/jaeger/storage/dependencystore/mocks" - "github.com/jaegertracing/jaeger/storage/spanstore" - spanStoreMocks "github.com/jaegertracing/jaeger/storage/spanstore/mocks" -) - -type mockStorageGRPCPlugin struct { - spanReader *spanStoreMocks.Reader - spanWriter *spanStoreMocks.Writer - depsReader *dependencyStoreMocks.Reader -} - -type mockArchiveStoragePlugin struct { - archiveReader *spanStoreMocks.Reader - archiveWriter *spanStoreMocks.Writer -} - -type mockStreamingSpanWriterPlugin struct { - streamWriter *spanStoreMocks.Writer -} - -func (plugin *mockArchiveStoragePlugin) ArchiveSpanReader() spanstore.Reader { - return plugin.archiveReader -} - -func (plugin *mockArchiveStoragePlugin) ArchiveSpanWriter() spanstore.Writer { - return plugin.archiveWriter -} - -func (plugin *mockStorageGRPCPlugin) SpanReader() spanstore.Reader { - return plugin.spanReader -} - -func (plugin *mockStorageGRPCPlugin) SpanWriter() spanstore.Writer { - return plugin.spanWriter -} - -func (plugin *mockStorageGRPCPlugin) DependencyReader() dependencystore.Reader { - return plugin.depsReader -} - -func (plugin *mockStreamingSpanWriterPlugin) StreamingSpanWriter() spanstore.Writer { - return plugin.streamWriter -} - -func TestStorageGRPCPlugin_RegisterHandlers(t *testing.T) { - plugin := StorageGRPCPlugin{ - Impl: &mockStorageGRPCPlugin{}, - ArchiveImpl: &mockArchiveStoragePlugin{}, - StreamImpl: &mockStreamingSpanWriterPlugin{}, - } - server := grpc.NewServer() - err := plugin.RegisterHandlers(server) - require.NoError(t, err) -} - -func TestStorageGRPCPlugin_GRPCServer(t *testing.T) { - plugin := &StorageGRPCPlugin{ - Impl: &mockStoragePlugin{}, - ArchiveImpl: &mockArchiveStoragePlugin{}, - StreamImpl: &mockStreamingSpanWriterPlugin{}, - } - server := grpc.NewServer() - err := plugin.GRPCServer(nil, server) - require.NoError(t, err) -} - -func TestStorageGRPCPlugin_GRPCClient(t *testing.T) { - clientConn := &grpc.ClientConn{} - plugin := &StorageGRPCPlugin{} - _, err := plugin.GRPCClient(context.Background(), nil, clientConn) - require.NoError(t, err) -} diff --git a/plugin/storage/integration/badgerstore_test.go b/plugin/storage/integration/badgerstore_test.go index 6ce061a74db..0ddb3a023c3 100644 --- a/plugin/storage/integration/badgerstore_test.go +++ b/plugin/storage/integration/badgerstore_test.go @@ -35,7 +35,7 @@ func (s *BadgerIntegrationStorage) initialize(t *testing.T) { s.factory = badger.NewFactory() s.factory.Options.Primary.Ephemeral = false - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) err := s.factory.Initialize(metrics.NullFactory, logger) require.NoError(t, err) t.Cleanup(func() { diff --git a/plugin/storage/integration/cassandra_test.go b/plugin/storage/integration/cassandra_test.go index 00271f114fa..1e442d8d8ba 100644 --- a/plugin/storage/integration/cassandra_test.go +++ b/plugin/storage/integration/cassandra_test.go @@ -51,7 +51,7 @@ func (s *CassandraStorageIntegration) cleanUp(t *testing.T) { } func (s *CassandraStorageIntegration) initializeCassandraFactory(t *testing.T, flags []string) *cassandra.Factory { - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) f := cassandra.NewFactory() v, command := config.Viperize(f.AddFlags) require.NoError(t, command.ParseFlags(flags)) diff --git a/plugin/storage/integration/elasticsearch_test.go b/plugin/storage/integration/elasticsearch_test.go index b78391754b0..e8534fc7dee 100644 --- a/plugin/storage/integration/elasticsearch_test.go +++ b/plugin/storage/integration/elasticsearch_test.go @@ -108,7 +108,7 @@ func (s *ESStorageIntegration) esCleanUp(t *testing.T) { } func (s *ESStorageIntegration) initializeESFactory(t *testing.T, allTagsAsFields bool) *es.Factory { - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) f := es.NewFactory() v, command := config.Viperize(f.AddFlags) args := []string{ @@ -201,7 +201,7 @@ func TestElasticsearchStorage_IndexTemplates(t *testing.T) { esVersion, err := s.getVersion() require.NoError(t, err) // TODO abstract this into pkg/es/client.IndexManagementLifecycleAPI - if esVersion <= 7 { + if esVersion == 7 { serviceTemplateExists, err := s.client.IndexTemplateExists(indexPrefix + "-jaeger-service").Do(context.Background()) require.NoError(t, err) assert.True(t, serviceTemplateExists) diff --git a/plugin/storage/integration/es_index_rollover_test.go b/plugin/storage/integration/es_index_rollover_test.go index 45d874c4475..4effa952363 100644 --- a/plugin/storage/integration/es_index_rollover_test.go +++ b/plugin/storage/integration/es_index_rollover_test.go @@ -33,11 +33,7 @@ func TestIndexRollover_FailIfILMNotPresent(t *testing.T) { SkipUnlessEnv(t, "elasticsearch", "opensearch") client, err := createESClient() require.NoError(t, err) - esVersion, err := getVersion(client) require.NoError(t, err) - if esVersion < 7 { - t.Skip("Integration test - " + t.Name() + " against ElasticSearch skipped for ES version " + fmt.Sprint(esVersion)) - } // make sure ES is clean cleanES(t, client, defaultILMPolicyName) envVars := []string{"ES_USE_ILM=true"} @@ -65,7 +61,6 @@ func TestIndexRollover_CreateIndicesWithILM(t *testing.T) { func runCreateIndicesWithILM(t *testing.T, ilmPolicyName string) { client, err := createESClient() require.NoError(t, err) - esVersion, err := getVersion(client) require.NoError(t, err) @@ -77,16 +72,7 @@ func runCreateIndicesWithILM(t *testing.T, ilmPolicyName string) { envVars = append(envVars, "ES_ILM_POLICY_NAME="+ilmPolicyName) } - if esVersion < 7 { - cleanES(t, client, "") - // Run the ES rollover test with adaptive sampling disabled (set to false). - err := runEsRollover("init", envVars, false) - require.EqualError(t, err, "exit status 1") - indices, err1 := client.IndexNames() - require.NoError(t, err1) - assert.Empty(t, indices) - - } else { + if esVersion >= 7 { expectedIndices := []string{"jaeger-span-000001", "jaeger-service-000001", "jaeger-dependencies-000001"} t.Run("NoPrefix", func(t *testing.T) { runIndexRolloverWithILMTest(t, client, "", expectedIndices, envVars, ilmPolicyName, false) diff --git a/plugin/storage/integration/grpc_test.go b/plugin/storage/integration/grpc_test.go index f7d7bafbb42..d5fa17d83ab 100644 --- a/plugin/storage/integration/grpc_test.go +++ b/plugin/storage/integration/grpc_test.go @@ -16,8 +16,6 @@ package integration import ( - "os" - "path" "testing" "github.com/stretchr/testify/require" @@ -29,25 +27,16 @@ import ( "github.com/jaegertracing/jaeger/plugin/storage/grpc" ) -const ( - defaultPluginBinaryPath = "../../../examples/memstore-plugin/memstore-plugin" - streamingPluginConfigPath = "fixtures/grpc_plugin_conf.yaml" -) - type GRPCStorageIntegrationTestSuite struct { StorageIntegration - flags []string - factory *grpc.Factory - useRemoteStorage bool - remoteStorage *RemoteMemoryStorage + flags []string + factory *grpc.Factory + remoteStorage *RemoteMemoryStorage } func (s *GRPCStorageIntegrationTestSuite) initialize(t *testing.T) { - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) - - if s.useRemoteStorage { - s.remoteStorage = StartNewRemoteMemoryStorage(t) - } + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) + s.remoteStorage = StartNewRemoteMemoryStorage(t) f := grpc.NewFactory() v, command := config.Viperize(f.AddFlags) @@ -73,9 +62,7 @@ func (s *GRPCStorageIntegrationTestSuite) initialize(t *testing.T) { func (s *GRPCStorageIntegrationTestSuite) close(t *testing.T) { require.NoError(t, s.factory.Close()) - if s.useRemoteStorage { - s.remoteStorage.Close(t) - } + s.remoteStorage.Close(t) } func (s *GRPCStorageIntegrationTestSuite) cleanUp(t *testing.T) { @@ -83,63 +70,13 @@ func (s *GRPCStorageIntegrationTestSuite) cleanUp(t *testing.T) { s.initialize(t) } -func getPluginFlags(t *testing.T) []string { - binaryPath := os.Getenv("PLUGIN_BINARY_PATH") - if binaryPath == "" { - t.Logf("PLUGIN_BINARY_PATH env var not set, using %s", defaultPluginBinaryPath) - binaryPath = defaultPluginBinaryPath - } - - return []string{ - "--grpc-storage-plugin.binary", binaryPath, - "--grpc-storage-plugin.log-level", "debug", - } -} - -func TestGRPCStorage(t *testing.T) { - SkipUnlessEnv(t, "grpc") - flags := getPluginFlags(t) - if configPath := os.Getenv("PLUGIN_CONFIG_PATH"); configPath == "" { - t.Log("PLUGIN_CONFIG_PATH env var not set") - } else { - flags = append(flags, "--grpc-storage-plugin.configuration-file", configPath) - } - - s := &GRPCStorageIntegrationTestSuite{ - flags: flags, - } - s.initialize(t) - defer s.close(t) - s.RunAll(t) -} - -func TestGRPCStreamingWriter(t *testing.T) { - SkipUnlessEnv(t, "grpc") - flags := getPluginFlags(t) - wd, err := os.Getwd() - require.NoError(t, err) - flags = append(flags, - "--grpc-storage-plugin.configuration-file", - path.Join(wd, streamingPluginConfigPath)) - - s := &GRPCStorageIntegrationTestSuite{ - flags: flags, - } - s.initialize(t) - defer s.close(t) - s.RunAll(t) -} - func TestGRPCRemoteStorage(t *testing.T) { SkipUnlessEnv(t, "grpc") - flags := []string{ - "--grpc-storage.server=localhost:17271", - "--grpc-storage.tls.enabled=false", - } - s := &GRPCStorageIntegrationTestSuite{ - flags: flags, - useRemoteStorage: true, + flags: []string{ + "--grpc-storage.server=localhost:17271", + "--grpc-storage.tls.enabled=false", + }, } s.initialize(t) defer s.close(t) diff --git a/plugin/storage/integration/integration.go b/plugin/storage/integration/integration.go index 9e73fedeb92..d85616987ca 100644 --- a/plugin/storage/integration/integration.go +++ b/plugin/storage/integration/integration.go @@ -71,10 +71,6 @@ type StorageIntegration struct { // Skip Archive Test if not supported by the storage backend SkipArchiveTest bool - // TODO: remove this after upstream issue in OTEL jaeger translator is fixed - // Skip testing trace binary tags, logs, and process - SkipBinaryAttrs bool - // List of tests which has to be skipped, it can be regex too. SkipList []string @@ -210,7 +206,7 @@ func (s *StorageIntegration) testGetLargeSpan(t *testing.T) { found := s.waitForCondition(t, func(t *testing.T) bool { var err error actual, err = s.SpanReader.GetTrace(context.Background(), expectedTraceID) - return err == nil && len(actual.Spans) == len(expected.Spans) + return err == nil && len(actual.Spans) >= len(expected.Spans) }) if !assert.True(t, found) { CompareTraces(t, expected, actual) @@ -338,6 +334,7 @@ func (s *StorageIntegration) findTracesByQuery(t *testing.T, query *spanstore.Tr } func (s *StorageIntegration) writeTrace(t *testing.T, trace *model.Trace) { + t.Logf("%-23s Writing trace with %d spans", time.Now().Format("2006-01-02 15:04:05.999"), len(trace.Spans)) for _, span := range trace.Spans { err := s.SpanWriter.WriteSpan(context.Background(), span) require.NoError(t, err, "Not expecting error when writing trace to storage") @@ -369,39 +366,7 @@ func (s *StorageIntegration) loadParseAndWriteLargeTrace(t *testing.T) *model.Tr func (s *StorageIntegration) getTraceFixture(t *testing.T, fixture string) *model.Trace { fileName := fmt.Sprintf("fixtures/traces/%s.json", fixture) - trace := getTraceFixtureExact(t, fileName) - - if s.SkipBinaryAttrs { - t.Logf("Dropped binary type attributes from trace ID: %s", trace.Spans[0].TraceID.String()) - trace = s.dropBinaryAttrs(t, trace) - } - - return trace -} - -func (s *StorageIntegration) dropBinaryAttrs(t *testing.T, trace *model.Trace) *model.Trace { - for _, span := range trace.Spans { - span.Tags = s.dropBinaryTags(t, span.Tags) - span.Process.Tags = s.dropBinaryTags(t, span.Process.Tags) - - for i := range span.Logs { - span.Logs[i].Fields = s.dropBinaryTags(t, span.Logs[i].Fields) - } - } - - return trace -} - -func (s *StorageIntegration) dropBinaryTags(_ *testing.T, tags []model.KeyValue) []model.KeyValue { - newTags := make([]model.KeyValue, 0) - for _, tag := range tags { - if tag.VType == model.ValueType_BINARY { - continue - } - newTags = append(newTags, tag) - } - - return newTags + return getTraceFixtureExact(t, fileName) } func getTraceFixtureExact(t *testing.T, fileName string) *model.Trace { diff --git a/plugin/storage/integration/kafka_test.go b/plugin/storage/integration/kafka_test.go index 90f1e9775ab..f333821f3c8 100644 --- a/plugin/storage/integration/kafka_test.go +++ b/plugin/storage/integration/kafka_test.go @@ -43,7 +43,7 @@ type KafkaIntegrationTestSuite struct { } func (s *KafkaIntegrationTestSuite) initialize(t *testing.T) { - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) const encoding = "json" const groupID = "kafka-integration-test" const clientID = "kafka-integration-test" diff --git a/plugin/storage/integration/remote_memory_storage.go b/plugin/storage/integration/remote_memory_storage.go index 5bb133771e2..1bd2dd7b3e5 100644 --- a/plugin/storage/integration/remote_memory_storage.go +++ b/plugin/storage/integration/remote_memory_storage.go @@ -4,12 +4,17 @@ package integration import ( + "context" "os" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/health/grpc_health_v1" "github.com/jaegertracing/jaeger/cmd/remote-storage/app" "github.com/jaegertracing/jaeger/pkg/config" @@ -26,7 +31,7 @@ type RemoteMemoryStorage struct { } func StartNewRemoteMemoryStorage(t *testing.T) *RemoteMemoryStorage { - logger := zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)) + logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller())) opts := &app.Options{ GRPCHostPort: ports.PortToHostPort(ports.RemoteStorageGRPC), Tenancy: tenancy.Options{ @@ -46,6 +51,26 @@ func StartNewRemoteMemoryStorage(t *testing.T) *RemoteMemoryStorage { require.NoError(t, err) require.NoError(t, server.Start()) + conn, err := grpc.NewClient( + opts.GRPCHostPort, + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err) + defer conn.Close() + healthClient := grpc_health_v1.NewHealthClient(conn) + require.Eventually(t, func() bool { + req := &grpc_health_v1.HealthCheckRequest{} + ctx, cancel := context.WithTimeout(context.Background(), time.Second*1) + defer cancel() + resp, err := healthClient.Check(ctx, req) + if err != nil { + t.Logf("remote storage server is not ready: err=%v", err) + return false + } + t.Logf("remote storage server status: %v", resp.Status) + return resp.GetStatus() == grpc_health_v1.HealthCheckResponse_SERVING + }, 30*time.Second, time.Second, "failed to ensure remote storage server is ready") + return &RemoteMemoryStorage{ server: server, storageFactory: storageFactory, diff --git a/plugin/storage/integration/trace_compare.go b/plugin/storage/integration/trace_compare.go index 7fed434a409..bb8c9ca83ba 100644 --- a/plugin/storage/integration/trace_compare.go +++ b/plugin/storage/integration/trace_compare.go @@ -47,6 +47,20 @@ func CompareSliceOfTraces(t *testing.T, expected []*model.Trace, actual []*model } } +// trace.Spans may contain spans with the same SpanID. Remove duplicates +// and keep the first one. Use a map to keep track of the spans we've seen. +func dedupeSpans(trace *model.Trace) { + seen := make(map[model.SpanID]bool) + var newSpans []*model.Span + for _, span := range trace.Spans { + if !seen[span.SpanID] { + seen[span.SpanID] = true + newSpans = append(newSpans, span) + } + } + trace.Spans = newSpans +} + // CompareTraces compares two traces func CompareTraces(t *testing.T, expected *model.Trace, actual *model.Trace) { if expected.Spans == nil { @@ -55,6 +69,14 @@ func CompareTraces(t *testing.T, expected *model.Trace, actual *model.Trace) { } require.NotNil(t, actual) require.NotNil(t, actual.Spans) + + // some storage implementation may retry writing of spans and end up with duplicates. + countBefore := len(actual.Spans) + dedupeSpans(actual) + if countAfter := len(actual.Spans); countAfter != countBefore { + t.Logf("Removed spans with duplicate span IDs; before=%d, after=%d", countBefore, countAfter) + } + model.SortTrace(expected) model.SortTrace(actual) checkSize(t, expected, actual) diff --git a/plugin/storage/integration/trace_compare_test.go b/plugin/storage/integration/trace_compare_test.go new file mode 100644 index 00000000000..a419d624ea8 --- /dev/null +++ b/plugin/storage/integration/trace_compare_test.go @@ -0,0 +1,30 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/jaegertracing/jaeger/model" +) + +func TestDedupeSpans(t *testing.T) { + trace := &model.Trace{ + Spans: []*model.Span{ + { + SpanID: 1, + }, + { + SpanID: 1, + }, + { + SpanID: 2, + }, + }, + } + dedupeSpans(trace) + assert.Len(t, trace.Spans, 2) +} diff --git a/scripts/check-go-version.sh b/scripts/check-go-version.sh index c7d2ab06fd4..ef95d52f404 100755 --- a/scripts/check-go-version.sh +++ b/scripts/check-go-version.sh @@ -70,7 +70,7 @@ function check() { check go.mod "^go\s\+$version_regex" "$go_previous_version" -check docker/Makefile "^.*golang:$version_regex" "$go_latest_version" +check docker/debug/Dockerfile "^.*golang:$version_regex" "$go_latest_version" IFS='|' read -r -a gha_workflows <<< "$(grep -rl go-version .github | tr '\n' '|')" for gha_workflow in "${gha_workflows[@]}"; do diff --git a/scripts/generate-help-output.sh b/scripts/generate-help-output.sh index 0cdb4a11fa8..68c884c118e 100755 --- a/scripts/generate-help-output.sh +++ b/scripts/generate-help-output.sh @@ -21,7 +21,7 @@ function gen { set -ex gen agent nostorage -gen collector cassandra elasticsearch memory kafka badger grpc-plugin -gen query cassandra elasticsearch memory badger grpc-plugin -gen ingester cassandra elasticsearch memory badger grpc-plugin -gen all-in-one cassandra elasticsearch memory badger grpc-plugin +gen collector cassandra elasticsearch memory kafka badger grpc +gen query cassandra elasticsearch memory badger grpc +gen ingester cassandra elasticsearch memory badger grpc +gen all-in-one cassandra elasticsearch memory badger grpc