@@ -76,9 +76,50 @@ type CWMetricStats struct {
76
76
Sum float64
77
77
}
78
78
79
+ // Wrapper interface for:
80
+ // - pdata.IntDataPointSlice
81
+ // - pdata.DoubleDataPointSlice
82
+ // - pdata.IntHistogramDataPointSlice
83
+ // - pdata.DoubleHistogramDataPointSlice
84
+ type DataPoints interface {
85
+ Len () int
86
+ At (int ) DataPoint
87
+ }
88
+
89
+ // Wrapper interface for:
90
+ // - pdata.IntDataPoint
91
+ // - pdata.DoubleDataPoint
92
+ // - pdata.IntHistogramDataPoint
93
+ // - pdata.DoubleHistogramDataPoint
94
+ type DataPoint interface {
95
+ IsNil () bool
96
+ LabelsMap () pdata.StringMap
97
+ }
98
+
99
+ // Define wrapper interfaces such that At(i) returns a `DataPoint`
100
+ type IntDataPointSlice struct {
101
+ pdata.IntDataPointSlice
102
+ }
103
+ type DoubleDataPointSlice struct {
104
+ pdata.DoubleDataPointSlice
105
+ }
106
+ type DoubleHistogramDataPointSlice struct {
107
+ pdata.DoubleHistogramDataPointSlice
108
+ }
109
+
110
+ func (dps IntDataPointSlice ) At (i int ) DataPoint {
111
+ return dps .IntDataPointSlice .At (i )
112
+ }
113
+ func (dps DoubleDataPointSlice ) At (i int ) DataPoint {
114
+ return dps .DoubleDataPointSlice .At (i )
115
+ }
116
+ func (dps DoubleHistogramDataPointSlice ) At (i int ) DataPoint {
117
+ return dps .DoubleHistogramDataPointSlice .At (i )
118
+ }
119
+
79
120
// TranslateOtToCWMetric converts OT metrics to CloudWatch Metric format
80
121
func TranslateOtToCWMetric (rm * pdata.ResourceMetrics , dimensionRollupOption string , namespace string ) ([]* CWMetrics , int ) {
81
- var cwMetricLists []* CWMetrics
122
+ var cwMetricList []* CWMetrics
82
123
totalDroppedMetrics := 0
83
124
var instrumentationLibName string
84
125
@@ -117,11 +158,11 @@ func TranslateOtToCWMetric(rm *pdata.ResourceMetrics, dimensionRollupOption stri
117
158
totalDroppedMetrics ++
118
159
continue
119
160
}
120
- cwMetricList := getMeasurements (& metric , namespace , instrumentationLibName , dimensionRollupOption )
121
- cwMetricLists = append (cwMetricLists , cwMetricList ... )
161
+ cwMetrics := getCWMetrics (& metric , namespace , instrumentationLibName , dimensionRollupOption )
162
+ cwMetricList = append (cwMetricList , cwMetrics ... )
122
163
}
123
164
}
124
- return cwMetricLists , totalDroppedMetrics
165
+ return cwMetricList , totalDroppedMetrics
125
166
}
126
167
127
168
func TranslateCWMetricToEMF (cwMetricLists []* CWMetrics ) []* LogEvent {
@@ -150,217 +191,127 @@ func TranslateCWMetricToEMF(cwMetricLists []*CWMetrics) []*LogEvent {
150
191
return ples
151
192
}
152
193
153
- func getMeasurements (metric * pdata.Metric , namespace string , instrumentationLibName string , dimensionRollupOption string ) []* CWMetrics {
194
+ // Translates OTLP Metric to list of CW Metrics
195
+ func getCWMetrics (metric * pdata.Metric , namespace string , instrumentationLibName string , dimensionRollupOption string ) []* CWMetrics {
154
196
var result []* CWMetrics
197
+ var dps DataPoints
155
198
156
199
// metric measure data from OT
157
200
metricMeasure := make (map [string ]string )
158
- // metric measure slice could include multiple metric measures
159
- metricSlice := []map [string ]string {}
160
201
metricMeasure ["Name" ] = metric .Name ()
161
202
metricMeasure ["Unit" ] = metric .Unit ()
162
- metricSlice = append (metricSlice , metricMeasure )
203
+ // metric measure slice could include multiple metric measures
204
+ metricSlice := []map [string ]string {metricMeasure }
163
205
206
+ // Retrieve data points
164
207
switch metric .DataType () {
165
208
case pdata .MetricDataTypeIntGauge :
166
- dps := metric .IntGauge ().DataPoints ()
167
- if dps .Len () == 0 {
168
- return result
169
- }
170
- for m := 0 ; m < dps .Len (); m ++ {
171
- dp := dps .At (m )
172
- if dp .IsNil () {
173
- continue
174
- }
175
- cwMetric := buildCWMetricFromDP (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
176
- if cwMetric != nil {
177
- result = append (result , cwMetric )
178
- }
179
- }
209
+ dps = IntDataPointSlice {metric .IntGauge ().DataPoints ()}
180
210
case pdata .MetricDataTypeDoubleGauge :
181
- dps := metric .DoubleGauge ().DataPoints ()
182
- if dps .Len () == 0 {
183
- return result
184
- }
185
- for m := 0 ; m < dps .Len (); m ++ {
186
- dp := dps .At (m )
187
- if dp .IsNil () {
188
- continue
189
- }
190
- cwMetric := buildCWMetricFromDP (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
191
- if cwMetric != nil {
192
- result = append (result , cwMetric )
193
- }
194
- }
211
+ dps = DoubleDataPointSlice {metric .DoubleGauge ().DataPoints ()}
195
212
case pdata .MetricDataTypeIntSum :
196
- dps := metric .IntSum ().DataPoints ()
197
- if dps .Len () == 0 {
198
- return result
199
- }
200
- for m := 0 ; m < dps .Len (); m ++ {
201
- dp := dps .At (m )
202
- if dp .IsNil () {
203
- continue
204
- }
205
- cwMetric := buildCWMetricFromDP (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
206
- if cwMetric != nil {
207
- result = append (result , cwMetric )
208
- }
209
- }
213
+ dps = IntDataPointSlice {metric .IntSum ().DataPoints ()}
210
214
case pdata .MetricDataTypeDoubleSum :
211
- dps := metric .DoubleSum ().DataPoints ()
212
- if dps .Len () == 0 {
213
- return result
214
- }
215
- for m := 0 ; m < dps .Len (); m ++ {
216
- dp := dps .At (m )
217
- if dp .IsNil () {
218
- continue
219
- }
220
- cwMetric := buildCWMetricFromDP (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
221
- if cwMetric != nil {
222
- result = append (result , cwMetric )
223
- }
224
- }
215
+ dps = DoubleDataPointSlice {metric .DoubleSum ().DataPoints ()}
225
216
case pdata .MetricDataTypeDoubleHistogram :
226
- dps := metric .DoubleHistogram ().DataPoints ()
227
- if dps .Len () == 0 {
228
- return result
217
+ dps = DoubleHistogramDataPointSlice {metric .DoubleHistogram ().DataPoints ()}
218
+ }
219
+
220
+ if dps .Len () == 0 {
221
+ return result
222
+ }
223
+ for m := 0 ; m < dps .Len (); m ++ {
224
+ dp := dps .At (m )
225
+ if dp .IsNil () {
226
+ continue
229
227
}
230
- for m := 0 ; m < dps .Len (); m ++ {
231
- dp := dps .At (m )
232
- if dp .IsNil () {
233
- continue
234
- }
235
- cwMetric := buildCWMetricFromHistogram (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
236
- if cwMetric != nil {
237
- result = append (result , cwMetric )
238
- }
228
+ cwMetric := buildCWMetric (dp , metric , namespace , metricSlice , instrumentationLibName , dimensionRollupOption )
229
+ if cwMetric != nil {
230
+ result = append (result , cwMetric )
239
231
}
240
232
}
241
233
return result
242
234
}
243
235
244
- func buildCWMetricFromDP (dp interface {}, pmd * pdata.Metric , namespace string , metricSlice []map [string ]string , instrumentationLibName string , dimensionRollupOption string ) * CWMetrics {
245
- // fields contains metric and dimensions key/value pairs
246
- fieldsPairs := make (map [string ]interface {})
247
- var dimensionArray [][]string
248
- // Dimensions Slice
249
- var dimensionSlice []string
250
- var dimensionKV pdata.StringMap
251
- switch metric := dp .(type ) {
252
- case pdata.IntDataPoint :
253
- dimensionKV = metric .LabelsMap ()
254
- case pdata.DoubleDataPoint :
255
- dimensionKV = metric .LabelsMap ()
256
- }
257
-
258
- dimensionKV .ForEach (func (k string , v pdata.StringValue ) {
259
- fieldsPairs [k ] = v .Value ()
260
- dimensionSlice = append (dimensionSlice , k )
261
- })
262
- // add OTel instrumentation lib name as an additional dimension if it is defined
263
- if instrumentationLibName != noInstrumentationLibraryName {
264
- fieldsPairs [OTellibDimensionKey ] = instrumentationLibName
265
- dimensionArray = append (dimensionArray , append (dimensionSlice , OTellibDimensionKey ))
266
- } else {
267
- dimensionArray = append (dimensionArray , dimensionSlice )
236
+ // Build CWMetric from DataPoint
237
+ func buildCWMetric (dp DataPoint , pmd * pdata.Metric , namespace string , metricSlice []map [string ]string , instrumentationLibName string , dimensionRollupOption string ) * CWMetrics {
238
+ dimensions , fields := createDimensions (dp , instrumentationLibName , dimensionRollupOption )
239
+ cwMeasurement := & CwMeasurement {
240
+ Namespace : namespace ,
241
+ Dimensions : dimensions ,
242
+ Metrics : metricSlice ,
268
243
}
269
-
244
+ metricList := [] CwMeasurement { * cwMeasurement }
270
245
timestamp := time .Now ().UnixNano () / int64 (time .Millisecond )
246
+
247
+ // Extract metric
271
248
var metricVal interface {}
272
249
switch metric := dp .(type ) {
273
250
case pdata.IntDataPoint :
274
- // Put a fake but identical metric value here in order to add metric name into fieldsPairs
251
+ // Put a fake but identical metric value here in order to add metric name into fields
275
252
// since calculateRate() needs metric name as one of metric identifiers
276
- fieldsPairs [pmd .Name ()] = int64 (FakeMetricValue )
253
+ fields [pmd .Name ()] = int64 (FakeMetricValue )
277
254
metricVal = metric .Value ()
278
255
if needsCalculateRate (pmd ) {
279
- metricVal = calculateRate (fieldsPairs , metric .Value (), timestamp )
256
+ metricVal = calculateRate (fields , metric .Value (), timestamp )
280
257
}
281
258
case pdata.DoubleDataPoint :
282
- fieldsPairs [pmd .Name ()] = float64 (FakeMetricValue )
259
+ fields [pmd .Name ()] = float64 (FakeMetricValue )
283
260
metricVal = metric .Value ()
284
261
if needsCalculateRate (pmd ) {
285
- metricVal = calculateRate (fieldsPairs , metric .Value (), timestamp )
262
+ metricVal = calculateRate (fields , metric .Value (), timestamp )
263
+ }
264
+ case pdata.DoubleHistogramDataPoint :
265
+ bucketBounds := metric .ExplicitBounds ()
266
+ metricVal = & CWMetricStats {
267
+ Min : bucketBounds [0 ],
268
+ Max : bucketBounds [len (bucketBounds )- 1 ],
269
+ Count : metric .Count (),
270
+ Sum : metric .Sum (),
286
271
}
287
272
}
288
273
if metricVal == nil {
289
274
return nil
290
275
}
291
- fieldsPairs [pmd .Name ()] = metricVal
276
+ fields [pmd .Name ()] = metricVal
292
277
293
- // EMF dimension attr takes list of list on dimensions. Including single/zero dimension rollup
294
- rollupDimensionArray := dimensionRollup (dimensionRollupOption , dimensionSlice , instrumentationLibName )
295
- if len (rollupDimensionArray ) > 0 {
296
- dimensionArray = append (dimensionArray , rollupDimensionArray ... )
297
- }
298
-
299
- cwMeasurement := & CwMeasurement {
300
- Namespace : namespace ,
301
- Dimensions : dimensionArray ,
302
- Metrics : metricSlice ,
303
- }
304
- metricList := make ([]CwMeasurement , 1 )
305
- metricList [0 ] = * cwMeasurement
306
278
cwMetric := & CWMetrics {
307
279
Measurements : metricList ,
308
280
Timestamp : timestamp ,
309
- Fields : fieldsPairs ,
281
+ Fields : fields ,
310
282
}
311
283
return cwMetric
312
284
}
313
285
314
- func buildCWMetricFromHistogram (metric pdata.DoubleHistogramDataPoint , pmd * pdata.Metric , namespace string , metricSlice []map [string ]string , instrumentationLibName string , dimensionRollupOption string ) * CWMetrics {
286
+ // Create dimensions from DataPoint labels, where dimensions is a 2D array of dimension names,
287
+ // and initialize fields with dimension key/value pairs
288
+ func createDimensions (dp DataPoint , instrumentationLibName string , dimensionRollupOption string ) (dimensions [][]string , fields map [string ]interface {}) {
315
289
// fields contains metric and dimensions key/value pairs
316
- fieldsPairs := make (map [string ]interface {})
317
- var dimensionArray [][]string
318
- // Dimensions Slice
319
- var dimensionSlice []string
320
- dimensionKV := metric .LabelsMap ()
290
+ fields = make (map [string ]interface {})
291
+ dimensionKV := dp .LabelsMap ()
321
292
293
+ dimensionSlice := make ([]string , dimensionKV .Len (), dimensionKV .Len ()+ 1 )
294
+ idx := 0
322
295
dimensionKV .ForEach (func (k string , v pdata.StringValue ) {
323
- fieldsPairs [k ] = v .Value ()
324
- dimensionSlice = append (dimensionSlice , k )
296
+ fields [k ] = v .Value ()
297
+ dimensionSlice [idx ] = k
298
+ idx ++
325
299
})
326
- // add OTel instrumentation lib name as an additional dimension if it is defined
300
+ // Add OTel instrumentation lib name as an additional dimension if it is defined
327
301
if instrumentationLibName != noInstrumentationLibraryName {
328
- fieldsPairs [OTellibDimensionKey ] = instrumentationLibName
329
- dimensionArray = append (dimensionArray , append (dimensionSlice , OTellibDimensionKey ))
302
+ fields [OTellibDimensionKey ] = instrumentationLibName
303
+ dimensions = append (dimensions , append (dimensionSlice , OTellibDimensionKey ))
330
304
} else {
331
- dimensionArray = append (dimensionArray , dimensionSlice )
332
- }
333
-
334
- timestamp := time .Now ().UnixNano () / int64 (time .Millisecond )
335
-
336
- bucketBounds := metric .ExplicitBounds ()
337
- metricStats := & CWMetricStats {
338
- Min : bucketBounds [0 ],
339
- Max : bucketBounds [len (bucketBounds )- 1 ],
340
- Count : metric .Count (),
341
- Sum : metric .Sum (),
305
+ dimensions = append (dimensions , dimensionSlice )
342
306
}
343
- fieldsPairs [pmd .Name ()] = metricStats
344
307
345
308
// EMF dimension attr takes list of list on dimensions. Including single/zero dimension rollup
346
309
rollupDimensionArray := dimensionRollup (dimensionRollupOption , dimensionSlice , instrumentationLibName )
347
310
if len (rollupDimensionArray ) > 0 {
348
- dimensionArray = append (dimensionArray , rollupDimensionArray ... )
311
+ dimensions = append (dimensions , rollupDimensionArray ... )
349
312
}
350
313
351
- cwMeasurement := & CwMeasurement {
352
- Namespace : namespace ,
353
- Dimensions : dimensionArray ,
354
- Metrics : metricSlice ,
355
- }
356
- metricList := make ([]CwMeasurement , 1 )
357
- metricList [0 ] = * cwMeasurement
358
- cwMetric := & CWMetrics {
359
- Measurements : metricList ,
360
- Timestamp : timestamp ,
361
- Fields : fieldsPairs ,
362
- }
363
- return cwMetric
314
+ return
364
315
}
365
316
366
317
// rate is calculated by valDelta / timeDelta
0 commit comments