From 97f8401153a431c5c91b93741f394d932d2b1a03 Mon Sep 17 00:00:00 2001 From: Liang Xuhao Date: Wed, 23 Oct 2024 15:39:25 +0800 Subject: [PATCH] Keep metadata for gRPC in context for log signal (#5911) Fixes #5905 --- CHANGELOG.md | 1 + exporters/otlp/otlplog/otlploggrpc/client.go | 7 +++- .../otlp/otlplog/otlploggrpc/client_test.go | 37 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5590bffe82..af1218c61ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed - `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` now keeps the metadata already present in the context when `WithHeaders` is used. (#5892) +- `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` now keeps the metadata already present in the context when `WithHeaders` is used. (#5911) diff --git a/exporters/otlp/otlplog/otlploggrpc/client.go b/exporters/otlp/otlplog/otlploggrpc/client.go index 21aafcd98db..05abd92eeec 100644 --- a/exporters/otlp/otlplog/otlploggrpc/client.go +++ b/exporters/otlp/otlplog/otlploggrpc/client.go @@ -198,7 +198,12 @@ func (c *client) exportContext(parent context.Context) (context.Context, context } if c.metadata.Len() > 0 { - ctx = metadata.NewOutgoingContext(ctx, c.metadata) + md := c.metadata + if outMD, ok := metadata.FromOutgoingContext(ctx); ok { + md = metadata.Join(md, outMD) + } + + ctx = metadata.NewOutgoingContext(ctx, md) } return ctx, cancel diff --git a/exporters/otlp/otlplog/otlploggrpc/client_test.go b/exporters/otlp/otlplog/otlploggrpc/client_test.go index b99383bc42b..b581620d884 100644 --- a/exporters/otlp/otlplog/otlploggrpc/client_test.go +++ b/exporters/otlp/otlplog/otlploggrpc/client_test.go @@ -25,6 +25,7 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/sdk/log" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" collogpb "go.opentelemetry.io/proto/otlp/collector/logs/v1" cpb "go.opentelemetry.io/proto/otlp/common/v1" @@ -561,3 +562,39 @@ func TestClient(t *testing.T) { assert.ErrorContains(t, errs[0], want) }) } + +func TestConfig(t *testing.T) { + factoryFunc := func(rCh <-chan exportResult, o ...Option) (log.Exporter, *grpcCollector) { + coll, err := newGRPCCollector("", rCh) + require.NoError(t, err) + + ctx := context.Background() + opts := append([]Option{ + WithEndpoint(coll.listener.Addr().String()), + WithInsecure(), + }, o...) + exp, err := New(ctx, opts...) + require.NoError(t, err) + return exp, coll + } + + t.Run("WithHeaders", func(t *testing.T) { + key := "my-custom-header" + headers := map[string]string{key: "custom-value"} + exp, coll := factoryFunc(nil, WithHeaders(headers)) + t.Cleanup(coll.srv.Stop) + + ctx := context.Background() + additionalKey := "additional-custom-header" + ctx = metadata.AppendToOutgoingContext(ctx, additionalKey, "additional-value") + require.NoError(t, exp.Export(ctx, make([]log.Record, 1))) + // Ensure everything is flushed. + require.NoError(t, exp.Shutdown(ctx)) + + got := metadata.Join(coll.headers) + require.Regexp(t, "OTel Go OTLP over gRPC logs exporter/[01]\\..*", got) + require.Contains(t, got, key) + require.Contains(t, got, additionalKey) + assert.Equal(t, []string{headers[key]}, got[key]) + }) +}