@@ -16,7 +16,6 @@ package smartagentreceiver
16
16
17
17
import (
18
18
"context"
19
- "fmt"
20
19
"time"
21
20
22
21
metadata "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata"
@@ -36,31 +35,33 @@ import (
36
35
const internalTransport = "internal"
37
36
38
37
// Output is an implementation of a Smart Agent FilteringOutput that receives datapoints, events, and dimension updates
39
- // from a configured monitor. It will forward all datapoints to the nextConsumer , all dimension updates to the
40
- // nextDimensionClients, and all events to the nextEventClients as determined by the associated
41
- // items in Config.MetadataClients .
38
+ // from a configured monitor. It will forward all datapoints to the nextMetricsConsumer , all dimension updates to the
39
+ // nextDimensionClients as determined by the associated items in Config.MetadataClients, and all events to the
40
+ // nextLogsConsumer .
42
41
type Output struct {
43
- nextConsumer consumer.MetricsConsumer
42
+ nextMetricsConsumer consumer.MetricsConsumer
43
+ nextLogsConsumer consumer.LogsConsumer
44
44
extraDimensions map [string ]string
45
45
logger * zap.Logger
46
46
converter Converter
47
47
monitorFiltering * monitorFiltering
48
48
receiverName string
49
49
nextDimensionClients []* metadata.MetadataExporter
50
- nextEventClients []* consumer.LogsConsumer
51
50
}
52
51
53
52
var _ types.Output = (* Output )(nil )
54
53
var _ types.FilteringOutput = (* Output )(nil )
55
54
56
- func NewOutput (config Config , filtering * monitorFiltering , nextConsumer consumer.MetricsConsumer , host component.Host , logger * zap.Logger ) * Output {
57
- metadataExporters := getMetadataExporters (config , host , & nextConsumer , logger )
58
- logConsumers := getLogsConsumers (config , host , & nextConsumer , logger )
55
+ func NewOutput (
56
+ config Config , filtering * monitorFiltering , nextMetricsConsumer consumer.MetricsConsumer ,
57
+ nextLogsConsumer consumer.LogsConsumer , host component.Host , logger * zap.Logger ,
58
+ ) * Output {
59
+ metadataExporters := getMetadataExporters (config , host , & nextMetricsConsumer , logger )
59
60
return & Output {
60
61
receiverName : config .Name (),
61
- nextConsumer : nextConsumer ,
62
+ nextMetricsConsumer : nextMetricsConsumer ,
63
+ nextLogsConsumer : nextLogsConsumer ,
62
64
nextDimensionClients : metadataExporters ,
63
- nextEventClients : logConsumers ,
64
65
logger : logger ,
65
66
converter : Converter {logger : logger },
66
67
extraDimensions : map [string ]string {},
@@ -71,11 +72,11 @@ func NewOutput(config Config, filtering *monitorFiltering, nextConsumer consumer
71
72
// getMetadataExporters walks through obtained Config.MetadataClients and returns all matching registered MetadataExporters,
72
73
// if any. At this time the SignalFx exporter is the only supported use case and adopter of this type.
73
74
func getMetadataExporters (
74
- config Config , host component.Host , nextConsumer * consumer.MetricsConsumer , logger * zap.Logger ,
75
+ config Config , host component.Host , nextMetricsConsumer * consumer.MetricsConsumer , logger * zap.Logger ,
75
76
) []* metadata.MetadataExporter {
76
77
var exporters []* metadata.MetadataExporter
77
78
78
- metadataExporters := getClientsFromMetricsExporters (config .DimensionClients , host , nextConsumer , "dimensionClients" , logger )
79
+ metadataExporters , noClientsSpecified := getDimensionClientsFromMetricsExporters (config .DimensionClients , host , nextMetricsConsumer , logger )
79
80
for _ , client := range metadataExporters {
80
81
if metadataExporter , ok := (* client ).(metadata.MetadataExporter ); ok {
81
82
exporters = append (exporters , & metadataExporter )
@@ -84,68 +85,75 @@ func getMetadataExporters(
84
85
}
85
86
}
86
87
88
+ if len (exporters ) == 0 && noClientsSpecified {
89
+ sfxExporter := getLoneSFxExporter (host , configmodels .MetricsDataType )
90
+ if sfxExporter != nil {
91
+ if sfx , ok := sfxExporter .(metadata.MetadataExporter ); ok {
92
+ exporters = append (exporters , & sfx )
93
+ }
94
+ }
95
+ }
96
+
87
97
if len (exporters ) == 0 {
88
98
logger .Debug ("no dimension updates are possible as no valid dimensionClients have been provided and next pipeline component isn't a MetadataExporter" )
89
99
}
90
100
91
101
return exporters
92
102
}
93
103
94
- // getLogsConsumers walks through obtained Config.EventClients and returns all matching registered LogsConsumers,
95
- // if any. At this time the SignalFx exporter is the only real target use case, but it's unexported and
96
- // as implemented all specified combination MetricsExporters and LogsConsumers will be returned.
97
- func getLogsConsumers (
98
- config Config , host component.Host , nextConsumer * consumer.MetricsConsumer , logger * zap.Logger ,
99
- ) []* consumer.LogsConsumer {
100
- var consumers []* consumer.LogsConsumer
101
-
102
- eventClients := getClientsFromMetricsExporters (config .EventClients , host , nextConsumer , "eventClients" , logger )
103
- for _ , client := range eventClients {
104
- if logsExporter , ok := (* client ).(consumer.LogsConsumer ); ok {
105
- consumers = append (consumers , & logsExporter )
106
- } else {
107
- logger .Info ("cannot send events to event client" , zap .Any ("client" , * client ))
104
+ // getDimensionClientsFromMetricsExporters will walk through all provided config.DimensionClients and retrieve matching registered
105
+ // MetricsExporters, the only truly supported component type.
106
+ // If config.MetadataClients is nil, it will return a slice with nextMetricsConsumer if it's a MetricsExporter.
107
+ func getDimensionClientsFromMetricsExporters (
108
+ specifiedClients []string , host component.Host , nextMetricsConsumer * consumer.MetricsConsumer , logger * zap.Logger ,
109
+ ) (clients []* metadata.MetadataExporter , wasNil bool ) {
110
+ if specifiedClients == nil {
111
+ wasNil = true
112
+ // default to nextMetricsConsumer if no clients have been provided
113
+ if asMetadataExporter , ok := (* nextMetricsConsumer ).(metadata.MetadataExporter ); ok {
114
+ clients = append (clients , & asMetadataExporter )
108
115
}
116
+ return
109
117
}
110
118
111
- if len (consumers ) == 0 {
112
- logger .Debug ("no SFx events are possible as no valid eventClients have been provided and next pipeline component isn't a LogsConsumer" )
119
+ if builtExporters , ok := host .GetExporters ()[configmodels .MetricsDataType ]; ok {
120
+ for _ , client := range specifiedClients {
121
+ var found bool
122
+ for exporterConfig , exporter := range builtExporters {
123
+ if exporterConfig .Name () == client {
124
+ if asMetadataExporter , ok := exporter .(metadata.MetadataExporter ); ok {
125
+ clients = append (clients , & asMetadataExporter )
126
+ }
127
+ found = true
128
+ }
129
+ }
130
+ if ! found {
131
+ logger .Info (
132
+ "specified dimension client is not an available exporter" ,
133
+ zap .String ("client" , client ),
134
+ )
135
+ }
136
+ }
113
137
}
114
-
115
- return consumers
138
+ return
116
139
}
117
140
118
- // getClientsFromMetricsExporters will walk through all provided config.DimensionClients and retrieve matching registered
119
- // MetricsExporters, the only truly supported component type.
120
- // If config.MetadataClients is nil, it will return a slice with nextConsumer if it's a MetricsExporter.
121
- func getClientsFromMetricsExporters (
122
- specifiedClients []string , host component.Host , nextConsumer * consumer.MetricsConsumer , fieldName string , logger * zap.Logger ,
123
- ) (clients []* interface {}) {
124
- if specifiedClients == nil {
125
- // default to nextConsumer if no clients have been provided
126
- asInterface := (* nextConsumer ).(interface {})
127
- clients = append (clients , & asInterface )
128
- return
129
- }
130
-
131
- builtExporters := host .GetExporters ()[configmodels .MetricsDataType ]
132
- for _ , client := range specifiedClients {
133
- var found bool
141
+ func getLoneSFxExporter (host component.Host , exporterType configmodels.DataType ) component.Exporter {
142
+ var sfxExporter component.Exporter
143
+ if builtExporters , ok := host .GetExporters ()[exporterType ]; ok {
134
144
for exporterConfig , exporter := range builtExporters {
135
- if exporterConfig .Name () == client {
136
- asInterface := exporter .(interface {})
137
- clients = append (clients , & asInterface )
138
- found = true
145
+ if exporterConfig .Type () == "signalfx" {
146
+ if sfxExporter == nil {
147
+ sfxExporter = exporter
148
+ } else { // we've already found one so no lone instance to use as default
149
+ return nil
150
+ }
151
+
139
152
}
140
153
}
141
- if ! found {
142
- logger .Info (
143
- fmt .Sprintf ("specified %s is not an available exporter" , fieldName ),
144
- zap .String ("client" , client ),
145
- )
146
- }
147
154
}
148
- return clients
155
+ return sfxExporter
156
+
149
157
}
150
158
151
159
func (output * Output ) AddDatapointExclusionFilter (filter dpfilters.DatapointFilter ) {
@@ -177,6 +185,10 @@ func (output *Output) Copy() types.Output {
177
185
}
178
186
179
187
func (output * Output ) SendDatapoints (datapoints ... * datapoint.Datapoint ) {
188
+ if output .nextMetricsConsumer == nil {
189
+ return
190
+ }
191
+
180
192
ctx := obsreport .ReceiverContext (context .Background (), output .receiverName , internalTransport )
181
193
ctx = obsreport .StartMetricsReceiveOp (ctx , typeStr , internalTransport )
182
194
@@ -192,21 +204,19 @@ func (output *Output) SendDatapoints(datapoints ...*datapoint.Datapoint) {
192
204
}
193
205
194
206
_ , numPoints := metrics .MetricAndDataPointCount ()
195
- err := output .nextConsumer .ConsumeMetrics (context .Background (), metrics )
207
+ err := output .nextMetricsConsumer .ConsumeMetrics (context .Background (), metrics )
196
208
obsreport .EndMetricsReceiveOp (ctx , typeStr , numPoints , err )
197
209
}
198
210
199
211
func (output * Output ) SendEvent (event * event.Event ) {
200
- if len ( output .nextEventClients ) == 0 {
212
+ if output .nextLogsConsumer == nil {
201
213
return
202
214
}
203
215
204
216
logRecord := eventToLog (event , output .logger )
205
- for _ , logsConsumer := range output .nextEventClients {
206
- err := (* logsConsumer ).ConsumeLogs (context .Background (), logRecord )
207
- if err != nil {
208
- output .logger .Debug ("SendEvent has failed" , zap .Error (err ))
209
- }
217
+ err := output .nextLogsConsumer .ConsumeLogs (context .Background (), logRecord )
218
+ if err != nil {
219
+ output .logger .Debug ("SendEvent has failed" , zap .Error (err ))
210
220
}
211
221
}
212
222
0 commit comments