@@ -19,11 +19,9 @@ import (
19
19
"fmt"
20
20
21
21
"github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer"
22
- "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata"
23
22
"go.opentelemetry.io/collector/component"
24
23
"go.opentelemetry.io/collector/consumer"
25
24
"go.opentelemetry.io/collector/pdata/pcommon"
26
- "go.opentelemetry.io/collector/pdata/plog"
27
25
"go.opentelemetry.io/collector/pdata/pmetric"
28
26
"go.uber.org/zap"
29
27
"go.uber.org/zap/zapcore"
@@ -47,12 +45,10 @@ var (
47
45
// Status match rules. If so, they emit log records for the matching metric.
48
46
type metricEvaluator struct {
49
47
* evaluator
50
- pLogs chan plog.Logs
51
48
}
52
49
53
- func newMetricEvaluator (logger * zap.Logger , cfg * Config , pLogs chan plog. Logs , correlations correlationStore ) * metricEvaluator {
50
+ func newMetricEvaluator (logger * zap.Logger , cfg * Config , correlations correlationStore ) * metricEvaluator {
54
51
return & metricEvaluator {
55
- pLogs : pLogs ,
56
52
evaluator : newEvaluator (logger , cfg , correlations ,
57
53
// TODO: provide more capable env w/ resource and metric attributes
58
54
func (pattern string ) map [string ]any {
@@ -67,15 +63,13 @@ func (m *metricEvaluator) Capabilities() consumer.Capabilities {
67
63
}
68
64
69
65
func (m * metricEvaluator ) ConsumeMetrics (_ context.Context , md pmetric.Metrics ) error {
70
- if pLogs := m .evaluateMetrics (md ); pLogs .LogRecordCount () > 0 {
71
- m .pLogs <- pLogs
72
- }
66
+ m .evaluateMetrics (md )
73
67
return nil
74
68
}
75
69
76
70
// evaluateMetrics parses the provided Metrics and returns plog.Logs with a single log record if it matches
77
71
// against the first applicable configured Status match rule.
78
- func (m * metricEvaluator ) evaluateMetrics (md pmetric.Metrics ) plog. Logs {
72
+ func (m * metricEvaluator ) evaluateMetrics (md pmetric.Metrics ) {
79
73
if ce := m .logger .Check (zapcore .DebugLevel , "evaluating metrics" ); ce != nil {
80
74
if mbytes , err := jsonMarshaler .MarshalMetrics (md ); err == nil {
81
75
ce .Write (zap .ByteString ("metrics" , mbytes ))
@@ -84,22 +78,22 @@ func (m *metricEvaluator) evaluateMetrics(md pmetric.Metrics) plog.Logs {
84
78
}
85
79
}
86
80
if md .MetricCount () == 0 {
87
- return plog . NewLogs ()
81
+ return
88
82
}
89
83
90
84
receiverID , endpointID := statussources .MetricsToReceiverIDs (md )
91
85
if receiverID == discovery .NoType || endpointID == "" {
92
86
m .logger .Debug ("unable to evaluate metrics from receiver without corresponding name or Endpoint.ID" , zap .Any ("metrics" , md ))
93
- return plog . NewLogs ()
87
+ return
94
88
}
95
89
96
90
rEntry , ok := m .config .Receivers [receiverID ]
97
91
if ! ok {
98
92
m .logger .Info ("No matching configured receiver for metric status evaluation" , zap .String ("receiver" , receiverID .String ()))
99
- return plog . NewLogs ()
93
+ return
100
94
}
101
95
if rEntry .Status == nil || len (rEntry .Status .Metrics ) == 0 {
102
- return plog . NewLogs ()
96
+ return
103
97
}
104
98
105
99
for _ , match := range rEntry .Status .Metrics {
@@ -108,20 +102,26 @@ func (m *metricEvaluator) evaluateMetrics(md pmetric.Metrics) plog.Logs {
108
102
continue
109
103
}
110
104
111
- entityEvents := experimentalmetricmetadata .NewEntityEventsSlice ()
112
- entityEvent := entityEvents .AppendEmpty ()
113
- entityEvent .ID ().PutStr (discovery .EndpointIDAttr , string (endpointID ))
114
- entityState := entityEvent .SetEntityState ()
115
-
116
- res .Attributes ().CopyTo (entityState .Attributes ())
117
105
corr := m .correlations .GetOrCreate (endpointID , receiverID )
118
- m . correlateResourceAttributes ( m . config , entityState . Attributes (), corr )
106
+ attrs := m . correlations . Attrs ( endpointID )
119
107
120
- // Remove the endpoint ID from the attributes as it's set in the entity ID.
121
- entityState .Attributes ().Remove (discovery .EndpointIDAttr )
108
+ // If the status is already the same as desired, we don't need to update the entity state.
109
+ if match .Status == discovery .StatusType (attrs [discovery .StatusAttr ]) {
110
+ return
111
+ }
122
112
123
- entityState .Attributes ().PutStr (eventTypeAttr , metricMatch )
124
- entityState .Attributes ().PutStr (receiverRuleAttr , rEntry .Rule .String ())
113
+ res .Attributes ().Range (func (k string , v pcommon.Value ) bool {
114
+ // skip endpoint ID attr since it's set in the entity ID
115
+ if k == discovery .EndpointIDAttr {
116
+ return true
117
+ }
118
+ attrs [k ] = v .AsString ()
119
+ return true
120
+ })
121
+ m .correlateResourceAttributes (m .config , attrs , corr )
122
+
123
+ attrs [eventTypeAttr ] = metricMatch
124
+ attrs [receiverRuleAttr ] = rEntry .Rule .String ()
125
125
126
126
desiredRecord := match .Record
127
127
if desiredRecord == nil {
@@ -131,19 +131,17 @@ func (m *metricEvaluator) evaluateMetrics(md pmetric.Metrics) plog.Logs {
131
131
if desiredRecord .Body != "" {
132
132
desiredMsg = desiredRecord .Body
133
133
}
134
- entityState . Attributes (). PutStr ( discovery .MessageAttr , desiredMsg )
134
+ attrs [ discovery .MessageAttr ] = desiredMsg
135
135
for k , v := range desiredRecord .Attributes {
136
- entityState .Attributes ().PutStr (k , v )
137
- }
138
- entityState .Attributes ().PutStr (metricNameAttr , metric .Name ())
139
- entityState .Attributes ().PutStr (discovery .StatusAttr , string (match .Status ))
140
- if ts := m .timestampFromMetric (metric ); ts != nil {
141
- entityEvent .SetTimestamp (* ts )
136
+ attrs [k ] = v
142
137
}
138
+ attrs [metricNameAttr ] = metric .Name ()
139
+ attrs [discovery .StatusAttr ] = string (match .Status )
140
+ m .correlations .UpdateAttrs (endpointID , attrs )
143
141
144
- return entityEvents .ConvertAndMoveToLogs ()
142
+ m .correlations .EmitCh () <- corr
143
+ return
145
144
}
146
- return plog .NewLogs ()
147
145
}
148
146
149
147
// findMatchedMetric finds the metric that matches the provided match rule and return it along with the resource if found.
@@ -166,42 +164,3 @@ func (m *metricEvaluator) findMatchedMetric(md pmetric.Metrics, match Match, rec
166
164
}
167
165
return pcommon .NewResource (), pmetric .NewMetric (), false
168
166
}
169
-
170
- func (m * metricEvaluator ) timestampFromMetric (metric pmetric.Metric ) * pcommon.Timestamp {
171
- var ts * pcommon.Timestamp
172
- switch dt := metric .Type (); dt {
173
- case pmetric .MetricTypeGauge :
174
- dps := metric .Gauge ().DataPoints ()
175
- if dps .Len () > 0 {
176
- t := dps .At (0 ).Timestamp ()
177
- ts = & t
178
- }
179
- case pmetric .MetricTypeSum :
180
- dps := metric .Sum ().DataPoints ()
181
- if dps .Len () > 0 {
182
- t := dps .At (0 ).Timestamp ()
183
- ts = & t
184
- }
185
- case pmetric .MetricTypeHistogram :
186
- dps := metric .Histogram ().DataPoints ()
187
- if dps .Len () > 0 {
188
- t := dps .At (0 ).Timestamp ()
189
- ts = & t
190
- }
191
- case pmetric .MetricTypeExponentialHistogram :
192
- dps := metric .ExponentialHistogram ().DataPoints ()
193
- if dps .Len () > 0 {
194
- t := dps .At (0 ).Timestamp ()
195
- ts = & t
196
- }
197
- case pmetric .MetricTypeSummary :
198
- dps := metric .Summary ().DataPoints ()
199
- if dps .Len () > 0 {
200
- t := dps .At (0 ).Timestamp ()
201
- ts = & t
202
- }
203
- default :
204
- m .logger .Debug ("cannot get timestamp from data type" , zap .String ("data type" , dt .String ()))
205
- }
206
- return ts
207
- }
0 commit comments