@@ -15,6 +15,8 @@ internal static class ProtobufOtlpMetricSerializer
1515 private static readonly Stack < List < Metric > > MetricListPool = [ ] ;
1616 private static readonly Dictionary < string , List < Metric > > ScopeMetricsList = [ ] ;
1717
18+ private delegate int WriteExemplarFunc ( byte [ ] buffer , int writePosition , in Exemplar exemplar ) ;
19+
1820 internal static int WriteMetricsData ( byte [ ] buffer , int writePosition , Resources . Resource ? resource , in Batch < Metric > batch )
1921 {
2022 foreach ( var metric in batch )
@@ -94,8 +96,6 @@ private static int WriteScopeMetric(byte[] buffer, int writePosition, string met
9496
9597 if ( meterTags != null )
9698 {
97- // TODO: Need to add unit tests for Instrumentation Scope Attributes (MeterTags)
98-
9999 if ( meterTags is IReadOnlyList < KeyValuePair < string , object ? > > readonlyMeterTags )
100100 {
101101 for ( int i = 0 ; i < readonlyMeterTags . Count ; i ++ )
@@ -266,13 +266,7 @@ private static int WriteMetric(byte[] buffer, int writePosition, Metric metric)
266266 }
267267 }
268268
269- if ( metricPoint . TryGetExemplars ( out var exemplars ) )
270- {
271- foreach ( ref readonly var exemplar in exemplars )
272- {
273- writePosition = WriteExemplar ( buffer , writePosition , in exemplar , exemplar . DoubleValue , ProtobufOtlpMetricFieldNumberConstants . HistogramDataPoint_Exemplars ) ;
274- }
275- }
269+ writePosition = WriteDoubleExemplars ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . HistogramDataPoint_Exemplars , in metricPoint ) ;
276270
277271 ProtobufSerializer . WriteReservedLength ( buffer , dataPointLengthPosition , writePosition - ( dataPointLengthPosition + ReserveSizeForLength ) ) ;
278272 }
@@ -336,13 +330,7 @@ private static int WriteMetric(byte[] buffer, int writePosition, Metric metric)
336330
337331 ProtobufSerializer . WriteReservedLength ( buffer , positiveBucketsLengthPosition , writePosition - ( positiveBucketsLengthPosition + ReserveSizeForLength ) ) ;
338332
339- if ( metricPoint . TryGetExemplars ( out var exemplars ) )
340- {
341- foreach ( ref readonly var exemplar in exemplars )
342- {
343- writePosition = WriteExemplar ( buffer , writePosition , in exemplar , exemplar . DoubleValue , ProtobufOtlpMetricFieldNumberConstants . ExponentialHistogramDataPoint_Exemplars ) ;
344- }
345- }
333+ writePosition = WriteDoubleExemplars ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . ExponentialHistogramDataPoint_Exemplars , in metricPoint ) ;
346334
347335 ProtobufSerializer . WriteReservedLength ( buffer , dataPointLengthPosition , writePosition - ( dataPointLengthPosition + ReserveSizeForLength ) ) ;
348336 }
@@ -381,7 +369,12 @@ private static int WriteNumberDataPoint(byte[] buffer, int writePosition, int fi
381369 {
382370 foreach ( ref readonly var exemplar in exemplars )
383371 {
384- writePosition = WriteExemplar ( buffer , writePosition , in exemplar , exemplar . LongValue , ProtobufOtlpMetricFieldNumberConstants . NumberDataPoint_Exemplars ) ;
372+ writePosition = WriteExemplar (
373+ buffer ,
374+ writePosition ,
375+ in exemplar ,
376+ ProtobufOtlpMetricFieldNumberConstants . NumberDataPoint_Exemplars ,
377+ static ( byte [ ] buffer , int writePosition , in Exemplar exemplar ) => ProtobufSerializer . WriteFixed64WithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Value_As_Int , ( ulong ) exemplar . LongValue ) ) ;
385378 }
386379 }
387380
@@ -409,13 +402,7 @@ private static int WriteNumberDataPoint(byte[] buffer, int writePosition, int fi
409402 writePosition = WriteTag ( buffer , writePosition , tag , ProtobufOtlpMetricFieldNumberConstants . NumberDataPoint_Attributes ) ;
410403 }
411404
412- if ( metricPoint . TryGetExemplars ( out var exemplars ) )
413- {
414- foreach ( ref readonly var exemplar in exemplars )
415- {
416- writePosition = WriteExemplar ( buffer , writePosition , in exemplar , exemplar . DoubleValue , ProtobufOtlpMetricFieldNumberConstants . NumberDataPoint_Exemplars ) ;
417- }
418- }
405+ writePosition = WriteDoubleExemplars ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . NumberDataPoint_Exemplars , in metricPoint ) ;
419406
420407 ProtobufSerializer . WriteReservedLength ( buffer , dataPointLengthPosition , writePosition - ( dataPointLengthPosition + ReserveSizeForLength ) ) ;
421408 return writePosition ;
@@ -439,41 +426,52 @@ private static int WriteTag(byte[] buffer, int writePosition, KeyValuePair<strin
439426 return otlpTagWriterState . WritePosition ;
440427 }
441428
442- private static int WriteExemplar ( byte [ ] buffer , int writePosition , in Exemplar exemplar , long value , int fieldNumber )
429+ private static int WriteDoubleExemplars ( byte [ ] buffer , int writePosition , int fieldNumber , in MetricPoint metricPoint )
443430 {
444- writePosition = ProtobufSerializer . WriteTag ( buffer , writePosition , fieldNumber , ProtobufWireType . LEN ) ;
445- int exemplarLengthPosition = writePosition ;
446- writePosition += ReserveSizeForLength ;
447-
448- // TODO: Need to serialize exemplar.FilteredTags and add unit tests.
449-
450- // Casting to ulong is ok here as the bit representation for long versus ulong will be the same
451- // The difference would in the way the bit representation is interpreted on decoding side (signed versus unsigned)
452- writePosition = ProtobufSerializer . WriteFixed64WithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Value_As_Int , ( ulong ) value ) ;
453-
454- var time = ( ulong ) exemplar . Timestamp . ToUnixTimeNanoseconds ( ) ;
455- writePosition = ProtobufSerializer . WriteFixed64WithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Time_Unix_Nano , time ) ;
456-
457- // TODO: Need to serialize exemplar.SpanID and exemplar.TraceId and add unit tests.
431+ if ( metricPoint . TryGetExemplars ( out var exemplars ) )
432+ {
433+ foreach ( ref readonly var exemplar in exemplars )
434+ {
435+ writePosition = WriteExemplar (
436+ buffer ,
437+ writePosition ,
438+ in exemplar ,
439+ fieldNumber ,
440+ static ( byte [ ] buffer , int writePosition , in Exemplar exemplar ) => ProtobufSerializer . WriteDoubleWithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Value_As_Double , exemplar . DoubleValue ) ) ;
441+ }
442+ }
458443
459- ProtobufSerializer . WriteReservedLength ( buffer , exemplarLengthPosition , writePosition - ( exemplarLengthPosition + ReserveSizeForLength ) ) ;
460444 return writePosition ;
461445 }
462446
463- private static int WriteExemplar ( byte [ ] buffer , int writePosition , in Exemplar exemplar , double value , int fieldNumber )
447+ private static int WriteExemplar ( byte [ ] buffer , int writePosition , in Exemplar exemplar , int fieldNumber , WriteExemplarFunc writeValueFunc )
464448 {
465449 writePosition = ProtobufSerializer . WriteTag ( buffer , writePosition , fieldNumber , ProtobufWireType . LEN ) ;
466450 int exemplarLengthPosition = writePosition ;
467451 writePosition += ReserveSizeForLength ;
468452
469- // TODO: Need to serialize exemplar.FilteredTags and add unit tests.
453+ foreach ( var tag in exemplar . FilteredTags )
454+ {
455+ writePosition = WriteTag ( buffer , writePosition , tag , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Filtered_Attributes ) ;
456+ }
470457
471- writePosition = ProtobufSerializer . WriteDoubleWithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Value_As_Double , value ) ;
458+ writePosition = writeValueFunc ( buffer , writePosition , in exemplar ) ;
472459
473460 var time = ( ulong ) exemplar . Timestamp . ToUnixTimeNanoseconds ( ) ;
474461 writePosition = ProtobufSerializer . WriteFixed64WithTag ( buffer , writePosition , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Time_Unix_Nano , time ) ;
475462
476- // TODO: Need to serialize exemplar.SpanID and exemplar.TraceId and add unit tests.
463+ if ( exemplar . SpanId != default )
464+ {
465+ writePosition = ProtobufSerializer . WriteTagAndLength ( buffer , writePosition , SpanIdSize , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Span_Id , ProtobufWireType . LEN ) ;
466+ var spanIdBytes = new Span < byte > ( buffer , writePosition , SpanIdSize ) ;
467+ exemplar . SpanId . CopyTo ( spanIdBytes ) ;
468+ writePosition += SpanIdSize ;
469+
470+ writePosition = ProtobufSerializer . WriteTagAndLength ( buffer , writePosition , TraceIdSize , ProtobufOtlpMetricFieldNumberConstants . Exemplar_Trace_Id , ProtobufWireType . LEN ) ;
471+ var traceIdBytes = new Span < byte > ( buffer , writePosition , TraceIdSize ) ;
472+ exemplar . TraceId . CopyTo ( traceIdBytes ) ;
473+ writePosition += TraceIdSize ;
474+ }
477475
478476 ProtobufSerializer . WriteReservedLength ( buffer , exemplarLengthPosition , writePosition - ( exemplarLengthPosition + ReserveSizeForLength ) ) ;
479477 return writePosition ;
0 commit comments