@@ -76,9 +76,50 @@ type CWMetricStats struct {
7676 Sum float64
7777}
7878
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+
79120// TranslateOtToCWMetric converts OT metrics to CloudWatch Metric format
80121func TranslateOtToCWMetric (rm * pdata.ResourceMetrics , dimensionRollupOption string , namespace string ) ([]* CWMetrics , int ) {
81- var cwMetricLists []* CWMetrics
122+ var cwMetricList []* CWMetrics
82123 totalDroppedMetrics := 0
83124 var instrumentationLibName string
84125
@@ -117,11 +158,11 @@ func TranslateOtToCWMetric(rm *pdata.ResourceMetrics, dimensionRollupOption stri
117158 totalDroppedMetrics ++
118159 continue
119160 }
120- cwMetricList := getMeasurements (& metric , namespace , instrumentationLibName , dimensionRollupOption )
121- cwMetricLists = append (cwMetricLists , cwMetricList ... )
161+ cwMetrics := getCWMetrics (& metric , namespace , instrumentationLibName , dimensionRollupOption )
162+ cwMetricList = append (cwMetricList , cwMetrics ... )
122163 }
123164 }
124- return cwMetricLists , totalDroppedMetrics
165+ return cwMetricList , totalDroppedMetrics
125166}
126167
127168func TranslateCWMetricToEMF (cwMetricLists []* CWMetrics ) []* LogEvent {
@@ -150,217 +191,127 @@ func TranslateCWMetricToEMF(cwMetricLists []*CWMetrics) []*LogEvent {
150191 return ples
151192}
152193
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 {
154196 var result []* CWMetrics
197+ var dps DataPoints
155198
156199 // metric measure data from OT
157200 metricMeasure := make (map [string ]string )
158- // metric measure slice could include multiple metric measures
159- metricSlice := []map [string ]string {}
160201 metricMeasure ["Name" ] = metric .Name ()
161202 metricMeasure ["Unit" ] = metric .Unit ()
162- metricSlice = append (metricSlice , metricMeasure )
203+ // metric measure slice could include multiple metric measures
204+ metricSlice := []map [string ]string {metricMeasure }
163205
206+ // Retrieve data points
164207 switch metric .DataType () {
165208 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 ()}
180210 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 ()}
195212 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 ()}
210214 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 ()}
225216 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
229227 }
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 )
239231 }
240232 }
241233 return result
242234}
243235
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 ,
268243 }
269-
244+ metricList := [] CwMeasurement { * cwMeasurement }
270245 timestamp := time .Now ().UnixNano () / int64 (time .Millisecond )
246+
247+ // Extract metric
271248 var metricVal interface {}
272249 switch metric := dp .(type ) {
273250 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
275252 // since calculateRate() needs metric name as one of metric identifiers
276- fieldsPairs [pmd .Name ()] = int64 (FakeMetricValue )
253+ fields [pmd .Name ()] = int64 (FakeMetricValue )
277254 metricVal = metric .Value ()
278255 if needsCalculateRate (pmd ) {
279- metricVal = calculateRate (fieldsPairs , metric .Value (), timestamp )
256+ metricVal = calculateRate (fields , metric .Value (), timestamp )
280257 }
281258 case pdata.DoubleDataPoint :
282- fieldsPairs [pmd .Name ()] = float64 (FakeMetricValue )
259+ fields [pmd .Name ()] = float64 (FakeMetricValue )
283260 metricVal = metric .Value ()
284261 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 (),
286271 }
287272 }
288273 if metricVal == nil {
289274 return nil
290275 }
291- fieldsPairs [pmd .Name ()] = metricVal
276+ fields [pmd .Name ()] = metricVal
292277
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
306278 cwMetric := & CWMetrics {
307279 Measurements : metricList ,
308280 Timestamp : timestamp ,
309- Fields : fieldsPairs ,
281+ Fields : fields ,
310282 }
311283 return cwMetric
312284}
313285
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 {}) {
315289 // 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 ()
321292
293+ dimensionSlice := make ([]string , dimensionKV .Len (), dimensionKV .Len ()+ 1 )
294+ idx := 0
322295 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 ++
325299 })
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
327301 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 ))
330304 } 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 )
342306 }
343- fieldsPairs [pmd .Name ()] = metricStats
344307
345308 // EMF dimension attr takes list of list on dimensions. Including single/zero dimension rollup
346309 rollupDimensionArray := dimensionRollup (dimensionRollupOption , dimensionSlice , instrumentationLibName )
347310 if len (rollupDimensionArray ) > 0 {
348- dimensionArray = append (dimensionArray , rollupDimensionArray ... )
311+ dimensions = append (dimensions , rollupDimensionArray ... )
349312 }
350313
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
364315}
365316
366317// rate is calculated by valDelta / timeDelta
0 commit comments