-
Notifications
You must be signed in to change notification settings - Fork 772
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OtlpMetricsExporter: Add test transforming metrics to OTLP metrics (#…
- Loading branch information
Showing
6 changed files
with
341 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricsService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// <copyright file="MetricsService.cs" company="OpenTelemetry Authors"> | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// </copyright> | ||
|
||
using System; | ||
using System.Threading; | ||
using Grpc.Core; | ||
|
||
namespace Opentelemetry.Proto.Collector.Metrics.V1 | ||
{ | ||
/// <summary> | ||
/// MetricsService extensions. | ||
/// </summary> | ||
internal static partial class MetricsService | ||
{ | ||
/// <summary>Interface for MetricService.</summary> | ||
public interface IMetricsServiceClient | ||
{ | ||
/// <summary> | ||
/// For performance reasons, it is recommended to keep this RPC | ||
/// alive for the entire life of the application. | ||
/// </summary> | ||
/// <param name="request">The request to send to the server.</param> | ||
/// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> | ||
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> | ||
/// <param name="cancellationToken">An optional token for canceling the call.</param> | ||
/// <returns>The response received from the server.</returns> | ||
ExportMetricsServiceResponse Export(ExportMetricsServiceRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default); | ||
} | ||
|
||
/// <summary> | ||
/// MetricServiceClient extensions. | ||
/// </summary> | ||
public partial class MetricsServiceClient : IMetricsServiceClient | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpMetricsExporterTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// <copyright file="OtlpMetricsExporterTests.cs" company="OpenTelemetry Authors"> | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// </copyright> | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.Metrics; | ||
using System.Linq; | ||
using System.Threading; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; | ||
using OpenTelemetry.Metrics; | ||
using OpenTelemetry.Resources; | ||
using OpenTelemetry.Tests; | ||
using OpenTelemetry.Trace; | ||
using Xunit; | ||
using GrpcCore = Grpc.Core; | ||
using OtlpCollector = Opentelemetry.Proto.Collector.Metrics.V1; | ||
using OtlpMetrics = Opentelemetry.Proto.Metrics.V1; | ||
|
||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests | ||
{ | ||
public class OtlpMetricsExporterTests | ||
{ | ||
[Theory] | ||
[InlineData(true)] | ||
[InlineData(false)] | ||
public void ToOtlpResourceMetricsTest(bool addResource) | ||
{ | ||
using var exporter = new OtlpMetricsExporter( | ||
new OtlpExporterOptions(), | ||
new NoopMetricsServiceClient()); | ||
|
||
if (addResource) | ||
{ | ||
exporter.SetResource( | ||
ResourceBuilder.CreateEmpty().AddAttributes( | ||
new List<KeyValuePair<string, object>> | ||
{ | ||
new KeyValuePair<string, object>(ResourceSemanticConventions.AttributeServiceName, "service-name"), | ||
new KeyValuePair<string, object>(ResourceSemanticConventions.AttributeServiceNamespace, "ns1"), | ||
}).Build()); | ||
} | ||
else | ||
{ | ||
exporter.SetResource(Resource.Empty); | ||
} | ||
|
||
var tags = new KeyValuePair<string, object>[] | ||
{ | ||
new KeyValuePair<string, object>("key1", "value1"), | ||
new KeyValuePair<string, object>("key2", "value2"), | ||
}; | ||
|
||
var processor = new PullMetricProcessor(new TestExporter<MetricItem>(RunTest), true); | ||
|
||
using var provider = Sdk.CreateMeterProviderBuilder() | ||
.AddSource("TestMeter") | ||
.AddMetricProcessor(processor) | ||
.Build(); | ||
|
||
using var meter = new Meter("TestMeter", "0.0.1"); | ||
|
||
var counter = meter.CreateCounter<int>("counter"); | ||
|
||
counter.Add(100, tags); | ||
|
||
var testCompleted = false; | ||
|
||
// Invokes the TestExporter which will invoke RunTest | ||
processor.PullRequest(); | ||
|
||
Assert.True(testCompleted); | ||
|
||
void RunTest(Batch<MetricItem> metricItem) | ||
{ | ||
var request = new OtlpCollector.ExportMetricsServiceRequest(); | ||
request.AddBatch(exporter.ProcessResource, metricItem); | ||
|
||
Assert.Single(request.ResourceMetrics); | ||
var resourceMetric = request.ResourceMetrics.First(); | ||
var oltpResource = resourceMetric.Resource; | ||
|
||
if (addResource) | ||
{ | ||
Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.StringValue == "service-name"); | ||
Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceNamespace && kvp.Value.StringValue == "ns1"); | ||
} | ||
else | ||
{ | ||
Assert.Contains(oltpResource.Attributes, (kvp) => kvp.Key == ResourceSemanticConventions.AttributeServiceName && kvp.Value.ToString().Contains("unknown_service:")); | ||
} | ||
|
||
Assert.Single(resourceMetric.InstrumentationLibraryMetrics); | ||
var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.First(); | ||
Assert.Equal(string.Empty, instrumentationLibraryMetrics.SchemaUrl); | ||
Assert.Equal("TestMeter", instrumentationLibraryMetrics.InstrumentationLibrary.Name); | ||
Assert.Equal("0.0.1", instrumentationLibraryMetrics.InstrumentationLibrary.Version); | ||
|
||
Assert.Single(instrumentationLibraryMetrics.Metrics); | ||
|
||
foreach (var metric in instrumentationLibraryMetrics.Metrics) | ||
{ | ||
Assert.Equal(string.Empty, metric.Description); | ||
Assert.Equal(string.Empty, metric.Unit); | ||
Assert.Equal("counter", metric.Name); | ||
|
||
Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Sum, metric.DataCase); | ||
Assert.True(metric.Sum.IsMonotonic); | ||
Assert.Equal(OtlpMetrics.AggregationTemporality.Delta, metric.Sum.AggregationTemporality); | ||
|
||
Assert.Single(metric.Sum.DataPoints); | ||
var dataPoint = metric.Sum.DataPoints.First(); | ||
Assert.True(dataPoint.StartTimeUnixNano > 0); | ||
Assert.True(dataPoint.TimeUnixNano > 0); | ||
Assert.Equal(OtlpMetrics.NumberDataPoint.ValueOneofCase.AsInt, dataPoint.ValueCase); | ||
Assert.Equal(100, dataPoint.AsInt); | ||
|
||
#pragma warning disable CS0612 // Type or member is obsolete | ||
Assert.Empty(dataPoint.Labels); | ||
#pragma warning restore CS0612 // Type or member is obsolete | ||
OtlpTestHelpers.AssertOtlpAttributes(tags.ToList(), dataPoint.Attributes); | ||
|
||
Assert.Empty(dataPoint.Exemplars); | ||
} | ||
|
||
testCompleted = true; | ||
} | ||
} | ||
|
||
private class NoopMetricsServiceClient : OtlpCollector.MetricsService.IMetricsServiceClient | ||
{ | ||
public OtlpCollector.ExportMetricsServiceResponse Export(OtlpCollector.ExportMetricsServiceRequest request, GrpcCore.Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) | ||
{ | ||
return null; | ||
} | ||
} | ||
} | ||
} |
120 changes: 120 additions & 0 deletions
120
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTestHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// <copyright file="OtlpTestHelpers.cs" company="OpenTelemetry Authors"> | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// </copyright> | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Google.Protobuf.Collections; | ||
using Xunit; | ||
using OtlpCommon = Opentelemetry.Proto.Common.V1; | ||
|
||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests | ||
{ | ||
internal static class OtlpTestHelpers | ||
{ | ||
public static void AssertOtlpAttributes( | ||
IEnumerable<KeyValuePair<string, object>> expected, | ||
RepeatedField<OtlpCommon.KeyValue> actual) | ||
{ | ||
var expectedAttributes = expected.ToList(); | ||
int expectedSize = 0; | ||
for (int i = 0; i < expectedAttributes.Count; i++) | ||
{ | ||
var current = expectedAttributes[i].Value; | ||
|
||
if (current.GetType().IsArray) | ||
{ | ||
if (current is bool[] boolArray) | ||
{ | ||
int index = 0; | ||
foreach (var item in boolArray) | ||
{ | ||
Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); | ||
AssertOtlpAttributeValue(item, actual[i + index]); | ||
index++; | ||
expectedSize++; | ||
} | ||
} | ||
else if (current is int[] intArray) | ||
{ | ||
int index = 1; | ||
foreach (var item in intArray) | ||
{ | ||
Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); | ||
AssertOtlpAttributeValue(item, actual[i + index]); | ||
index++; | ||
expectedSize++; | ||
} | ||
} | ||
else if (current is double[] doubleArray) | ||
{ | ||
int index = 2; | ||
foreach (var item in doubleArray) | ||
{ | ||
Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); | ||
AssertOtlpAttributeValue(item, actual[i + index]); | ||
index++; | ||
expectedSize++; | ||
} | ||
} | ||
else if (current is string[] stringArray) | ||
{ | ||
int index = 3; | ||
foreach (var item in stringArray) | ||
{ | ||
Assert.Equal(expectedAttributes[i].Key, actual[i + index].Key); | ||
AssertOtlpAttributeValue(item, actual[i + index]); | ||
index++; | ||
expectedSize++; | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
Assert.Equal(expectedAttributes[i].Key, actual[i].Key); | ||
AssertOtlpAttributeValue(current, actual[i]); | ||
expectedSize++; | ||
} | ||
} | ||
|
||
Assert.Equal(expectedSize, actual.Count); | ||
} | ||
|
||
private static void AssertOtlpAttributeValue(object expected, OtlpCommon.KeyValue actual) | ||
{ | ||
switch (expected) | ||
{ | ||
case string s: | ||
Assert.Equal(s, actual.Value.StringValue); | ||
break; | ||
case bool b: | ||
Assert.Equal(b, actual.Value.BoolValue); | ||
break; | ||
case long l: | ||
Assert.Equal(l, actual.Value.IntValue); | ||
break; | ||
case double d: | ||
Assert.Equal(d, actual.Value.DoubleValue); | ||
break; | ||
case int i: | ||
Assert.Equal(i, actual.Value.IntValue); | ||
break; | ||
default: | ||
Assert.Equal(expected.ToString(), actual.Value.StringValue); | ||
break; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.