@@ -173,152 +173,26 @@ def _get_aggregation(
173
173
return instrument_class_aggregation
174
174
175
175
176
- def encode_metrics (data : MetricsData ) -> ExportMetricsServiceRequest :
177
- resource_metrics_dict = {}
178
-
179
- for resource_metrics in data .resource_metrics :
180
-
181
- resource = resource_metrics .resource
176
+ class EncodingException (Exception ):
177
+ """
178
+ Raised by encode_metrics() when an exception is caught during encoding. Contains the problematic metric so
179
+ the misbehaving metric name and details can be logged during exception handling.
180
+ """
182
181
183
- # It is safe to assume that each entry in data.resource_metrics is
184
- # associated with an unique resource.
185
- scope_metrics_dict = {}
182
+ def __init__ (self , original_exception , metric ):
183
+ super ().__init__ ()
184
+ self .original_exception = original_exception
185
+ self .metric = metric
186
186
187
- resource_metrics_dict [resource ] = scope_metrics_dict
188
-
189
- for scope_metrics in resource_metrics .scope_metrics :
190
-
191
- instrumentation_scope = scope_metrics .scope
192
-
193
- # The SDK groups metrics in instrumentation scopes already so
194
- # there is no need to check for existing instrumentation scopes
195
- # here.
196
- pb2_scope_metrics = pb2 .ScopeMetrics (
197
- scope = InstrumentationScope (
198
- name = instrumentation_scope .name ,
199
- version = instrumentation_scope .version ,
200
- )
201
- )
187
+ def __str__ (self ):
188
+ return f"{ self .metric } \n { self .original_exception } "
202
189
203
- scope_metrics_dict [instrumentation_scope ] = pb2_scope_metrics
204
190
205
- for metric in scope_metrics .metrics :
206
- pb2_metric = pb2 .Metric (
207
- name = metric .name ,
208
- description = metric .description ,
209
- unit = metric .unit ,
210
- )
191
+ def encode_metrics (data : MetricsData ) -> ExportMetricsServiceRequest :
192
+ resource_metrics_dict = {}
211
193
212
- if isinstance (metric .data , Gauge ):
213
- for data_point in metric .data .data_points :
214
- pt = pb2 .NumberDataPoint (
215
- attributes = _encode_attributes (
216
- data_point .attributes
217
- ),
218
- time_unix_nano = data_point .time_unix_nano ,
219
- )
220
- if isinstance (data_point .value , int ):
221
- pt .as_int = data_point .value
222
- else :
223
- pt .as_double = data_point .value
224
- pb2_metric .gauge .data_points .append (pt )
225
-
226
- elif isinstance (metric .data , HistogramType ):
227
- for data_point in metric .data .data_points :
228
- pt = pb2 .HistogramDataPoint (
229
- attributes = _encode_attributes (
230
- data_point .attributes
231
- ),
232
- time_unix_nano = data_point .time_unix_nano ,
233
- start_time_unix_nano = (
234
- data_point .start_time_unix_nano
235
- ),
236
- count = data_point .count ,
237
- sum = data_point .sum ,
238
- bucket_counts = data_point .bucket_counts ,
239
- explicit_bounds = data_point .explicit_bounds ,
240
- max = data_point .max ,
241
- min = data_point .min ,
242
- )
243
- pb2_metric .histogram .aggregation_temporality = (
244
- metric .data .aggregation_temporality
245
- )
246
- pb2_metric .histogram .data_points .append (pt )
247
-
248
- elif isinstance (metric .data , Sum ):
249
- for data_point in metric .data .data_points :
250
- pt = pb2 .NumberDataPoint (
251
- attributes = _encode_attributes (
252
- data_point .attributes
253
- ),
254
- start_time_unix_nano = (
255
- data_point .start_time_unix_nano
256
- ),
257
- time_unix_nano = data_point .time_unix_nano ,
258
- )
259
- if isinstance (data_point .value , int ):
260
- pt .as_int = data_point .value
261
- else :
262
- pt .as_double = data_point .value
263
- # note that because sum is a message type, the
264
- # fields must be set individually rather than
265
- # instantiating a pb2.Sum and setting it once
266
- pb2_metric .sum .aggregation_temporality = (
267
- metric .data .aggregation_temporality
268
- )
269
- pb2_metric .sum .is_monotonic = metric .data .is_monotonic
270
- pb2_metric .sum .data_points .append (pt )
271
-
272
- elif isinstance (metric .data , ExponentialHistogramType ):
273
- for data_point in metric .data .data_points :
274
-
275
- if data_point .positive .bucket_counts :
276
- positive = pb2 .ExponentialHistogramDataPoint .Buckets (
277
- offset = data_point .positive .offset ,
278
- bucket_counts = data_point .positive .bucket_counts ,
279
- )
280
- else :
281
- positive = None
282
-
283
- if data_point .negative .bucket_counts :
284
- negative = pb2 .ExponentialHistogramDataPoint .Buckets (
285
- offset = data_point .negative .offset ,
286
- bucket_counts = data_point .negative .bucket_counts ,
287
- )
288
- else :
289
- negative = None
290
-
291
- pt = pb2 .ExponentialHistogramDataPoint (
292
- attributes = _encode_attributes (
293
- data_point .attributes
294
- ),
295
- time_unix_nano = data_point .time_unix_nano ,
296
- start_time_unix_nano = (
297
- data_point .start_time_unix_nano
298
- ),
299
- count = data_point .count ,
300
- sum = data_point .sum ,
301
- scale = data_point .scale ,
302
- zero_count = data_point .zero_count ,
303
- positive = positive ,
304
- negative = negative ,
305
- flags = data_point .flags ,
306
- max = data_point .max ,
307
- min = data_point .min ,
308
- )
309
- pb2_metric .exponential_histogram .aggregation_temporality = (
310
- metric .data .aggregation_temporality
311
- )
312
- pb2_metric .exponential_histogram .data_points .append (pt )
313
-
314
- else :
315
- _logger .warning (
316
- "unsupported data type %s" ,
317
- metric .data .__class__ .__name__ ,
318
- )
319
- continue
320
-
321
- pb2_scope_metrics .metrics .append (pb2_metric )
194
+ for resource_metrics in data .resource_metrics :
195
+ _encode_resource_metrics (resource_metrics , resource_metrics_dict )
322
196
323
197
resource_data = []
324
198
for (
@@ -334,5 +208,137 @@ def encode_metrics(data: MetricsData) -> ExportMetricsServiceRequest:
334
208
schema_url = sdk_resource .schema_url ,
335
209
)
336
210
)
337
- resource_metrics = resource_data
338
- return ExportMetricsServiceRequest (resource_metrics = resource_metrics )
211
+ return ExportMetricsServiceRequest (resource_metrics = resource_data )
212
+
213
+
214
+ def _encode_resource_metrics (resource_metrics , resource_metrics_dict ):
215
+ resource = resource_metrics .resource
216
+ # It is safe to assume that each entry in data.resource_metrics is
217
+ # associated with an unique resource.
218
+ scope_metrics_dict = {}
219
+ resource_metrics_dict [resource ] = scope_metrics_dict
220
+ for scope_metrics in resource_metrics .scope_metrics :
221
+ instrumentation_scope = scope_metrics .scope
222
+
223
+ # The SDK groups metrics in instrumentation scopes already so
224
+ # there is no need to check for existing instrumentation scopes
225
+ # here.
226
+ pb2_scope_metrics = pb2 .ScopeMetrics (
227
+ scope = InstrumentationScope (
228
+ name = instrumentation_scope .name ,
229
+ version = instrumentation_scope .version ,
230
+ )
231
+ )
232
+
233
+ scope_metrics_dict [instrumentation_scope ] = pb2_scope_metrics
234
+
235
+ for metric in scope_metrics .metrics :
236
+ pb2_metric = pb2 .Metric (
237
+ name = metric .name ,
238
+ description = metric .description ,
239
+ unit = metric .unit ,
240
+ )
241
+
242
+ try :
243
+ _encode_metric (metric , pb2_metric )
244
+ except Exception as ex :
245
+ # `from None` so we don't get "During handling of the above exception, another exception occurred:"
246
+ raise EncodingException (ex , metric ) from None
247
+
248
+ pb2_scope_metrics .metrics .append (pb2_metric )
249
+
250
+
251
+ def _encode_metric (metric , pb2_metric ):
252
+ if isinstance (metric .data , Gauge ):
253
+ for data_point in metric .data .data_points :
254
+ pt = pb2 .NumberDataPoint (
255
+ attributes = _encode_attributes (data_point .attributes ),
256
+ time_unix_nano = data_point .time_unix_nano ,
257
+ )
258
+ if isinstance (data_point .value , int ):
259
+ pt .as_int = data_point .value
260
+ else :
261
+ pt .as_double = data_point .value
262
+ pb2_metric .gauge .data_points .append (pt )
263
+
264
+ elif isinstance (metric .data , HistogramType ):
265
+ for data_point in metric .data .data_points :
266
+ pt = pb2 .HistogramDataPoint (
267
+ attributes = _encode_attributes (data_point .attributes ),
268
+ time_unix_nano = data_point .time_unix_nano ,
269
+ start_time_unix_nano = data_point .start_time_unix_nano ,
270
+ count = data_point .count ,
271
+ sum = data_point .sum ,
272
+ bucket_counts = data_point .bucket_counts ,
273
+ explicit_bounds = data_point .explicit_bounds ,
274
+ max = data_point .max ,
275
+ min = data_point .min ,
276
+ )
277
+ pb2_metric .histogram .aggregation_temporality = (
278
+ metric .data .aggregation_temporality
279
+ )
280
+ pb2_metric .histogram .data_points .append (pt )
281
+
282
+ elif isinstance (metric .data , Sum ):
283
+ for data_point in metric .data .data_points :
284
+ pt = pb2 .NumberDataPoint (
285
+ attributes = _encode_attributes (data_point .attributes ),
286
+ start_time_unix_nano = data_point .start_time_unix_nano ,
287
+ time_unix_nano = data_point .time_unix_nano ,
288
+ )
289
+ if isinstance (data_point .value , int ):
290
+ pt .as_int = data_point .value
291
+ else :
292
+ pt .as_double = data_point .value
293
+ # note that because sum is a message type, the
294
+ # fields must be set individually rather than
295
+ # instantiating a pb2.Sum and setting it once
296
+ pb2_metric .sum .aggregation_temporality = (
297
+ metric .data .aggregation_temporality
298
+ )
299
+ pb2_metric .sum .is_monotonic = metric .data .is_monotonic
300
+ pb2_metric .sum .data_points .append (pt )
301
+
302
+ elif isinstance (metric .data , ExponentialHistogramType ):
303
+ for data_point in metric .data .data_points :
304
+
305
+ if data_point .positive .bucket_counts :
306
+ positive = pb2 .ExponentialHistogramDataPoint .Buckets (
307
+ offset = data_point .positive .offset ,
308
+ bucket_counts = data_point .positive .bucket_counts ,
309
+ )
310
+ else :
311
+ positive = None
312
+
313
+ if data_point .negative .bucket_counts :
314
+ negative = pb2 .ExponentialHistogramDataPoint .Buckets (
315
+ offset = data_point .negative .offset ,
316
+ bucket_counts = data_point .negative .bucket_counts ,
317
+ )
318
+ else :
319
+ negative = None
320
+
321
+ pt = pb2 .ExponentialHistogramDataPoint (
322
+ attributes = _encode_attributes (data_point .attributes ),
323
+ time_unix_nano = data_point .time_unix_nano ,
324
+ start_time_unix_nano = data_point .start_time_unix_nano ,
325
+ count = data_point .count ,
326
+ sum = data_point .sum ,
327
+ scale = data_point .scale ,
328
+ zero_count = data_point .zero_count ,
329
+ positive = positive ,
330
+ negative = negative ,
331
+ flags = data_point .flags ,
332
+ max = data_point .max ,
333
+ min = data_point .min ,
334
+ )
335
+ pb2_metric .exponential_histogram .aggregation_temporality = (
336
+ metric .data .aggregation_temporality
337
+ )
338
+ pb2_metric .exponential_histogram .data_points .append (pt )
339
+
340
+ else :
341
+ _logger .warning (
342
+ "unsupported data type %s" ,
343
+ metric .data .__class__ .__name__ ,
344
+ )
0 commit comments