Skip to content

Commit a2817f5

Browse files
authored
Fix issue with metrics exporter in otelcol.exporter.loadbalancing (#5684)
1 parent b76dc33 commit a2817f5

File tree

7 files changed

+104
-22
lines changed

7 files changed

+104
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ Main (unreleased)
146146
- Fixed an issue in the static config converter where exporter instance values
147147
were not being mapped when translating to flow. (@erikbaranowski)
148148

149+
- Fix a bug which prevented Agent from running `otelcol.exporter.loadbalancing`
150+
with a `routing_key` of `traceID`. (@ptodev)
151+
149152
v0.37.4 (2023-11-06)
150153
-----------------
151154

@@ -159,7 +162,7 @@ v0.37.4 (2023-11-06)
159162
- Fix a bug where reloading the configuration of a `loki.write` component lead
160163
to a panic. (@tpaschalis)
161164

162-
- Added Kubernetes service resolver to static node's loadbalancing exporter
165+
- Added Kubernetes service resolver to static node's loadbalancing exporter
163166
and to Flow's `otelcol.exporter.loadbalancing`. (@ptodev)
164167

165168
v0.37.3 (2023-10-26)

component/otelcol/exporter/exporter.go

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,33 @@ type Arguments interface {
4444
DebugMetricsConfig() otelcol.DebugMetricsArguments
4545
}
4646

47+
// TypeSignal is a bit field to indicate which telemetry signals the exporter supports.
48+
type TypeSignal byte
49+
50+
const (
51+
TypeLogs TypeSignal = 1 << iota // 1
52+
TypeMetrics // 2
53+
TypeTraces // 4
54+
)
55+
56+
// TypeAll indicates that the exporter supports all telemetry signals.
57+
const TypeAll = TypeLogs | TypeMetrics | TypeTraces
58+
59+
// SupportsLogs returns true if the exporter supports logs.
60+
func (s TypeSignal) SupportsLogs() bool {
61+
return s&TypeLogs != 0
62+
}
63+
64+
// SupportsMetrics returns true if the exporter supports metrics.
65+
func (s TypeSignal) SupportsMetrics() bool {
66+
return s&TypeMetrics != 0
67+
}
68+
69+
// SupportsTraces returns true if the exporter supports traces.
70+
func (s TypeSignal) SupportsTraces() bool {
71+
return s&TypeTraces != 0
72+
}
73+
4774
// Exporter is a Flow component shim which manages an OpenTelemetry Collector
4875
// exporter component.
4976
type Exporter struct {
@@ -56,6 +83,10 @@ type Exporter struct {
5683

5784
sched *scheduler.Scheduler
5885
collector *lazycollector.Collector
86+
87+
// Signals which the exporter is able to export.
88+
// Can be logs, metrics, traces or any combination of them.
89+
supportedSignals TypeSignal
5990
}
6091

6192
var (
@@ -69,7 +100,7 @@ var (
69100
//
70101
// The registered component must be registered to export the
71102
// otelcol.ConsumerExports type, otherwise New will panic.
72-
func New(opts component.Options, f otelexporter.Factory, args Arguments) (*Exporter, error) {
103+
func New(opts component.Options, f otelexporter.Factory, args Arguments, supportedSignals TypeSignal) (*Exporter, error) {
73104
ctx, cancel := context.WithCancel(context.Background())
74105

75106
consumer := lazyconsumer.New(ctx)
@@ -96,6 +127,8 @@ func New(opts component.Options, f otelexporter.Factory, args Arguments) (*Expor
96127

97128
sched: scheduler.New(opts.Logger),
98129
collector: collector,
130+
131+
supportedSignals: supportedSignals,
99132
}
100133
if err := e.Update(args); err != nil {
101134
return nil, err
@@ -162,25 +195,34 @@ func (e *Exporter) Update(args component.Arguments) error {
162195
// supported telemetry signals.
163196
var components []otelcomponent.Component
164197

165-
tracesExporter, err := e.factory.CreateTracesExporter(e.ctx, settings, exporterConfig)
166-
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
167-
return err
168-
} else if tracesExporter != nil {
169-
components = append(components, tracesExporter)
198+
var tracesExporter otelexporter.Traces
199+
if e.supportedSignals.SupportsTraces() {
200+
tracesExporter, err = e.factory.CreateTracesExporter(e.ctx, settings, exporterConfig)
201+
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
202+
return err
203+
} else if tracesExporter != nil {
204+
components = append(components, tracesExporter)
205+
}
170206
}
171207

172-
metricsExporter, err := e.factory.CreateMetricsExporter(e.ctx, settings, exporterConfig)
173-
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
174-
return err
175-
} else if metricsExporter != nil {
176-
components = append(components, metricsExporter)
208+
var metricsExporter otelexporter.Metrics
209+
if e.supportedSignals.SupportsMetrics() {
210+
metricsExporter, err = e.factory.CreateMetricsExporter(e.ctx, settings, exporterConfig)
211+
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
212+
return err
213+
} else if metricsExporter != nil {
214+
components = append(components, metricsExporter)
215+
}
177216
}
178217

179-
logsExporter, err := e.factory.CreateLogsExporter(e.ctx, settings, exporterConfig)
180-
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
181-
return err
182-
} else if logsExporter != nil {
183-
components = append(components, logsExporter)
218+
var logsExporter otelexporter.Logs
219+
if e.supportedSignals.SupportsLogs() {
220+
logsExporter, err = e.factory.CreateLogsExporter(e.ctx, settings, exporterConfig)
221+
if err != nil && !errors.Is(err, otelcomponent.ErrDataTypeIsNotSupported) {
222+
return err
223+
} else if logsExporter != nil {
224+
components = append(components, logsExporter)
225+
}
184226
}
185227

186228
// Schedule the components to run once our component is running.

component/otelcol/exporter/exporter_test.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func newTestEnvironment(t *testing.T, fe *fakeExporter) *testEnvironment {
103103
}, otelcomponent.StabilityLevelUndefined),
104104
)
105105

106-
return exporter.New(opts, factory, args.(exporter.Arguments))
106+
return exporter.New(opts, factory, args.(exporter.Arguments), exporter.TypeAll)
107107
},
108108
}
109109

@@ -198,3 +198,37 @@ func createTestTraces() ptrace.Traces {
198198
}
199199
return data
200200
}
201+
202+
func TestExporterSignalType(t *testing.T) {
203+
//
204+
// Check if ExporterAll supports all signals
205+
//
206+
require.True(t, exporter.TypeAll.SupportsLogs())
207+
require.True(t, exporter.TypeAll.SupportsMetrics())
208+
require.True(t, exporter.TypeAll.SupportsTraces())
209+
210+
//
211+
// Make sure each of the 3 signals supports itself
212+
//
213+
require.True(t, exporter.TypeLogs.SupportsLogs())
214+
require.True(t, exporter.TypeMetrics.SupportsMetrics())
215+
require.True(t, exporter.TypeTraces.SupportsTraces())
216+
217+
//
218+
// Make sure Logs does not support Metrics and Traces.
219+
//
220+
require.False(t, exporter.TypeLogs.SupportsMetrics())
221+
require.False(t, exporter.TypeLogs.SupportsTraces())
222+
223+
//
224+
// Make sure Metrics does not support Logs and Traces.
225+
//
226+
require.False(t, exporter.TypeMetrics.SupportsLogs())
227+
require.False(t, exporter.TypeMetrics.SupportsTraces())
228+
229+
//
230+
// Make sure Traces does not support Logs and Metrics.
231+
//
232+
require.False(t, exporter.TypeTraces.SupportsLogs())
233+
require.False(t, exporter.TypeTraces.SupportsMetrics())
234+
}

component/otelcol/exporter/loadbalancing/loadbalancing.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ func init() {
3131

3232
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
3333
fact := loadbalancingexporter.NewFactory()
34-
return exporter.New(opts, fact, args.(Arguments))
34+
//TODO(ptodev): LB exporter cannot yet work with metrics due to a limitation in the Agent:
35+
// https://github.com/grafana/agent/pull/5684
36+
// Once the limitation is removed, we may be able to remove the need for exporter.TypeSignal altogether.
37+
return exporter.New(opts, fact, args.(Arguments), exporter.TypeLogs|exporter.TypeTraces)
3538
},
3639
})
3740
}

component/otelcol/exporter/logging/logging.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func init() {
2121

2222
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
2323
fact := loggingexporter.NewFactory()
24-
return exporter.New(opts, fact, args.(Arguments))
24+
return exporter.New(opts, fact, args.(Arguments), exporter.TypeAll)
2525
},
2626
})
2727
}

component/otelcol/exporter/otlp/otlp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func init() {
2323

2424
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
2525
fact := otlpexporter.NewFactory()
26-
return exporter.New(opts, fact, args.(Arguments))
26+
return exporter.New(opts, fact, args.(Arguments), exporter.TypeAll)
2727
},
2828
})
2929
}

component/otelcol/exporter/otlphttp/otlphttp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func init() {
2323

2424
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
2525
fact := otlphttpexporter.NewFactory()
26-
return exporter.New(opts, fact, args.(Arguments))
26+
return exporter.New(opts, fact, args.(Arguments), exporter.TypeAll)
2727
},
2828
})
2929
}

0 commit comments

Comments
 (0)