Skip to content

Commit

Permalink
[Exporter.Geneva] [otlp format] Add double counter support (#1626)
Browse files Browse the repository at this point in the history
  • Loading branch information
vishweshbankwar authored Mar 27, 2024
1 parent 67d46c3 commit e39306f
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,54 @@ private void SerializeMetric(byte[] buffer, ref int cursor, Metric metric)
case MetricType.DoubleSum:
case MetricType.DoubleSumNonMonotonic:
{
// TODO
cursor = this.instrumentValueIndex;

// Write isMonotonic tag
ProtobufSerializerHelper.WriteBoolWithTag(buffer, ref cursor, FieldNumberConstants.Sum_is_monotonic, metric.MetricType == MetricType.DoubleSum);

// Write aggregationTemporality tag
ProtobufSerializerHelper.WriteEnumWithTag(buffer, ref cursor, FieldNumberConstants.Sum_aggregation_temporality, metric.Temporality == AggregationTemporality.Cumulative ? 2 : 1);

this.metricPointTagAndLengthIndex = cursor;
this.metricPointValueIndex = cursor + TagAndLengthSize;
foreach (var metricPoint in metric.GetMetricPoints())
{
try
{
// Reset cursor to write new metricPoint
cursor = this.metricPointValueIndex;

var sum = metricPoint.GetSumDouble();

ProtobufSerializerHelper.WriteDoubleWithTag(buffer, ref cursor, FieldNumberConstants.NumberDataPoint_as_double, sum);

var startTime = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds();
ProtobufSerializerHelper.WriteFixed64WithTag(buffer, ref cursor, FieldNumberConstants.NumberDataPoint_start_time_unix_nano, startTime);

var endTime = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds();
ProtobufSerializerHelper.WriteFixed64WithTag(buffer, ref cursor, FieldNumberConstants.NumberDataPoint_time_unix_nano, endTime);

SerializeTags(buffer, ref cursor, metricPoint.Tags, FieldNumberConstants.NumberDataPoint_attributes);

// TODO: exemplars.

var metricPointStartPosition = this.metricPointTagAndLengthIndex;

// Write numberdatapoint {Repeated field}
ProtobufSerializerHelper.WriteTagAndLengthPrefix(buffer, ref metricPointStartPosition, cursor - this.metricPointValueIndex, FieldNumberConstants.Sum_data_points, WireType.LEN);

// Finish writing current batch
this.WriteIndividualMessageTagsAndLength(buffer, ref cursor, metric.MetricType);

// Send metricPoint
this.SendMetricPoint(buffer, ref cursor);
}
catch
{
// TODO: log exception.
}
}

break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ namespace OpenTelemetry.Exporter.Geneva.Tests;
public class OtlpProtobufMetricExporterTests
{
[Theory]
[InlineData(123)]
[InlineData(-123)]
public void LongCounterSerializationSingleMetricPoint(long value)
[InlineData("longcounter", 123L, null)]
[InlineData("doublecounter", null, 123.45)]
[InlineData("longcounter", -123L, null)]
[InlineData("doublecounter", null, -123.45)]
public void CounterSerializationSingleMetricPoint(string instrumentName, long? longValue, double? doubleValue)
{
using var meter = new Meter(nameof(this.LongCounterSerializationSingleMetricPoint), "0.0.1");
var longCounter = meter.CreateCounter<long>("longCounter");
using var meter = new Meter(nameof(this.CounterSerializationSingleMetricPoint), "0.0.1");

var exportedItems = new List<Metric>();
using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
{
Expand All @@ -35,11 +37,20 @@ public void LongCounterSerializationSingleMetricPoint(long value)
.AddAttributes(new[] { new KeyValuePair<string, object>("TestResourceKey", "TestResourceValue") });
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.SetResourceBuilder(resourceBuilder)
.AddMeter(nameof(this.LongCounterSerializationSingleMetricPoint))
.AddMeter(nameof(this.CounterSerializationSingleMetricPoint))
.AddReader(inMemoryReader)
.Build();
.Build();

longCounter.Add(value, new("tag1", "value1"), new("tag2", "value2"));
if (longValue != null)
{
var counter = meter.CreateCounter<long>(instrumentName);
counter.Add(longValue.Value, new("tag1", "value1"), new("tag2", "value2"));
}
else
{
var counter = meter.CreateCounter<double>(instrumentName);
counter.Add(doubleValue.Value, new("tag1", "value1"), new("tag2", "value2"));
}

meterProvider.ForceFlush();

Expand Down Expand Up @@ -72,7 +83,7 @@ public void LongCounterSerializationSingleMetricPoint(long value)

var metric = request.ResourceMetrics[0].ScopeMetrics[0].Metrics[0];

Assert.Equal(longCounter.Name, metric.Name);
Assert.Equal(instrumentName, metric.Name);

Assert.NotNull(metric.Sum);

Expand All @@ -84,57 +95,75 @@ public void LongCounterSerializationSingleMetricPoint(long value)

var dataPoint = metric.Sum.DataPoints[0];

Assert.Equal(value, dataPoint.AsInt);
if (longValue != null)
{
Assert.Equal(longValue, dataPoint.AsInt);
}
else
{
Assert.Equal(doubleValue, dataPoint.AsDouble);
}

// Assert time
var metricPointsEnumerator = exportedItems[0].GetMetricPoints().GetEnumerator();
metricPointsEnumerator.MoveNext();
var metricPoint = metricPointsEnumerator.Current;

Assert.Equal((ulong)TimestampHelpers.ToUnixTimeNanoseconds(metricPoint.StartTime), dataPoint.StartTimeUnixNano);
Assert.Equal((ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), dataPoint.StartTimeUnixNano);

Assert.Equal((ulong)TimestampHelpers.ToUnixTimeNanoseconds(metricPoint.EndTime), dataPoint.TimeUnixNano);
Assert.Equal((ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), dataPoint.TimeUnixNano);

AssertOtlpAttributes([new("tag1", "value1"), new("tag2", "value2")], dataPoint.Attributes);
}

[Fact]
public void LongCounterSerializationMultipleMetricPoints()
[Theory]
[InlineData("longcounter", new long[] { 10, 20, 30 }, null)]
[InlineData("longcounter", new long[] { -10, 2, -30 }, null)]
[InlineData("doublecounter", null, new double[] { 10.20, 2, 30.65 })]
[InlineData("doublecounter", null, new double[] { -10.20, 2, -30.65 })]
public void CounterSerializationMultipleMetricPoints(string instrumentName, long[] longValues, double[] doubleValues)
{
using var meter = new Meter(nameof(this.LongCounterSerializationMultipleMetricPoints), "0.0.1");
var longCounter = meter.CreateCounter<long>("longCounter");
using var meter = new Meter(nameof(this.CounterSerializationMultipleMetricPoints), "0.0.1");
var exportedItems = new List<Metric>();
using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter<Metric>(exportedItems))
{
TemporalityPreference = MetricReaderTemporalityPreference.Delta,
};

using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter(nameof(this.LongCounterSerializationMultipleMetricPoints))
.AddMeter(nameof(this.CounterSerializationMultipleMetricPoints))
.AddReader(inMemoryReader)
.Build();

TagList[] tags = new TagList[3];

tags[0].Add(new("tag1", "value1"));
tags[0].Add(new("tag2", "value2"));

tags[1].Add(new("tag1", "value1"));
tags[1].Add(new("tag2", "value2"));
tags[1].Add(new("tag3", "value3"));
int expectedMetricPoints = longValues != null ? longValues.Length : doubleValues.Length;
TagList[] tags = new TagList[expectedMetricPoints];

tags[2].Add(new("tag1", "value1"));
tags[2].Add(new("tag2", "value2"));
tags[2].Add(new("tag3", "value3"));
tags[2].Add(new("tag4", "value4"));

longCounter.Add(62, tags[0]);
for (int i = 0; i < tags.Length; i++)
{
for (int j = 1; j <= (i + 1); j++)
{
tags[i].Add(new("tag" + j, "value" + j));
}
}

longCounter.Add(62, tags[0]);
if (longValues != null)
{
var counter = meter.CreateCounter<long>(instrumentName);

longCounter.Add(124, tags[1]);
for (int i = 0; i < longValues.Length; i++)
{
counter.Add(longValues[i], tags[i]);
}
}
else
{
var counter = meter.CreateCounter<double>(instrumentName);

longCounter.Add(124, tags[2]);
for (int i = 0; i < doubleValues.Length; i++)
{
counter.Add(doubleValues[i], tags[i]);
}
}

meterProvider.ForceFlush();

Expand All @@ -145,14 +174,12 @@ public void LongCounterSerializationMultipleMetricPoints()

otlpProtobufSerializer.SerializeAndSendMetrics(buffer, Resource.Empty, new Batch<Metric>(exportedItems.ToArray(), exportedItems.Count));

// 3 unique measurements.
var exportedItemsCount = testTransport.ExportedItems.Count;
Assert.Equal(3, exportedItemsCount);
Assert.Equal(expectedMetricPoints, testTransport.ExportedItems.Count);

// For asserting time
var metricPointsEnumerator = exportedItems[0].GetMetricPoints().GetEnumerator();

for (int i = 0; i < exportedItemsCount; i++)
for (int i = 0; i < expectedMetricPoints; i++)
{
var request = new OtlpCollector.ExportMetricsServiceRequest();

Expand All @@ -170,7 +197,7 @@ public void LongCounterSerializationMultipleMetricPoints()

var metric = request.ResourceMetrics[0].ScopeMetrics[0].Metrics[0];

Assert.Equal(longCounter.Name, metric.Name);
Assert.Equal(instrumentName, metric.Name);

Assert.NotNull(metric.Sum);

Expand All @@ -182,14 +209,21 @@ public void LongCounterSerializationMultipleMetricPoints()

var dataPoint = metric.Sum.DataPoints[0];

Assert.Equal(124, dataPoint.AsInt);
if (longValues != null)
{
Assert.Equal(longValues[i], dataPoint.AsInt);
}
else
{
Assert.Equal(doubleValues[i], dataPoint.AsDouble);
}

metricPointsEnumerator.MoveNext();
var metricPoint = metricPointsEnumerator.Current;

Assert.Equal((ulong)TimestampHelpers.ToUnixTimeNanoseconds(metricPoint.StartTime), dataPoint.StartTimeUnixNano);
Assert.Equal((ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), dataPoint.StartTimeUnixNano);

Assert.Equal((ulong)TimestampHelpers.ToUnixTimeNanoseconds(metricPoint.EndTime), dataPoint.TimeUnixNano);
Assert.Equal((ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), dataPoint.TimeUnixNano);

AssertOtlpAttributes(tags[i], dataPoint.Attributes);
}
Expand Down

0 comments on commit e39306f

Please sign in to comment.