Skip to content

Commit bd69bd6

Browse files
authored
Refactor Aggregator and Export data structure (#2214)
1 parent d6d815e commit bd69bd6

19 files changed

Lines changed: 634 additions & 293 deletions

File tree

src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,44 +56,53 @@ public override ExportResult Export(in Batch<MetricItem> batch)
5656
var tags = metric.Attributes.ToArray().Select(k => $"{k.Key}={k.Value?.ToString()}");
5757

5858
string valueDisplay = string.Empty;
59-
if (metric is ISumMetric sumMetric)
60-
{
61-
if (sumMetric.Sum.Value is double doubleSum)
62-
{
63-
valueDisplay = ((double)doubleSum).ToString(CultureInfo.InvariantCulture);
64-
}
65-
else if (sumMetric.Sum.Value is long longSum)
66-
{
67-
valueDisplay = ((long)longSum).ToString();
68-
}
69-
}
70-
else if (metric is IGaugeMetric gaugeMetric)
71-
{
72-
if (gaugeMetric.LastValue.Value is double doubleValue)
73-
{
74-
valueDisplay = ((double)doubleValue).ToString();
75-
}
76-
else if (gaugeMetric.LastValue.Value is long longValue)
77-
{
78-
valueDisplay = ((long)longValue).ToString();
79-
}
8059

81-
// Qn: tags again ? gaugeMetric.LastValue.Tags
82-
}
83-
else if (metric is ISummaryMetric summaryMetric)
60+
// Switch would be faster than the if.else ladder
61+
// of try and cast.
62+
switch (metric.MetricType)
8463
{
85-
valueDisplay = string.Format("Sum: {0} Count: {1}", summaryMetric.PopulationSum, summaryMetric.PopulationCount);
64+
case MetricType.LongSum:
65+
{
66+
valueDisplay = (metric as ISumMetricLong).LongSum.ToString(CultureInfo.InvariantCulture);
67+
break;
68+
}
69+
70+
case MetricType.DoubleSum:
71+
{
72+
valueDisplay = (metric as ISumMetricDouble).DoubleSum.ToString(CultureInfo.InvariantCulture);
73+
break;
74+
}
75+
76+
case MetricType.LongGauge:
77+
{
78+
// TODOs
79+
break;
80+
}
81+
82+
case MetricType.DoubleGauge:
83+
{
84+
// TODOs
85+
break;
86+
}
87+
88+
case MetricType.Histogram:
89+
{
90+
var histogramMetric = metric as IHistogramMetric;
91+
valueDisplay = string.Format("Sum: {0} Count: {1}", histogramMetric.PopulationSum, histogramMetric.PopulationCount);
92+
break;
93+
}
94+
95+
case MetricType.Summary:
96+
{
97+
var summaryMetric = metric as ISummaryMetric;
98+
valueDisplay = string.Format("Sum: {0} Count: {1}", summaryMetric.PopulationSum, summaryMetric.PopulationCount);
99+
break;
100+
}
86101
}
87-
else if (metric is IHistogramMetric histogramMetric)
88-
{
89-
valueDisplay = string.Format("Sum: {0} Count: {1}", histogramMetric.PopulationSum, histogramMetric.PopulationCount);
90-
}
91-
92-
var kind = metric.GetType().Name;
93102

94103
string time = $"{metric.StartTimeExclusive.ToLocalTime().ToString("HH:mm:ss.fff")} {metric.EndTimeInclusive.ToLocalTime().ToString("HH:mm:ss.fff")}";
95104

96-
var msg = new StringBuilder($"Export {time} {metric.Name} [{string.Join(";", tags)}] {kind} Value: {valueDisplay}");
105+
var msg = new StringBuilder($"Export {time} {metric.Name} [{string.Join(";", tags)}] {metric.MetricType} Value: {valueDisplay}");
97106

98107
if (!string.IsNullOrEmpty(metric.Description))
99108
{

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs

Lines changed: 118 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -132,95 +132,135 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this IMetric metric)
132132
otlpMetric.Unit = metric.Unit;
133133
}
134134

135-
if (metric is ISumMetric sumMetric)
135+
switch (metric.MetricType)
136136
{
137-
var sum = new OtlpMetrics.Sum
138-
{
139-
IsMonotonic = sumMetric.IsMonotonic,
140-
AggregationTemporality = sumMetric.IsDeltaTemporality
137+
case MetricType.LongSum:
138+
{
139+
var sumMetric = metric as ISumMetricLong;
140+
var sum = new OtlpMetrics.Sum
141+
{
142+
IsMonotonic = sumMetric.IsMonotonic,
143+
AggregationTemporality = sumMetric.IsDeltaTemporality
141144
? OtlpMetrics.AggregationTemporality.Delta
142145
: OtlpMetrics.AggregationTemporality.Cumulative,
143-
};
144-
var dataPoint = metric.ToNumberDataPoint(sumMetric.Sum.Value, sumMetric.Exemplars);
145-
sum.DataPoints.Add(dataPoint);
146-
otlpMetric.Sum = sum;
147-
}
148-
else if (metric is IGaugeMetric gaugeMetric)
149-
{
150-
var gauge = new OtlpMetrics.Gauge();
151-
var dataPoint = metric.ToNumberDataPoint(gaugeMetric.LastValue.Value, gaugeMetric.Exemplars);
152-
gauge.DataPoints.Add(dataPoint);
153-
otlpMetric.Gauge = gauge;
154-
}
155-
else if (metric is ISummaryMetric summaryMetric)
156-
{
157-
var summary = new OtlpMetrics.Summary();
158-
159-
var dataPoint = new OtlpMetrics.SummaryDataPoint
160-
{
161-
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
162-
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
163-
Count = (ulong)summaryMetric.PopulationCount,
164-
Sum = summaryMetric.PopulationSum,
165-
};
166-
167-
// TODO: Do TagEnumerationState thing.
168-
foreach (var attribute in metric.Attributes)
169-
{
170-
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
171-
}
146+
};
147+
var dataPoint = metric.ToNumberDataPoint(sumMetric.LongSum, sumMetric.Exemplars);
148+
sum.DataPoints.Add(dataPoint);
149+
otlpMetric.Sum = sum;
150+
break;
151+
}
172152

173-
foreach (var quantile in summaryMetric.Quantiles)
174-
{
175-
var quantileValue = new OtlpMetrics.SummaryDataPoint.Types.ValueAtQuantile
153+
case MetricType.DoubleSum:
176154
{
177-
Quantile = quantile.Quantile,
178-
Value = quantile.Value,
179-
};
180-
dataPoint.QuantileValues.Add(quantileValue);
181-
}
182-
183-
otlpMetric.Summary = summary;
184-
}
185-
else if (metric is IHistogramMetric histogramMetric)
186-
{
187-
var histogram = new OtlpMetrics.Histogram
188-
{
189-
AggregationTemporality = histogramMetric.IsDeltaTemporality
155+
var sumMetric = metric as ISumMetricDouble;
156+
var sum = new OtlpMetrics.Sum
157+
{
158+
IsMonotonic = sumMetric.IsMonotonic,
159+
AggregationTemporality = sumMetric.IsDeltaTemporality
190160
? OtlpMetrics.AggregationTemporality.Delta
191161
: OtlpMetrics.AggregationTemporality.Cumulative,
192-
};
193-
194-
var dataPoint = new OtlpMetrics.HistogramDataPoint
195-
{
196-
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
197-
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
198-
Count = (ulong)histogramMetric.PopulationCount,
199-
Sum = histogramMetric.PopulationSum,
200-
};
201-
202-
foreach (var bucket in histogramMetric.Buckets)
203-
{
204-
dataPoint.BucketCounts.Add((ulong)bucket.Count);
162+
};
163+
var dataPoint = metric.ToNumberDataPoint(sumMetric.DoubleSum, sumMetric.Exemplars);
164+
sum.DataPoints.Add(dataPoint);
165+
otlpMetric.Sum = sum;
166+
break;
167+
}
205168

206-
// TODO: Verify how to handle the bounds. We've modeled things with
207-
// a LowBoundary and HighBoundary. OTLP data model has modeled this
208-
// differently: https://github.com/open-telemetry/opentelemetry-proto/blob/bacfe08d84e21fb2a779e302d12e8dfeb67e7b86/opentelemetry/proto/metrics/v1/metrics.proto#L554-L568
209-
dataPoint.ExplicitBounds.Add(bucket.HighBoundary);
210-
}
169+
case MetricType.LongGauge:
170+
{
171+
var gaugeMetric = metric as IGaugeMetric;
172+
var gauge = new OtlpMetrics.Gauge();
173+
var dataPoint = metric.ToNumberDataPoint(gaugeMetric.LastValue.Value, gaugeMetric.Exemplars);
174+
gauge.DataPoints.Add(dataPoint);
175+
otlpMetric.Gauge = gauge;
176+
break;
177+
}
211178

212-
// TODO: Do TagEnumerationState thing.
213-
foreach (var attribute in metric.Attributes)
214-
{
215-
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
216-
}
179+
case MetricType.DoubleGauge:
180+
{
181+
var gaugeMetric = metric as IGaugeMetric;
182+
var gauge = new OtlpMetrics.Gauge();
183+
var dataPoint = metric.ToNumberDataPoint(gaugeMetric.LastValue.Value, gaugeMetric.Exemplars);
184+
gauge.DataPoints.Add(dataPoint);
185+
otlpMetric.Gauge = gauge;
186+
break;
187+
}
217188

218-
foreach (var exemplar in histogramMetric.Exemplars)
219-
{
220-
dataPoint.Exemplars.Add(exemplar.ToOtlpExemplar());
221-
}
189+
case MetricType.Histogram:
190+
{
191+
var histogramMetric = metric as IHistogramMetric;
192+
var histogram = new OtlpMetrics.Histogram
193+
{
194+
AggregationTemporality = histogramMetric.IsDeltaTemporality
195+
? OtlpMetrics.AggregationTemporality.Delta
196+
: OtlpMetrics.AggregationTemporality.Cumulative,
197+
};
198+
199+
var dataPoint = new OtlpMetrics.HistogramDataPoint
200+
{
201+
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
202+
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
203+
Count = (ulong)histogramMetric.PopulationCount,
204+
Sum = histogramMetric.PopulationSum,
205+
};
206+
207+
foreach (var bucket in histogramMetric.Buckets)
208+
{
209+
dataPoint.BucketCounts.Add((ulong)bucket.Count);
210+
211+
// TODO: Verify how to handle the bounds. We've modeled things with
212+
// a LowBoundary and HighBoundary. OTLP data model has modeled this
213+
// differently: https://github.com/open-telemetry/opentelemetry-proto/blob/bacfe08d84e21fb2a779e302d12e8dfeb67e7b86/opentelemetry/proto/metrics/v1/metrics.proto#L554-L568
214+
dataPoint.ExplicitBounds.Add(bucket.HighBoundary);
215+
}
216+
217+
// TODO: Do TagEnumerationState thing.
218+
foreach (var attribute in metric.Attributes)
219+
{
220+
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
221+
}
222+
223+
foreach (var exemplar in histogramMetric.Exemplars)
224+
{
225+
dataPoint.Exemplars.Add(exemplar.ToOtlpExemplar());
226+
}
227+
228+
otlpMetric.Histogram = histogram;
229+
break;
230+
}
222231

223-
otlpMetric.Histogram = histogram;
232+
case MetricType.Summary:
233+
{
234+
var summaryMetric = metric as ISummaryMetric;
235+
var summary = new OtlpMetrics.Summary();
236+
237+
var dataPoint = new OtlpMetrics.SummaryDataPoint
238+
{
239+
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
240+
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
241+
Count = (ulong)summaryMetric.PopulationCount,
242+
Sum = summaryMetric.PopulationSum,
243+
};
244+
245+
// TODO: Do TagEnumerationState thing.
246+
foreach (var attribute in metric.Attributes)
247+
{
248+
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
249+
}
250+
251+
foreach (var quantile in summaryMetric.Quantiles)
252+
{
253+
var quantileValue = new OtlpMetrics.SummaryDataPoint.Types.ValueAtQuantile
254+
{
255+
Quantile = quantile.Quantile,
256+
Value = quantile.Value,
257+
};
258+
dataPoint.QuantileValues.Add(quantileValue);
259+
}
260+
261+
otlpMetric.Summary = summary;
262+
break;
263+
}
224264
}
225265

226266
return otlpMetric;

src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterExtensions.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,14 @@ public static void WriteMetricsCollection(this PrometheusExporter exporter, Stre
5050
.WithName(metric.Name)
5151
.WithDescription(metric.Name);
5252

53-
if (metric is ISumMetric sumMetric)
53+
// TODO: Use switch case for higher perf.
54+
if (metric.MetricType == MetricType.LongSum)
5455
{
55-
if (sumMetric.Sum.Value is double doubleSum)
56-
{
57-
WriteSum(writer, builder, metric.Attributes, doubleSum);
58-
}
59-
else if (sumMetric.Sum.Value is long longSum)
60-
{
61-
WriteSum(writer, builder, metric.Attributes, longSum);
62-
}
56+
WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricLong).LongSum);
57+
}
58+
else if (metric.MetricType == MetricType.DoubleSum)
59+
{
60+
WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricDouble).DoubleSum);
6361
}
6462
}
6563
}

src/OpenTelemetry/Metrics/AggregatorStore.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,20 @@ internal IAggregator[] MapToMetrics(string[] seqKey, object[] seqVal)
5151
var dt = DateTimeOffset.UtcNow;
5252

5353
// TODO: Need to map each instrument to metrics (based on View API)
54-
if (this.instrument.GetType().Name.Contains("Counter"))
54+
// TODO: move most of this logic out of hotpath, and to MeterProvider's
55+
// InstrumentPublished event, which is once per instrument creation.
56+
57+
if (this.instrument.GetType() == typeof(Counter<long>)
58+
|| this.instrument.GetType() == typeof(Counter<int>)
59+
|| this.instrument.GetType() == typeof(Counter<short>)
60+
|| this.instrument.GetType() == typeof(Counter<byte>))
61+
{
62+
aggregators.Add(new SumMetricAggregatorLong(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
63+
}
64+
else if (this.instrument.GetType() == typeof(Counter<double>)
65+
|| this.instrument.GetType() == typeof(Counter<float>))
5566
{
56-
aggregators.Add(new SumMetricAggregator(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
67+
aggregators.Add(new SumMetricAggregatorDouble(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
5768
}
5869
else if (this.instrument.GetType().Name.Contains("Gauge"))
5970
{

src/OpenTelemetry/Metrics/MetricAggregators/GaugeMetricAggregator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ internal GaugeMetricAggregator(string name, string description, string unit, Met
3333
this.Meter = meter;
3434
this.StartTimeExclusive = startTimeExclusive;
3535
this.Attributes = attributes;
36+
37+
// TODO: Split this class into two or leverage generic
38+
this.MetricType = MetricType.LongGauge;
3639
}
3740

3841
public string Name { get; private set; }
@@ -53,6 +56,8 @@ internal GaugeMetricAggregator(string name, string description, string unit, Met
5356

5457
public IDataValue LastValue => this.value;
5558

59+
public MetricType MetricType { get; private set; }
60+
5661
public void Update<T>(T value)
5762
where T : struct
5863
{

src/OpenTelemetry/Metrics/MetricAggregators/HistogramMetricAggregator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ internal HistogramMetricAggregator(string name, string description, string unit,
5050

5151
this.boundaries = boundaries;
5252
this.buckets = this.InitializeBucket(boundaries);
53+
this.MetricType = MetricType.Summary;
5354
}
5455

5556
public string Name { get; private set; }
@@ -74,6 +75,8 @@ internal HistogramMetricAggregator(string name, string description, string unit,
7475

7576
public double PopulationSum { get; private set; }
7677

78+
public MetricType MetricType { get; private set; }
79+
7780
public IEnumerable<HistogramBucket> Buckets => this.buckets;
7881

7982
public void Update<T>(T value)

src/OpenTelemetry/Metrics/MetricAggregators/IMetric.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public interface IMetric
3636

3737
KeyValuePair<string, object>[] Attributes { get; }
3838

39+
MetricType MetricType { get; }
40+
3941
string ToDisplayString();
4042
}
4143
}

src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,5 @@ public interface ISumMetric : IMetric
2525
bool IsMonotonic { get; }
2626

2727
IEnumerable<IExemplar> Exemplars { get; }
28-
29-
IDataValue Sum { get; }
3028
}
3129
}

0 commit comments

Comments
 (0)