Skip to content

Commit 0480119

Browse files
jmacdf7o
authored andcommitted
OTel-Arrow exporter timeout propagation (open-telemetry#34733)
**Description:** Exporter side of open-telemetry/otel-arrow#227. The receiver side is open-telemetry#34742. **Link to tracking Issue:** open-telemetry/otel-arrow#227 **Testing:** Adds a test for the expected metadata propagation. **Documentation:** Since this is expected of gRPC receivers, no docs are changed.
1 parent c899faf commit 0480119

File tree

8 files changed

+124
-49
lines changed

8 files changed

+124
-49
lines changed
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: otelarrowexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add gRPC timeout propagation.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34733]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

cmd/otelcontribcol/builder-config.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -499,3 +499,5 @@ replaces:
499499
- github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/cfgardenobserver => ../../extension/observer/cfgardenobserver
500500
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter => ../../exporter/rabbitmqexporter
501501
- github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubreceiver => ../../receiver/githubreceiver
502+
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil
503+

cmd/otelcontribcol/go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ require (
641641
github.com/open-telemetry/opentelemetry-collector-contrib/internal/docker v0.108.0 // indirect
642642
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.108.0 // indirect
643643
github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.108.0 // indirect
644+
github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil v0.108.0 // indirect
644645
github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.108.0 // indirect
645646
github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka v0.108.0 // indirect
646647
github.com/open-telemetry/opentelemetry-collector-contrib/internal/kubelet v0.108.0 // indirect
@@ -1371,3 +1372,5 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/obse
13711372
replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter => ../../exporter/rabbitmqexporter
13721373

13731374
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubreceiver => ../../receiver/githubreceiver
1375+
1376+
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil

exporter/otelarrowexporter/go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.22.0
44

55
require (
66
github.com/apache/arrow/go/v16 v16.1.0
7+
github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil v0.108.0
78
github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow v0.108.0
89
github.com/open-telemetry/otel-arrow v0.25.0
910
github.com/stretchr/testify v1.9.0
@@ -105,3 +106,5 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/otela
105106
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/otelarrowreceiver => ../../receiver/otelarrowreceiver
106107

107108
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent => ../../internal/sharedcomponent
109+
110+
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil

exporter/otelarrowexporter/internal/arrow/exporter.go

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"google.golang.org/grpc/credentials"
2424
"google.golang.org/grpc/status"
2525

26+
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil"
2627
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/netstats"
2728
)
2829

@@ -310,6 +311,10 @@ func (e *Exporter) SendAndWait(ctx context.Context, data any) (bool, error) {
310311
}
311312
md["otlp-pdata-size"] = strconv.Itoa(uncompSize)
312313

314+
if dead, ok := ctx.Deadline(); ok {
315+
md["grpc-timeout"] = grpcutil.EncodeTimeout(time.Until(dead))
316+
}
317+
313318
wri := writeItem{
314319
records: data,
315320
md: md,

exporter/otelarrowexporter/internal/arrow/exporter_test.go

+79-49
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"google.golang.org/grpc/metadata"
3333
"google.golang.org/grpc/status"
3434

35+
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil"
3536
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/netstats"
3637
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/testdata"
3738
)
@@ -576,65 +577,94 @@ func TestArrowExporterStreaming(t *testing.T) {
576577

577578
// TestArrowExporterHeaders tests a mix of outgoing context headers.
578579
func TestArrowExporterHeaders(t *testing.T) {
579-
tc := newSingleStreamMetadataTestCase(t)
580-
channel := newHealthyTestChannel()
580+
for _, withDeadline := range []bool{true, false} {
581+
t.Run(fmt.Sprint("with_deadline=", withDeadline), func(t *testing.T) {
581582

582-
tc.traceCall.AnyTimes().DoAndReturn(tc.returnNewStream(channel))
583+
tc := newSingleStreamMetadataTestCase(t)
584+
channel := newHealthyTestChannel()
583585

584-
ctx, cancel := context.WithCancel(context.Background())
585-
defer cancel()
586-
require.NoError(t, tc.exporter.Start(ctx))
586+
tc.traceCall.AnyTimes().DoAndReturn(tc.returnNewStream(channel))
587587

588-
var expectOutput []metadata.MD
589-
var actualOutput []metadata.MD
588+
ctx, cancel := context.WithCancel(context.Background())
589+
defer cancel()
590590

591-
var wg sync.WaitGroup
592-
wg.Add(1)
593-
go func() {
594-
defer wg.Done()
595-
md := metadata.MD{}
596-
hpd := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
597-
md[f.Name] = append(md[f.Name], f.Value)
598-
})
599-
for data := range channel.sendChannel() {
600-
if len(data.Headers) == 0 {
601-
actualOutput = append(actualOutput, nil)
602-
} else {
603-
_, err := hpd.Write(data.Headers)
591+
require.NoError(t, tc.exporter.Start(ctx))
592+
593+
var expectOutput []metadata.MD
594+
var actualOutput []metadata.MD
595+
596+
var wg sync.WaitGroup
597+
wg.Add(1)
598+
go func() {
599+
defer wg.Done()
600+
md := metadata.MD{}
601+
hpd := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
602+
md[f.Name] = append(md[f.Name], f.Value)
603+
})
604+
for data := range channel.sendChannel() {
605+
if len(data.Headers) == 0 {
606+
actualOutput = append(actualOutput, nil)
607+
} else {
608+
_, err := hpd.Write(data.Headers)
609+
require.NoError(t, err)
610+
actualOutput = append(actualOutput, md)
611+
md = metadata.MD{}
612+
}
613+
channel.recv <- statusOKFor(data.BatchId)
614+
}
615+
}()
616+
617+
for times := 0; times < 10; times++ {
618+
input := testdata.GenerateTraces(2)
619+
620+
if times%2 == 1 {
621+
md := metadata.MD{
622+
"expected1": []string{"metadata1"},
623+
"expected2": []string{fmt.Sprint(times)},
624+
"otlp-pdata-size": []string{"329"},
625+
}
626+
expectOutput = append(expectOutput, md)
627+
} else {
628+
expectOutput = append(expectOutput, metadata.MD{
629+
"otlp-pdata-size": []string{"329"},
630+
})
631+
}
632+
633+
sendCtx := ctx
634+
if withDeadline {
635+
var sendCancel context.CancelFunc
636+
sendCtx, sendCancel = context.WithTimeout(sendCtx, time.Second)
637+
defer sendCancel()
638+
}
639+
640+
sent, err := tc.exporter.SendAndWait(sendCtx, input)
604641
require.NoError(t, err)
605-
actualOutput = append(actualOutput, md)
606-
md = metadata.MD{}
642+
require.True(t, sent)
607643
}
608-
channel.recv <- statusOKFor(data.BatchId)
609-
}
610-
}()
611-
612-
for times := 0; times < 10; times++ {
613-
input := testdata.GenerateTraces(2)
644+
// Stop the test conduit started above.
645+
cancel()
646+
wg.Wait()
614647

615-
if times%2 == 1 {
616-
md := metadata.MD{
617-
"expected1": []string{"metadata1"},
618-
"expected2": []string{fmt.Sprint(times)},
619-
"otlp-pdata-size": []string{"329"},
648+
// Manual check for proper deadline propagation. Since the test
649+
// is timed we don't expect an exact match.
650+
if withDeadline {
651+
for _, out := range actualOutput {
652+
dead := out.Get("grpc-timeout")
653+
require.Len(t, dead, 1)
654+
require.NotEmpty(t, dead[0])
655+
to, err := grpcutil.DecodeTimeout(dead[0])
656+
require.NoError(t, err)
657+
// Allow the test to lapse for 0.5s.
658+
require.Less(t, time.Second/2, to)
659+
require.GreaterOrEqual(t, time.Second, to)
660+
out.Delete("grpc-timeout")
661+
}
620662
}
621-
expectOutput = append(expectOutput, md)
622-
} else {
623-
expectOutput = append(expectOutput, metadata.MD{
624-
"otlp-pdata-size": []string{"329"},
625-
})
626-
}
627663

628-
sent, err := tc.exporter.SendAndWait(context.Background(), input)
629-
require.NoError(t, err)
630-
require.True(t, sent)
664+
require.Equal(t, expectOutput, actualOutput)
665+
require.NoError(t, tc.exporter.Shutdown(ctx))
666+
})
631667
}
632-
// Stop the test conduit started above.
633-
cancel()
634-
wg.Wait()
635-
636-
require.Equal(t, expectOutput, actualOutput)
637-
require.NoError(t, tc.exporter.Shutdown(ctx))
638668
}
639669

640670
// TestArrowExporterIsTraced tests whether trace and span ID are

internal/otelarrow/go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ require (
6464
github.com/modern-go/reflect2 v1.0.2 // indirect
6565
github.com/mostynb/go-grpc-compression v1.2.3 // indirect
6666
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
67+
github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil v0.108.0 // indirect
6768
github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent v0.108.0 // indirect
6869
github.com/pierrec/lz4/v4 v4.1.21 // indirect
6970
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -110,3 +111,5 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/otela
110111
replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/otelarrowexporter => ../../exporter/otelarrowexporter
111112

112113
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent => ../sharedcomponent
114+
115+
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../grpcutil

receiver/otelarrowreceiver/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,5 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/otela
106106
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent => ../../internal/sharedcomponent
107107

108108
replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/otelarrowexporter => ../../exporter/otelarrowexporter
109+
110+
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil

0 commit comments

Comments
 (0)