From 3660c3abe3dbc384305979d1341a1d0b775c309c Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 10:14:07 -0800 Subject: [PATCH 01/17] Add support for instrumentation scope attributes (Meter tags) --- examples/Console/TestOtlpExporter.cs | 4 +- .../ConsoleMetricExporter.cs | 13 +++- .../CHANGELOG.md | 2 + .../Implementation/MetricItemExtensions.cs | 62 ++++++++++++------- .../.publicApi/Stable/PublicAPI.Unshipped.txt | 1 + src/OpenTelemetry/CHANGELOG.md | 3 + src/OpenTelemetry/Metrics/Metric.cs | 5 ++ .../Metrics/MetricStreamIdentity.cs | 5 ++ .../Metrics/MetricApiTestsBase.cs | 36 +++++++++++ 9 files changed, 104 insertions(+), 27 deletions(-) diff --git a/examples/Console/TestOtlpExporter.cs b/examples/Console/TestOtlpExporter.cs index 793d9f11937..af73004b0b0 100644 --- a/examples/Console/TestOtlpExporter.cs +++ b/examples/Console/TestOtlpExporter.cs @@ -33,10 +33,10 @@ internal static object Run(string endpoint, string protocol) * launch the OpenTelemetry Collector with an OTLP receiver, by running: * * - On Unix based systems use: - * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml + * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:latest --config=/cfg/otlp-collector-example/config.yaml * * - On Windows use: - * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml + * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:latest --config=/cfg/otlp-collector-example/config.yaml * * Open another terminal window at the examples/Console/ directory and * launch the OTLP example by running: diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs index e0483f82c9c..b902bd5efbd 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs @@ -50,8 +50,8 @@ public override ExportResult Export(in Batch batch) foreach (var metric in batch) { - var msg = new StringBuilder($"\nExport "); - msg.Append(metric.Name); + var msg = new StringBuilder($"\n"); + msg.Append($"Metric Name: {metric.Name}"); if (metric.Description != string.Empty) { msg.Append(", "); @@ -75,6 +75,15 @@ public override ExportResult Export(in Batch batch) this.WriteLine(msg.ToString()); + foreach (var meterTag in metric.MeterTags) + { + this.WriteLine("\tMeter Tags:"); + if (ConsoleTagTransformer.Instance.TryTransformTag(meterTag, out var result)) + { + this.WriteLine($"\t {result}"); + } + } + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) { string valueDisplay = string.Empty; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index c6c60e92cc1..fce9222165c 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -3,6 +3,8 @@ ## Unreleased * Made `OpenTelemetry.Exporter.OtlpLogExporter` public. ([#4979](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4979)) +* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing + issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). ## 1.7.0-alpha.1 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 9c20d38cb78..c2f1bfa23a1 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -1,26 +1,26 @@ -// -// 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 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. +// + using System.Collections.Concurrent; using System.Runtime.CompilerServices; using Google.Protobuf; using Google.Protobuf.Collections; using OpenTelemetry.Metrics; +using OpenTelemetry.Proto.Common.V1; using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; -using OtlpCommon = OpenTelemetry.Proto.Common.V1; using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; using OtlpResource = OpenTelemetry.Proto.Resource.V1; @@ -58,7 +58,7 @@ internal static void AddMetrics( var meterName = metric.MeterName; if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) { - scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion); + scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion, metric.MeterTags); metricsByLibrary.Add(meterName, scopeMetrics); resourceMetrics.ScopeMetrics.Add(scopeMetrics); @@ -85,28 +85,33 @@ internal static void Return(this OtlpCollector.ExportMetricsServiceRequest reque } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version) + internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable> meterTags) { if (!MetricListPool.TryTake(out var metrics)) { metrics = new OtlpMetrics.ScopeMetrics { - Scope = new OtlpCommon.InstrumentationScope + Scope = new InstrumentationScope { Name = name, // Name is enforced to not be null, but it can be empty. Version = version ?? string.Empty, // NRE throw by proto }, }; + + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); } else { metrics.Scope.Name = name; metrics.Scope.Version = version ?? string.Empty; + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); } return metrics; - } - + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) { @@ -357,7 +362,7 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) return otlpMetric; } - private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) + private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) { foreach (var tag in tags) { @@ -368,6 +373,17 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField> meterTags, RepeatedField attributes) + { + foreach (var tag in meterTags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + attributes.Add(result); + } + } + } + /* [MethodImpl(MethodImplOptions.AggressiveInlining)] private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) diff --git a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt index e69de29bb2d..b4381fdd907 100644 --- a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +OpenTelemetry.Metrics.Metric.MeterTags.get -> System.Collections.Generic.IEnumerable>! \ No newline at end of file diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index d8c66536741..eb397ada64d 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -44,6 +44,9 @@ before setting up the `MeterProvider`. ([#5052](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5052)) +* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing + issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ## 1.7.0-alpha.1 Released 2023-Oct-16 diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 6fe6036498e..f54182f8854 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -207,6 +207,11 @@ internal Metric( /// public string MeterVersion => this.InstrumentIdentity.MeterVersion; + /// + /// Gets the attributes (tags) for the metric stream. + /// + public IEnumerable> MeterTags => this.InstrumentIdentity.MeterTags; + /// /// Gets the for the metric stream. /// diff --git a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs index a8a42f57708..46529b520bb 100644 --- a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs +++ b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs @@ -27,6 +27,7 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration? me { this.MeterName = instrument.Meter.Name; this.MeterVersion = instrument.Meter.Version ?? string.Empty; + this.MeterTags = instrument.Meter.Tags ?? Enumerable.Empty>(); this.InstrumentName = metricStreamConfiguration?.Name ?? instrument.Name; this.Unit = instrument.Unit ?? string.Empty; this.Description = metricStreamConfiguration?.Description ?? instrument.Description ?? string.Empty; @@ -75,6 +76,8 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration? me hash = (hash * 31) + this.InstrumentType.GetHashCode(); hash = (hash * 31) + this.MeterName.GetHashCode(); hash = (hash * 31) + this.MeterVersion.GetHashCode(); + + // MeterTags is not part of identity, so not included here. hash = (hash * 31) + this.InstrumentName.GetHashCode(); hash = (hash * 31) + this.HistogramRecordMinMax.GetHashCode(); hash = (hash * 31) + this.ExponentialHistogramMaxSize.GetHashCode(); @@ -101,6 +104,8 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration? me public string MeterVersion { get; } + public IEnumerable> MeterTags { get; } + public string InstrumentName { get; } public string Unit { get; } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index ff226b8e360..516f3d41ee4 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -217,6 +217,42 @@ public void MetricDescriptionIsExportedCorrectly(string description) Assert.Equal(description ?? string.Empty, metric.Description); } + [Fact] + public void MetricInstrumentationScopeIsExportedCorrectly() + { + var exportedItems = new List(); + var meterName = Utils.GetCurrentMethodName(); + var meterVersion = "1.0"; + var meterTags = new List> + { + new( + "MeterTagKey", + "MeterTagValue"), + }; + using var meter = new Meter($"{meterName}", meterVersion, meterTags); + var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() + .ConfigureServices(services => + { + services.AddSingleton(this.configuration); + }) + .AddMeter(meter.Name) + .AddInMemoryExporter(exportedItems); + + using var meterProvider = meterProviderBuilder.Build(); + + var counter = meter.CreateCounter("name1"); + counter.Add(10); + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + Assert.Single(exportedItems); + var metric = exportedItems[0]; + Assert.Equal(meterName, metric.MeterName); + Assert.Equal(meterVersion, metric.MeterVersion); + + bool containsMeterTags = metric.MeterTags.Any(kvp => + kvp.Key == meterTags[0].Key && Equals(kvp.Value, meterTags[0].Value)); + Assert.True(containsMeterTags); + } + [Fact] public void DuplicateInstrumentRegistration_NoViews_IdenticalInstruments() { From 4448413c84b8184ab4fd7454fde9ee075113744f Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 10:19:49 -0800 Subject: [PATCH 02/17] changelog order --- .../CHANGELOG.md | 3 +++ src/OpenTelemetry/CHANGELOG.md | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 71559a538c6..c635bcd235b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -15,6 +15,9 @@ accepts a `name` parameter to support named options. ([#4916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4916)) +* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing + issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ## 1.7.0-alpha.1 Released 2023-Oct-16 diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index d8417e38b38..76b989d6684 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -44,9 +44,6 @@ before setting up the `MeterProvider`. ([#5052](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5052)) -* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing - issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). - * Update Metrics SDK to override the default histogram buckets for ASP.NET (.NET Framework). @@ -61,6 +58,9 @@ implementationFactory)`. ([#4916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4916)) +* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing + issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ## 1.7.0-alpha.1 Released 2023-Oct-16 From 2997c6cff4179c188e8847d543a425ebe9a833e7 Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 10:26:31 -0800 Subject: [PATCH 03/17] move to new style --- .../Metrics/MetricApiTestsBase.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index 8b1a3bff16a..9f706a2331b 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -184,22 +184,16 @@ public void MetricInstrumentationScopeIsExportedCorrectly() var exportedItems = new List(); var meterName = Utils.GetCurrentMethodName(); var meterVersion = "1.0"; - var meterTags = new List> + var meterTags = new List> { new( "MeterTagKey", "MeterTagValue"), }; using var meter = new Meter($"{meterName}", meterVersion, meterTags); - var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() - .ConfigureServices(services => - { - services.AddSingleton(this.configuration); - }) + using var container = this.BuildMeterProvider(out var meterProvider, builder => builder .AddMeter(meter.Name) - .AddInMemoryExporter(exportedItems); - - using var meterProvider = meterProviderBuilder.Build(); + .AddInMemoryExporter(exportedItems)); var counter = meter.CreateCounter("name1"); counter.Add(10); From d48e1bfb1a6d47fee7083a94901f9e466c8d7a47 Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 10:41:26 -0800 Subject: [PATCH 04/17] revert line ending --- .../Implementation/MetricItemExtensions.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index c2f1bfa23a1..3638267e1a8 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -1,17 +1,17 @@ -// -// 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 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. // using System.Collections.Concurrent; From 5392119bf2017663ff7a490d57ddf43f38e9cd6a Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 10:48:07 -0800 Subject: [PATCH 05/17] line ending is diff in this machine --- .../Implementation/MetricItemExtensions.cs | 854 +++++++++--------- 1 file changed, 427 insertions(+), 427 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 3638267e1a8..f6f958f7f80 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -1,434 +1,434 @@ -// -// 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 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. // -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using Google.Protobuf; -using Google.Protobuf.Collections; -using OpenTelemetry.Metrics; -using OpenTelemetry.Proto.Common.V1; -using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; -using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; -using OtlpResource = OpenTelemetry.Proto.Resource.V1; - -namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; - -internal static class MetricItemExtensions -{ - private static readonly ConcurrentBag MetricListPool = new(); - - internal static void AddMetrics( - this OtlpCollector.ExportMetricsServiceRequest request, - OtlpResource.Resource processResource, - in Batch metrics) - { - var metricsByLibrary = new Dictionary(); - var resourceMetrics = new OtlpMetrics.ResourceMetrics - { - Resource = processResource, - }; - request.ResourceMetrics.Add(resourceMetrics); - - foreach (var metric in metrics) - { - var otlpMetric = metric.ToOtlpMetric(); - - // TODO: Replace null check with exception handling. - if (otlpMetric == null) - { - OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateMetric( - nameof(MetricItemExtensions), - nameof(AddMetrics)); - continue; - } - - var meterName = metric.MeterName; - if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) - { - scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion, metric.MeterTags); - - metricsByLibrary.Add(meterName, scopeMetrics); - resourceMetrics.ScopeMetrics.Add(scopeMetrics); - } - - scopeMetrics.Metrics.Add(otlpMetric); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Return(this OtlpCollector.ExportMetricsServiceRequest request) - { - var resourceMetrics = request.ResourceMetrics.FirstOrDefault(); - if (resourceMetrics == null) - { - return; - } - - foreach (var scope in resourceMetrics.ScopeMetrics) - { - scope.Metrics.Clear(); - MetricListPool.Add(scope); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable> meterTags) - { - if (!MetricListPool.TryTake(out var metrics)) - { - metrics = new OtlpMetrics.ScopeMetrics - { - Scope = new InstrumentationScope - { - Name = name, // Name is enforced to not be null, but it can be empty. - Version = version ?? string.Empty, // NRE throw by proto - }, - }; - - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); - } - else - { - metrics.Scope.Name = name; - metrics.Scope.Version = version ?? string.Empty; - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); - } - - return metrics; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using Google.Protobuf; +using Google.Protobuf.Collections; +using OpenTelemetry.Metrics; +using OpenTelemetry.Proto.Common.V1; +using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; +using OtlpCommon = OpenTelemetry.Proto.Common.V1; +using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; +using OtlpResource = OpenTelemetry.Proto.Resource.V1; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; + +internal static class MetricItemExtensions +{ + private static readonly ConcurrentBag MetricListPool = new(); + + internal static void AddMetrics( + this OtlpCollector.ExportMetricsServiceRequest request, + OtlpResource.Resource processResource, + in Batch metrics) + { + var metricsByLibrary = new Dictionary(); + var resourceMetrics = new OtlpMetrics.ResourceMetrics + { + Resource = processResource, + }; + request.ResourceMetrics.Add(resourceMetrics); + + foreach (var metric in metrics) + { + var otlpMetric = metric.ToOtlpMetric(); + + // TODO: Replace null check with exception handling. + if (otlpMetric == null) + { + OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateMetric( + nameof(MetricItemExtensions), + nameof(AddMetrics)); + continue; + } + + var meterName = metric.MeterName; + if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) + { + scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion, metric.MeterTags); + + metricsByLibrary.Add(meterName, scopeMetrics); + resourceMetrics.ScopeMetrics.Add(scopeMetrics); + } + + scopeMetrics.Metrics.Add(otlpMetric); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Return(this OtlpCollector.ExportMetricsServiceRequest request) + { + var resourceMetrics = request.ResourceMetrics.FirstOrDefault(); + if (resourceMetrics == null) + { + return; + } + + foreach (var scope in resourceMetrics.ScopeMetrics) + { + scope.Metrics.Clear(); + MetricListPool.Add(scope); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable> meterTags) + { + if (!MetricListPool.TryTake(out var metrics)) + { + metrics = new OtlpMetrics.ScopeMetrics + { + Scope = new OtlpCommon.InstrumentationScope + { + Name = name, // Name is enforced to not be null, but it can be empty. + Version = version ?? string.Empty, // NRE throw by proto + }, + }; + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); + } + else + { + metrics.Scope.Name = name; + metrics.Scope.Version = version ?? string.Empty; + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); + } + + return metrics; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) + { + var otlpMetric = new OtlpMetrics.Metric + { + Name = metric.Name, + }; + + if (metric.Description != null) + { + otlpMetric.Description = metric.Description; + } + + if (metric.Unit != null) + { + otlpMetric.Unit = metric.Unit; + } + + OtlpMetrics.AggregationTemporality temporality; + if (metric.Temporality == AggregationTemporality.Delta) + { + temporality = OtlpMetrics.AggregationTemporality.Delta; + } + else + { + temporality = OtlpMetrics.AggregationTemporality.Cumulative; + } + + switch (metric.MetricType) + { + case MetricType.LongSum: + case MetricType.LongSumNonMonotonic: + { + var sum = new OtlpMetrics.Sum + { + IsMonotonic = metric.MetricType == MetricType.LongSum, + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsInt = metricPoint.GetSumLong(); + sum.DataPoints.Add(dataPoint); + } + + otlpMetric.Sum = sum; + break; + } + + case MetricType.DoubleSum: + case MetricType.DoubleSumNonMonotonic: + { + var sum = new OtlpMetrics.Sum + { + IsMonotonic = metric.MetricType == MetricType.DoubleSum, + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsDouble = metricPoint.GetSumDouble(); + sum.DataPoints.Add(dataPoint); + } + + otlpMetric.Sum = sum; + break; + } + + case MetricType.LongGauge: + { + var gauge = new OtlpMetrics.Gauge(); + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsInt = metricPoint.GetGaugeLastValueLong(); + gauge.DataPoints.Add(dataPoint); + } + + otlpMetric.Gauge = gauge; + break; + } + + case MetricType.DoubleGauge: + { + var gauge = new OtlpMetrics.Gauge(); + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsDouble = metricPoint.GetGaugeLastValueDouble(); + gauge.DataPoints.Add(dataPoint); + } + + otlpMetric.Gauge = gauge; + break; + } + + case MetricType.Histogram: + { + var histogram = new OtlpMetrics.Histogram + { + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.HistogramDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); + dataPoint.Sum = metricPoint.GetHistogramSum(); + + if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) + { + dataPoint.Min = min; + dataPoint.Max = max; + } + + foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) + { + dataPoint.BucketCounts.Add((ulong)histogramMeasurement.BucketCount); + if (histogramMeasurement.ExplicitBound != double.PositiveInfinity) + { + dataPoint.ExplicitBounds.Add(histogramMeasurement.ExplicitBound); + } + } + + var exemplars = metricPoint.GetExemplars(); + foreach (var examplar in exemplars) + { + if (examplar.Timestamp != default) + { + byte[] traceIdBytes = new byte[16]; + examplar.TraceId?.CopyTo(traceIdBytes); + + byte[] spanIdBytes = new byte[8]; + examplar.SpanId?.CopyTo(spanIdBytes); + + var otlpExemplar = new OtlpMetrics.Exemplar + { + TimeUnixNano = (ulong)examplar.Timestamp.ToUnixTimeNanoseconds(), + TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes), + SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes), + AsDouble = examplar.DoubleValue, + }; + + if (examplar.FilteredTags != null) + { + foreach (var tag in examplar.FilteredTags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + otlpExemplar.FilteredAttributes.Add(result); + } + } + } + + dataPoint.Exemplars.Add(otlpExemplar); + } + } + + histogram.DataPoints.Add(dataPoint); + } + + otlpMetric.Histogram = histogram; + break; + } + + case MetricType.ExponentialHistogram: + { + var histogram = new OtlpMetrics.ExponentialHistogram + { + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.ExponentialHistogramDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); + dataPoint.Sum = metricPoint.GetHistogramSum(); + + if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) + { + dataPoint.Min = min; + dataPoint.Max = max; + } + + var exponentialHistogramData = metricPoint.GetExponentialHistogramData(); + dataPoint.Scale = exponentialHistogramData.Scale; + dataPoint.ZeroCount = (ulong)exponentialHistogramData.ZeroCount; + + dataPoint.Positive = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets(); + dataPoint.Positive.Offset = exponentialHistogramData.PositiveBuckets.Offset; + foreach (var bucketCount in exponentialHistogramData.PositiveBuckets) + { + dataPoint.Positive.BucketCounts.Add((ulong)bucketCount); + } + + // TODO: exemplars. + + histogram.DataPoints.Add(dataPoint); + } + + otlpMetric.ExponentialHistogram = histogram; + break; + } + } + + return otlpMetric; + } + + private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) + { + foreach (var tag in tags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + attributes.Add(result); + } + } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) - { - var otlpMetric = new OtlpMetrics.Metric - { - Name = metric.Name, - }; - - if (metric.Description != null) - { - otlpMetric.Description = metric.Description; - } - - if (metric.Unit != null) - { - otlpMetric.Unit = metric.Unit; - } - - OtlpMetrics.AggregationTemporality temporality; - if (metric.Temporality == AggregationTemporality.Delta) - { - temporality = OtlpMetrics.AggregationTemporality.Delta; - } - else - { - temporality = OtlpMetrics.AggregationTemporality.Cumulative; - } - - switch (metric.MetricType) - { - case MetricType.LongSum: - case MetricType.LongSumNonMonotonic: - { - var sum = new OtlpMetrics.Sum - { - IsMonotonic = metric.MetricType == MetricType.LongSum, - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsInt = metricPoint.GetSumLong(); - sum.DataPoints.Add(dataPoint); - } - - otlpMetric.Sum = sum; - break; - } - - case MetricType.DoubleSum: - case MetricType.DoubleSumNonMonotonic: - { - var sum = new OtlpMetrics.Sum - { - IsMonotonic = metric.MetricType == MetricType.DoubleSum, - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsDouble = metricPoint.GetSumDouble(); - sum.DataPoints.Add(dataPoint); - } - - otlpMetric.Sum = sum; - break; - } - - case MetricType.LongGauge: - { - var gauge = new OtlpMetrics.Gauge(); - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsInt = metricPoint.GetGaugeLastValueLong(); - gauge.DataPoints.Add(dataPoint); - } - - otlpMetric.Gauge = gauge; - break; - } - - case MetricType.DoubleGauge: - { - var gauge = new OtlpMetrics.Gauge(); - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsDouble = metricPoint.GetGaugeLastValueDouble(); - gauge.DataPoints.Add(dataPoint); - } - - otlpMetric.Gauge = gauge; - break; - } - - case MetricType.Histogram: - { - var histogram = new OtlpMetrics.Histogram - { - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.HistogramDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); - dataPoint.Sum = metricPoint.GetHistogramSum(); - - if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) - { - dataPoint.Min = min; - dataPoint.Max = max; - } - - foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) - { - dataPoint.BucketCounts.Add((ulong)histogramMeasurement.BucketCount); - if (histogramMeasurement.ExplicitBound != double.PositiveInfinity) - { - dataPoint.ExplicitBounds.Add(histogramMeasurement.ExplicitBound); - } - } - - var exemplars = metricPoint.GetExemplars(); - foreach (var examplar in exemplars) - { - if (examplar.Timestamp != default) - { - byte[] traceIdBytes = new byte[16]; - examplar.TraceId?.CopyTo(traceIdBytes); - - byte[] spanIdBytes = new byte[8]; - examplar.SpanId?.CopyTo(spanIdBytes); - - var otlpExemplar = new OtlpMetrics.Exemplar - { - TimeUnixNano = (ulong)examplar.Timestamp.ToUnixTimeNanoseconds(), - TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes), - SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes), - AsDouble = examplar.DoubleValue, - }; - - if (examplar.FilteredTags != null) - { - foreach (var tag in examplar.FilteredTags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - otlpExemplar.FilteredAttributes.Add(result); - } - } - } - - dataPoint.Exemplars.Add(otlpExemplar); - } - } - - histogram.DataPoints.Add(dataPoint); - } - - otlpMetric.Histogram = histogram; - break; - } - - case MetricType.ExponentialHistogram: - { - var histogram = new OtlpMetrics.ExponentialHistogram - { - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.ExponentialHistogramDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); - dataPoint.Sum = metricPoint.GetHistogramSum(); - - if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) - { - dataPoint.Min = min; - dataPoint.Max = max; - } - - var exponentialHistogramData = metricPoint.GetExponentialHistogramData(); - dataPoint.Scale = exponentialHistogramData.Scale; - dataPoint.ZeroCount = (ulong)exponentialHistogramData.ZeroCount; - - dataPoint.Positive = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets(); - dataPoint.Positive.Offset = exponentialHistogramData.PositiveBuckets.Offset; - foreach (var bucketCount in exponentialHistogramData.PositiveBuckets) - { - dataPoint.Positive.BucketCounts.Add((ulong)bucketCount); - } - - // TODO: exemplars. - - histogram.DataPoints.Add(dataPoint); - } - - otlpMetric.ExponentialHistogram = histogram; - break; - } - } - - return otlpMetric; - } - - private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) - { - foreach (var tag in tags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - attributes.Add(result); - } - } - } - private static void AddAttributes(IEnumerable> meterTags, RepeatedField attributes) { - foreach (var tag in meterTags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - attributes.Add(result); - } + foreach (var tag in meterTags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + attributes.Add(result); + } + } + } + + /* + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) + { + var otlpExemplar = new OtlpMetrics.Exemplar(); + + if (exemplar.Value is double doubleValue) + { + otlpExemplar.AsDouble = doubleValue; } - } - - /* - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) - { - var otlpExemplar = new OtlpMetrics.Exemplar(); - - if (exemplar.Value is double doubleValue) - { - otlpExemplar.AsDouble = doubleValue; - } - else if (exemplar.Value is long longValue) - { - otlpExemplar.AsInt = longValue; - } - else - { - // TODO: Determine how we want to handle exceptions here. - // Do we want to just skip this exemplar and move on? - // Should we skip recording the whole metric? - throw new ArgumentException(); - } - - otlpExemplar.TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds(); - - // TODO: Do the TagEnumerationState thing. - foreach (var tag in exemplar.FilteredTags) - { - otlpExemplar.FilteredAttributes.Add(tag.ToOtlpAttribute()); - } - - if (exemplar.TraceId != default) - { - byte[] traceIdBytes = new byte[16]; - exemplar.TraceId.CopyTo(traceIdBytes); - otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes); - } - - if (exemplar.SpanId != default) - { - byte[] spanIdBytes = new byte[8]; - exemplar.SpanId.CopyTo(spanIdBytes); - otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes); - } - - return otlpExemplar; - } - */ -} + else if (exemplar.Value is long longValue) + { + otlpExemplar.AsInt = longValue; + } + else + { + // TODO: Determine how we want to handle exceptions here. + // Do we want to just skip this exemplar and move on? + // Should we skip recording the whole metric? + throw new ArgumentException(); + } + + otlpExemplar.TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds(); + + // TODO: Do the TagEnumerationState thing. + foreach (var tag in exemplar.FilteredTags) + { + otlpExemplar.FilteredAttributes.Add(tag.ToOtlpAttribute()); + } + + if (exemplar.TraceId != default) + { + byte[] traceIdBytes = new byte[16]; + exemplar.TraceId.CopyTo(traceIdBytes); + otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes); + } + + if (exemplar.SpanId != default) + { + byte[] spanIdBytes = new byte[8]; + exemplar.SpanId.CopyTo(spanIdBytes); + otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes); + } + + return otlpExemplar; + } + */ +} From 2ecc2fedde686e2b109240f44b73b85da48116f8 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:10:38 -0800 Subject: [PATCH 06/17] fmt --- .../Implementation/MetricItemExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index f6f958f7f80..a44cb19d876 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -19,7 +19,6 @@ using Google.Protobuf; using Google.Protobuf.Collections; using OpenTelemetry.Metrics; -using OpenTelemetry.Proto.Common.V1; using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; using OtlpCommon = OpenTelemetry.Proto.Common.V1; using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; From 054637bec0947de91ef4c675024841510d581dc3 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:20:43 -0800 Subject: [PATCH 07/17] tmp revert --- .../Implementation/MetricItemExtensions.cs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index a44cb19d876..7902e8f6be3 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -58,7 +58,7 @@ internal static void AddMetrics( var meterName = metric.MeterName; if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) { - scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion, metric.MeterTags); + scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion); metricsByLibrary.Add(meterName, scopeMetrics); resourceMetrics.ScopeMetrics.Add(scopeMetrics); @@ -85,7 +85,7 @@ internal static void Return(this OtlpCollector.ExportMetricsServiceRequest reque } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable> meterTags) + internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version) { if (!MetricListPool.TryTake(out var metrics)) { @@ -97,15 +97,11 @@ internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, stri Version = version ?? string.Empty, // NRE throw by proto }, }; - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); } else { metrics.Scope.Name = name; metrics.Scope.Version = version ?? string.Empty; - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); } return metrics; @@ -372,17 +368,6 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField> meterTags, RepeatedField attributes) - { - foreach (var tag in meterTags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - attributes.Add(result); - } - } - } - /* [MethodImpl(MethodImplOptions.AggressiveInlining)] private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) From 3ef487f2a7cf6e96966fd85da681a1d801975d1e Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:21:58 -0800 Subject: [PATCH 08/17] lf --- .../Implementation/MetricItemExtensions.cs | 836 +++++++++--------- 1 file changed, 418 insertions(+), 418 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 7902e8f6be3..9c20d38cb78 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -1,418 +1,418 @@ -// -// 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. -// - -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using Google.Protobuf; -using Google.Protobuf.Collections; -using OpenTelemetry.Metrics; -using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; -using OtlpCommon = OpenTelemetry.Proto.Common.V1; -using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; -using OtlpResource = OpenTelemetry.Proto.Resource.V1; - -namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; - -internal static class MetricItemExtensions -{ - private static readonly ConcurrentBag MetricListPool = new(); - - internal static void AddMetrics( - this OtlpCollector.ExportMetricsServiceRequest request, - OtlpResource.Resource processResource, - in Batch metrics) - { - var metricsByLibrary = new Dictionary(); - var resourceMetrics = new OtlpMetrics.ResourceMetrics - { - Resource = processResource, - }; - request.ResourceMetrics.Add(resourceMetrics); - - foreach (var metric in metrics) - { - var otlpMetric = metric.ToOtlpMetric(); - - // TODO: Replace null check with exception handling. - if (otlpMetric == null) - { - OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateMetric( - nameof(MetricItemExtensions), - nameof(AddMetrics)); - continue; - } - - var meterName = metric.MeterName; - if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) - { - scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion); - - metricsByLibrary.Add(meterName, scopeMetrics); - resourceMetrics.ScopeMetrics.Add(scopeMetrics); - } - - scopeMetrics.Metrics.Add(otlpMetric); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Return(this OtlpCollector.ExportMetricsServiceRequest request) - { - var resourceMetrics = request.ResourceMetrics.FirstOrDefault(); - if (resourceMetrics == null) - { - return; - } - - foreach (var scope in resourceMetrics.ScopeMetrics) - { - scope.Metrics.Clear(); - MetricListPool.Add(scope); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version) - { - if (!MetricListPool.TryTake(out var metrics)) - { - metrics = new OtlpMetrics.ScopeMetrics - { - Scope = new OtlpCommon.InstrumentationScope - { - Name = name, // Name is enforced to not be null, but it can be empty. - Version = version ?? string.Empty, // NRE throw by proto - }, - }; - } - else - { - metrics.Scope.Name = name; - metrics.Scope.Version = version ?? string.Empty; - } - - return metrics; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) - { - var otlpMetric = new OtlpMetrics.Metric - { - Name = metric.Name, - }; - - if (metric.Description != null) - { - otlpMetric.Description = metric.Description; - } - - if (metric.Unit != null) - { - otlpMetric.Unit = metric.Unit; - } - - OtlpMetrics.AggregationTemporality temporality; - if (metric.Temporality == AggregationTemporality.Delta) - { - temporality = OtlpMetrics.AggregationTemporality.Delta; - } - else - { - temporality = OtlpMetrics.AggregationTemporality.Cumulative; - } - - switch (metric.MetricType) - { - case MetricType.LongSum: - case MetricType.LongSumNonMonotonic: - { - var sum = new OtlpMetrics.Sum - { - IsMonotonic = metric.MetricType == MetricType.LongSum, - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsInt = metricPoint.GetSumLong(); - sum.DataPoints.Add(dataPoint); - } - - otlpMetric.Sum = sum; - break; - } - - case MetricType.DoubleSum: - case MetricType.DoubleSumNonMonotonic: - { - var sum = new OtlpMetrics.Sum - { - IsMonotonic = metric.MetricType == MetricType.DoubleSum, - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsDouble = metricPoint.GetSumDouble(); - sum.DataPoints.Add(dataPoint); - } - - otlpMetric.Sum = sum; - break; - } - - case MetricType.LongGauge: - { - var gauge = new OtlpMetrics.Gauge(); - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsInt = metricPoint.GetGaugeLastValueLong(); - gauge.DataPoints.Add(dataPoint); - } - - otlpMetric.Gauge = gauge; - break; - } - - case MetricType.DoubleGauge: - { - var gauge = new OtlpMetrics.Gauge(); - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.NumberDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - - dataPoint.AsDouble = metricPoint.GetGaugeLastValueDouble(); - gauge.DataPoints.Add(dataPoint); - } - - otlpMetric.Gauge = gauge; - break; - } - - case MetricType.Histogram: - { - var histogram = new OtlpMetrics.Histogram - { - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.HistogramDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); - dataPoint.Sum = metricPoint.GetHistogramSum(); - - if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) - { - dataPoint.Min = min; - dataPoint.Max = max; - } - - foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) - { - dataPoint.BucketCounts.Add((ulong)histogramMeasurement.BucketCount); - if (histogramMeasurement.ExplicitBound != double.PositiveInfinity) - { - dataPoint.ExplicitBounds.Add(histogramMeasurement.ExplicitBound); - } - } - - var exemplars = metricPoint.GetExemplars(); - foreach (var examplar in exemplars) - { - if (examplar.Timestamp != default) - { - byte[] traceIdBytes = new byte[16]; - examplar.TraceId?.CopyTo(traceIdBytes); - - byte[] spanIdBytes = new byte[8]; - examplar.SpanId?.CopyTo(spanIdBytes); - - var otlpExemplar = new OtlpMetrics.Exemplar - { - TimeUnixNano = (ulong)examplar.Timestamp.ToUnixTimeNanoseconds(), - TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes), - SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes), - AsDouble = examplar.DoubleValue, - }; - - if (examplar.FilteredTags != null) - { - foreach (var tag in examplar.FilteredTags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - otlpExemplar.FilteredAttributes.Add(result); - } - } - } - - dataPoint.Exemplars.Add(otlpExemplar); - } - } - - histogram.DataPoints.Add(dataPoint); - } - - otlpMetric.Histogram = histogram; - break; - } - - case MetricType.ExponentialHistogram: - { - var histogram = new OtlpMetrics.ExponentialHistogram - { - AggregationTemporality = temporality, - }; - - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) - { - var dataPoint = new OtlpMetrics.ExponentialHistogramDataPoint - { - StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), - TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), - }; - - AddAttributes(metricPoint.Tags, dataPoint.Attributes); - dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); - dataPoint.Sum = metricPoint.GetHistogramSum(); - - if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) - { - dataPoint.Min = min; - dataPoint.Max = max; - } - - var exponentialHistogramData = metricPoint.GetExponentialHistogramData(); - dataPoint.Scale = exponentialHistogramData.Scale; - dataPoint.ZeroCount = (ulong)exponentialHistogramData.ZeroCount; - - dataPoint.Positive = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets(); - dataPoint.Positive.Offset = exponentialHistogramData.PositiveBuckets.Offset; - foreach (var bucketCount in exponentialHistogramData.PositiveBuckets) - { - dataPoint.Positive.BucketCounts.Add((ulong)bucketCount); - } - - // TODO: exemplars. - - histogram.DataPoints.Add(dataPoint); - } - - otlpMetric.ExponentialHistogram = histogram; - break; - } - } - - return otlpMetric; - } - - private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) - { - foreach (var tag in tags) - { - if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) - { - attributes.Add(result); - } - } - } - - /* - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) - { - var otlpExemplar = new OtlpMetrics.Exemplar(); - - if (exemplar.Value is double doubleValue) - { - otlpExemplar.AsDouble = doubleValue; - } - else if (exemplar.Value is long longValue) - { - otlpExemplar.AsInt = longValue; - } - else - { - // TODO: Determine how we want to handle exceptions here. - // Do we want to just skip this exemplar and move on? - // Should we skip recording the whole metric? - throw new ArgumentException(); - } - - otlpExemplar.TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds(); - - // TODO: Do the TagEnumerationState thing. - foreach (var tag in exemplar.FilteredTags) - { - otlpExemplar.FilteredAttributes.Add(tag.ToOtlpAttribute()); - } - - if (exemplar.TraceId != default) - { - byte[] traceIdBytes = new byte[16]; - exemplar.TraceId.CopyTo(traceIdBytes); - otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes); - } - - if (exemplar.SpanId != default) - { - byte[] spanIdBytes = new byte[8]; - exemplar.SpanId.CopyTo(spanIdBytes); - otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes); - } - - return otlpExemplar; - } - */ -} +// +// 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. +// + +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using Google.Protobuf; +using Google.Protobuf.Collections; +using OpenTelemetry.Metrics; +using OtlpCollector = OpenTelemetry.Proto.Collector.Metrics.V1; +using OtlpCommon = OpenTelemetry.Proto.Common.V1; +using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1; +using OtlpResource = OpenTelemetry.Proto.Resource.V1; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; + +internal static class MetricItemExtensions +{ + private static readonly ConcurrentBag MetricListPool = new(); + + internal static void AddMetrics( + this OtlpCollector.ExportMetricsServiceRequest request, + OtlpResource.Resource processResource, + in Batch metrics) + { + var metricsByLibrary = new Dictionary(); + var resourceMetrics = new OtlpMetrics.ResourceMetrics + { + Resource = processResource, + }; + request.ResourceMetrics.Add(resourceMetrics); + + foreach (var metric in metrics) + { + var otlpMetric = metric.ToOtlpMetric(); + + // TODO: Replace null check with exception handling. + if (otlpMetric == null) + { + OpenTelemetryProtocolExporterEventSource.Log.CouldNotTranslateMetric( + nameof(MetricItemExtensions), + nameof(AddMetrics)); + continue; + } + + var meterName = metric.MeterName; + if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) + { + scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion); + + metricsByLibrary.Add(meterName, scopeMetrics); + resourceMetrics.ScopeMetrics.Add(scopeMetrics); + } + + scopeMetrics.Metrics.Add(otlpMetric); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Return(this OtlpCollector.ExportMetricsServiceRequest request) + { + var resourceMetrics = request.ResourceMetrics.FirstOrDefault(); + if (resourceMetrics == null) + { + return; + } + + foreach (var scope in resourceMetrics.ScopeMetrics) + { + scope.Metrics.Clear(); + MetricListPool.Add(scope); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version) + { + if (!MetricListPool.TryTake(out var metrics)) + { + metrics = new OtlpMetrics.ScopeMetrics + { + Scope = new OtlpCommon.InstrumentationScope + { + Name = name, // Name is enforced to not be null, but it can be empty. + Version = version ?? string.Empty, // NRE throw by proto + }, + }; + } + else + { + metrics.Scope.Name = name; + metrics.Scope.Version = version ?? string.Empty; + } + + return metrics; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) + { + var otlpMetric = new OtlpMetrics.Metric + { + Name = metric.Name, + }; + + if (metric.Description != null) + { + otlpMetric.Description = metric.Description; + } + + if (metric.Unit != null) + { + otlpMetric.Unit = metric.Unit; + } + + OtlpMetrics.AggregationTemporality temporality; + if (metric.Temporality == AggregationTemporality.Delta) + { + temporality = OtlpMetrics.AggregationTemporality.Delta; + } + else + { + temporality = OtlpMetrics.AggregationTemporality.Cumulative; + } + + switch (metric.MetricType) + { + case MetricType.LongSum: + case MetricType.LongSumNonMonotonic: + { + var sum = new OtlpMetrics.Sum + { + IsMonotonic = metric.MetricType == MetricType.LongSum, + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsInt = metricPoint.GetSumLong(); + sum.DataPoints.Add(dataPoint); + } + + otlpMetric.Sum = sum; + break; + } + + case MetricType.DoubleSum: + case MetricType.DoubleSumNonMonotonic: + { + var sum = new OtlpMetrics.Sum + { + IsMonotonic = metric.MetricType == MetricType.DoubleSum, + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsDouble = metricPoint.GetSumDouble(); + sum.DataPoints.Add(dataPoint); + } + + otlpMetric.Sum = sum; + break; + } + + case MetricType.LongGauge: + { + var gauge = new OtlpMetrics.Gauge(); + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsInt = metricPoint.GetGaugeLastValueLong(); + gauge.DataPoints.Add(dataPoint); + } + + otlpMetric.Gauge = gauge; + break; + } + + case MetricType.DoubleGauge: + { + var gauge = new OtlpMetrics.Gauge(); + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.NumberDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + + dataPoint.AsDouble = metricPoint.GetGaugeLastValueDouble(); + gauge.DataPoints.Add(dataPoint); + } + + otlpMetric.Gauge = gauge; + break; + } + + case MetricType.Histogram: + { + var histogram = new OtlpMetrics.Histogram + { + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.HistogramDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); + dataPoint.Sum = metricPoint.GetHistogramSum(); + + if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) + { + dataPoint.Min = min; + dataPoint.Max = max; + } + + foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) + { + dataPoint.BucketCounts.Add((ulong)histogramMeasurement.BucketCount); + if (histogramMeasurement.ExplicitBound != double.PositiveInfinity) + { + dataPoint.ExplicitBounds.Add(histogramMeasurement.ExplicitBound); + } + } + + var exemplars = metricPoint.GetExemplars(); + foreach (var examplar in exemplars) + { + if (examplar.Timestamp != default) + { + byte[] traceIdBytes = new byte[16]; + examplar.TraceId?.CopyTo(traceIdBytes); + + byte[] spanIdBytes = new byte[8]; + examplar.SpanId?.CopyTo(spanIdBytes); + + var otlpExemplar = new OtlpMetrics.Exemplar + { + TimeUnixNano = (ulong)examplar.Timestamp.ToUnixTimeNanoseconds(), + TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes), + SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes), + AsDouble = examplar.DoubleValue, + }; + + if (examplar.FilteredTags != null) + { + foreach (var tag in examplar.FilteredTags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + otlpExemplar.FilteredAttributes.Add(result); + } + } + } + + dataPoint.Exemplars.Add(otlpExemplar); + } + } + + histogram.DataPoints.Add(dataPoint); + } + + otlpMetric.Histogram = histogram; + break; + } + + case MetricType.ExponentialHistogram: + { + var histogram = new OtlpMetrics.ExponentialHistogram + { + AggregationTemporality = temporality, + }; + + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + var dataPoint = new OtlpMetrics.ExponentialHistogramDataPoint + { + StartTimeUnixNano = (ulong)metricPoint.StartTime.ToUnixTimeNanoseconds(), + TimeUnixNano = (ulong)metricPoint.EndTime.ToUnixTimeNanoseconds(), + }; + + AddAttributes(metricPoint.Tags, dataPoint.Attributes); + dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); + dataPoint.Sum = metricPoint.GetHistogramSum(); + + if (metricPoint.TryGetHistogramMinMaxValues(out double min, out double max)) + { + dataPoint.Min = min; + dataPoint.Max = max; + } + + var exponentialHistogramData = metricPoint.GetExponentialHistogramData(); + dataPoint.Scale = exponentialHistogramData.Scale; + dataPoint.ZeroCount = (ulong)exponentialHistogramData.ZeroCount; + + dataPoint.Positive = new OtlpMetrics.ExponentialHistogramDataPoint.Types.Buckets(); + dataPoint.Positive.Offset = exponentialHistogramData.PositiveBuckets.Offset; + foreach (var bucketCount in exponentialHistogramData.PositiveBuckets) + { + dataPoint.Positive.BucketCounts.Add((ulong)bucketCount); + } + + // TODO: exemplars. + + histogram.DataPoints.Add(dataPoint); + } + + otlpMetric.ExponentialHistogram = histogram; + break; + } + } + + return otlpMetric; + } + + private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField attributes) + { + foreach (var tag in tags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + attributes.Add(result); + } + } + } + + /* + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) + { + var otlpExemplar = new OtlpMetrics.Exemplar(); + + if (exemplar.Value is double doubleValue) + { + otlpExemplar.AsDouble = doubleValue; + } + else if (exemplar.Value is long longValue) + { + otlpExemplar.AsInt = longValue; + } + else + { + // TODO: Determine how we want to handle exceptions here. + // Do we want to just skip this exemplar and move on? + // Should we skip recording the whole metric? + throw new ArgumentException(); + } + + otlpExemplar.TimeUnixNano = (ulong)exemplar.Timestamp.ToUnixTimeNanoseconds(); + + // TODO: Do the TagEnumerationState thing. + foreach (var tag in exemplar.FilteredTags) + { + otlpExemplar.FilteredAttributes.Add(tag.ToOtlpAttribute()); + } + + if (exemplar.TraceId != default) + { + byte[] traceIdBytes = new byte[16]; + exemplar.TraceId.CopyTo(traceIdBytes); + otlpExemplar.TraceId = UnsafeByteOperations.UnsafeWrap(traceIdBytes); + } + + if (exemplar.SpanId != default) + { + byte[] spanIdBytes = new byte[8]; + exemplar.SpanId.CopyTo(spanIdBytes); + otlpExemplar.SpanId = UnsafeByteOperations.UnsafeWrap(spanIdBytes); + } + + return otlpExemplar; + } + */ +} From 81b9bd56f8685feb0eb97e89bee174286d61841a Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:24:16 -0800 Subject: [PATCH 09/17] add tags back --- .../Implementation/MetricItemExtensions.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 9c20d38cb78..62a9d392ce6 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -58,7 +58,7 @@ internal static void AddMetrics( var meterName = metric.MeterName; if (!metricsByLibrary.TryGetValue(meterName, out var scopeMetrics)) { - scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion); + scopeMetrics = GetMetricListFromPool(meterName, metric.MeterVersion, metric.MeterTags); metricsByLibrary.Add(meterName, scopeMetrics); resourceMetrics.ScopeMetrics.Add(scopeMetrics); @@ -85,7 +85,7 @@ internal static void Return(this OtlpCollector.ExportMetricsServiceRequest reque } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version) + internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, string version, IEnumerable> meterTags) { if (!MetricListPool.TryTake(out var metrics)) { @@ -97,11 +97,15 @@ internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, stri Version = version ?? string.Empty, // NRE throw by proto }, }; + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); } else { metrics.Scope.Name = name; metrics.Scope.Version = version ?? string.Empty; + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); } return metrics; @@ -368,6 +372,17 @@ private static void AddAttributes(ReadOnlyTagCollection tags, RepeatedField> meterTags, RepeatedField attributes) + { + foreach (var tag in meterTags) + { + if (OtlpKeyValueTransformer.Instance.TryTransformTag(tag, out var result)) + { + attributes.Add(result); + } + } + } + /* [MethodImpl(MethodImplOptions.AggressiveInlining)] private static OtlpMetrics.Exemplar ToOtlpExemplar(this IExemplar exemplar) From 28593255e70612932c7047d690fc2b7c8ee8a993 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:36:49 -0800 Subject: [PATCH 10/17] console fix --- .../ConsoleMetricExporter.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs index b902bd5efbd..232fcc8294e 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs @@ -75,15 +75,15 @@ public override ExportResult Export(in Batch batch) this.WriteLine(msg.ToString()); - foreach (var meterTag in metric.MeterTags) - { - this.WriteLine("\tMeter Tags:"); - if (ConsoleTagTransformer.Instance.TryTransformTag(meterTag, out var result)) - { - this.WriteLine($"\t {result}"); - } - } - + foreach (var meterTag in metric.MeterTags) + { + this.WriteLine("\tMeter Tags:"); + if (ConsoleTagTransformer.Instance.TryTransformTag(meterTag, out var result)) + { + this.WriteLine($"\t {result}"); + } + } + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) { string valueDisplay = string.Empty; From d847336e094905fb627a632ea6b1dd6164f554af Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 11:38:15 -0800 Subject: [PATCH 11/17] fix test class --- test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index 9f706a2331b..6022f030620 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -203,7 +203,7 @@ public void MetricInstrumentationScopeIsExportedCorrectly() Assert.Equal(meterName, metric.MeterName); Assert.Equal(meterVersion, metric.MeterVersion); - bool containsMeterTags = metric.MeterTags.Any(kvp => + bool containsMeterTags = metric.MeterTags.Any(kvp => kvp.Key == meterTags[0].Key && Equals(kvp.Value, meterTags[0].Value)); Assert.True(containsMeterTags); } From f00c651594f9369df08e5a9beeb0f13c36260e9b Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 12:23:31 -0800 Subject: [PATCH 12/17] feedbacks addressed --- examples/Console/TestMetrics.cs | 9 ++++++++- .../Implementation/MetricItemExtensions.cs | 14 ++++++++++---- .../.publicApi/Stable/PublicAPI.Unshipped.txt | 2 +- src/OpenTelemetry/Metrics/Metric.cs | 2 +- src/OpenTelemetry/Metrics/MetricStreamIdentity.cs | 4 ++-- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/examples/Console/TestMetrics.cs b/examples/Console/TestMetrics.cs index 34824b12461..5b814be1cc8 100644 --- a/examples/Console/TestMetrics.cs +++ b/examples/Console/TestMetrics.cs @@ -27,7 +27,14 @@ internal class TestMetrics { internal static object Run(MetricsOptions options) { - using var meter = new Meter("TestMeter"); + var meterVersion = "1.0"; + var meterTags = new List> + { + new( + "MeterTagKey", + "MeterTagValue"), + }; + using var meter = new Meter("TestMeter", meterVersion, meterTags); var providerBuilder = Sdk.CreateMeterProviderBuilder() .ConfigureResource(r => r.AddService("myservice")) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 62a9d392ce6..95ad61f286d 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -97,15 +97,21 @@ internal static OtlpMetrics.ScopeMetrics GetMetricListFromPool(string name, stri Version = version ?? string.Empty, // NRE throw by proto }, }; - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); + + if (meterTags != null) + { + AddAttributes(meterTags, metrics.Scope.Attributes); + } } else { metrics.Scope.Name = name; metrics.Scope.Version = version ?? string.Empty; - metrics.Scope.Attributes.Clear(); - AddAttributes(meterTags, metrics.Scope.Attributes); + if (meterTags != null) + { + metrics.Scope.Attributes.Clear(); + AddAttributes(meterTags, metrics.Scope.Attributes); + } } return metrics; diff --git a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt index b4381fdd907..01e38e9263f 100644 --- a/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/Stable/PublicAPI.Unshipped.txt @@ -1 +1 @@ -OpenTelemetry.Metrics.Metric.MeterTags.get -> System.Collections.Generic.IEnumerable>! \ No newline at end of file +OpenTelemetry.Metrics.Metric.MeterTags.get -> System.Collections.Generic.IEnumerable>? diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 7143b01a947..7deba4b36e9 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -210,7 +210,7 @@ internal Metric( /// /// Gets the attributes (tags) for the metric stream. /// - public IEnumerable> MeterTags => this.InstrumentIdentity.MeterTags; + public IEnumerable>? MeterTags => this.InstrumentIdentity.MeterTags; /// /// Gets the for the metric stream. diff --git a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs index 46529b520bb..cdaca57db09 100644 --- a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs +++ b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs @@ -27,7 +27,7 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration? me { this.MeterName = instrument.Meter.Name; this.MeterVersion = instrument.Meter.Version ?? string.Empty; - this.MeterTags = instrument.Meter.Tags ?? Enumerable.Empty>(); + this.MeterTags = instrument.Meter.Tags; this.InstrumentName = metricStreamConfiguration?.Name ?? instrument.Name; this.Unit = instrument.Unit ?? string.Empty; this.Description = metricStreamConfiguration?.Description ?? instrument.Description ?? string.Empty; @@ -104,7 +104,7 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration? me public string MeterVersion { get; } - public IEnumerable> MeterTags { get; } + public IEnumerable>? MeterTags { get; } public string InstrumentName { get; } From 7baed5d0b55d677d506a9780809927aef5866a20 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 13:41:58 -0800 Subject: [PATCH 13/17] add unit test to confirm the nonidentity of meter tags --- .../Metrics/MetricApiTestsBase.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index 6022f030620..7a6ea647452 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -208,6 +208,53 @@ public void MetricInstrumentationScopeIsExportedCorrectly() Assert.True(containsMeterTags); } + [Fact] + public void MetricInstrumentationScopeAttributesAreNotTreatedAsIdentifyingProperty() + { + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#get-a-meter + // Meters are identified by name, version, and schema_url fields + // and not with tags. + var exportedItems = new List(); + var meterName = "MyMeter"; + var meterVersion = "1.0"; + var meterTags1 = new List> + { + new( + "Key1", + "Value1"), + }; + var meterTags2 = new List> + { + new( + "Key2", + "Value2"), + }; + using var meter1 = new Meter(meterName, meterVersion, meterTags1); + using var meter2 = new Meter(meterName, meterVersion, meterTags2); + using var container = this.BuildMeterProvider(out var meterProvider, builder => builder + .AddMeter(meterName) + .AddInMemoryExporter(exportedItems)); + + var counter1 = meter1.CreateCounter("my-counter"); + counter1.Add(10); + var counter2 = meter2.CreateCounter("my-counter"); + counter2.Add(10); + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + // The instruments differ only in the Meter.Tags, which is not an identifying property. + // The first instrument's Meter.Tags is exported. + // It is considered a user-error to create Meters with same name,version but with + // different tags. TODO: See if we can emit an internal log about this. + Assert.Single(exportedItems); + var metric = exportedItems[0]; + Assert.Equal(meterName, metric.MeterName); + Assert.Equal(meterVersion, metric.MeterVersion); + + bool containsMeterTags = metric.MeterTags.Any(kvp => + kvp.Key == meterTags1[0].Key && Equals(kvp.Value, meterTags1[0].Value)); + Assert.True(containsMeterTags); + } + [Fact] public void DuplicateInstrumentRegistration_NoViews_IdenticalInstruments() { From 3ac1cf5ef565111a5edb6d48da958a6efe2e052d Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 13:57:39 -0800 Subject: [PATCH 14/17] console cl --- src/OpenTelemetry.Exporter.Console/CHANGELOG.md | 3 +++ src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 3255a0371d4..97f7672fd84 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing + issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ## 1.7.0-alpha.1 Released 2023-Oct-16 diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs index 232fcc8294e..fe45b0cf118 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleMetricExporter.cs @@ -80,7 +80,7 @@ public override ExportResult Export(in Batch batch) this.WriteLine("\tMeter Tags:"); if (ConsoleTagTransformer.Instance.TryTransformTag(meterTag, out var result)) { - this.WriteLine($"\t {result}"); + this.WriteLine($"\t\t{result}"); } } From f2b7bacf3dcde19cb8536f41debb6a846f46e1b8 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 16:38:17 -0800 Subject: [PATCH 15/17] changelog gix --- src/OpenTelemetry.Exporter.Console/CHANGELOG.md | 7 +++++-- .../CHANGELOG.md | 7 +++++-- src/OpenTelemetry/CHANGELOG.md | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 97f7672fd84..976da186951 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,8 +2,11 @@ ## Unreleased -* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing - issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). +* Add support for Instrumentation Scope Attributes (i.e [Meter + Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.tags)), + fixing issue + [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ([#5089](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5089)) ## 1.7.0-alpha.1 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index c635bcd235b..62c49881578 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -15,8 +15,11 @@ accepts a `name` parameter to support named options. ([#4916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4916)) -* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing - issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). +* Add support for Instrumentation Scope Attributes (i.e [Meter + Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.tags)), + fixing issue + [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ([#5089](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5089)) ## 1.7.0-alpha.1 diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 76b989d6684..79926bb48d2 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -58,8 +58,11 @@ implementationFactory)`. ([#4916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4916)) -* Add support for Instrumentation Scope Attributes (i.e Meter Tags), fixing - issue [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). +* Add support for Instrumentation Scope Attributes (i.e [Meter + Tags](https://learn.microsoft.com/dotnet/api/system.diagnostics.metrics.meter.tags)), + fixing issue + [#4563](https://github.com/open-telemetry/opentelemetry-dotnet/issues/4563). + ([#5089](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5089)) ## 1.7.0-alpha.1 From d3ba4d4e51d52b23b66813dbaecda26892105d65 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 28 Nov 2023 16:42:48 -0800 Subject: [PATCH 16/17] better test asserts --- .../Metrics/MetricApiTestsBase.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index 7a6ea647452..6af083a14cb 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -203,9 +203,7 @@ public void MetricInstrumentationScopeIsExportedCorrectly() Assert.Equal(meterName, metric.MeterName); Assert.Equal(meterVersion, metric.MeterVersion); - bool containsMeterTags = metric.MeterTags.Any(kvp => - kvp.Key == meterTags[0].Key && Equals(kvp.Value, meterTags[0].Value)); - Assert.True(containsMeterTags); + Assert.Single(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags[0].Key && kvp.Value == meterTags[0].Value)); } [Fact] @@ -238,7 +236,7 @@ public void MetricInstrumentationScopeAttributesAreNotTreatedAsIdentifyingProper var counter1 = meter1.CreateCounter("my-counter"); counter1.Add(10); var counter2 = meter2.CreateCounter("my-counter"); - counter2.Add(10); + counter2.Add(15); meterProvider.ForceFlush(MaxTimeToAllowForFlush); // The instruments differ only in the Meter.Tags, which is not an identifying property. @@ -250,9 +248,18 @@ public void MetricInstrumentationScopeAttributesAreNotTreatedAsIdentifyingProper Assert.Equal(meterName, metric.MeterName); Assert.Equal(meterVersion, metric.MeterVersion); - bool containsMeterTags = metric.MeterTags.Any(kvp => - kvp.Key == meterTags1[0].Key && Equals(kvp.Value, meterTags1[0].Value)); - Assert.True(containsMeterTags); + Assert.Single(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags1[0].Key && kvp.Value == meterTags1[0].Value)); + Assert.DoesNotContain(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags2[0].Key && kvp.Value == meterTags2[0].Value)); + + List metricPoints = new List(); + foreach (ref readonly var mp in metric.GetMetricPoints()) + { + metricPoints.Add(mp); + } + + Assert.Single(metricPoints); + var metricPoint1 = metricPoints[0]; + Assert.Equal(25, metricPoint1.GetSumLong()); } [Fact] From 505bb7d35e4cf9f73b22d491856364b02dc1dcbe Mon Sep 17 00:00:00 2001 From: "Cijo Thomas (from Dev Box)" Date: Tue, 28 Nov 2023 16:45:48 -0800 Subject: [PATCH 17/17] fix test logic --- test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs index 6af083a14cb..2f077636c08 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricApiTestsBase.cs @@ -203,7 +203,7 @@ public void MetricInstrumentationScopeIsExportedCorrectly() Assert.Equal(meterName, metric.MeterName); Assert.Equal(meterVersion, metric.MeterVersion); - Assert.Single(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags[0].Key && kvp.Value == meterTags[0].Value)); + Assert.Single(metric.MeterTags.Where(kvp => kvp.Key == meterTags[0].Key && kvp.Value == meterTags[0].Value)); } [Fact] @@ -248,8 +248,8 @@ public void MetricInstrumentationScopeAttributesAreNotTreatedAsIdentifyingProper Assert.Equal(meterName, metric.MeterName); Assert.Equal(meterVersion, metric.MeterVersion); - Assert.Single(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags1[0].Key && kvp.Value == meterTags1[0].Value)); - Assert.DoesNotContain(metric.MeterTags.Attributes.Where(kvp => kvp.Key == meterTags2[0].Key && kvp.Value == meterTags2[0].Value)); + Assert.Single(metric.MeterTags.Where(kvp => kvp.Key == meterTags1[0].Key && kvp.Value == meterTags1[0].Value)); + Assert.Empty(metric.MeterTags.Where(kvp => kvp.Key == meterTags2[0].Key && kvp.Value == meterTags2[0].Value)); List metricPoints = new List(); foreach (ref readonly var mp in metric.GetMetricPoints())