Skip to content

Commit

Permalink
Refactor Aggregator and Export data structure (#2214)
Browse files Browse the repository at this point in the history
  • Loading branch information
cijothomas authored Aug 2, 2021
1 parent d6d815e commit bd69bd6
Show file tree
Hide file tree
Showing 19 changed files with 634 additions and 293 deletions.
73 changes: 41 additions & 32 deletions src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,53 @@ public override ExportResult Export(in Batch<MetricItem> batch)
var tags = metric.Attributes.ToArray().Select(k => $"{k.Key}={k.Value?.ToString()}");

string valueDisplay = string.Empty;
if (metric is ISumMetric sumMetric)
{
if (sumMetric.Sum.Value is double doubleSum)
{
valueDisplay = ((double)doubleSum).ToString(CultureInfo.InvariantCulture);
}
else if (sumMetric.Sum.Value is long longSum)
{
valueDisplay = ((long)longSum).ToString();
}
}
else if (metric is IGaugeMetric gaugeMetric)
{
if (gaugeMetric.LastValue.Value is double doubleValue)
{
valueDisplay = ((double)doubleValue).ToString();
}
else if (gaugeMetric.LastValue.Value is long longValue)
{
valueDisplay = ((long)longValue).ToString();
}

// Qn: tags again ? gaugeMetric.LastValue.Tags
}
else if (metric is ISummaryMetric summaryMetric)
// Switch would be faster than the if.else ladder
// of try and cast.
switch (metric.MetricType)
{
valueDisplay = string.Format("Sum: {0} Count: {1}", summaryMetric.PopulationSum, summaryMetric.PopulationCount);
case MetricType.LongSum:
{
valueDisplay = (metric as ISumMetricLong).LongSum.ToString(CultureInfo.InvariantCulture);
break;
}

case MetricType.DoubleSum:
{
valueDisplay = (metric as ISumMetricDouble).DoubleSum.ToString(CultureInfo.InvariantCulture);
break;
}

case MetricType.LongGauge:
{
// TODOs
break;
}

case MetricType.DoubleGauge:
{
// TODOs
break;
}

case MetricType.Histogram:
{
var histogramMetric = metric as IHistogramMetric;
valueDisplay = string.Format("Sum: {0} Count: {1}", histogramMetric.PopulationSum, histogramMetric.PopulationCount);
break;
}

case MetricType.Summary:
{
var summaryMetric = metric as ISummaryMetric;
valueDisplay = string.Format("Sum: {0} Count: {1}", summaryMetric.PopulationSum, summaryMetric.PopulationCount);
break;
}
}
else if (metric is IHistogramMetric histogramMetric)
{
valueDisplay = string.Format("Sum: {0} Count: {1}", histogramMetric.PopulationSum, histogramMetric.PopulationCount);
}

var kind = metric.GetType().Name;

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

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

if (!string.IsNullOrEmpty(metric.Description))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,95 +132,135 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this IMetric metric)
otlpMetric.Unit = metric.Unit;
}

if (metric is ISumMetric sumMetric)
switch (metric.MetricType)
{
var sum = new OtlpMetrics.Sum
{
IsMonotonic = sumMetric.IsMonotonic,
AggregationTemporality = sumMetric.IsDeltaTemporality
case MetricType.LongSum:
{
var sumMetric = metric as ISumMetricLong;
var sum = new OtlpMetrics.Sum
{
IsMonotonic = sumMetric.IsMonotonic,
AggregationTemporality = sumMetric.IsDeltaTemporality
? OtlpMetrics.AggregationTemporality.Delta
: OtlpMetrics.AggregationTemporality.Cumulative,
};
var dataPoint = metric.ToNumberDataPoint(sumMetric.Sum.Value, sumMetric.Exemplars);
sum.DataPoints.Add(dataPoint);
otlpMetric.Sum = sum;
}
else if (metric is IGaugeMetric gaugeMetric)
{
var gauge = new OtlpMetrics.Gauge();
var dataPoint = metric.ToNumberDataPoint(gaugeMetric.LastValue.Value, gaugeMetric.Exemplars);
gauge.DataPoints.Add(dataPoint);
otlpMetric.Gauge = gauge;
}
else if (metric is ISummaryMetric summaryMetric)
{
var summary = new OtlpMetrics.Summary();

var dataPoint = new OtlpMetrics.SummaryDataPoint
{
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
Count = (ulong)summaryMetric.PopulationCount,
Sum = summaryMetric.PopulationSum,
};

// TODO: Do TagEnumerationState thing.
foreach (var attribute in metric.Attributes)
{
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
}
};
var dataPoint = metric.ToNumberDataPoint(sumMetric.LongSum, sumMetric.Exemplars);
sum.DataPoints.Add(dataPoint);
otlpMetric.Sum = sum;
break;
}

foreach (var quantile in summaryMetric.Quantiles)
{
var quantileValue = new OtlpMetrics.SummaryDataPoint.Types.ValueAtQuantile
case MetricType.DoubleSum:
{
Quantile = quantile.Quantile,
Value = quantile.Value,
};
dataPoint.QuantileValues.Add(quantileValue);
}

otlpMetric.Summary = summary;
}
else if (metric is IHistogramMetric histogramMetric)
{
var histogram = new OtlpMetrics.Histogram
{
AggregationTemporality = histogramMetric.IsDeltaTemporality
var sumMetric = metric as ISumMetricDouble;
var sum = new OtlpMetrics.Sum
{
IsMonotonic = sumMetric.IsMonotonic,
AggregationTemporality = sumMetric.IsDeltaTemporality
? OtlpMetrics.AggregationTemporality.Delta
: OtlpMetrics.AggregationTemporality.Cumulative,
};

var dataPoint = new OtlpMetrics.HistogramDataPoint
{
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
Count = (ulong)histogramMetric.PopulationCount,
Sum = histogramMetric.PopulationSum,
};

foreach (var bucket in histogramMetric.Buckets)
{
dataPoint.BucketCounts.Add((ulong)bucket.Count);
};
var dataPoint = metric.ToNumberDataPoint(sumMetric.DoubleSum, sumMetric.Exemplars);
sum.DataPoints.Add(dataPoint);
otlpMetric.Sum = sum;
break;
}

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

// TODO: Do TagEnumerationState thing.
foreach (var attribute in metric.Attributes)
{
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
}
case MetricType.DoubleGauge:
{
var gaugeMetric = metric as IGaugeMetric;
var gauge = new OtlpMetrics.Gauge();
var dataPoint = metric.ToNumberDataPoint(gaugeMetric.LastValue.Value, gaugeMetric.Exemplars);
gauge.DataPoints.Add(dataPoint);
otlpMetric.Gauge = gauge;
break;
}

foreach (var exemplar in histogramMetric.Exemplars)
{
dataPoint.Exemplars.Add(exemplar.ToOtlpExemplar());
}
case MetricType.Histogram:
{
var histogramMetric = metric as IHistogramMetric;
var histogram = new OtlpMetrics.Histogram
{
AggregationTemporality = histogramMetric.IsDeltaTemporality
? OtlpMetrics.AggregationTemporality.Delta
: OtlpMetrics.AggregationTemporality.Cumulative,
};

var dataPoint = new OtlpMetrics.HistogramDataPoint
{
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
Count = (ulong)histogramMetric.PopulationCount,
Sum = histogramMetric.PopulationSum,
};

foreach (var bucket in histogramMetric.Buckets)
{
dataPoint.BucketCounts.Add((ulong)bucket.Count);

// TODO: Verify how to handle the bounds. We've modeled things with
// a LowBoundary and HighBoundary. OTLP data model has modeled this
// differently: https://github.com/open-telemetry/opentelemetry-proto/blob/bacfe08d84e21fb2a779e302d12e8dfeb67e7b86/opentelemetry/proto/metrics/v1/metrics.proto#L554-L568
dataPoint.ExplicitBounds.Add(bucket.HighBoundary);
}

// TODO: Do TagEnumerationState thing.
foreach (var attribute in metric.Attributes)
{
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
}

foreach (var exemplar in histogramMetric.Exemplars)
{
dataPoint.Exemplars.Add(exemplar.ToOtlpExemplar());
}

otlpMetric.Histogram = histogram;
break;
}

otlpMetric.Histogram = histogram;
case MetricType.Summary:
{
var summaryMetric = metric as ISummaryMetric;
var summary = new OtlpMetrics.Summary();

var dataPoint = new OtlpMetrics.SummaryDataPoint
{
StartTimeUnixNano = (ulong)metric.StartTimeExclusive.ToUnixTimeNanoseconds(),
TimeUnixNano = (ulong)metric.EndTimeInclusive.ToUnixTimeNanoseconds(),
Count = (ulong)summaryMetric.PopulationCount,
Sum = summaryMetric.PopulationSum,
};

// TODO: Do TagEnumerationState thing.
foreach (var attribute in metric.Attributes)
{
dataPoint.Attributes.Add(attribute.ToOtlpAttribute());
}

foreach (var quantile in summaryMetric.Quantiles)
{
var quantileValue = new OtlpMetrics.SummaryDataPoint.Types.ValueAtQuantile
{
Quantile = quantile.Quantile,
Value = quantile.Value,
};
dataPoint.QuantileValues.Add(quantileValue);
}

otlpMetric.Summary = summary;
break;
}
}

return otlpMetric;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,14 @@ public static void WriteMetricsCollection(this PrometheusExporter exporter, Stre
.WithName(metric.Name)
.WithDescription(metric.Name);

if (metric is ISumMetric sumMetric)
// TODO: Use switch case for higher perf.
if (metric.MetricType == MetricType.LongSum)
{
if (sumMetric.Sum.Value is double doubleSum)
{
WriteSum(writer, builder, metric.Attributes, doubleSum);
}
else if (sumMetric.Sum.Value is long longSum)
{
WriteSum(writer, builder, metric.Attributes, longSum);
}
WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricLong).LongSum);
}
else if (metric.MetricType == MetricType.DoubleSum)
{
WriteSum(writer, builder, metric.Attributes, (metric as ISumMetricDouble).DoubleSum);
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,20 @@ internal IAggregator[] MapToMetrics(string[] seqKey, object[] seqVal)
var dt = DateTimeOffset.UtcNow;

// TODO: Need to map each instrument to metrics (based on View API)
if (this.instrument.GetType().Name.Contains("Counter"))
// TODO: move most of this logic out of hotpath, and to MeterProvider's
// InstrumentPublished event, which is once per instrument creation.

if (this.instrument.GetType() == typeof(Counter<long>)
|| this.instrument.GetType() == typeof(Counter<int>)
|| this.instrument.GetType() == typeof(Counter<short>)
|| this.instrument.GetType() == typeof(Counter<byte>))
{
aggregators.Add(new SumMetricAggregatorLong(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
}
else if (this.instrument.GetType() == typeof(Counter<double>)
|| this.instrument.GetType() == typeof(Counter<float>))
{
aggregators.Add(new SumMetricAggregator(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
aggregators.Add(new SumMetricAggregatorDouble(this.instrument.Name, this.instrument.Description, this.instrument.Unit, this.instrument.Meter, dt, tags));
}
else if (this.instrument.GetType().Name.Contains("Gauge"))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ internal GaugeMetricAggregator(string name, string description, string unit, Met
this.Meter = meter;
this.StartTimeExclusive = startTimeExclusive;
this.Attributes = attributes;

// TODO: Split this class into two or leverage generic
this.MetricType = MetricType.LongGauge;
}

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

public IDataValue LastValue => this.value;

public MetricType MetricType { get; private set; }

public void Update<T>(T value)
where T : struct
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ internal HistogramMetricAggregator(string name, string description, string unit,

this.boundaries = boundaries;
this.buckets = this.InitializeBucket(boundaries);
this.MetricType = MetricType.Summary;
}

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

public double PopulationSum { get; private set; }

public MetricType MetricType { get; private set; }

public IEnumerable<HistogramBucket> Buckets => this.buckets;

public void Update<T>(T value)
Expand Down
2 changes: 2 additions & 0 deletions src/OpenTelemetry/Metrics/MetricAggregators/IMetric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public interface IMetric

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

MetricType MetricType { get; }

string ToDisplayString();
}
}
2 changes: 0 additions & 2 deletions src/OpenTelemetry/Metrics/MetricAggregators/ISumMetric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,5 @@ public interface ISumMetric : IMetric
bool IsMonotonic { get; }

IEnumerable<IExemplar> Exemplars { get; }

IDataValue Sum { get; }
}
}
Loading

0 comments on commit bd69bd6

Please sign in to comment.