Skip to content

Commit 0e8ebef

Browse files
tylerbensonmx-psiMovieStoreGuy
authored andcommitted
[kafka] Add option to supply destination topic through context (open-telemetry#34503)
**Description:** <Describe what has changed.> <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> Add option to get destination topic from context. This allows for upstream connectors to control the destination without polluting the data being written. **Link to tracking Issue:** <Issue number if applicable> Fixes open-telemetry#34432 **Testing:** <Describe what testing was performed and which tests were added.> Added unit tests. **Documentation:** <Describe the documentation added.> Updated the component readme with the added setting. --------- Co-authored-by: Pablo Baeyens <[email protected]> Co-authored-by: Sean Marciniak <[email protected]>
1 parent 9770a84 commit 0e8ebef

File tree

19 files changed

+203
-20
lines changed

19 files changed

+203
-20
lines changed

.chloggen/kafka-topic-context.yaml

Lines changed: 27 additions & 0 deletions
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: kafkaexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add option to supply destination topic through context.
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: [34503, 34432]
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: [api]

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pkg/batchpersignal/ @open-teleme
149149
pkg/datadog/ @open-telemetry/collector-contrib-approvers @mx-psi @dineshg13 @liustanley @songy23 @mackjmr @ankitpatel96
150150
pkg/experimentalmetricmetadata/ @open-telemetry/collector-contrib-approvers @rmfitzpatrick
151151
pkg/golden/ @open-telemetry/collector-contrib-approvers @djaglowski @atoulme
152+
pkg/kafka/topic/ @open-telemetry/collector-contrib-approvers @pavolloffay @MovieStoreGuy
152153
pkg/ottl/ @open-telemetry/collector-contrib-approvers @TylerHelmuth @kentquirk @bogdandrutu @evan-bradley
153154
pkg/pdatatest/ @open-telemetry/collector-contrib-approvers @djaglowski @fatsheep9146
154155
pkg/pdatautil/ @open-telemetry/collector-contrib-approvers @dmitryax

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ body:
145145
- pkg/datadog
146146
- pkg/experimentalmetricmetadata
147147
- pkg/golden
148+
- pkg/kafka/topic
148149
- pkg/ottl
149150
- pkg/pdatatest
150151
- pkg/pdatautil

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ body:
139139
- pkg/datadog
140140
- pkg/experimentalmetricmetadata
141141
- pkg/golden
142+
- pkg/kafka/topic
142143
- pkg/ottl
143144
- pkg/pdatatest
144145
- pkg/pdatautil

.github/ISSUE_TEMPLATE/other.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ body:
139139
- pkg/datadog
140140
- pkg/experimentalmetricmetadata
141141
- pkg/golden
142+
- pkg/kafka/topic
142143
- pkg/ottl
143144
- pkg/pdatatest
144145
- pkg/pdatautil

.github/ISSUE_TEMPLATE/unmaintained.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ body:
144144
- pkg/datadog
145145
- pkg/experimentalmetricmetadata
146146
- pkg/golden
147+
- pkg/kafka/topic
147148
- pkg/ottl
148149
- pkg/pdatatest
149150
- pkg/pdatautil

cmd/otelcontribcol/builder-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ replaces:
398398
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter => ../../exporter/fileexporter
399399
- github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry => ../../pkg/resourcetotelemetry
400400
- github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden
401+
- github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic => ../../pkg/kafka/topic
401402
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter => ../../exporter/opencensusexporter
402403
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opensearchexporter => ../../exporter/opensearchexporter
403404
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/metadataproviders => ../../internal/metadataproviders

cmd/otelcontribcol/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ require (
658658
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/batchpersignal v0.109.0 // indirect
659659
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/datadog v0.0.0-00010101000000-000000000000 // indirect
660660
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata v0.109.0 // indirect
661+
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic v0.109.0 // indirect
661662
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.109.0 // indirect
662663
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.109.0 // indirect
663664
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.109.0 // indirect
@@ -1183,6 +1184,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourceto
11831184

11841185
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden
11851186

1187+
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic => ../../pkg/kafka/topic
1188+
11861189
replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter => ../../exporter/opencensusexporter
11871190

11881191
replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opensearchexporter => ../../exporter/opensearchexporter

exporter/kafkaexporter/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ The following settings can be optionally configured:
2424
- `brokers` (default = localhost:9092): The list of kafka brokers.
2525
- `resolve_canonical_bootstrap_servers_only` (default = false): Whether to resolve then reverse-lookup broker IPs during startup.
2626
- `client_id` (default = "sarama"): The client ID to configure the Sarama Kafka client with. The client ID will be used for all produce requests.
27-
- `topic` (default = otlp_spans for traces, otlp_metrics for metrics, otlp_logs for logs): The name of the kafka topic to export to.
28-
- `topic_from_attribute` (default = ""): Specify the resource attribute whose value should be used as the message's topic. This option, when set, will take precedence over the default topic. If `topic_from_attribute` is not set, the message's topic will be set to the value of the configuration option `topic` instead.
27+
- `topic` (default = otlp_spans for traces, otlp_metrics for metrics, otlp_logs for logs): The name of the default kafka topic to export to. See [Destination Topic](#destination-topic) below for more details.
28+
- `topic_from_attribute` (default = ""): Specify the resource attribute whose value should be used as the message's topic. See [Destination Topic](#destination-topic) below for more details.
2929
- `encoding` (default = otlp_proto): The encoding of the traces sent to kafka. All available encodings:
3030
- `otlp_proto`: payload is Protobuf serialized from `ExportTraceServiceRequest` if set as a traces exporter or `ExportMetricsServiceRequest` for metrics or `ExportLogsServiceRequest` for logs.
3131
- `otlp_json`: payload is JSON serialized from `ExportTraceServiceRequest` if set as a traces exporter or `ExportMetricsServiceRequest` for metrics or `ExportLogsServiceRequest` for logs.
@@ -105,3 +105,9 @@ exporters:
105105
- localhost:9092
106106
protocol_version: 2.0.0
107107
```
108+
109+
## Destination Topic
110+
The destination topic can be defined in a few different ways and takes priority in the following order:
111+
1. When `topic_from_attribute` is configured, and the corresponding attribute is found on the ingested data, the value of this attribute is used.
112+
2. If a prior component in the collector pipeline sets the topic on the context via the `topic.WithTopic` function (from the `github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic` package), the value set in the context is used.
113+
3. Finally, the `topic` configuration is used as a default/fallback destination.

exporter/kafkaexporter/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.109.0
1111
github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka v0.109.0
1212
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/batchpersignal v0.109.0
13+
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic v0.109.0
1314
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.109.0
1415
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.109.0
1516
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.109.0
@@ -106,6 +107,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka
106107

107108
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/batchpersignal => ../../pkg/batchpersignal
108109

110+
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic => ../../pkg/kafka/topic
111+
109112
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger => ../../pkg/translator/jaeger
110113

111114
retract (

exporter/kafkaexporter/kafka_exporter.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"go.uber.org/zap"
2020

2121
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka"
22+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic"
2223
)
2324

2425
var errUnrecognizedEncoding = fmt.Errorf("unrecognized encoding")
@@ -40,8 +41,8 @@ func (ke kafkaErrors) Error() string {
4041
return fmt.Sprintf("Failed to deliver %d messages due to %s", ke.count, ke.err)
4142
}
4243

43-
func (e *kafkaTracesProducer) tracesPusher(_ context.Context, td ptrace.Traces) error {
44-
messages, err := e.marshaler.Marshal(td, getTopic(&e.cfg, td.ResourceSpans()))
44+
func (e *kafkaTracesProducer) tracesPusher(ctx context.Context, td ptrace.Traces) error {
45+
messages, err := e.marshaler.Marshal(td, getTopic(ctx, &e.cfg, td.ResourceSpans()))
4546
if err != nil {
4647
return consumererror.NewPermanent(err)
4748
}
@@ -98,8 +99,8 @@ type kafkaMetricsProducer struct {
9899
logger *zap.Logger
99100
}
100101

101-
func (e *kafkaMetricsProducer) metricsDataPusher(_ context.Context, md pmetric.Metrics) error {
102-
messages, err := e.marshaler.Marshal(md, getTopic(&e.cfg, md.ResourceMetrics()))
102+
func (e *kafkaMetricsProducer) metricsDataPusher(ctx context.Context, md pmetric.Metrics) error {
103+
messages, err := e.marshaler.Marshal(md, getTopic(ctx, &e.cfg, md.ResourceMetrics()))
103104
if err != nil {
104105
return consumererror.NewPermanent(err)
105106
}
@@ -156,8 +157,8 @@ type kafkaLogsProducer struct {
156157
logger *zap.Logger
157158
}
158159

159-
func (e *kafkaLogsProducer) logsDataPusher(_ context.Context, ld plog.Logs) error {
160-
messages, err := e.marshaler.Marshal(ld, getTopic(&e.cfg, ld.ResourceLogs()))
160+
func (e *kafkaLogsProducer) logsDataPusher(ctx context.Context, ld plog.Logs) error {
161+
messages, err := e.marshaler.Marshal(ld, getTopic(ctx, &e.cfg, ld.ResourceLogs()))
161162
if err != nil {
162163
return consumererror.NewPermanent(err)
163164
}
@@ -283,16 +284,19 @@ type resource interface {
283284
Resource() pcommon.Resource
284285
}
285286

286-
func getTopic[T resource](cfg *Config, resources resourceSlice[T]) string {
287-
if cfg.TopicFromAttribute == "" {
288-
return cfg.Topic
289-
}
290-
for i := 0; i < resources.Len(); i++ {
291-
rv, ok := resources.At(i).Resource().Attributes().Get(cfg.TopicFromAttribute)
292-
if ok && rv.Str() != "" {
293-
return rv.Str()
287+
func getTopic[T resource](ctx context.Context, cfg *Config, resources resourceSlice[T]) string {
288+
if cfg.TopicFromAttribute != "" {
289+
for i := 0; i < resources.Len(); i++ {
290+
rv, ok := resources.At(i).Resource().Attributes().Get(cfg.TopicFromAttribute)
291+
if ok && rv.Str() != "" {
292+
return rv.Str()
293+
}
294294
}
295295
}
296+
contextTopic, ok := topic.FromContext(ctx)
297+
if ok {
298+
return contextTopic
299+
}
296300
return cfg.Topic
297301
}
298302

exporter/kafkaexporter/kafka_exporter_test.go

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"go.uber.org/zap"
2424

2525
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka"
26+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic"
2627
)
2728

2829
func TestNewExporter_err_version(t *testing.T) {
@@ -205,6 +206,22 @@ func TestTracesPusher_attr(t *testing.T) {
205206
require.NoError(t, err)
206207
}
207208

209+
func TestTracesPusher_ctx(t *testing.T) {
210+
c := sarama.NewConfig()
211+
producer := mocks.NewSyncProducer(t, c)
212+
producer.ExpectSendMessageAndSucceed()
213+
214+
p := kafkaTracesProducer{
215+
producer: producer,
216+
marshaler: newPdataTracesMarshaler(&ptrace.ProtoMarshaler{}, defaultEncoding, false),
217+
}
218+
t.Cleanup(func() {
219+
require.NoError(t, p.Close(context.Background()))
220+
})
221+
err := p.tracesPusher(topic.WithTopic(context.Background(), "my_topic"), testdata.GenerateTraces(2))
222+
require.NoError(t, err)
223+
}
224+
208225
func TestTracesPusher_err(t *testing.T) {
209226
c := sarama.NewConfig()
210227
producer := mocks.NewSyncProducer(t, c)
@@ -271,6 +288,22 @@ func TestMetricsDataPusher_attr(t *testing.T) {
271288
require.NoError(t, err)
272289
}
273290

291+
func TestMetricsDataPusher_ctx(t *testing.T) {
292+
c := sarama.NewConfig()
293+
producer := mocks.NewSyncProducer(t, c)
294+
producer.ExpectSendMessageAndSucceed()
295+
296+
p := kafkaMetricsProducer{
297+
producer: producer,
298+
marshaler: newPdataMetricsMarshaler(&pmetric.ProtoMarshaler{}, defaultEncoding, false),
299+
}
300+
t.Cleanup(func() {
301+
require.NoError(t, p.Close(context.Background()))
302+
})
303+
err := p.metricsDataPusher(topic.WithTopic(context.Background(), "my_topic"), testdata.GenerateMetrics(2))
304+
require.NoError(t, err)
305+
}
306+
274307
func TestMetricsDataPusher_err(t *testing.T) {
275308
c := sarama.NewConfig()
276309
producer := mocks.NewSyncProducer(t, c)
@@ -337,6 +370,22 @@ func TestLogsDataPusher_attr(t *testing.T) {
337370
require.NoError(t, err)
338371
}
339372

373+
func TestLogsDataPusher_ctx(t *testing.T) {
374+
c := sarama.NewConfig()
375+
producer := mocks.NewSyncProducer(t, c)
376+
producer.ExpectSendMessageAndSucceed()
377+
378+
p := kafkaLogsProducer{
379+
producer: producer,
380+
marshaler: newPdataLogsMarshaler(&plog.ProtoMarshaler{}, defaultEncoding, false),
381+
}
382+
t.Cleanup(func() {
383+
require.NoError(t, p.Close(context.Background()))
384+
})
385+
err := p.logsDataPusher(topic.WithTopic(context.Background(), "my_topic"), testdata.GenerateLogs(1))
386+
require.NoError(t, err)
387+
}
388+
340389
func TestLogsDataPusher_err(t *testing.T) {
341390
c := sarama.NewConfig()
342391
producer := mocks.NewSyncProducer(t, c)
@@ -410,6 +459,7 @@ func Test_GetTopic(t *testing.T) {
410459
tests := []struct {
411460
name string
412461
cfg Config
462+
ctx context.Context
413463
resource any
414464
wantTopic string
415465
}{
@@ -419,6 +469,7 @@ func Test_GetTopic(t *testing.T) {
419469
TopicFromAttribute: "resource-attr",
420470
Topic: "defaultTopic",
421471
},
472+
ctx: topic.WithTopic(context.Background(), "context-topic"),
422473
resource: testdata.GenerateMetrics(1).ResourceMetrics(),
423474
wantTopic: "resource-attr-val-1",
424475
},
@@ -428,6 +479,7 @@ func Test_GetTopic(t *testing.T) {
428479
TopicFromAttribute: "resource-attr",
429480
Topic: "defaultTopic",
430481
},
482+
ctx: topic.WithTopic(context.Background(), "context-topic"),
431483
resource: testdata.GenerateTraces(1).ResourceSpans(),
432484
wantTopic: "resource-attr-val-1",
433485
},
@@ -437,6 +489,7 @@ func Test_GetTopic(t *testing.T) {
437489
TopicFromAttribute: "resource-attr",
438490
Topic: "defaultTopic",
439491
},
492+
ctx: topic.WithTopic(context.Background(), "context-topic"),
440493
resource: testdata.GenerateLogs(1).ResourceLogs(),
441494
wantTopic: "resource-attr-val-1",
442495
},
@@ -446,14 +499,58 @@ func Test_GetTopic(t *testing.T) {
446499
TopicFromAttribute: "nonexistent_attribute",
447500
Topic: "defaultTopic",
448501
},
502+
ctx: context.Background(),
503+
resource: testdata.GenerateMetrics(1).ResourceMetrics(),
504+
wantTopic: "defaultTopic",
505+
},
506+
507+
{
508+
name: "Valid metric context, return topic name",
509+
cfg: Config{
510+
TopicFromAttribute: "nonexistent_attribute",
511+
Topic: "defaultTopic",
512+
},
513+
ctx: topic.WithTopic(context.Background(), "context-topic"),
514+
resource: testdata.GenerateMetrics(1).ResourceMetrics(),
515+
wantTopic: "context-topic",
516+
},
517+
{
518+
name: "Valid trace context, return topic name",
519+
cfg: Config{
520+
TopicFromAttribute: "nonexistent_attribute",
521+
Topic: "defaultTopic",
522+
},
523+
ctx: topic.WithTopic(context.Background(), "context-topic"),
524+
resource: testdata.GenerateTraces(1).ResourceSpans(),
525+
wantTopic: "context-topic",
526+
},
527+
{
528+
name: "Valid log context, return topic name",
529+
cfg: Config{
530+
TopicFromAttribute: "nonexistent_attribute",
531+
Topic: "defaultTopic",
532+
},
533+
ctx: topic.WithTopic(context.Background(), "context-topic"),
534+
resource: testdata.GenerateLogs(1).ResourceLogs(),
535+
wantTopic: "context-topic",
536+
},
537+
538+
{
539+
name: "Attribute not found",
540+
cfg: Config{
541+
TopicFromAttribute: "nonexistent_attribute",
542+
Topic: "defaultTopic",
543+
},
544+
ctx: context.Background(),
449545
resource: testdata.GenerateMetrics(1).ResourceMetrics(),
450546
wantTopic: "defaultTopic",
451547
},
452548
{
453-
name: "TopicFromAttribute not set, return default topic",
549+
name: "TopicFromAttribute, return default topic",
454550
cfg: Config{
455551
Topic: "defaultTopic",
456552
},
553+
ctx: context.Background(),
457554
resource: testdata.GenerateMetrics(1).ResourceMetrics(),
458555
wantTopic: "defaultTopic",
459556
},
@@ -464,11 +561,11 @@ func Test_GetTopic(t *testing.T) {
464561
topic := ""
465562
switch r := tests[i].resource.(type) {
466563
case pmetric.ResourceMetricsSlice:
467-
topic = getTopic(&tests[i].cfg, r)
564+
topic = getTopic(tests[i].ctx, &tests[i].cfg, r)
468565
case ptrace.ResourceSpansSlice:
469-
topic = getTopic(&tests[i].cfg, r)
566+
topic = getTopic(tests[i].ctx, &tests[i].cfg, r)
470567
case plog.ResourceLogsSlice:
471-
topic = getTopic(&tests[i].cfg, r)
568+
topic = getTopic(tests[i].ctx, &tests[i].cfg, r)
472569
}
473570
assert.Equal(t, tests[i].wantTopic, topic)
474571
})

pkg/kafka/topic/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../../Makefile.Common

pkg/kafka/topic/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Kafka Topic Context Accessor
2+
3+
This module is used for accessing the topic within a context.
4+
See the [kafka exporter readme](../../../exporter/kafkaexporter/README.md#destination-topic) for more details.

pkg/kafka/topic/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/open-telemetry/opentelemetry-collector-contrib/pkg/kafka/topic
2+
3+
go 1.22

0 commit comments

Comments
 (0)