From f53d8b644881014cae3beb6ee4d498c75147dac9 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 23 Sep 2021 14:10:44 -0400 Subject: [PATCH 001/111] Squashed commit of the following: commit 080927d4659354b2cac5a5d0ee7eba534c928cc2 Author: Cijo Thomas Date: Thu Sep 23 10:07:05 2021 -0700 Changelog update for 1.2.0.alpha4 (#2407) commit 61aaf2e6ed89238e5a90c657905b063aaa9ff132 Author: Reiley Yang Date: Thu Sep 23 09:37:18 2021 -0700 Simplify tutorials (#2406) commit 78baf7c261100c6ad4ee00607cf242a303681d78 Author: Reiley Yang Date: Thu Sep 23 08:02:09 2021 -0700 Implement the metrics dispose/shutdown logic (#2404) commit 256fc2d2fec5e1dee3393f58168e1e193ae9871f Author: Michael Maxwell Date: Wed Sep 22 17:35:15 2021 -0400 Use `Stopwatch.StartNew()` (#2403) --- OpenTelemetry.sln | 18 +---- README.md | 2 +- docs/metrics/README.md | 6 -- docs/metrics/extending-the-sdk/MyReader.cs | 3 +- .../metrics/getting-started-counter/README.md | 77 ------------------- docs/metrics/getting-started-gauge/Program.cs | 45 ----------- .../getting-started-histogram/README.md | 67 ---------------- .../getting-started-histogram.csproj | 6 -- .../Program.cs | 45 ----------- .../README.md | 63 --------------- .../getting-started-observable-counter.csproj | 6 -- .../Program.cs | 12 +-- .../README.md | 28 ++++--- .../getting-started.csproj} | 0 .../Program.cs | 27 ++++++- .../learning-more-instruments/README.md | 3 + .../learning-more-instruments.csproj} | 0 src/OpenTelemetry.Api/CHANGELOG.md | 4 + .../CHANGELOG.md | 4 + .../ConsoleExporterMetricsExtensions.cs | 7 ++ .../ConsoleExporterOptions.cs | 5 +- .../CHANGELOG.md | 4 + .../CHANGELOG.md | 4 + .../CHANGELOG.md | 4 + .../CHANGELOG.md | 4 + .../CHANGELOG.md | 4 + src/OpenTelemetry/CHANGELOG.md | 4 + .../Metrics/BaseExportingMetricReader.cs | 19 ++++- src/OpenTelemetry/Metrics/MetricReader.cs | 2 +- .../MetricTests.cs | 3 - .../HttpClientTests.netcore31.cs | 3 - .../Metrics/MetricAPITest.cs | 6 +- test/StressTestMetrics/Program.cs | 3 +- 33 files changed, 117 insertions(+), 371 deletions(-) delete mode 100644 docs/metrics/README.md delete mode 100644 docs/metrics/getting-started-counter/README.md delete mode 100644 docs/metrics/getting-started-gauge/Program.cs delete mode 100644 docs/metrics/getting-started-histogram/README.md delete mode 100644 docs/metrics/getting-started-histogram/getting-started-histogram.csproj delete mode 100644 docs/metrics/getting-started-observable-counter/Program.cs delete mode 100644 docs/metrics/getting-started-observable-counter/README.md delete mode 100644 docs/metrics/getting-started-observable-counter/getting-started-observable-counter.csproj rename docs/metrics/{getting-started-counter => getting-started}/Program.cs (69%) rename docs/metrics/{getting-started-gauge => getting-started}/README.md (59%) rename docs/metrics/{getting-started-counter/getting-started-counter.csproj => getting-started/getting-started.csproj} (100%) rename docs/metrics/{getting-started-histogram => learning-more-instruments}/Program.cs (55%) create mode 100644 docs/metrics/learning-more-instruments/README.md rename docs/metrics/{getting-started-gauge/getting-started-observable-gauge.csproj => learning-more-instruments/learning-more-instruments.csproj} (100%) diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 3e98154fc26..570f9212a42 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -212,13 +212,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentati EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Tests", "test\OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Tests\OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.Tests.csproj", "{4D7201BC-7124-4401-AD65-FAB58A053D45}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-histogram", "docs\metrics\getting-started-histogram\getting-started-histogram.csproj", "{92ED77A6-37B4-447D-B4C4-15DB005A589C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "learning-more-instruments", "docs\metrics\learning-more-instruments\learning-more-instruments.csproj", "{E7F491CC-C37E-4A56-9CA7-8F77F59E0614}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-observable-gauge", "docs\metrics\getting-started-gauge\getting-started-observable-gauge.csproj", "{E7F491CC-C37E-4A56-9CA7-8F77F59E0614}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-observable-counter", "docs\metrics\getting-started-observable-counter\getting-started-observable-counter.csproj", "{43005998-0247-4620-AF88-27DACD48712E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started-counter", "docs\metrics\getting-started-counter\getting-started-counter.csproj", "{EA60B549-F712-4ABE-8E44-FCA83B78C06E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "docs\metrics\getting-started\getting-started.csproj", "{EA60B549-F712-4ABE-8E44-FCA83B78C06E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "extending-the-sdk", "docs\metrics\extending-the-sdk\extending-the-sdk.csproj", "{1F9D7748-D099-4E25-97F5-9C969D6FF969}" EndProject @@ -430,18 +426,10 @@ Global {4D7201BC-7124-4401-AD65-FAB58A053D45}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D7201BC-7124-4401-AD65-FAB58A053D45}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D7201BC-7124-4401-AD65-FAB58A053D45}.Release|Any CPU.Build.0 = Release|Any CPU - {92ED77A6-37B4-447D-B4C4-15DB005A589C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92ED77A6-37B4-447D-B4C4-15DB005A589C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92ED77A6-37B4-447D-B4C4-15DB005A589C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92ED77A6-37B4-447D-B4C4-15DB005A589C}.Release|Any CPU.Build.0 = Release|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Release|Any CPU.Build.0 = Release|Any CPU - {43005998-0247-4620-AF88-27DACD48712E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43005998-0247-4620-AF88-27DACD48712E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43005998-0247-4620-AF88-27DACD48712E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43005998-0247-4620-AF88-27DACD48712E}.Release|Any CPU.Build.0 = Release|Any CPU {EA60B549-F712-4ABE-8E44-FCA83B78C06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA60B549-F712-4ABE-8E44-FCA83B78C06E}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA60B549-F712-4ABE-8E44-FCA83B78C06E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -485,9 +473,7 @@ Global {972396A8-E35B-499C-9BA1-765E9B8822E1} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F} {08D29501-F0A3-468F-B18D-BD1821A72383} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818} {64E3D8BB-93AB-4571-93F7-ED8D64DFFD06} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818} - {92ED77A6-37B4-447D-B4C4-15DB005A589C} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} {E7F491CC-C37E-4A56-9CA7-8F77F59E0614} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} - {43005998-0247-4620-AF88-27DACD48712E} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} {EA60B549-F712-4ABE-8E44-FCA83B78C06E} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} {A885DBE2-4B82-432C-A77B-19844D7BBC96} = {0169B149-FB8B-46F4-9EF7-8A0E69F8FAAF} {1F9D7748-D099-4E25-97F5-9C969D6FF969} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} diff --git a/README.md b/README.md index bee231f7a05..57de8832bcd 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Any exceptions to this are noted in the individual `README.md` files. If you are new here, please read the getting started docs: * [logs](./docs/logs/getting-started/README.md) -* [metrics](./docs/metrics/README.md) (experimental) +* [metrics](./docs/metrics/getting-started/README.md) (experimental) * [trace](./docs/trace/getting-started/README.md) This repository includes multiple installable components, available on diff --git a/docs/metrics/README.md b/docs/metrics/README.md deleted file mode 100644 index f7177c5af94..00000000000 --- a/docs/metrics/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Getting Started with OpenTelemetry .NET Metrics in 5 Minutes - -* [Getting started with Counter](./getting-started-counter/README.md) -* [Getting started with Observable Counter](./getting-started-observable-counter/README.md) -* [Getting started with Observable Gauge](./getting-started-gauge/README.md) -* [Getting started with Histogram](./getting-started-histogram/README.md) diff --git a/docs/metrics/extending-the-sdk/MyReader.cs b/docs/metrics/extending-the-sdk/MyReader.cs index 84cb64eabb0..f42ddb53e27 100644 --- a/docs/metrics/extending-the-sdk/MyReader.cs +++ b/docs/metrics/extending-the-sdk/MyReader.cs @@ -36,11 +36,12 @@ protected override bool ProcessMetrics(Batch metrics, int timeoutMillise protected override bool OnShutdown(int timeoutMilliseconds) { Console.WriteLine($"{this.name}.OnShutdown(timeoutMilliseconds={timeoutMilliseconds})"); - return true; + return base.OnShutdown(timeoutMilliseconds); } protected override void Dispose(bool disposing) { Console.WriteLine($"{this.name}.Dispose({disposing})"); + base.Dispose(disposing); } } diff --git a/docs/metrics/getting-started-counter/README.md b/docs/metrics/getting-started-counter/README.md deleted file mode 100644 index 290a59b3282..00000000000 --- a/docs/metrics/getting-started-counter/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Getting Started with OpenTelemetry .NET in 5 Minutes - -First, download and install the [.NET Core -SDK](https://dotnet.microsoft.com/download) on your computer. - -Create a new console application and run it: - -```sh -dotnet new console --output getting-started-counter -cd getting-started-counter -dotnet run -``` - -You should see the following output: - -```text -Hello World! -``` - -Install the -[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md) -package: - -```sh -dotnet add package --prerelease OpenTelemetry.Exporter.Console -``` - -Update the `Program.cs` file with the code from [Program.cs](./Program.cs): - -Run the application again (using `dotnet run`) and you should see the metric -output from the console, similar to shown below: - - -```text -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:37.1096398Z, 2021-09-03T04:29:38.0649233Z] tag1:value1tag2:value2 LongSum -Value: 460 - -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:38.0649233Z, 2021-09-03T04:29:39.1483639Z] tag1:value1tag2:value2 LongSum -Value: 640 - -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:39.1483639Z, 2021-09-03T04:29:40.1679696Z] tag1:value1tag2:value2 LongSum -Value: 420 - -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:40.1679696Z, 2021-09-03T04:29:41.1774527Z] tag1:value1tag2:value2 LongSum -Value: 560 - -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:41.1774527Z, 2021-09-03T04:29:42.1791523Z] tag1:value1tag2:value2 LongSum -Value: 650 - -Export MyCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 -(2021-09-03T04:29:42.1791523Z, 2021-09-03T04:29:43.1875033Z] tag1:value1tag2:value2 LongSum -Value: 620 -``` - - -Congratulations! You are now collecting metrics using OpenTelemetry. - -What does the above program do? - -The program creates a -[Meter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meter) -instance named "MyCompany.MyProduct.MyLibrary" and then creates a -[Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter) -instrument from it. This counter is used to repeatedly report metric -measurements until it reaches a certain number of loops. - -An OpenTelemetry -[MeterProvider](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meterprovider) -is configured to subscribe to instruments from the Meter -`MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory. The -pre-aggregated metrics are exported every 1 second to a `ConsoleExporter`. -`ConsoleExporter` simply displays it on the console. diff --git a/docs/metrics/getting-started-gauge/Program.cs b/docs/metrics/getting-started-gauge/Program.cs deleted file mode 100644 index 3082222ee33..00000000000 --- a/docs/metrics/getting-started-gauge/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Diagnostics.Metrics; -using System.Threading.Tasks; -using OpenTelemetry; -using OpenTelemetry.Metrics; - -public class Program -{ - private static readonly Meter MyMeter = new Meter("MyCompany.MyProduct.MyLibrary", "1.0"); - - public static async Task Main(string[] args) - { - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddSource("MyCompany.MyProduct.MyLibrary") - .AddConsoleExporter() - .Build(); - - var random = new Random(); - MyMeter.CreateObservableGauge( - "MyGauge", - () => new List>() - { - new(random.Next(1, 1000), new("tag1", "value1"), new("tag2", "value2")), - }); - - await Task.Delay(10000); - } -} diff --git a/docs/metrics/getting-started-histogram/README.md b/docs/metrics/getting-started-histogram/README.md deleted file mode 100644 index fd57a48c7fd..00000000000 --- a/docs/metrics/getting-started-histogram/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Getting Started with OpenTelemetry .NET in 5 Minutes - -First, download and install the [.NET Core -SDK](https://dotnet.microsoft.com/download) on your computer. - -Create a new console application and run it: - -```sh -dotnet new console --output getting-started-histogram -cd getting-started-histogram -dotnet run -``` - -You should see the following output: - -```text -Hello World! -``` - -Install the -[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md) -package: - -```sh -dotnet add package --prerelease OpenTelemetry.Exporter.Console -``` - -Update the `Program.cs` file with the code from [Program.cs](./Program.cs): - -Run the application again (using `dotnet run`) and you should see the metric -output from the console, similar to shown below: - - -```text -Export (2021-09-02T01:02:09.8013446Z, 2021-09-02T01:02:19.9749573Z] histogram tag1=value1;tag2=value2 Histogram, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: Sum: 304929 Count: 623 -(-Infinity, 0]: 0 -(0, 5]: 5 -(5, 10]: 5 -(10, 25]: 14 -(25, 50]: 15 -(50, 75]: 18 -(75, 100]: 17 -(100, 250]: 91 -(250, 500]: 158 -(500, 1000]: 300 -(1000, +Infinity): 0 -``` - - -Congratulations! You are now collecting histogram metrics using OpenTelemetry. - -What does the above program do? - -The program creates a -[Meter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meter) -instance named "MyCompany.MyProduct.MyLibrary" and then creates a -[Histogram](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#histogram) -instrument from it. This histogram is used to repeatedly report random metric -measurements until it reaches a certain number of loops. - -An OpenTelemetry -[MeterProvider](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meterprovider) -is configured to subscribe to instruments from the Meter -`MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory. The -pre-aggregated metrics are exported every 1 second to a `ConsoleExporter`. -`ConsoleExporter` simply displays it on the console. diff --git a/docs/metrics/getting-started-histogram/getting-started-histogram.csproj b/docs/metrics/getting-started-histogram/getting-started-histogram.csproj deleted file mode 100644 index 9f5b6b79bc3..00000000000 --- a/docs/metrics/getting-started-histogram/getting-started-histogram.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/docs/metrics/getting-started-observable-counter/Program.cs b/docs/metrics/getting-started-observable-counter/Program.cs deleted file mode 100644 index 7663f7bbef4..00000000000 --- a/docs/metrics/getting-started-observable-counter/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// 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.Generic; -using System.Diagnostics; -using System.Diagnostics.Metrics; -using System.Threading.Tasks; -using OpenTelemetry; -using OpenTelemetry.Metrics; - -public class Program -{ - private static readonly Meter MyMeter = new Meter("MyCompany.MyProduct.MyLibrary", "1.0"); - - public static async Task Main(string[] args) - { - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddSource("MyCompany.MyProduct.MyLibrary") - .AddConsoleExporter() - .Build(); - - var process = Process.GetCurrentProcess(); - MyMeter.CreateObservableCounter( - "ProcessCpuTime", - () => new List>() - { - new(process.TotalProcessorTime.TotalMilliseconds, new("tag1", "value1"), new("tag2", "value2")), - }); - - await Task.Delay(10000); - } -} diff --git a/docs/metrics/getting-started-observable-counter/README.md b/docs/metrics/getting-started-observable-counter/README.md deleted file mode 100644 index c470b1e45ee..00000000000 --- a/docs/metrics/getting-started-observable-counter/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Getting Started with OpenTelemetry .NET in 5 Minutes - -First, download and install the [.NET Core -SDK](https://dotnet.microsoft.com/download) on your computer. - -Create a new console application and run it: - -```sh -dotnet new console --output getting-started-observable-counter -cd getting-started-observable-counter -dotnet run -``` - -You should see the following output: - -```text -Hello World! -``` - -Install the -[OpenTelemetry.Exporter.Console](../../../src/OpenTelemetry.Exporter.Console/README.md) -package: - -```sh -dotnet add package --prerelease OpenTelemetry.Exporter.Console -``` - -Update the `Program.cs` file with the code from [Program.cs](./Program.cs): - -Run the application again (using `dotnet run`) and you should see the metric -output from the console, similar to shown below: - - -```text -Service.Nameunknown_service:getting-started-observable-counter -Export 16:35:25.669 16:35:25.670 observable-counter [tag1=value1;tag2=value2] LongSum, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 10 -Export 16:35:25.669 16:35:26.698 observable-counter [tag1=value1;tag2=value2] LongSum, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 20 -Export 16:35:25.669 16:35:27.711 observable-counter [tag1=value1;tag2=value2] LongSum, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 30 -Export 16:35:25.669 16:35:28.729 observable-counter [tag1=value1;tag2=value2] LongSum, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 40 -``` - - -Congratulations! You are now collecting metrics using OpenTelemetry. - -What does the above program do? - -The program creates a -[Meter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meter) -instance named "MyCompany.MyProduct.MyLibrary" and then creates a [Asynchronous -Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-counter) -instrument from it. This Counter reports an ever increasing number as its -measurement until exited after 10 seconds. - -An OpenTelemetry -[MeterProvider](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meterprovider) -is configured to subscribe to instruments from the Meter -`MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory. The -pre-aggregated metrics are exported every 1 second to a `ConsoleExporter`. -`ConsoleExporter` simply displays it on the console. diff --git a/docs/metrics/getting-started-observable-counter/getting-started-observable-counter.csproj b/docs/metrics/getting-started-observable-counter/getting-started-observable-counter.csproj deleted file mode 100644 index 9f5b6b79bc3..00000000000 --- a/docs/metrics/getting-started-observable-counter/getting-started-observable-counter.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/docs/metrics/getting-started-counter/Program.cs b/docs/metrics/getting-started/Program.cs similarity index 69% rename from docs/metrics/getting-started-counter/Program.cs rename to docs/metrics/getting-started/Program.cs index d560d11eca6..b4ef547bc75 100644 --- a/docs/metrics/getting-started-counter/Program.cs +++ b/docs/metrics/getting-started/Program.cs @@ -29,11 +29,13 @@ public static void Main(string[] args) .AddConsoleExporter() .Build(); - var counter = MyMeter.CreateCounter("MyCounter"); + var counter = MyMeter.CreateCounter("MyFruitCounter"); - for (int i = 0; i < 20000000; i++) - { - counter.Add(1, new("tag1", "value1"), new("tag2", "value2")); - } + counter.Add(1, new("name", "apple"), new("color", "red")); + counter.Add(2, new("name", "lemon"), new("color", "yellow")); + counter.Add(1, new("name", "lemon"), new("color", "yellow")); + counter.Add(2, new("name", "apple"), new("color", "green")); + counter.Add(5, new("name", "apple"), new("color", "red")); + counter.Add(4, new("name", "lemon"), new("color", "yellow")); } } diff --git a/docs/metrics/getting-started-gauge/README.md b/docs/metrics/getting-started/README.md similarity index 59% rename from docs/metrics/getting-started-gauge/README.md rename to docs/metrics/getting-started/README.md index 6185d374e68..59d89c9dbb4 100644 --- a/docs/metrics/getting-started-gauge/README.md +++ b/docs/metrics/getting-started/README.md @@ -6,8 +6,8 @@ SDK](https://dotnet.microsoft.com/download) on your computer. Create a new console application and run it: ```sh -dotnet new console --output getting-started-observable-gauge -cd getting-started-observable-gauge +dotnet new console --output getting-started +cd getting-started dotnet run ``` @@ -32,13 +32,13 @@ output from the console, similar to shown below: ```text -Service.Nameunknown_service:getting-started-observable-gauge -Export 15:44:05.262 15:44:05.263 Gauge [tag1=value1;tag2=value2] LongGauge, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 306 -Export 15:44:05.262 15:44:06.290 Gauge [tag1=value1;tag2=value2] LongGauge, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 693 -Export 15:44:05.262 15:44:07.302 Gauge [tag1=value1;tag2=value2] LongGauge, Meter: MyCompany.MyProduct.MyLibrary/1.0 -Value: 78 +Export MyFruitCounter, Meter: MyCompany.MyProduct.MyLibrary/1.0 +2021-09-23T03:17:30.6198292Z, 2021-09-23T03:17:30.6356517Z] color:redname:apple LongSum +Value: 6 +2021-09-23T03:17:30.6198292Z, 2021-09-23T03:17:30.6356517Z] color:yellowname:lemon LongSum +Value: 7 +2021-09-23T03:17:30.6198292Z, 2021-09-23T03:17:30.6356517Z] color:greenname:apple LongSum +Value: 2 ``` @@ -48,14 +48,12 @@ What does the above program do? The program creates a [Meter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meter) -instance named "MyCompany.MyProduct.MyLibrary" and then creates a [Asynchronous -Gauge](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#asynchronous-gauge) -instrument from it. This Gauge reports a randomly generated number as its -measurement until exited after 10 seconds. +instance named "MyCompany.MyProduct.MyLibrary" and then creates a +[Counter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#counter) +instrument from it. This counter is used to report several metric measurements. An OpenTelemetry [MeterProvider](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meterprovider) is configured to subscribe to instruments from the Meter `MyCompany.MyProduct.MyLibrary`, and aggregate the measurements in-memory. The -pre-aggregated metrics are exported every 1 second to a `ConsoleExporter`. -`ConsoleExporter` simply displays it on the console. +pre-aggregated metrics are exported to a `ConsoleExporter`. diff --git a/docs/metrics/getting-started-counter/getting-started-counter.csproj b/docs/metrics/getting-started/getting-started.csproj similarity index 100% rename from docs/metrics/getting-started-counter/getting-started-counter.csproj rename to docs/metrics/getting-started/getting-started.csproj diff --git a/docs/metrics/getting-started-histogram/Program.cs b/docs/metrics/learning-more-instruments/Program.cs similarity index 55% rename from docs/metrics/getting-started-histogram/Program.cs rename to docs/metrics/learning-more-instruments/Program.cs index b28b0f9e5c3..0691e96e692 100644 --- a/docs/metrics/getting-started-histogram/Program.cs +++ b/docs/metrics/learning-more-instruments/Program.cs @@ -15,6 +15,8 @@ // using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Metrics; using OpenTelemetry; using OpenTelemetry.Metrics; @@ -30,12 +32,33 @@ public static void Main(string[] args) .AddConsoleExporter() .Build(); + var process = Process.GetCurrentProcess(); + + MyMeter.CreateObservableCounter("Thread.CpuTime", () => GetThreadCpuTime(process), "seconds"); + + MyMeter.CreateObservableGauge("Thread.State", () => GetThreadState(process)); + var random = new Random(); var histogram = MyMeter.CreateHistogram("MyHistogram"); + for (int i = 0; i < 1000; i++) + { + histogram.Record(random.Next(1, 1000)); + } + } - for (int i = 0; i < 20000000; i++) + private static IEnumerable> GetThreadCpuTime(Process process) + { + foreach (ProcessThread thread in process.Threads) + { + yield return new(thread.TotalProcessorTime.TotalMilliseconds, new("ProcessId", process.Id), new("ThreadId", thread.Id)); + } + } + + private static IEnumerable> GetThreadState(Process process) + { + foreach (ProcessThread thread in process.Threads) { - histogram.Record(random.Next(1, 1000), new("tag1", "value1"), new("tag2", "value2")); + yield return new((int)thread.ThreadState, new("ProcessId", process.Id), new("ThreadId", thread.Id)); } } } diff --git a/docs/metrics/learning-more-instruments/README.md b/docs/metrics/learning-more-instruments/README.md new file mode 100644 index 00000000000..768f0c52382 --- /dev/null +++ b/docs/metrics/learning-more-instruments/README.md @@ -0,0 +1,3 @@ +# Learning more about Instruments + +TBD diff --git a/docs/metrics/getting-started-gauge/getting-started-observable-gauge.csproj b/docs/metrics/learning-more-instruments/learning-more-instruments.csproj similarity index 100% rename from docs/metrics/getting-started-gauge/getting-started-observable-gauge.csproj rename to docs/metrics/learning-more-instruments/learning-more-instruments.csproj diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 6ae34651961..273ab4fba3a 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + * Updated System.Diagnostics.DiagnosticSource to version 6.0.0-rc.1.21451.13 ## 1.2.0-alpha3 diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index d6fff879d82..7ae3d4f1b01 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs index 6ad8ba1402f..258d418ce92 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterMetricsExtensions.cs @@ -15,6 +15,7 @@ // using System; +using System.Threading; using OpenTelemetry.Exporter; namespace OpenTelemetry.Metrics @@ -39,6 +40,12 @@ public static MeterProviderBuilder AddConsoleExporter(this MeterProviderBuilder configure?.Invoke(options); var exporter = new ConsoleMetricExporter(options); + + if (options.MetricExportIntervalMilliseconds == Timeout.Infinite) + { + return builder.AddMetricReader(new BaseExportingMetricReader(exporter)); + } + return builder.AddMetricReader(new PeriodicExportingMetricReader(exporter, options.MetricExportIntervalMilliseconds)); } } diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleExporterOptions.cs b/src/OpenTelemetry.Exporter.Console/ConsoleExporterOptions.cs index 85ab099748b..3c75ef2d9d1 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleExporterOptions.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System.Threading; using OpenTelemetry.Metrics; namespace OpenTelemetry.Exporter @@ -26,9 +27,9 @@ public class ConsoleExporterOptions public ConsoleExporterOutputTargets Targets { get; set; } = ConsoleExporterOutputTargets.Console; /// - /// Gets or sets the metric export interval in milliseconds. The default value is 1000 milliseconds. + /// Gets or sets the metric export interval in milliseconds. The default value is Timeout.Infinite. /// - public int MetricExportIntervalMilliseconds { get; set; } = 1000; + public int MetricExportIntervalMilliseconds { get; set; } = Timeout.Infinite; /// /// Gets or sets the AggregationTemporality used for Histogram diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md index 47a93c99fe1..ff0a7b0c913 100644 --- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 0df9973e436..2813491f84d 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 76b5920cc6b..35f7cb13124 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md index 6042a99e2e9..0db52ab39ba 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index b0db090ef54..955d56d15a4 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + ## 1.2.0-alpha3 Released 2021-Sep-13 diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 613a4fa91dd..949d26e42b2 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.2.0-alpha4 + +Released 2021-Sep-23 + * `BatchExportProcessor.OnShutdown` will now log the count of dropped telemetry items. ([#2331](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2331)) * Changed `CompositeProcessor.OnForceFlush` to meet with the spec diff --git a/src/OpenTelemetry/Metrics/BaseExportingMetricReader.cs b/src/OpenTelemetry/Metrics/BaseExportingMetricReader.cs index 06409b924a5..058d590be77 100644 --- a/src/OpenTelemetry/Metrics/BaseExportingMetricReader.cs +++ b/src/OpenTelemetry/Metrics/BaseExportingMetricReader.cs @@ -15,6 +15,8 @@ // using System; +using System.Diagnostics; +using System.Threading; namespace OpenTelemetry.Metrics { @@ -97,7 +99,22 @@ protected override bool OnCollect(int timeoutMilliseconds) /// protected override bool OnShutdown(int timeoutMilliseconds) { - return this.exporter.Shutdown(timeoutMilliseconds); + var result = true; + + if (timeoutMilliseconds == Timeout.Infinite) + { + result = this.Collect(Timeout.Infinite) && result; + result = this.exporter.Shutdown(Timeout.Infinite) && result; + } + else + { + var sw = Stopwatch.StartNew(); + result = this.Collect(timeoutMilliseconds) && result; + var timeout = timeoutMilliseconds - sw.ElapsedMilliseconds; + result = this.exporter.Shutdown((int)Math.Max(timeout, 0)) && result; + } + + return result; } /// diff --git a/src/OpenTelemetry/Metrics/MetricReader.cs b/src/OpenTelemetry/Metrics/MetricReader.cs index fe300d75527..65a8a47d2fe 100644 --- a/src/OpenTelemetry/Metrics/MetricReader.cs +++ b/src/OpenTelemetry/Metrics/MetricReader.cs @@ -211,7 +211,7 @@ protected virtual bool OnCollect(int timeoutMilliseconds) /// protected virtual bool OnShutdown(int timeoutMilliseconds) { - return true; + return this.Collect(timeoutMilliseconds); } /// diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 85461b349d9..b71a74b3f78 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -84,9 +84,6 @@ void ProcessExport(Batch batch) // giving some breezing room for the End callback to complete await Task.Delay(TimeSpan.FromSeconds(1)); - // Invokes the TestExporter which will invoke ProcessExport - metricReader.Collect(); - this.meterProvider.Dispose(); var requestMetrics = metricItems diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index 1227347b9f9..c2fbccac6a3 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -112,9 +112,6 @@ void ProcessExport(Batch batch) } } - // Invokes the TestExporter which will invoke ProcessExport - metricReader.Collect(); - meterProvider.Dispose(); var requestMetrics = metricItems diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 668a6aa1328..f2e06df3a31 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -284,8 +284,7 @@ void ProcessExport(Batch batch) // Block until all threads started. mreToEnsureAllThreadsStarted.WaitOne(); - Stopwatch sw = new Stopwatch(); - sw.Start(); + Stopwatch sw = Stopwatch.StartNew(); // unblock all the threads. // (i.e let them start counter.Add) @@ -354,8 +353,7 @@ void ProcessExport(Batch batch) // Block until all threads started. mreToEnsureAllThreadsStarted.WaitOne(); - Stopwatch sw = new Stopwatch(); - sw.Start(); + Stopwatch sw = Stopwatch.StartNew(); // unblock all the threads. // (i.e let them start counter.Add) diff --git a/test/StressTestMetrics/Program.cs b/test/StressTestMetrics/Program.cs index bd2e102f957..872fb4af49e 100644 --- a/test/StressTestMetrics/Program.cs +++ b/test/StressTestMetrics/Program.cs @@ -38,8 +38,7 @@ public static void Main(string[] args) using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddSource("TestMeter") .Build(); - Stopwatch sw = new Stopwatch(); - sw.Start(); + Stopwatch sw = Stopwatch.StartNew(); Parallel.Invoke( () => From ccd3b53d56e63a7f9f1965f738138715e7bbe575 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 18 Oct 2021 15:32:48 -0700 Subject: [PATCH 002/111] Guard Type summary comment fix --- src/OpenTelemetry.Api/Internal/Guard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Api/Internal/Guard.cs b/src/OpenTelemetry.Api/Internal/Guard.cs index 73f5caa261f..b3ca0c9c4b9 100644 --- a/src/OpenTelemetry.Api/Internal/Guard.cs +++ b/src/OpenTelemetry.Api/Internal/Guard.cs @@ -136,7 +136,7 @@ public static void Range(double value, string paramName = DefaultParamName, doub } /// - /// Throw an exception if the value is not within the given range. + /// Throw an exception if the value is not of the expected type. /// /// The value to check. /// The parameter name to use in the thrown exception. From 1cac13fc9a3047bd6a7a2b77f3844a728fb0ccff Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 18 Oct 2021 16:27:55 -0700 Subject: [PATCH 003/111] Update TracerProviderBuilder.cs --- src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs index e902a38722e..f63564ec9bd 100644 --- a/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs +++ b/src/OpenTelemetry.Api/Trace/TracerProviderBuilder.cs @@ -51,7 +51,7 @@ public abstract TracerProviderBuilder AddInstrumentation( /// Adds a listener for objects created with the given operation name to the . /// /// - /// This is provided to capture legacy objects created without using the API. + /// This is provided to capture legacy objects created without using the API. /// /// Operation name of the objects to capture. /// Returns for chaining. From d971dae3059cf41b89a9894d48b241f1fdfea9c0 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 11:45:49 -0700 Subject: [PATCH 004/111] TryFetch optional param to skip obj null check --- .../DiagnosticSourceInstrumentation/PropertyFetcher.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs b/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs index e77e702b538..1070b5f04bd 100644 --- a/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs +++ b/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs @@ -48,7 +48,7 @@ public T Fetch(object obj) { Guard.Null(obj, nameof(obj)); - if (!this.TryFetch(obj, out T value)) + if (!this.TryFetch(obj, out T value, true)) { throw new ArgumentException($"Unable to fetch property: '{nameof(obj)}'", nameof(obj)); } @@ -61,10 +61,11 @@ public T Fetch(object obj) /// /// Object to be fetched. /// Fetched value. - /// if the property was fetched. - public bool TryFetch(object obj, out T value) + /// Set this to if we know is not . + /// if the property was fetched. + public bool TryFetch(object obj, out T value, bool skipObjNullCheck = false) { - if (obj == null) + if (skipObjNullCheck || obj == null) { value = default; return false; From 8ba84c58020741a04c865c207c4e8457b6d02ba2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 11:47:42 -0700 Subject: [PATCH 005/111] Make guard internal --- src/OpenTelemetry.Api/Internal/Guard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Api/Internal/Guard.cs b/src/OpenTelemetry.Api/Internal/Guard.cs index b3ca0c9c4b9..a2d0da79d61 100644 --- a/src/OpenTelemetry.Api/Internal/Guard.cs +++ b/src/OpenTelemetry.Api/Internal/Guard.cs @@ -24,7 +24,7 @@ namespace OpenTelemetry.Internal /// /// Methods for guarding against exception throwing values. /// - public static class Guard + internal static class Guard { private const string DefaultParamName = "N/A"; From 45d4caf915871ea139c1ce6d5591d5de0c1a666d Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 11:47:54 -0700 Subject: [PATCH 006/111] GuardTest doesn't need to be a static class --- test/OpenTelemetry.Tests/Internal/GuardTest.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/OpenTelemetry.Tests/Internal/GuardTest.cs b/test/OpenTelemetry.Tests/Internal/GuardTest.cs index 8b1e666694b..64bd41accbe 100644 --- a/test/OpenTelemetry.Tests/Internal/GuardTest.cs +++ b/test/OpenTelemetry.Tests/Internal/GuardTest.cs @@ -21,10 +21,10 @@ namespace OpenTelemetry.Tests.Internal { - public static class GuardTest + public class GuardTest { [Fact] - public static void NullTest() + public void NullTest() { // Valid Guard.Null(1); @@ -38,7 +38,7 @@ public static void NullTest() } [Fact] - public static void NullOrEmptyTest() + public void NullOrEmptyTest() { // Valid Guard.NullOrEmpty("a"); @@ -53,7 +53,7 @@ public static void NullOrEmptyTest() } [Fact] - public static void NullOrWhitespaceTest() + public void NullOrWhitespaceTest() { // Valid Guard.NullOrWhitespace("a"); @@ -70,7 +70,7 @@ public static void NullOrWhitespaceTest() } [Fact] - public static void InvalidTimeoutTest() + public void InvalidTimeoutTest() { // Valid Guard.InvalidTimeout(Timeout.Infinite); @@ -83,7 +83,7 @@ public static void InvalidTimeoutTest() } [Fact] - public static void RangeIntTest() + public void RangeIntTest() { // Valid Guard.Range(0); @@ -101,7 +101,7 @@ public static void RangeIntTest() } [Fact] - public static void RangeDoubleTest() + public void RangeDoubleTest() { // Valid Guard.Range(1.0, min: 1.0, max: 1.0); @@ -117,7 +117,7 @@ public static void RangeDoubleTest() } [Fact] - public static void TypeTest() + public void TypeTest() { // Valid Guard.Type(0); @@ -130,7 +130,7 @@ public static void TypeTest() } [Fact] - public static void ZeroTest() + public void ZeroTest() { // Valid Guard.Zero(1); From 0b4c80ec3cd6c9c743d6ceed524aacebee55f054 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 13:15:32 -0700 Subject: [PATCH 007/111] Update src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit yes thank you, good catch Co-authored-by: Robert PajÄ…k --- .../DiagnosticSourceInstrumentation/PropertyFetcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs b/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs index 1070b5f04bd..debe49a679a 100644 --- a/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs +++ b/src/OpenTelemetry/DiagnosticSourceInstrumentation/PropertyFetcher.cs @@ -65,7 +65,7 @@ public T Fetch(object obj) /// if the property was fetched. public bool TryFetch(object obj, out T value, bool skipObjNullCheck = false) { - if (skipObjNullCheck || obj == null) + if (!skipObjNullCheck && obj == null) { value = default; return false; From 964e9a65cd256203045a015f678cf6c008bb4cd0 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 13:26:51 -0700 Subject: [PATCH 008/111] Update Guard.cs --- src/OpenTelemetry.Api/Internal/Guard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Api/Internal/Guard.cs b/src/OpenTelemetry.Api/Internal/Guard.cs index a2d0da79d61..ae6e816ae06 100644 --- a/src/OpenTelemetry.Api/Internal/Guard.cs +++ b/src/OpenTelemetry.Api/Internal/Guard.cs @@ -140,7 +140,7 @@ public static void Range(double value, string paramName = DefaultParamName, doub /// /// The value to check. /// The parameter name to use in the thrown exception. - /// The type to attempt to convert to. + /// The type attempted to convert to. /// The value casted to the specified type. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] From 169547a83302202aeb69ba3f2c009b59443e3968 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 14:03:35 -0700 Subject: [PATCH 009/111] Add Compile Guard to required project files --- .../OpenTelemetry.Exporter.Console.csproj | 1 + .../OpenTelemetry.Exporter.InMemory.csproj | 4 ++++ .../OpenTelemetry.Exporter.Jaeger.csproj | 1 + .../OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj | 1 + .../OpenTelemetry.Exporter.Prometheus.csproj | 1 + .../OpenTelemetry.Exporter.ZPages.csproj | 1 + .../OpenTelemetry.Exporter.Zipkin.csproj | 1 + .../OpenTelemetry.Extensions.Hosting.csproj | 1 + ...elemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj | 1 + .../OpenTelemetry.Instrumentation.AspNet.csproj | 1 + .../OpenTelemetry.Instrumentation.AspNetCore.csproj | 1 + .../OpenTelemetry.Instrumentation.GrpcNetClient.csproj | 1 + .../OpenTelemetry.Instrumentation.Http.csproj | 4 ++++ .../OpenTelemetry.Instrumentation.SqlClient.csproj | 4 ++++ .../OpenTelemetry.Instrumentation.StackExchangeRedis.csproj | 1 + .../OpenTelemetry.Shims.OpenTracing.csproj | 4 ++++ 16 files changed, 28 insertions(+) diff --git a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj index 1336a810fa8..aa23bb337a1 100644 --- a/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj +++ b/src/OpenTelemetry.Exporter.Console/OpenTelemetry.Exporter.Console.csproj @@ -17,6 +17,7 @@ + diff --git a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj index 8eb494b7f2a..404dc1b16d2 100644 --- a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj +++ b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj index 1b264bc21fd..3d22d432107 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj +++ b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj @@ -25,6 +25,7 @@ + diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index fa9ece21ad7..d9490575f39 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -42,6 +42,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj b/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj index f69c2c2d9d4..5730aec8ab8 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj @@ -24,6 +24,7 @@ + diff --git a/src/OpenTelemetry.Exporter.ZPages/OpenTelemetry.Exporter.ZPages.csproj b/src/OpenTelemetry.Exporter.ZPages/OpenTelemetry.Exporter.ZPages.csproj index 14dadaf44c0..ea031a58f5c 100644 --- a/src/OpenTelemetry.Exporter.ZPages/OpenTelemetry.Exporter.ZPages.csproj +++ b/src/OpenTelemetry.Exporter.ZPages/OpenTelemetry.Exporter.ZPages.csproj @@ -10,6 +10,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj index 3555bd8722f..7ed212f9268 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj +++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj @@ -16,6 +16,7 @@ + diff --git a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj index 27fcf6fef9f..2919f598bf6 100644 --- a/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj +++ b/src/OpenTelemetry.Extensions.Hosting/OpenTelemetry.Extensions.Hosting.csproj @@ -10,6 +10,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj index 51ed98cb929..3af39924213 100644 --- a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj +++ b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.csproj @@ -7,6 +7,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj b/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj index 353cf46280b..27a45714bda 100644 --- a/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj +++ b/src/OpenTelemetry.Instrumentation.AspNet/OpenTelemetry.Instrumentation.AspNet.csproj @@ -12,6 +12,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj b/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj index 6fd27b06c5c..26c13d6114f 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj @@ -10,6 +10,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj b/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj index b599e57b18f..e7c5b916221 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj @@ -8,6 +8,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj b/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj index 95ad43be5f7..d98c1b39330 100644 --- a/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj +++ b/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj @@ -7,6 +7,10 @@ true + + + + diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/OpenTelemetry.Instrumentation.SqlClient.csproj b/src/OpenTelemetry.Instrumentation.SqlClient/OpenTelemetry.Instrumentation.SqlClient.csproj index 0ade9df7361..662610993cd 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/OpenTelemetry.Instrumentation.SqlClient.csproj +++ b/src/OpenTelemetry.Instrumentation.SqlClient/OpenTelemetry.Instrumentation.SqlClient.csproj @@ -7,6 +7,10 @@ true + + + + diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj index 9890827d021..c0f8d415e4e 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj @@ -9,6 +9,7 @@ + diff --git a/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj b/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj index 669d7c68aa1..6736743f281 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj +++ b/src/OpenTelemetry.Shims.OpenTracing/OpenTelemetry.Shims.OpenTracing.csproj @@ -18,4 +18,8 @@ + + + + From a47388991e664a5e641efa8ba4f8f2965cdc9739 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 20 Oct 2021 14:11:20 -0700 Subject: [PATCH 010/111] Update OpenTelemetry.Instrumentation.Http.csproj --- .../OpenTelemetry.Instrumentation.Http.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj b/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj index d98c1b39330..55ab8e552f3 100644 --- a/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj +++ b/src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj @@ -10,7 +10,7 @@ - + From 01c45772b102329d9251566a5fbc2c12ab1e41b4 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 11:30:12 -0800 Subject: [PATCH 011/111] WIP compacting MetricPoint struct part 2. --- src/OpenTelemetry/Metrics/AggregationType.cs | 2 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 28 +++++++++++-------- ...e.cs => MetricPointPrimaryValueStorage.cs} | 12 +++++++- 3 files changed, 29 insertions(+), 13 deletions(-) rename src/OpenTelemetry/Metrics/{MetricPointValueStorage.cs => MetricPointPrimaryValueStorage.cs} (72%) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index bd87c9e5b4f..2ee2b6d1e0e 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum AggregationType + internal enum AggregationType : sbyte { /// /// Invalid. diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index e91c1253ace..645dfc6d16c 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -63,11 +63,7 @@ internal MetricPoint( } else if (this.aggType == AggregationType.HistogramSumCount) { - this.histogramBuckets = new HistogramBuckets(null); - } - else - { - this.histogramBuckets = null; + this.secondaryValue.HistogramBuckets = new HistogramBuckets(null); } } @@ -313,17 +309,19 @@ internal void Update(double number) case AggregationType.Histogram: { + var histogramBuckets = this.secondaryValue.HistogramBuckets; + int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) + for (i = 0; i < histogramBuckets.ExplicitBounds.Length; i++) { // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) + if (number <= histogramBuckets.ExplicitBounds[i]) { break; } } - lock (this.histogramBuckets.LockObject) + lock (histogramBuckets.LockObject) { this.runningValue.AsLong++; this.histogramBuckets.RunningSum += number; @@ -335,7 +333,9 @@ internal void Update(double number) case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { this.runningValue.AsLong++; this.histogramBuckets.RunningSum += number; @@ -393,6 +393,8 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { + MetricPointDeltaState deltaState = this.EnsureDeltaState(); + // TODO: // Is this thread-safe way to read double? // As long as the value is not -ve infinity, @@ -460,7 +462,9 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { this.snapshotValue.AsLong = this.runningValue.AsLong; this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; @@ -487,7 +491,9 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) + var histogramBuckets = this.secondaryValue.HistogramBuckets; + + lock (histogramBuckets.LockObject) { this.snapshotValue.AsLong = this.runningValue.AsLong; this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; diff --git a/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs b/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs similarity index 72% rename from src/OpenTelemetry/Metrics/MetricPointValueStorage.cs rename to src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs index 778e97885bb..8578c9129c4 100644 --- a/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs +++ b/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,16 @@ namespace OpenTelemetry.Metrics { + [StructLayout(LayoutKind.Explicit)] + internal struct MetricPointPrimaryValueStorage + { + [FieldOffset(0)] + public MetricPointValueStorage Current; + + [FieldOffset(8)] + public MetricPointValueStorage Snapshot; + } + [StructLayout(LayoutKind.Explicit)] internal struct MetricPointValueStorage { From d6da88ade8d67831c68c76c7e6bc19881d776178 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 11:36:47 -0800 Subject: [PATCH 012/111] Smaller storage size for MetricPointStatus. --- src/OpenTelemetry/Metrics/MetricPointStatus.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/MetricPointStatus.cs b/src/OpenTelemetry/Metrics/MetricPointStatus.cs index 0ecd2a0c062..d24a46a8cc9 100644 --- a/src/OpenTelemetry/Metrics/MetricPointStatus.cs +++ b/src/OpenTelemetry/Metrics/MetricPointStatus.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum MetricPointStatus + internal enum MetricPointStatus : byte { /// /// This status is applied to s with status after a Collect. From 7faec57d166b540baf3cc39b855121f13b4d8ad2 Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Wed, 1 Dec 2021 20:54:22 -0800 Subject: [PATCH 013/111] Cleanup and xml comments. --- src/OpenTelemetry/Metrics/AggregationType.cs | 2 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 28 ++++++++----------- .../Metrics/MetricPointStatus.cs | 2 +- ...eStorage.cs => MetricPointValueStorage.cs} | 12 +------- 4 files changed, 14 insertions(+), 30 deletions(-) rename src/OpenTelemetry/Metrics/{MetricPointPrimaryValueStorage.cs => MetricPointValueStorage.cs} (72%) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index 2ee2b6d1e0e..bd87c9e5b4f 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum AggregationType : sbyte + internal enum AggregationType { /// /// Invalid. diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 645dfc6d16c..e91c1253ace 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -63,7 +63,11 @@ internal MetricPoint( } else if (this.aggType == AggregationType.HistogramSumCount) { - this.secondaryValue.HistogramBuckets = new HistogramBuckets(null); + this.histogramBuckets = new HistogramBuckets(null); + } + else + { + this.histogramBuckets = null; } } @@ -309,19 +313,17 @@ internal void Update(double number) case AggregationType.Histogram: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - int i; - for (i = 0; i < histogramBuckets.ExplicitBounds.Length; i++) + for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) { // Upper bound is inclusive - if (number <= histogramBuckets.ExplicitBounds[i]) + if (number <= this.histogramBuckets.ExplicitBounds[i]) { break; } } - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { this.runningValue.AsLong++; this.histogramBuckets.RunningSum += number; @@ -333,9 +335,7 @@ internal void Update(double number) case AggregationType.HistogramSumCount: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { this.runningValue.AsLong++; this.histogramBuckets.RunningSum += number; @@ -393,8 +393,6 @@ internal void TakeSnapshot(bool outputDelta) { if (outputDelta) { - MetricPointDeltaState deltaState = this.EnsureDeltaState(); - // TODO: // Is this thread-safe way to read double? // As long as the value is not -ve infinity, @@ -462,9 +460,7 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { this.snapshotValue.AsLong = this.runningValue.AsLong; this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; @@ -491,9 +487,7 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.HistogramSumCount: { - var histogramBuckets = this.secondaryValue.HistogramBuckets; - - lock (histogramBuckets.LockObject) + lock (this.histogramBuckets.LockObject) { this.snapshotValue.AsLong = this.runningValue.AsLong; this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; diff --git a/src/OpenTelemetry/Metrics/MetricPointStatus.cs b/src/OpenTelemetry/Metrics/MetricPointStatus.cs index d24a46a8cc9..0ecd2a0c062 100644 --- a/src/OpenTelemetry/Metrics/MetricPointStatus.cs +++ b/src/OpenTelemetry/Metrics/MetricPointStatus.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - internal enum MetricPointStatus : byte + internal enum MetricPointStatus { /// /// This status is applied to s with status after a Collect. diff --git a/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs similarity index 72% rename from src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs rename to src/OpenTelemetry/Metrics/MetricPointValueStorage.cs index 8578c9129c4..778e97885bb 100644 --- a/src/OpenTelemetry/Metrics/MetricPointPrimaryValueStorage.cs +++ b/src/OpenTelemetry/Metrics/MetricPointValueStorage.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,16 +18,6 @@ namespace OpenTelemetry.Metrics { - [StructLayout(LayoutKind.Explicit)] - internal struct MetricPointPrimaryValueStorage - { - [FieldOffset(0)] - public MetricPointValueStorage Current; - - [FieldOffset(8)] - public MetricPointValueStorage Snapshot; - } - [StructLayout(LayoutKind.Explicit)] internal struct MetricPointValueStorage { From eb3eed37b0304565b33b0501eb9e6f9fb425e6c9 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 10 Dec 2021 22:39:38 -0800 Subject: [PATCH 014/111] Histogram MinMax Configurable --- .../netstandard2.0/PublicAPI.Unshipped.txt | 6 + src/OpenTelemetry/CHANGELOG.md | 8 +- src/OpenTelemetry/Metrics/AggregationType.cs | 5 + .../ExplicitBucketHistogramConfiguration.cs | 2 +- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 8 +- .../Metrics/HistogramConfiguration.cs | 26 ++++ .../Metrics/MeterProviderBuilderSdk.cs | 2 +- src/OpenTelemetry/Metrics/Metric.cs | 8 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 115 ++++++++++++++++++ src/OpenTelemetry/Metrics/MetricReaderExt.cs | 16 ++- src/OpenTelemetry/Metrics/MetricType.cs | 7 +- .../Metrics/MetricTypeExtensions.cs | 9 +- .../Metrics/MetricTestData.cs | 15 +++ .../Metrics/MetricViewTests.cs | 81 ++++++++++++ 14 files changed, 296 insertions(+), 12 deletions(-) create mode 100644 src/OpenTelemetry/Metrics/HistogramConfiguration.cs diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 6d964985981..152601f2a3d 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -20,7 +20,11 @@ OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Current.get -> OpenTelemetry.M OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Enumerator() -> void OpenTelemetry.Metrics.HistogramBuckets.Enumerator.MoveNext() -> bool OpenTelemetry.Metrics.HistogramBuckets.GetEnumerator() -> OpenTelemetry.Metrics.HistogramBuckets.Enumerator +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.MetricPoint.EndTime.get -> System.DateTimeOffset +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.GetSumDouble() -> double OpenTelemetry.Metrics.MetricPoint.GetSumLong() -> long OpenTelemetry.Metrics.MetricPoint.GetGaugeLastValueDouble() -> double @@ -88,6 +92,7 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -131,6 +136,7 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool +static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index d08f572cb45..1755c28a392 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,8 +2,12 @@ ## Unreleased +* Make recording of `Min` and `Max` for histograms configurable, enabled by + default. + ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) + * Make `MetricPoint` of `MetricPointAccessor` readonly. - ([2736](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2736)) + ([#2736](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2736)) ## 1.2.0-rc1 @@ -11,7 +15,7 @@ Released 2021-Nov-29 * Prevent accessing activity Id before sampler runs in case of legacy activities. - ([2659](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2659)) + ([#2659](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2659)) * Added `ReadOnlyTagCollection` and expose `Tags` on `MetricPoint` instead of `Keys`+`Values` diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index bd87c9e5b4f..901af2cd9ca 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -62,5 +62,10 @@ internal enum AggregationType /// Histogram with sum, count only. /// HistogramSumCount = 7, + + /// + /// Histogram with minimum and maximum. + /// + HistogramWithMinMax = 8, } } diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index 7ed4a0fadd2..018de15190f 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -16,7 +16,7 @@ namespace OpenTelemetry.Metrics { - public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration + public class ExplicitBucketHistogramConfiguration : HistogramConfiguration { /// /// Gets or sets the values representing explicit histogram bucket diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index a68033d4300..9344d975934 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -25,13 +25,17 @@ public class HistogramBuckets internal readonly double[] ExplicitBounds; internal readonly long[] RunningBucketCounts; - internal readonly long[] SnapshotBucketCounts; internal double RunningSum; - internal double SnapshotSum; + internal double RunningMin; + internal double SnapshotMin; + + internal double RunningMax; + internal double SnapshotMax; + internal HistogramBuckets(double[] explicitBounds) { this.ExplicitBounds = explicitBounds; diff --git a/src/OpenTelemetry/Metrics/HistogramConfiguration.cs b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs new file mode 100644 index 00000000000..9d3983dc3a8 --- /dev/null +++ b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs @@ -0,0 +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. +// + +namespace OpenTelemetry.Metrics; + +public class HistogramConfiguration : MetricStreamConfiguration +{ + /// + /// Gets or sets a value indicating whether Min, Max + /// should be collected. + /// + internal bool RecordMinMax { get; set; } = true; +} diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index 47bd282cd96..60624b773cb 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -44,7 +44,7 @@ internal static bool IsValidInstrumentName(string instrumentName) /// /// See specification: . /// The view name. - /// Boolean indicating if the instrument is valid. + /// Boolean indicating if the view name is valid. internal static bool IsValidViewName(string customViewName) { // Only validate the view name in case it's not null. In case it's null, the view name will be the instrument name as per the spec. diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 983976d5e9e..ea85a4d7a39 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -33,7 +33,8 @@ internal Metric( string metricDescription, int maxMetricPointsPerMetricStream, double[] histogramBounds = null, - string[] tagKeysInteresting = null) + string[] tagKeysInteresting = null, + bool histogramRecordMinMax = true) { this.Name = metricName; this.Description = metricDescription ?? string.Empty; @@ -97,6 +98,11 @@ internal Metric( { aggType = AggregationType.HistogramSumCount; } + else if (histogramRecordMinMax) + { + aggType = AggregationType.HistogramWithMinMax; + this.MetricType = MetricType.HistogramWithMinMax; + } else { aggType = AggregationType.Histogram; diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index e91c1253ace..e3cc47c25da 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -61,6 +61,10 @@ internal MetricPoint( { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); } + else if (this.aggType == AggregationType.HistogramWithMinMax) + { + this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); + } else if (this.aggType == AggregationType.HistogramSumCount) { this.histogramBuckets = new HistogramBuckets(null); @@ -221,6 +225,52 @@ public double GetHistogramSum() return this.histogramBuckets.SnapshotSum; } + /// + /// Gets the minimum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Minimum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMin() + { + if (this.aggType != AggregationType.HistogramWithMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); + } + + if (this.runningValue.AsLong == 0) + { + throw new InvalidOperationException("No values have been recorded yet."); + } + + return this.histogramBuckets.SnapshotMin; + } + + /// + /// Gets the maximum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Maximum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMax() + { + if (this.aggType != AggregationType.HistogramWithMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); + } + + if (this.runningValue.AsLong == 0) + { + throw new InvalidOperationException("No values have been recorded yet."); + } + + return this.histogramBuckets.SnapshotMax; + } + /// /// Gets the buckets of the histogram associated with the metric point. /// @@ -333,6 +383,39 @@ internal void Update(double number) break; } + case AggregationType.HistogramWithMinMax: + { + int i; + for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) + { + // Upper bound is inclusive + if (number <= this.histogramBuckets.ExplicitBounds[i]) + { + break; + } + } + + lock (this.histogramBuckets.LockObject) + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningBucketCounts[i]++; + + if (this.runningValue.AsLong == 1) + { + this.histogramBuckets.RunningMin = number; + this.histogramBuckets.RunningMax = number; + } + else + { + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + } + + break; + } + case AggregationType.HistogramSumCount: { lock (this.histogramBuckets.LockObject) @@ -485,6 +568,38 @@ internal void TakeSnapshot(bool outputDelta) break; } + case AggregationType.HistogramWithMinMax: + { + lock (this.histogramBuckets.LockObject) + { + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + this.histogramBuckets.RunningMin = 0; + this.histogramBuckets.RunningMax = 0; + } + + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + } + + break; + } + case AggregationType.HistogramSumCount: { lock (this.histogramBuckets.LockObject) diff --git a/src/OpenTelemetry/Metrics/MetricReaderExt.cs b/src/OpenTelemetry/Metrics/MetricReaderExt.cs index c963a9b9cb3..43451010410 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderExt.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderExt.cs @@ -124,9 +124,19 @@ internal List AddMetricsListWithViews(Instrument instrument, List Histogram = 0x40, + + /// + /// Histogram with minimum and maximum. + /// + HistogramWithMinMax = 0x50, } } diff --git a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs index 393a5cfe790..0ffd92e518b 100644 --- a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs +++ b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs @@ -26,8 +26,9 @@ public static class MetricTypeExtensions internal const MetricType METRIC_TYPE_SUM = (MetricType)0x10; internal const MetricType METRIC_TYPE_GAUGE = (MetricType)0x20; - /* internal const byte METRIC_TYPE_SUMMARY = 0x30; // not used */ + /* internal const MetricType METRIC_TYPE_SUMMARY = 0x30; // not used */ internal const MetricType METRIC_TYPE_HISTOGRAM = (MetricType)0x40; + internal const MetricType METRIC_TYPE_HISTOGRAM_WITH_MIN_MAX = (MetricType)0x50; internal const MetricType POINT_KIND_MASK = (MetricType)0x0f; @@ -62,6 +63,12 @@ public static bool IsHistogram(this MetricType self) return self.HasFlag(METRIC_TYPE_HISTOGRAM); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsHistogramWithMinMax(this MetricType self) + { + return self.HasFlag(METRIC_TYPE_HISTOGRAM_WITH_MIN_MAX); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDouble(this MetricType self) { diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 0664dc18c00..7919e4a7ce6 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -49,5 +49,20 @@ public static IEnumerable InvalidHistogramBoundaries new object[] { new double[] { 0, 1, 1, 2 } }, new object[] { new double[] { 0, 1, 2, -1 } }, }; + + public static IEnumerable ValidHistogramWithMinMax + => new List + { + new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, + new object[] { new double[] { double.NegativeInfinity, 0, double.PositiveInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.PositiveInfinity }, + new object[] { new double[] { 0 }, new HistogramConfiguration(), 0, 0 }, + }; + + public static IEnumerable InvalidHistogramWithMinMax + => new List + { + new object[] { new double[] { 1 }, new HistogramConfiguration() { RecordMinMax = false } }, + new object[] { new double[] { 1 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, RecordMinMax = false } }, + }; } } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 2f76de70efc..259a9577981 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -434,6 +434,75 @@ public void ViewToProduceCustomHistogramBound() Assert.Equal(boundaries.Length + 1, actualCount); } + [Theory] + [MemberData(nameof(MetricTestData.ValidHistogramWithMinMax), MemberType = typeof(MetricTestData))] + public void HistogramWithMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView("MyHistogram", histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + var histogram = meter.CreateHistogram("MyHistogram"); + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + List metricPointsDefault = new List(); + foreach (ref var mp in exportedItems[0].GetMetricPoints()) + { + metricPointsDefault.Add(mp); + } + + var histogramPoint = metricPointsDefault[0]; + var min = histogramPoint.GetHistogramMin(); + var max = histogramPoint.GetHistogramMax(); + + Assert.Equal(expectedMin, min); + Assert.Equal(expectedMax, max); + } + + [Theory] + [MemberData(nameof(MetricTestData.InvalidHistogramWithMinMax), MemberType = typeof(MetricTestData))] + public void HistogramWithMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView("MyHistogram", histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + var histogram = meter.CreateHistogram("MyHistogram"); + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + List metricPointsDefault = new List(); + foreach (ref var mp in exportedItems[0].GetMetricPoints()) + { + metricPointsDefault.Add(mp); + } + + var histogramPoint = metricPointsDefault[0]; + + var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMin)} is not supported for this metric type.", ex.Message); + + ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMax)} is not supported for this metric type.", ex.Message); + } + [Fact] public void ViewToSelectTagKeys() { @@ -576,5 +645,17 @@ public void MetricStreamConfigurationForDropMustNotAllowOverriding() MetricStreamConfiguration.Drop.Aggregation = Aggregation.Histogram; Assert.Equal(Aggregation.Drop, MetricStreamConfiguration.Drop.Aggregation); } + + [Fact] + public void GetHistogramMinThrows() + { + var histogramPoint = new MetricPoint(AggregationType.HistogramWithMinMax, DateTime.Now, null, null, new double[] { 0 }); + + var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); + Assert.Equal("No values have been recorded yet.", ex.Message); + + ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); + Assert.Equal("No values have been recorded yet.", ex.Message); + } } } From 41ed3f08a13beb842f4c7ab8a639e747deb0c5dd Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Sat, 11 Dec 2021 00:17:40 -0800 Subject: [PATCH 015/111] Fix test + fix sum and count for HistogramWithMinMax --- src/OpenTelemetry/Metrics/MetricPoint.cs | 6 +++--- .../HttpClientTests.netcore31.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index e3cc47c25da..f8516fa1fc1 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -199,7 +199,7 @@ public double GetGaugeLastValueDouble() [MethodImpl(MethodImplOptions.AggressiveInlining)] public long GetHistogramCount() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramCount)); } @@ -217,7 +217,7 @@ public long GetHistogramCount() [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetHistogramSum() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramSum)); } @@ -281,7 +281,7 @@ public double GetHistogramMax() [MethodImpl(MethodImplOptions.AggressiveInlining)] public HistogramBuckets GetHistogramBuckets() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index a843e9fab4b..b514a8f35e2 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -149,7 +149,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) From 8e85649d61dd0dfce1e47dd9f48aea7d8f37847a Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Sat, 11 Dec 2021 14:06:18 -0800 Subject: [PATCH 016/111] Refactor and fix RequestMetricIsCaptured in MetricTest.cs --- .../MetricTests.cs | 2 +- test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index bfeda28b387..8f3a9e145cc 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -89,7 +89,7 @@ public async Task RequestMetricIsCaptured() var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) { diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 259a9577981..db980450777 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -454,13 +454,13 @@ public void HistogramWithMinMax(double[] values, HistogramConfiguration histogra meterProvider.ForceFlush(MaxTimeToAllowForFlush); - List metricPointsDefault = new List(); + var metricPoints = new List(); foreach (ref var mp in exportedItems[0].GetMetricPoints()) { - metricPointsDefault.Add(mp); + metricPoints.Add(mp); } - var histogramPoint = metricPointsDefault[0]; + var histogramPoint = metricPoints[0]; var min = histogramPoint.GetHistogramMin(); var max = histogramPoint.GetHistogramMax(); @@ -488,13 +488,13 @@ public void HistogramWithMinMaxThrows(double[] values, HistogramConfiguration hi meterProvider.ForceFlush(MaxTimeToAllowForFlush); - List metricPointsDefault = new List(); + var metricPoints = new List(); foreach (ref var mp in exportedItems[0].GetMetricPoints()) { - metricPointsDefault.Add(mp); + metricPoints.Add(mp); } - var histogramPoint = metricPointsDefault[0]; + var histogramPoint = metricPoints[0]; var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); Assert.Contains($"{nameof(histogramPoint.GetHistogramMin)} is not supported for this metric type.", ex.Message); From 87816e0997c4d02b8525c2a4e5816af3dc03111b Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 13 Dec 2021 09:36:06 -0800 Subject: [PATCH 017/111] Update PublicAPI.Unshipped.txt --- src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt index 6d964985981..152601f2a3d 100644 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt @@ -20,7 +20,11 @@ OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Current.get -> OpenTelemetry.M OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Enumerator() -> void OpenTelemetry.Metrics.HistogramBuckets.Enumerator.MoveNext() -> bool OpenTelemetry.Metrics.HistogramBuckets.GetEnumerator() -> OpenTelemetry.Metrics.HistogramBuckets.Enumerator +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.MetricPoint.EndTime.get -> System.DateTimeOffset +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricPoint.GetSumDouble() -> double OpenTelemetry.Metrics.MetricPoint.GetSumLong() -> long OpenTelemetry.Metrics.MetricPoint.GetGaugeLastValueDouble() -> double @@ -88,6 +92,7 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -131,6 +136,7 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool +static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder From 342924868d60106911f25f8277765c6da4e8e131 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 14 Dec 2021 17:23:19 -0800 Subject: [PATCH 018/111] Fixed failing tests --- .../Implementation/MetricItemExtensions.cs | 1 + src/OpenTelemetry/Metrics/MetricPoint.cs | 1 + test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index eafacb2f979..ba09421f51c 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -233,6 +233,7 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: + case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram(); histogram.AggregationTemporality = temporality; diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index f8516fa1fc1..7440c7329a2 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -313,6 +313,7 @@ internal void Update(long number) case AggregationType.Histogram: case AggregationType.HistogramSumCount: + case AggregationType.HistogramWithMinMax: { this.Update((double)number); break; diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index db980450777..6f0b0144e01 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -455,7 +455,7 @@ public void HistogramWithMinMax(double[] values, HistogramConfiguration histogra meterProvider.ForceFlush(MaxTimeToAllowForFlush); var metricPoints = new List(); - foreach (ref var mp in exportedItems[0].GetMetricPoints()) + foreach (ref readonly var mp in exportedItems[0].GetMetricPoints()) { metricPoints.Add(mp); } @@ -489,7 +489,7 @@ public void HistogramWithMinMaxThrows(double[] values, HistogramConfiguration hi meterProvider.ForceFlush(MaxTimeToAllowForFlush); var metricPoints = new List(); - foreach (ref var mp in exportedItems[0].GetMetricPoints()) + foreach (ref readonly var mp in exportedItems[0].GetMetricPoints()) { metricPoints.Add(mp); } From f151e29d1cc46ade7946bde2203b5afd3f6b9fc2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 14 Dec 2021 17:48:58 -0800 Subject: [PATCH 019/111] add another test case --- test/OpenTelemetry.Tests/Metrics/MetricTestData.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 7919e4a7ce6..2c646553058 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -55,7 +55,8 @@ public static IEnumerable ValidHistogramWithMinMax { new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, new object[] { new double[] { double.NegativeInfinity, 0, double.PositiveInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.PositiveInfinity }, - new object[] { new double[] { 0 }, new HistogramConfiguration(), 0, 0 }, + new object[] { new double[] { 1 }, new HistogramConfiguration(), 1, 1 }, + new object[] { new double[] { 5, 100, 4, 101, -2, 97 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } }, -2, 101 }, }; public static IEnumerable InvalidHistogramWithMinMax From ce6db94747ee4d171f7e06e28ee6c6e30ea59abb Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 10 Jan 2022 09:33:09 -0800 Subject: [PATCH 020/111] histogram update and snapshot generalisation --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 4 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 170 ++++++++---------- 2 files changed, 78 insertions(+), 96 deletions(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 9344d975934..a712c1547d9 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -30,10 +30,10 @@ public class HistogramBuckets internal double RunningSum; internal double SnapshotSum; - internal double RunningMin; + internal double RunningMin = double.PositiveInfinity; internal double SnapshotMin; - internal double RunningMax; + internal double RunningMax = double.NegativeInfinity; internal double SnapshotMax; internal HistogramBuckets(double[] explicitBounds) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 7440c7329a2..3d74f12e32e 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -364,56 +364,13 @@ internal void Update(double number) case AggregationType.Histogram: { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) - { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) - { - break; - } - } - - lock (this.histogramBuckets.LockObject) - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - this.histogramBuckets.RunningBucketCounts[i]++; - } - + this.HistogramUpdate(number, false); break; } case AggregationType.HistogramWithMinMax: { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) - { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) - { - break; - } - } - - lock (this.histogramBuckets.LockObject) - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - this.histogramBuckets.RunningBucketCounts[i]++; - - if (this.runningValue.AsLong == 1) - { - this.histogramBuckets.RunningMin = number; - this.histogramBuckets.RunningMax = number; - } - else - { - this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); - this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); - } - } - + this.HistogramUpdate(number, true); break; } @@ -544,60 +501,13 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - lock (this.histogramBuckets.LockObject) - { - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) - { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) - { - this.histogramBuckets.RunningBucketCounts[i] = 0; - } - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - } - + this.HistogramSnapshot(outputDelta, false); break; } case AggregationType.HistogramWithMinMax: { - lock (this.histogramBuckets.LockObject) - { - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; - this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; - - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - this.histogramBuckets.RunningMin = 0; - this.histogramBuckets.RunningMax = 0; - } - - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) - { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) - { - this.histogramBuckets.RunningBucketCounts[i] = 0; - } - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - } - + this.HistogramSnapshot(outputDelta, true); break; } @@ -626,5 +536,77 @@ private void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } + + [MethodImpl(MethodImplOptions.NoInlining)] + private int FindHistogramBucket(double number) + { + int i; + for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) + { + // Upper bound is inclusive + if (number <= this.histogramBuckets.ExplicitBounds[i]) + { + break; + } + } + + return i; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void HistogramUpdate(double number, bool hasMinMax) + { + int i = this.FindHistogramBucket(number); + + lock (this.histogramBuckets.LockObject) + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningBucketCounts[i]++; + + if (hasMinMax) + { + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void HistogramSnapshot(bool outputDelta, bool hasMinMax) + { + lock (this.histogramBuckets.LockObject) + { + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + if (hasMinMax) + { + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + } + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + if (hasMinMax) + { + this.histogramBuckets.RunningMin = 0; + this.histogramBuckets.RunningMax = 0; + } + } + + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + } + } } } From 7c3e80694d1844f38533113c9075e6866e6f3be8 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Jan 2022 04:39:38 -0800 Subject: [PATCH 021/111] Inlining: Aggressive instead of No Also included `FindHistogramBucket`'s body in `HistogramUpdate` since it was only being called from it. --- src/OpenTelemetry/Metrics/MetricPoint.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 3d74f12e32e..0ee95a8f25d 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -537,8 +537,8 @@ private void ThrowNotSupportedMetricTypeException(string methodName) throw new NotSupportedException($"{methodName} is not supported for this metric type."); } - [MethodImpl(MethodImplOptions.NoInlining)] - private int FindHistogramBucket(double number) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void HistogramUpdate(double number, bool hasMinMax) { int i; for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) @@ -550,14 +550,6 @@ private int FindHistogramBucket(double number) } } - return i; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void HistogramUpdate(double number, bool hasMinMax) - { - int i = this.FindHistogramBucket(number); - lock (this.histogramBuckets.LockObject) { this.runningValue.AsLong++; @@ -572,7 +564,7 @@ private void HistogramUpdate(double number, bool hasMinMax) } } - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void HistogramSnapshot(bool outputDelta, bool hasMinMax) { lock (this.histogramBuckets.LockObject) From bb72e5da59cb7581bd012971f1c93127f1188b29 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Jan 2022 05:22:09 -0800 Subject: [PATCH 022/111] Update MetricViewTests.cs --- test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 6f0b0144e01..6d114accf88 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -439,14 +439,14 @@ public void ViewToProduceCustomHistogramBound() public void HistogramWithMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) { using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) - .AddView("MyHistogram", histogramConfiguration) + .AddView(histogram.Name, histogramConfiguration) .AddInMemoryExporter(exportedItems) .Build(); - var histogram = meter.CreateHistogram("MyHistogram"); for (var i = 0; i < values.Length; i++) { histogram.Record(values[i]); @@ -473,14 +473,14 @@ public void HistogramWithMinMax(double[] values, HistogramConfiguration histogra public void HistogramWithMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) { using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) - .AddView("MyHistogram", histogramConfiguration) + .AddView(histogram.Name, histogramConfiguration) .AddInMemoryExporter(exportedItems) .Build(); - var histogram = meter.CreateHistogram("MyHistogram"); for (var i = 0; i < values.Length; i++) { histogram.Record(values[i]); From ecf86980fee6a8092fdf98c7beb529c5e02b9857 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 1 Feb 2022 09:11:56 -0800 Subject: [PATCH 023/111] aggregation types --- .../Implementation/MetricItemExtensions.cs | 1 - .../.publicApi/net461/PublicAPI.Unshipped.txt | 4 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 4 +- src/OpenTelemetry/Metrics/AggregationType.cs | 15 ++- .../Metrics/HistogramConfiguration.cs | 2 +- src/OpenTelemetry/Metrics/Metric.cs | 18 +-- src/OpenTelemetry/Metrics/MetricPoint.cs | 110 ++++++++++-------- src/OpenTelemetry/Metrics/MetricReaderExt.cs | 2 +- src/OpenTelemetry/Metrics/MetricType.cs | 6 - .../Metrics/MetricTypeExtensions.cs | 7 -- .../MetricTests.cs | 2 +- .../HttpClientTests.netcore31.cs | 2 +- .../Metrics/MetricTestData.cs | 4 +- .../Metrics/MetricViewTests.cs | 10 +- 14 files changed, 90 insertions(+), 97 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index ba09421f51c..eafacb2f979 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -233,7 +233,6 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: - case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram(); histogram.AggregationTemporality = temporality; diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt index 152601f2a3d..8a2fbed7a71 100644 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt @@ -22,6 +22,8 @@ OpenTelemetry.Metrics.HistogramBuckets.Enumerator.MoveNext() -> bool OpenTelemetry.Metrics.HistogramBuckets.GetEnumerator() -> OpenTelemetry.Metrics.HistogramBuckets.Enumerator OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.EndTime.get -> System.DateTimeOffset OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double @@ -92,7 +94,6 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -136,7 +137,6 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 152601f2a3d..8a2fbed7a71 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -22,6 +22,8 @@ OpenTelemetry.Metrics.HistogramBuckets.Enumerator.MoveNext() -> bool OpenTelemetry.Metrics.HistogramBuckets.GetEnumerator() -> OpenTelemetry.Metrics.HistogramBuckets.Enumerator OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.EndTime.get -> System.DateTimeOffset OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double @@ -92,7 +94,6 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -136,7 +137,6 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index 901af2cd9ca..eff60b2d91d 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -54,18 +54,23 @@ internal enum AggregationType DoubleGauge = 5, /// - /// Histogram. + /// Histogram with sum, count, buckets. /// Histogram = 6, /// - /// Histogram with sum, count only. + /// Histogram with sum, count, min, max, buckets. /// - HistogramSumCount = 7, + HistogramMinMax = 7, /// - /// Histogram with minimum and maximum. + /// Histogram with sum, count. /// - HistogramWithMinMax = 8, + HistogramSumCount = 8, + + /// + /// Histogram with sum, count, min, max. + /// + HistogramSumCountMinMax = 9, } } diff --git a/src/OpenTelemetry/Metrics/HistogramConfiguration.cs b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs index 9d3983dc3a8..37980098937 100644 --- a/src/OpenTelemetry/Metrics/HistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs @@ -22,5 +22,5 @@ public class HistogramConfiguration : MetricStreamConfiguration /// Gets or sets a value indicating whether Min, Max /// should be collected. /// - internal bool RecordMinMax { get; set; } = true; + public bool RecordMinMax { get; set; } = true; } diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index ea85a4d7a39..c4f2e21f791 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -93,20 +93,10 @@ internal Metric( { this.MetricType = MetricType.Histogram; - if (histogramBounds != null - && histogramBounds.Length == 0) - { - aggType = AggregationType.HistogramSumCount; - } - else if (histogramRecordMinMax) - { - aggType = AggregationType.HistogramWithMinMax; - this.MetricType = MetricType.HistogramWithMinMax; - } - else - { - aggType = AggregationType.Histogram; - } + // Use histogramBounds and histogramRecordMinMax to determine the aggregation type + aggType = histogramBounds != null && histogramBounds.Length == 0 + ? (histogramRecordMinMax ? AggregationType.HistogramSumCountMinMax : AggregationType.HistogramSumCount) + : (histogramRecordMinMax ? AggregationType.HistogramMinMax : AggregationType.Histogram); } else { diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 0ee95a8f25d..9dfd8924d55 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -57,15 +57,13 @@ internal MetricPoint( this.deltaLastValue = default; this.MetricPointStatus = MetricPointStatus.NoCollectPending; - if (this.aggType == AggregationType.Histogram) + if (this.aggType == AggregationType.Histogram || + this.aggType == AggregationType.HistogramMinMax) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); } - else if (this.aggType == AggregationType.HistogramWithMinMax) - { - this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); - } - else if (this.aggType == AggregationType.HistogramSumCount) + else if (this.aggType == AggregationType.HistogramSumCount || + this.aggType == AggregationType.HistogramSumCountMinMax) { this.histogramBuckets = new HistogramBuckets(null); } @@ -199,7 +197,10 @@ public double GetGaugeLastValueDouble() [MethodImpl(MethodImplOptions.AggressiveInlining)] public long GetHistogramCount() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramCount)); } @@ -217,7 +218,10 @@ public long GetHistogramCount() [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetHistogramSum() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramSum)); } @@ -229,13 +233,14 @@ public double GetHistogramSum() /// Gets the minimum value of the histogram associated with the metric point. /// /// - /// Applies to metric type. + /// Applies to metric type. /// /// Minimum value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetHistogramMin() { - if (this.aggType != AggregationType.HistogramWithMinMax) + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); } @@ -252,13 +257,14 @@ public double GetHistogramMin() /// Gets the maximum value of the histogram associated with the metric point. /// /// - /// Applies to metric type. + /// Applies to metric type. /// /// Maximum value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public double GetHistogramMax() { - if (this.aggType != AggregationType.HistogramWithMinMax) + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); } @@ -281,7 +287,8 @@ public double GetHistogramMax() [MethodImpl(MethodImplOptions.AggressiveInlining)] public HistogramBuckets GetHistogramBuckets() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount && this.aggType != AggregationType.HistogramWithMinMax) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } @@ -312,8 +319,9 @@ internal void Update(long number) } case AggregationType.Histogram: + case AggregationType.HistogramMinMax: case AggregationType.HistogramSumCount: - case AggregationType.HistogramWithMinMax: + case AggregationType.HistogramSumCountMinMax: { this.Update((double)number); break; @@ -364,24 +372,25 @@ internal void Update(double number) case AggregationType.Histogram: { - this.HistogramUpdate(number, false); + this.HistogramUpdate(number, true, false); break; } - case AggregationType.HistogramWithMinMax: + case AggregationType.HistogramMinMax: { - this.HistogramUpdate(number, true); + this.HistogramUpdate(number, true, true); break; } case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - } + this.HistogramUpdate(number, false, false); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramUpdate(number, false, true); break; } } @@ -501,31 +510,25 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - this.HistogramSnapshot(outputDelta, false); + this.HistogramSnapshot(outputDelta, true, false); break; } - case AggregationType.HistogramWithMinMax: + case AggregationType.HistogramMinMax: { - this.HistogramSnapshot(outputDelta, true); + this.HistogramSnapshot(outputDelta, true, true); break; } case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) - { - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - } + this.HistogramSnapshot(outputDelta, false, false); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramSnapshot(outputDelta, false, true); break; } } @@ -538,15 +541,18 @@ private void ThrowNotSupportedMetricTypeException(string methodName) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void HistogramUpdate(double number, bool hasMinMax) + private void HistogramUpdate(double number, bool hasBuckets, bool hasMinMax) { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) + int i = 0; + if (hasBuckets) { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) + for (; i < this.histogramBuckets.ExplicitBounds.Length; i++) { - break; + // Upper bound is inclusive + if (number <= this.histogramBuckets.ExplicitBounds[i]) + { + break; + } } } @@ -554,7 +560,10 @@ private void HistogramUpdate(double number, bool hasMinMax) { this.runningValue.AsLong++; this.histogramBuckets.RunningSum += number; - this.histogramBuckets.RunningBucketCounts[i]++; + if (hasBuckets) + { + this.histogramBuckets.RunningBucketCounts[i]++; + } if (hasMinMax) { @@ -565,7 +574,7 @@ private void HistogramUpdate(double number, bool hasMinMax) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void HistogramSnapshot(bool outputDelta, bool hasMinMax) + private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax) { lock (this.histogramBuckets.LockObject) { @@ -588,12 +597,15 @@ private void HistogramSnapshot(bool outputDelta, bool hasMinMax) } } - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + if (hasBuckets) { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) { - this.histogramBuckets.RunningBucketCounts[i] = 0; + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } } } diff --git a/src/OpenTelemetry/Metrics/MetricReaderExt.cs b/src/OpenTelemetry/Metrics/MetricReaderExt.cs index 43451010410..91eb131683a 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderExt.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderExt.cs @@ -125,7 +125,7 @@ internal List AddMetricsListWithViews(Instrument instrument, List Histogram = 0x40, - - /// - /// Histogram with minimum and maximum. - /// - HistogramWithMinMax = 0x50, } } diff --git a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs index 0ffd92e518b..87934689264 100644 --- a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs +++ b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs @@ -28,7 +28,6 @@ public static class MetricTypeExtensions internal const MetricType METRIC_TYPE_GAUGE = (MetricType)0x20; /* internal const MetricType METRIC_TYPE_SUMMARY = 0x30; // not used */ internal const MetricType METRIC_TYPE_HISTOGRAM = (MetricType)0x40; - internal const MetricType METRIC_TYPE_HISTOGRAM_WITH_MIN_MAX = (MetricType)0x50; internal const MetricType POINT_KIND_MASK = (MetricType)0x0f; @@ -63,12 +62,6 @@ public static bool IsHistogram(this MetricType self) return self.HasFlag(METRIC_TYPE_HISTOGRAM); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsHistogramWithMinMax(this MetricType self) - { - return self.HasFlag(METRIC_TYPE_HISTOGRAM_WITH_MIN_MAX); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsDouble(this MetricType self) { diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 8f3a9e145cc..bfeda28b387 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -89,7 +89,7 @@ public async Task RequestMetricIsCaptured() var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); + Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index b514a8f35e2..a843e9fab4b 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -149,7 +149,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); + Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 2c646553058..f1a2b517a93 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -50,7 +50,7 @@ public static IEnumerable InvalidHistogramBoundaries new object[] { new double[] { 0, 1, 2, -1 } }, }; - public static IEnumerable ValidHistogramWithMinMax + public static IEnumerable ValidHistogramMinMax => new List { new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, @@ -59,7 +59,7 @@ public static IEnumerable ValidHistogramWithMinMax new object[] { new double[] { 5, 100, 4, 101, -2, 97 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } }, -2, 101 }, }; - public static IEnumerable InvalidHistogramWithMinMax + public static IEnumerable InvalidHistogramMinMax => new List { new object[] { new double[] { 1 }, new HistogramConfiguration() { RecordMinMax = false } }, diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 6d114accf88..6af4509292f 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -435,8 +435,8 @@ public void ViewToProduceCustomHistogramBound() } [Theory] - [MemberData(nameof(MetricTestData.ValidHistogramWithMinMax), MemberType = typeof(MetricTestData))] - public void HistogramWithMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) + [MemberData(nameof(MetricTestData.ValidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) { using var meter = new Meter(Utils.GetCurrentMethodName()); var histogram = meter.CreateHistogram("MyHistogram"); @@ -469,8 +469,8 @@ public void HistogramWithMinMax(double[] values, HistogramConfiguration histogra } [Theory] - [MemberData(nameof(MetricTestData.InvalidHistogramWithMinMax), MemberType = typeof(MetricTestData))] - public void HistogramWithMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) + [MemberData(nameof(MetricTestData.InvalidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) { using var meter = new Meter(Utils.GetCurrentMethodName()); var histogram = meter.CreateHistogram("MyHistogram"); @@ -649,7 +649,7 @@ public void MetricStreamConfigurationForDropMustNotAllowOverriding() [Fact] public void GetHistogramMinThrows() { - var histogramPoint = new MetricPoint(AggregationType.HistogramWithMinMax, DateTime.Now, null, null, new double[] { 0 }); + var histogramPoint = new MetricPoint(AggregationType.HistogramMinMax, DateTime.Now, null, null, new double[] { 0 }); var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); Assert.Equal("No values have been recorded yet.", ex.Message); From 436c32819afe18b05391c65be6a9e6ec2ad4863c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 1 Feb 2022 10:04:33 -0800 Subject: [PATCH 024/111] Update MetricPoint.cs --- src/OpenTelemetry/Metrics/MetricPoint.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 9dfd8924d55..8631219c5e0 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -288,7 +288,9 @@ public double GetHistogramMax() public HistogramBuckets GetHistogramBuckets() { if (this.aggType != AggregationType.Histogram && - this.aggType != AggregationType.HistogramMinMax) + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } From 8a05290ea80126258153612375b9074053c4a828 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 2 Feb 2022 12:38:00 -0800 Subject: [PATCH 025/111] add: HistogramWithMinMax MetricType --- src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt | 2 ++ .../.publicApi/netstandard2.0/PublicAPI.Unshipped.txt | 2 ++ src/OpenTelemetry/Metrics/Metric.cs | 3 +-- src/OpenTelemetry/Metrics/MetricType.cs | 6 ++++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt index a405dabea7f..74354d885e7 100644 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt @@ -93,6 +93,7 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -136,6 +137,7 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool +static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index a405dabea7f..74354d885e7 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -93,6 +93,7 @@ OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType OpenTelemetry.Metrics.MetricTypeExtensions @@ -136,6 +137,7 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool +static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index c4f2e21f791..02704141fcb 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -91,9 +91,8 @@ internal Metric( || instrument.GetType() == typeof(Histogram) || instrument.GetType() == typeof(Histogram)) { - this.MetricType = MetricType.Histogram; + this.MetricType = histogramRecordMinMax ? MetricType.HistogramWithMinMax : MetricType.Histogram; - // Use histogramBounds and histogramRecordMinMax to determine the aggregation type aggType = histogramBounds != null && histogramBounds.Length == 0 ? (histogramRecordMinMax ? AggregationType.HistogramSumCountMinMax : AggregationType.HistogramSumCount) : (histogramRecordMinMax ? AggregationType.HistogramMinMax : AggregationType.Histogram); diff --git a/src/OpenTelemetry/Metrics/MetricType.cs b/src/OpenTelemetry/Metrics/MetricType.cs index b2052ca717c..8a339d10347 100644 --- a/src/OpenTelemetry/Metrics/MetricType.cs +++ b/src/OpenTelemetry/Metrics/MetricType.cs @@ -27,6 +27,7 @@ public enum MetricType : byte 0x20: Gauge 0x30: Summary (reserved) 0x40: Histogram + 0x50: HistogramWithMinMax 0x60: ExponentialHistogram (reserved) 0x70: ExponentialHistogramWithMinMax (reserved) 0x80: Reserved @@ -68,5 +69,10 @@ public enum MetricType : byte /// Histogram. /// Histogram = 0x40, + + /// + /// Histogram with minimum and maximum values. + /// + HistogramWithMinMax = 0x50, } } From 6ba455bf8fb28fabb196c42ee8f94f1c1eb8d886 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 18 Feb 2022 11:19:39 -0800 Subject: [PATCH 026/111] remove api --- src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt | 1 - .../.publicApi/netstandard2.0/PublicAPI.Unshipped.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt index 51c4e93c193..b8e5a0156c7 100644 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt @@ -139,7 +139,6 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 51c4e93c193..b8e5a0156c7 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -139,7 +139,6 @@ static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this Ope static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder From a69121ccd4c6323f2c6356be3efa43a83debd810 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 15:35:13 -0700 Subject: [PATCH 027/111] Binary search for large bucket count histograms --- src/OpenTelemetry/CHANGELOG.md | 5 +- src/OpenTelemetry/Metrics/Metric.cs | 2 + src/OpenTelemetry/Metrics/MetricPoint.cs | 59 ++++++++++++++++--- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 4 +- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 2b3bd30138f..b13adfe4b1b 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,9 +2,12 @@ ## Unreleased +* Use binary search for histograms with a large amount of buckets. + ([#3251](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3251)) + * Exposed public setters for `LogRecord.State`, `LogRecord.StateValues`, and `LogRecord.FormattedMessage`. - ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) + ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) ## 1.3.0-beta.1 diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 61443173f70..78c66787d6a 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -27,6 +27,8 @@ public sealed class Metric { internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; + internal static readonly int DefaultHistogramCountForBinarySearch = 140; + private readonly AggregatorStore aggStore; internal Metric( diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index f848c319594..53ab36d6505 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -30,6 +30,8 @@ public struct MetricPoint private readonly AggregationType aggType; + private readonly Func findHistogramBucketIndex; + private HistogramBuckets histogramBuckets; // Represents temporality adjusted "value" for double/long metric types or "count" when histogram @@ -61,6 +63,9 @@ internal MetricPoint( if (this.aggType == AggregationType.Histogram) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); + this.findHistogramBucketIndex = histogramExplicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch + ? FindHistogramBucketIndexBinary + : FindHistogramBucketIndexLinear; } else if (this.aggType == AggregationType.HistogramSumCount) { @@ -324,15 +329,9 @@ internal void Update(double number) case AggregationType.Histogram: { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) - { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) - { - break; - } - } + int i = double.IsNaN(number) + ? this.histogramBuckets.ExplicitBounds.Length + : this.findHistogramBucketIndex(this.histogramBuckets.ExplicitBounds, number); var sw = default(SpinWait); while (true) @@ -545,5 +544,47 @@ private readonly void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } + +#pragma warning disable SA1204 // Static elements should appear before instance elements + private static int FindHistogramBucketIndexLinear(double[] bounds, double number) +#pragma warning restore SA1204 // Static elements should appear before instance elements + { + int i; + + for (i = 0; i < bounds.Length; i++) + { + if (number <= bounds[i]) + { + break; + } + } + + return i; + } + + private static int FindHistogramBucketIndexBinary(double[] bounds, double number) + { + var left = 0; + var right = bounds.Length - 1; + + while (left <= right) + { + var mid = (int)Math.Floor((double)(left + right) / 2); + if (number == bounds[mid]) + { + return mid; + } + else if (number > bounds[mid]) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + return right + 1; + } } } diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 5511b82a0eb..70fdc7362a7 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -59,7 +59,7 @@ namespace Benchmarks.Metrics { public class HistogramBenchmarks { - private const int MaxValue = 1000; + private const int MaxValue = 10000; private readonly Random random = new(); private readonly string[] dimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; private Histogram histogram; @@ -67,7 +67,7 @@ public class HistogramBenchmarks private Meter meter; private double[] bounds; - [Params(10, 20, 50, 100)] + [Params(10, 20, 50, 100, 200, 500, 1000)] public int BoundCount { get; set; } [GlobalSetup] From 6e446cdd45e9f4da73e398dbe9ab30b69cb303bc Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 15:39:17 -0700 Subject: [PATCH 028/111] Update CHANGELOG.md --- src/OpenTelemetry/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index b13adfe4b1b..baf4717353e 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased * Use binary search for histograms with a large amount of buckets. - ([#3251](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3251)) + ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) * Exposed public setters for `LogRecord.State`, `LogRecord.StateValues`, and `LogRecord.FormattedMessage`. From e420a15287b325b97895189bf5ba5b2062a7fd17 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 15:49:27 -0700 Subject: [PATCH 029/111] netcoreapp3.1 was complaining --- src/OpenTelemetry/Metrics/MetricPoint.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 53ab36d6505..4a1f16c122f 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -30,7 +30,7 @@ public struct MetricPoint private readonly AggregationType aggType; - private readonly Func findHistogramBucketIndex; + private readonly Func findHistogramBucketIndex = FindHistogramBucketIndexLinear; private HistogramBuckets histogramBuckets; @@ -63,9 +63,10 @@ internal MetricPoint( if (this.aggType == AggregationType.Histogram) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); - this.findHistogramBucketIndex = histogramExplicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch - ? FindHistogramBucketIndexBinary - : FindHistogramBucketIndexLinear; + if (histogramExplicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch) + { + this.findHistogramBucketIndex = FindHistogramBucketIndexBinary; + } } else if (this.aggType == AggregationType.HistogramSumCount) { From e8913b242b14026c024daeb8b03db13ce257ef1c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 15:58:38 -0700 Subject: [PATCH 030/111] ci rerun From 4ade35a974d8ebfb0f409fa11d8a673290527bb7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 16:35:53 -0700 Subject: [PATCH 031/111] ci rerun From 52e2c43c708bcaa50167dbdd28f0c8ada252f1d3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 16:56:01 -0700 Subject: [PATCH 032/111] Update MetricTestData.cs --- test/OpenTelemetry.Tests/Metrics/MetricTestData.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 0664dc18c00..2e7052b773a 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -44,6 +44,7 @@ public static IEnumerable ValidInstrumentNames public static IEnumerable InvalidHistogramBoundaries => new List { + new object[] { new double[] { double.NaN } }, new object[] { new double[] { 0, 0 } }, new object[] { new double[] { 1, 0 } }, new object[] { new double[] { 0, 1, 1, 2 } }, From f7e88af9dcd0fc1ecaf23b6bada4567851a4cd7f Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 12 May 2022 11:50:30 -0700 Subject: [PATCH 033/111] use 400 buckets --- src/OpenTelemetry/Metrics/Metric.cs | 2 +- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 52 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 78c66787d6a..961d0b06ed5 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -27,7 +27,7 @@ public sealed class Metric { internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; - internal static readonly int DefaultHistogramCountForBinarySearch = 140; + internal static readonly int DefaultHistogramCountForBinarySearch = 400; private readonly AggregatorStore aggStore; diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 70fdc7362a7..dbca35b2924 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -24,35 +24,35 @@ using OpenTelemetry.Tests; /* -BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000 -Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores -.NET SDK=6.0.200 - [Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT - DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT +BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1706 (21H2) +AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores +.NET SDK=6.0.203 + [Host] : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT + DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT | Method | BoundCount | Mean | Error | StdDev | Allocated | |---------------------------- |----------- |----------:|---------:|---------:|----------:| -| HistogramHotPath | 10 | 45.27 ns | 0.384 ns | 0.359 ns | - | -| HistogramWith1LabelHotPath | 10 | 89.99 ns | 0.373 ns | 0.312 ns | - | -| HistogramWith3LabelsHotPath | 10 | 185.34 ns | 3.184 ns | 3.667 ns | - | -| HistogramWith5LabelsHotPath | 10 | 266.69 ns | 1.391 ns | 1.301 ns | - | -| HistogramWith7LabelsHotPath | 10 | 323.20 ns | 1.834 ns | 1.531 ns | - | -| HistogramHotPath | 20 | 48.69 ns | 0.347 ns | 0.307 ns | - | -| HistogramWith1LabelHotPath | 20 | 93.84 ns | 0.696 ns | 0.651 ns | - | -| HistogramWith3LabelsHotPath | 20 | 189.82 ns | 1.208 ns | 1.071 ns | - | -| HistogramWith5LabelsHotPath | 20 | 269.23 ns | 2.027 ns | 1.693 ns | - | -| HistogramWith7LabelsHotPath | 20 | 329.92 ns | 1.272 ns | 1.128 ns | - | -| HistogramHotPath | 50 | 55.73 ns | 0.339 ns | 0.317 ns | - | -| HistogramWith1LabelHotPath | 50 | 100.38 ns | 0.455 ns | 0.425 ns | - | -| HistogramWith3LabelsHotPath | 50 | 200.02 ns | 1.011 ns | 0.844 ns | - | -| HistogramWith5LabelsHotPath | 50 | 279.94 ns | 1.595 ns | 1.492 ns | - | -| HistogramWith7LabelsHotPath | 50 | 346.88 ns | 1.064 ns | 0.943 ns | - | -| HistogramHotPath | 100 | 66.39 ns | 0.167 ns | 0.148 ns | - | -| HistogramWith1LabelHotPath | 100 | 114.98 ns | 1.340 ns | 1.253 ns | - | -| HistogramWith3LabelsHotPath | 100 | 220.52 ns | 1.723 ns | 1.528 ns | - | -| HistogramWith5LabelsHotPath | 100 | 299.10 ns | 1.950 ns | 1.629 ns | - | -| HistogramWith7LabelsHotPath | 100 | 356.25 ns | 2.153 ns | 1.798 ns | - | +| HistogramHotPath | 10 | 42.68 ns | 0.116 ns | 0.109 ns | - | +| HistogramWith1LabelHotPath | 10 | 89.94 ns | 0.195 ns | 0.173 ns | - | +| HistogramWith3LabelsHotPath | 10 | 175.81 ns | 0.597 ns | 0.558 ns | - | +| HistogramWith5LabelsHotPath | 10 | 259.52 ns | 0.435 ns | 0.363 ns | - | +| HistogramWith7LabelsHotPath | 10 | 316.83 ns | 0.530 ns | 0.470 ns | - | +| HistogramHotPath | 50 | 50.70 ns | 0.356 ns | 0.333 ns | - | +| HistogramWith1LabelHotPath | 50 | 101.23 ns | 0.155 ns | 0.145 ns | - | +| HistogramWith3LabelsHotPath | 50 | 185.92 ns | 0.290 ns | 0.271 ns | - | +| HistogramWith5LabelsHotPath | 50 | 275.40 ns | 0.357 ns | 0.316 ns | - | +| HistogramWith7LabelsHotPath | 50 | 333.33 ns | 0.646 ns | 0.540 ns | - | +| HistogramHotPath | 390 | 115.16 ns | 0.115 ns | 0.108 ns | - | +| HistogramWith1LabelHotPath | 390 | 165.81 ns | 0.378 ns | 0.353 ns | - | +| HistogramWith3LabelsHotPath | 390 | 265.34 ns | 1.043 ns | 0.975 ns | - | +| HistogramWith5LabelsHotPath | 390 | 374.90 ns | 0.938 ns | 0.878 ns | - | +| HistogramWith7LabelsHotPath | 390 | 437.83 ns | 1.014 ns | 0.847 ns | - | +| HistogramHotPath | 410 | 118.25 ns | 0.103 ns | 0.096 ns | - | +| HistogramWith1LabelHotPath | 410 | 171.96 ns | 0.139 ns | 0.130 ns | - | +| HistogramWith3LabelsHotPath | 410 | 269.87 ns | 0.679 ns | 0.635 ns | - | +| HistogramWith5LabelsHotPath | 410 | 355.99 ns | 0.831 ns | 0.778 ns | - | +| HistogramWith7LabelsHotPath | 410 | 421.68 ns | 0.663 ns | 0.587 ns | - | */ namespace Benchmarks.Metrics @@ -67,7 +67,7 @@ public class HistogramBenchmarks private Meter meter; private double[] bounds; - [Params(10, 20, 50, 100, 200, 500, 1000)] + [Params(10, 50, 390, 410)] public int BoundCount { get; set; } [GlobalSetup] From 51d7219d140a937cfc3baef63ffbe78c3a62bff7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 4 May 2022 15:35:13 -0700 Subject: [PATCH 034/111] Update ExplicitBucketHistogramConfiguration.cs Binary search for large bucket count histograms Update CHANGELOG.md netcoreapp3.1 was complaining ci rerun ci rerun Update MetricTestData.cs use 400 buckets --- src/OpenTelemetry/CHANGELOG.md | 5 +- .../ExplicitBucketHistogramConfiguration.cs | 11 +++- src/OpenTelemetry/Metrics/Metric.cs | 2 + src/OpenTelemetry/Metrics/MetricPoint.cs | 60 ++++++++++++++++--- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 54 ++++++++--------- .../Metrics/MetricTestData.cs | 1 + 6 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 2b3bd30138f..baf4717353e 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,9 +2,12 @@ ## Unreleased +* Use binary search for histograms with a large amount of buckets. + ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) + * Exposed public setters for `LogRecord.State`, `LogRecord.StateValues`, and `LogRecord.FormattedMessage`. - ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) + ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) ## 1.3.0-beta.1 diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index 58bfc245b10..bf2f896d404 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -30,7 +30,7 @@ public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration /// Requirements: /// /// The array must be in ascending order with distinct - /// values. + /// values. double.NaN is not allowed /// An empty array would result in no histogram buckets being /// calculated. /// A null value would result in default bucket boundaries being @@ -58,7 +58,7 @@ public double[] Boundaries { if (!IsSortedAndDistinct(value)) { - throw new ArgumentException($"Histogram boundaries are invalid. Histogram boundaries must be in ascending order with distinct values.", nameof(value)); + throw new ArgumentException($"Histogram boundaries are invalid. Histogram boundaries must be in ascending order with distinct values. double.NaN is not allowed.", nameof(value)); } double[] copy = new double[value.Length]; @@ -76,9 +76,14 @@ public double[] Boundaries private static bool IsSortedAndDistinct(double[] values) { + if (double.IsNaN(values[0])) + { + return false; + } + for (int i = 1; i < values.Length; i++) { - if (values[i] <= values[i - 1]) + if (double.IsNaN(values[i]) || values[i] <= values[i - 1]) { return false; } diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 61443173f70..961d0b06ed5 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -27,6 +27,8 @@ public sealed class Metric { internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; + internal static readonly int DefaultHistogramCountForBinarySearch = 400; + private readonly AggregatorStore aggStore; internal Metric( diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index f848c319594..4a1f16c122f 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -30,6 +30,8 @@ public struct MetricPoint private readonly AggregationType aggType; + private readonly Func findHistogramBucketIndex = FindHistogramBucketIndexLinear; + private HistogramBuckets histogramBuckets; // Represents temporality adjusted "value" for double/long metric types or "count" when histogram @@ -61,6 +63,10 @@ internal MetricPoint( if (this.aggType == AggregationType.Histogram) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); + if (histogramExplicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch) + { + this.findHistogramBucketIndex = FindHistogramBucketIndexBinary; + } } else if (this.aggType == AggregationType.HistogramSumCount) { @@ -324,15 +330,9 @@ internal void Update(double number) case AggregationType.Histogram: { - int i; - for (i = 0; i < this.histogramBuckets.ExplicitBounds.Length; i++) - { - // Upper bound is inclusive - if (number <= this.histogramBuckets.ExplicitBounds[i]) - { - break; - } - } + int i = double.IsNaN(number) + ? this.histogramBuckets.ExplicitBounds.Length + : this.findHistogramBucketIndex(this.histogramBuckets.ExplicitBounds, number); var sw = default(SpinWait); while (true) @@ -545,5 +545,47 @@ private readonly void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } + +#pragma warning disable SA1204 // Static elements should appear before instance elements + private static int FindHistogramBucketIndexLinear(double[] bounds, double number) +#pragma warning restore SA1204 // Static elements should appear before instance elements + { + int i; + + for (i = 0; i < bounds.Length; i++) + { + if (number <= bounds[i]) + { + break; + } + } + + return i; + } + + private static int FindHistogramBucketIndexBinary(double[] bounds, double number) + { + var left = 0; + var right = bounds.Length - 1; + + while (left <= right) + { + var mid = (int)Math.Floor((double)(left + right) / 2); + if (number == bounds[mid]) + { + return mid; + } + else if (number > bounds[mid]) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + return right + 1; + } } } diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 5511b82a0eb..dbca35b2924 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -24,42 +24,42 @@ using OpenTelemetry.Tests; /* -BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000 -Intel Core i7-9700 CPU 3.00GHz, 1 CPU, 8 logical and 8 physical cores -.NET SDK=6.0.200 - [Host] : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT - DefaultJob : .NET 6.0.2 (6.0.222.6406), X64 RyuJIT +BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1706 (21H2) +AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores +.NET SDK=6.0.203 + [Host] : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT + DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT | Method | BoundCount | Mean | Error | StdDev | Allocated | |---------------------------- |----------- |----------:|---------:|---------:|----------:| -| HistogramHotPath | 10 | 45.27 ns | 0.384 ns | 0.359 ns | - | -| HistogramWith1LabelHotPath | 10 | 89.99 ns | 0.373 ns | 0.312 ns | - | -| HistogramWith3LabelsHotPath | 10 | 185.34 ns | 3.184 ns | 3.667 ns | - | -| HistogramWith5LabelsHotPath | 10 | 266.69 ns | 1.391 ns | 1.301 ns | - | -| HistogramWith7LabelsHotPath | 10 | 323.20 ns | 1.834 ns | 1.531 ns | - | -| HistogramHotPath | 20 | 48.69 ns | 0.347 ns | 0.307 ns | - | -| HistogramWith1LabelHotPath | 20 | 93.84 ns | 0.696 ns | 0.651 ns | - | -| HistogramWith3LabelsHotPath | 20 | 189.82 ns | 1.208 ns | 1.071 ns | - | -| HistogramWith5LabelsHotPath | 20 | 269.23 ns | 2.027 ns | 1.693 ns | - | -| HistogramWith7LabelsHotPath | 20 | 329.92 ns | 1.272 ns | 1.128 ns | - | -| HistogramHotPath | 50 | 55.73 ns | 0.339 ns | 0.317 ns | - | -| HistogramWith1LabelHotPath | 50 | 100.38 ns | 0.455 ns | 0.425 ns | - | -| HistogramWith3LabelsHotPath | 50 | 200.02 ns | 1.011 ns | 0.844 ns | - | -| HistogramWith5LabelsHotPath | 50 | 279.94 ns | 1.595 ns | 1.492 ns | - | -| HistogramWith7LabelsHotPath | 50 | 346.88 ns | 1.064 ns | 0.943 ns | - | -| HistogramHotPath | 100 | 66.39 ns | 0.167 ns | 0.148 ns | - | -| HistogramWith1LabelHotPath | 100 | 114.98 ns | 1.340 ns | 1.253 ns | - | -| HistogramWith3LabelsHotPath | 100 | 220.52 ns | 1.723 ns | 1.528 ns | - | -| HistogramWith5LabelsHotPath | 100 | 299.10 ns | 1.950 ns | 1.629 ns | - | -| HistogramWith7LabelsHotPath | 100 | 356.25 ns | 2.153 ns | 1.798 ns | - | +| HistogramHotPath | 10 | 42.68 ns | 0.116 ns | 0.109 ns | - | +| HistogramWith1LabelHotPath | 10 | 89.94 ns | 0.195 ns | 0.173 ns | - | +| HistogramWith3LabelsHotPath | 10 | 175.81 ns | 0.597 ns | 0.558 ns | - | +| HistogramWith5LabelsHotPath | 10 | 259.52 ns | 0.435 ns | 0.363 ns | - | +| HistogramWith7LabelsHotPath | 10 | 316.83 ns | 0.530 ns | 0.470 ns | - | +| HistogramHotPath | 50 | 50.70 ns | 0.356 ns | 0.333 ns | - | +| HistogramWith1LabelHotPath | 50 | 101.23 ns | 0.155 ns | 0.145 ns | - | +| HistogramWith3LabelsHotPath | 50 | 185.92 ns | 0.290 ns | 0.271 ns | - | +| HistogramWith5LabelsHotPath | 50 | 275.40 ns | 0.357 ns | 0.316 ns | - | +| HistogramWith7LabelsHotPath | 50 | 333.33 ns | 0.646 ns | 0.540 ns | - | +| HistogramHotPath | 390 | 115.16 ns | 0.115 ns | 0.108 ns | - | +| HistogramWith1LabelHotPath | 390 | 165.81 ns | 0.378 ns | 0.353 ns | - | +| HistogramWith3LabelsHotPath | 390 | 265.34 ns | 1.043 ns | 0.975 ns | - | +| HistogramWith5LabelsHotPath | 390 | 374.90 ns | 0.938 ns | 0.878 ns | - | +| HistogramWith7LabelsHotPath | 390 | 437.83 ns | 1.014 ns | 0.847 ns | - | +| HistogramHotPath | 410 | 118.25 ns | 0.103 ns | 0.096 ns | - | +| HistogramWith1LabelHotPath | 410 | 171.96 ns | 0.139 ns | 0.130 ns | - | +| HistogramWith3LabelsHotPath | 410 | 269.87 ns | 0.679 ns | 0.635 ns | - | +| HistogramWith5LabelsHotPath | 410 | 355.99 ns | 0.831 ns | 0.778 ns | - | +| HistogramWith7LabelsHotPath | 410 | 421.68 ns | 0.663 ns | 0.587 ns | - | */ namespace Benchmarks.Metrics { public class HistogramBenchmarks { - private const int MaxValue = 1000; + private const int MaxValue = 10000; private readonly Random random = new(); private readonly string[] dimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; private Histogram histogram; @@ -67,7 +67,7 @@ public class HistogramBenchmarks private Meter meter; private double[] bounds; - [Params(10, 20, 50, 100)] + [Params(10, 50, 390, 410)] public int BoundCount { get; set; } [GlobalSetup] diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 0664dc18c00..2e7052b773a 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -44,6 +44,7 @@ public static IEnumerable ValidInstrumentNames public static IEnumerable InvalidHistogramBoundaries => new List { + new object[] { new double[] { double.NaN } }, new object[] { new double[] { 0, 0 } }, new object[] { new double[] { 1, 0 } }, new object[] { new double[] { 0, 1, 1, 2 } }, From 1bb61e9b8d13e5672e24634ef8040d3dcaa20662 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 12 May 2022 12:52:59 -0700 Subject: [PATCH 035/111] separate nan part --- .../Metrics/ExplicitBucketHistogramConfiguration.cs | 11 +++-------- src/OpenTelemetry/Metrics/MetricPoint.cs | 4 +--- test/OpenTelemetry.Tests/Metrics/MetricTestData.cs | 1 - 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index bf2f896d404..58bfc245b10 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -30,7 +30,7 @@ public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration /// Requirements: /// /// The array must be in ascending order with distinct - /// values. double.NaN is not allowed + /// values. /// An empty array would result in no histogram buckets being /// calculated. /// A null value would result in default bucket boundaries being @@ -58,7 +58,7 @@ public double[] Boundaries { if (!IsSortedAndDistinct(value)) { - throw new ArgumentException($"Histogram boundaries are invalid. Histogram boundaries must be in ascending order with distinct values. double.NaN is not allowed.", nameof(value)); + throw new ArgumentException($"Histogram boundaries are invalid. Histogram boundaries must be in ascending order with distinct values.", nameof(value)); } double[] copy = new double[value.Length]; @@ -76,14 +76,9 @@ public double[] Boundaries private static bool IsSortedAndDistinct(double[] values) { - if (double.IsNaN(values[0])) - { - return false; - } - for (int i = 1; i < values.Length; i++) { - if (double.IsNaN(values[i]) || values[i] <= values[i - 1]) + if (values[i] <= values[i - 1]) { return false; } diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 4a1f16c122f..41921f6586e 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -330,9 +330,7 @@ internal void Update(double number) case AggregationType.Histogram: { - int i = double.IsNaN(number) - ? this.histogramBuckets.ExplicitBounds.Length - : this.findHistogramBucketIndex(this.histogramBuckets.ExplicitBounds, number); + int i = this.findHistogramBucketIndex(this.histogramBuckets.ExplicitBounds, number); var sw = default(SpinWait); while (true) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 2e7052b773a..0664dc18c00 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -44,7 +44,6 @@ public static IEnumerable ValidInstrumentNames public static IEnumerable InvalidHistogramBoundaries => new List { - new object[] { new double[] { double.NaN } }, new object[] { new double[] { 0, 0 } }, new object[] { new double[] { 1, 0 } }, new object[] { new double[] { 0, 1, 1, 2 } }, From 685b46e11034eeb681815f8186ed6f4ddea2a949 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 12 May 2022 15:12:07 -0700 Subject: [PATCH 036/111] Address PR comments - Remove conversion to float from `FindHistogramBucketIndexBinary` - Make `DefaultHistogramCountForBinarySearch` a `const` instead of a `static readonly` --- src/OpenTelemetry/Metrics/Metric.cs | 4 ++-- src/OpenTelemetry/Metrics/MetricPoint.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 961d0b06ed5..90752f19f76 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -25,9 +25,9 @@ namespace OpenTelemetry.Metrics /// public sealed class Metric { - internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; + internal const int DefaultHistogramCountForBinarySearch = 400; - internal static readonly int DefaultHistogramCountForBinarySearch = 400; + internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; private readonly AggregatorStore aggStore; diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 41921f6586e..6c7ba9dcf86 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -563,12 +563,12 @@ private static int FindHistogramBucketIndexLinear(double[] bounds, double number private static int FindHistogramBucketIndexBinary(double[] bounds, double number) { - var left = 0; - var right = bounds.Length - 1; + int left = 0; + int right = bounds.Length - 1; while (left <= right) { - var mid = (int)Math.Floor((double)(left + right) / 2); + int mid = (left + right) / 2; if (number == bounds[mid]) { return mid; From de60b0e520f769e77a69d05a7b83e53bca00d961 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 12 May 2022 16:39:41 -0700 Subject: [PATCH 037/111] update to 140 --- src/OpenTelemetry/Metrics/Metric.cs | 4 +- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 48 +++++++++++-------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 887aa61aeed..9bda48aea24 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -25,12 +25,10 @@ namespace OpenTelemetry.Metrics /// public sealed class Metric { - internal const int DefaultHistogramCountForBinarySearch = 400; + internal const int DefaultHistogramCountForBinarySearch = 140; internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; - internal static readonly int DefaultHistogramCountForBinarySearch = 400; - private readonly AggregatorStore aggStore; internal Metric( diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index dbca35b2924..ca5ed2246ac 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -33,26 +33,31 @@ | Method | BoundCount | Mean | Error | StdDev | Allocated | |---------------------------- |----------- |----------:|---------:|---------:|----------:| -| HistogramHotPath | 10 | 42.68 ns | 0.116 ns | 0.109 ns | - | -| HistogramWith1LabelHotPath | 10 | 89.94 ns | 0.195 ns | 0.173 ns | - | -| HistogramWith3LabelsHotPath | 10 | 175.81 ns | 0.597 ns | 0.558 ns | - | -| HistogramWith5LabelsHotPath | 10 | 259.52 ns | 0.435 ns | 0.363 ns | - | -| HistogramWith7LabelsHotPath | 10 | 316.83 ns | 0.530 ns | 0.470 ns | - | -| HistogramHotPath | 50 | 50.70 ns | 0.356 ns | 0.333 ns | - | -| HistogramWith1LabelHotPath | 50 | 101.23 ns | 0.155 ns | 0.145 ns | - | -| HistogramWith3LabelsHotPath | 50 | 185.92 ns | 0.290 ns | 0.271 ns | - | -| HistogramWith5LabelsHotPath | 50 | 275.40 ns | 0.357 ns | 0.316 ns | - | -| HistogramWith7LabelsHotPath | 50 | 333.33 ns | 0.646 ns | 0.540 ns | - | -| HistogramHotPath | 390 | 115.16 ns | 0.115 ns | 0.108 ns | - | -| HistogramWith1LabelHotPath | 390 | 165.81 ns | 0.378 ns | 0.353 ns | - | -| HistogramWith3LabelsHotPath | 390 | 265.34 ns | 1.043 ns | 0.975 ns | - | -| HistogramWith5LabelsHotPath | 390 | 374.90 ns | 0.938 ns | 0.878 ns | - | -| HistogramWith7LabelsHotPath | 390 | 437.83 ns | 1.014 ns | 0.847 ns | - | -| HistogramHotPath | 410 | 118.25 ns | 0.103 ns | 0.096 ns | - | -| HistogramWith1LabelHotPath | 410 | 171.96 ns | 0.139 ns | 0.130 ns | - | -| HistogramWith3LabelsHotPath | 410 | 269.87 ns | 0.679 ns | 0.635 ns | - | -| HistogramWith5LabelsHotPath | 410 | 355.99 ns | 0.831 ns | 0.778 ns | - | -| HistogramWith7LabelsHotPath | 410 | 421.68 ns | 0.663 ns | 0.587 ns | - | +| HistogramHotPath | 10 | 41.79 ns | 0.096 ns | 0.089 ns | - | +| HistogramWith1LabelHotPath | 10 | 93.32 ns | 0.185 ns | 0.173 ns | - | +| HistogramWith3LabelsHotPath | 10 | 173.11 ns | 0.090 ns | 0.079 ns | - | +| HistogramWith5LabelsHotPath | 10 | 263.42 ns | 0.542 ns | 0.507 ns | - | +| HistogramWith7LabelsHotPath | 10 | 318.65 ns | 0.388 ns | 0.344 ns | - | +| HistogramHotPath | 50 | 51.52 ns | 0.234 ns | 0.208 ns | - | +| HistogramWith1LabelHotPath | 50 | 102.16 ns | 0.201 ns | 0.178 ns | - | +| HistogramWith3LabelsHotPath | 50 | 188.54 ns | 0.263 ns | 0.246 ns | - | +| HistogramWith5LabelsHotPath | 50 | 274.89 ns | 0.471 ns | 0.441 ns | - | +| HistogramWith7LabelsHotPath | 50 | 334.87 ns | 0.541 ns | 0.451 ns | - | +| HistogramHotPath | 139 | 75.40 ns | 0.085 ns | 0.075 ns | - | +| HistogramWith1LabelHotPath | 139 | 123.86 ns | 0.510 ns | 0.477 ns | - | +| HistogramWith3LabelsHotPath | 139 | 211.11 ns | 0.415 ns | 0.368 ns | - | +| HistogramWith5LabelsHotPath | 139 | 298.31 ns | 0.788 ns | 0.737 ns | - | +| HistogramWith7LabelsHotPath | 139 | 357.28 ns | 0.619 ns | 0.548 ns | - | +| HistogramHotPath | 140 | 69.13 ns | 0.171 ns | 0.160 ns | - | +| HistogramWith1LabelHotPath | 140 | 117.86 ns | 0.182 ns | 0.171 ns | - | +| HistogramWith3LabelsHotPath | 140 | 208.26 ns | 0.382 ns | 0.319 ns | - | +| HistogramWith5LabelsHotPath | 140 | 297.56 ns | 0.769 ns | 0.682 ns | - | +| HistogramWith7LabelsHotPath | 140 | 349.53 ns | 0.581 ns | 0.515 ns | - | +| HistogramHotPath | 1000 | 85.90 ns | 0.263 ns | 0.246 ns | - | +| HistogramWith1LabelHotPath | 1000 | 136.94 ns | 0.475 ns | 0.444 ns | - | +| HistogramWith3LabelsHotPath | 1000 | 230.74 ns | 0.465 ns | 0.435 ns | - | +| HistogramWith5LabelsHotPath | 1000 | 325.73 ns | 2.040 ns | 1.908 ns | - | +| HistogramWith7LabelsHotPath | 1000 | 379.81 ns | 2.100 ns | 1.964 ns | - | */ namespace Benchmarks.Metrics @@ -67,7 +72,8 @@ public class HistogramBenchmarks private Meter meter; private double[] bounds; - [Params(10, 50, 390, 410)] + // Note: Values related to `Metric.DefaultHistogramCountForBinarySearch` + [Params(10, 50, 139, 140, 1000)] public int BoundCount { get; set; } [GlobalSetup] From 020c42e7efa1ab2c7d6b8b30d699a1bc9e37171e Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 12 May 2022 16:41:03 -0700 Subject: [PATCH 038/111] remove double.nan from invalid hist bounds --- test/OpenTelemetry.Tests/Metrics/MetricTestData.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 2e7052b773a..0664dc18c00 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -44,7 +44,6 @@ public static IEnumerable ValidInstrumentNames public static IEnumerable InvalidHistogramBoundaries => new List { - new object[] { new double[] { double.NaN } }, new object[] { new double[] { 0, 0 } }, new object[] { new double[] { 1, 0 } }, new object[] { new double[] { 0, 1, 1, 2 } }, From daf1a806151dc194bb8ea4e95d6015deb979b3ca Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 25 May 2022 15:27:49 -0700 Subject: [PATCH 039/111] Refactor and perf to histogram bucket index find Thanks to @CodeBlanch !! --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 92 +++++++++++++++++++ src/OpenTelemetry/Metrics/MetricPoint.cs | 52 +---------- 2 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 626779d4901..4ccf984414b 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -15,6 +15,8 @@ // using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; namespace OpenTelemetry.Metrics { @@ -36,9 +38,38 @@ public class HistogramBuckets internal int IsCriticalSectionOccupied = 0; + private readonly Bucket root; + + private readonly Func findHistogramBucketIndex; + internal HistogramBuckets(double[] explicitBounds) { this.ExplicitBounds = explicitBounds; + this.findHistogramBucketIndex = this.FindBucketIndexLinear; + if (explicitBounds != null && explicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch) + { + this.root = ConstructBalancedTree(explicitBounds, 0, explicitBounds.Length); + this.findHistogramBucketIndex = this.FindBucketIndexBinary; + + static Bucket ConstructBalancedTree(double[] values, int min, int max) + { + if (min == max) + { + return null; + } + + int median = min + ((max - min) / 2); + return new Bucket + { + Index = median, + UpperBoundInclusive = values[median], + LowerBoundExclusive = median > 0 ? values[median - 1] : double.MinValue, + Left = ConstructBalancedTree(values, min, median), + Right = ConstructBalancedTree(values, median + 1, max), + }; + } + } + this.RunningBucketCounts = explicitBounds != null ? new long[explicitBounds.Length + 1] : null; this.SnapshotBucketCounts = explicitBounds != null ? new long[explicitBounds.Length + 1] : new long[0]; } @@ -57,6 +88,54 @@ internal HistogramBuckets Copy() return copy; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int FindBucketIndex(double value) + { + return this.findHistogramBucketIndex(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int FindBucketIndexBinary(double value) + { + Bucket current = this.root; + + Debug.Assert(current != null, "Bucket root was null."); + + while (current != null) + { + if (value <= current.LowerBoundExclusive) + { + current = current.Left; + } + else if (value > current.UpperBoundInclusive) + { + current = current.Right; + } + else + { + return current.Index; + } + } + + return this.ExplicitBounds.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int FindBucketIndexLinear(double value) + { + int i; + for (i = 0; i < this.ExplicitBounds.Length; i++) + { + // Upper bound is inclusive + if (value <= this.ExplicitBounds[i]) + { + break; + } + } + + return i; + } + /// /// Enumerates the elements of a . /// @@ -104,5 +183,18 @@ public bool MoveNext() return false; } } + + private class Bucket + { + public double UpperBoundInclusive { get; set; } + + public double LowerBoundExclusive { get; set; } + + public int Index { get; set; } + + public Bucket Left { get; set; } + + public Bucket Right { get; set; } + } } } diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index b0eb3f24687..149f20bc8f8 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -30,8 +30,6 @@ public struct MetricPoint private readonly AggregationType aggType; - private readonly Func findHistogramBucketIndex = FindHistogramBucketIndexLinear; - private HistogramBuckets histogramBuckets; // Represents temporality adjusted "value" for double/long metric types or "count" when histogram @@ -63,10 +61,6 @@ internal MetricPoint( if (this.aggType == AggregationType.Histogram) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); - if (histogramExplicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch) - { - this.findHistogramBucketIndex = FindHistogramBucketIndexBinary; - } } else if (this.aggType == AggregationType.HistogramSumCount) { @@ -330,9 +324,7 @@ internal void Update(double number) case AggregationType.Histogram: { - int i = double.IsNaN(number) - ? this.histogramBuckets.ExplicitBounds.Length - : this.findHistogramBucketIndex(this.histogramBuckets.ExplicitBounds, number); + int i = this.histogramBuckets.FindBucketIndex(number); var sw = default(SpinWait); while (true) @@ -545,47 +537,5 @@ private readonly void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } - -#pragma warning disable SA1204 // Static elements should appear before instance elements - private static int FindHistogramBucketIndexLinear(double[] bounds, double number) -#pragma warning restore SA1204 // Static elements should appear before instance elements - { - int i; - - for (i = 0; i < bounds.Length; i++) - { - if (number <= bounds[i]) - { - break; - } - } - - return i; - } - - private static int FindHistogramBucketIndexBinary(double[] bounds, double number) - { - int left = 0; - int right = bounds.Length - 1; - - while (left <= right) - { - int mid = (left + right) / 2; - if (number == bounds[mid]) - { - return mid; - } - else if (number > bounds[mid]) - { - left = mid + 1; - } - else - { - right = mid - 1; - } - } - - return right + 1; - } } } From 5bc4998d64adb9932fa2df57835d44bc4d689d25 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 25 May 2022 17:19:38 -0700 Subject: [PATCH 040/111] fine tune bound limit to switch to binary search --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 4 +++- src/OpenTelemetry/Metrics/Metric.cs | 2 -- test/Benchmarks/Metrics/HistogramBenchmarks.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 4ccf984414b..9ac390fde2f 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -26,6 +26,8 @@ namespace OpenTelemetry.Metrics // Note: Does not implement IEnumerable<> to prevent accidental boxing. public class HistogramBuckets { + internal const int DefaultHistogramCountForBinarySearch = 50; + internal readonly double[] ExplicitBounds; internal readonly long[] RunningBucketCounts; @@ -46,7 +48,7 @@ internal HistogramBuckets(double[] explicitBounds) { this.ExplicitBounds = explicitBounds; this.findHistogramBucketIndex = this.FindBucketIndexLinear; - if (explicitBounds != null && explicitBounds.Length >= Metric.DefaultHistogramCountForBinarySearch) + if (explicitBounds != null && explicitBounds.Length >= DefaultHistogramCountForBinarySearch) { this.root = ConstructBalancedTree(explicitBounds, 0, explicitBounds.Length); this.findHistogramBucketIndex = this.FindBucketIndexBinary; diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 9bda48aea24..61443173f70 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -25,8 +25,6 @@ namespace OpenTelemetry.Metrics /// public sealed class Metric { - internal const int DefaultHistogramCountForBinarySearch = 140; - internal static readonly double[] DefaultHistogramBounds = new double[] { 0, 5, 10, 25, 50, 75, 100, 250, 500, 1000 }; private readonly AggregatorStore aggStore; diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index ca5ed2246ac..e82164c21fa 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -72,8 +72,8 @@ public class HistogramBenchmarks private Meter meter; private double[] bounds; - // Note: Values related to `Metric.DefaultHistogramCountForBinarySearch` - [Params(10, 50, 139, 140, 1000)] + // Note: Values related to `HistogramBuckets.DefaultHistogramCountForBinarySearch` + [Params(10, 49, 50, 1000)] public int BoundCount { get; set; } [GlobalSetup] From e84127ad58f58ab6dfb9a8a01ca2fdc747b89cc1 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 25 May 2022 18:19:39 -0700 Subject: [PATCH 041/111] included benchmark results in comment --- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index e82164c21fa..fdab0386ac3 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -24,40 +24,35 @@ using OpenTelemetry.Tests; /* -BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1706 (21H2) -AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores +BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000 +Intel Core i7-1065G7 CPU 1.30GHz, 1 CPU, 8 logical and 4 physical cores .NET SDK=6.0.203 [Host] : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT -| Method | BoundCount | Mean | Error | StdDev | Allocated | -|---------------------------- |----------- |----------:|---------:|---------:|----------:| -| HistogramHotPath | 10 | 41.79 ns | 0.096 ns | 0.089 ns | - | -| HistogramWith1LabelHotPath | 10 | 93.32 ns | 0.185 ns | 0.173 ns | - | -| HistogramWith3LabelsHotPath | 10 | 173.11 ns | 0.090 ns | 0.079 ns | - | -| HistogramWith5LabelsHotPath | 10 | 263.42 ns | 0.542 ns | 0.507 ns | - | -| HistogramWith7LabelsHotPath | 10 | 318.65 ns | 0.388 ns | 0.344 ns | - | -| HistogramHotPath | 50 | 51.52 ns | 0.234 ns | 0.208 ns | - | -| HistogramWith1LabelHotPath | 50 | 102.16 ns | 0.201 ns | 0.178 ns | - | -| HistogramWith3LabelsHotPath | 50 | 188.54 ns | 0.263 ns | 0.246 ns | - | -| HistogramWith5LabelsHotPath | 50 | 274.89 ns | 0.471 ns | 0.441 ns | - | -| HistogramWith7LabelsHotPath | 50 | 334.87 ns | 0.541 ns | 0.451 ns | - | -| HistogramHotPath | 139 | 75.40 ns | 0.085 ns | 0.075 ns | - | -| HistogramWith1LabelHotPath | 139 | 123.86 ns | 0.510 ns | 0.477 ns | - | -| HistogramWith3LabelsHotPath | 139 | 211.11 ns | 0.415 ns | 0.368 ns | - | -| HistogramWith5LabelsHotPath | 139 | 298.31 ns | 0.788 ns | 0.737 ns | - | -| HistogramWith7LabelsHotPath | 139 | 357.28 ns | 0.619 ns | 0.548 ns | - | -| HistogramHotPath | 140 | 69.13 ns | 0.171 ns | 0.160 ns | - | -| HistogramWith1LabelHotPath | 140 | 117.86 ns | 0.182 ns | 0.171 ns | - | -| HistogramWith3LabelsHotPath | 140 | 208.26 ns | 0.382 ns | 0.319 ns | - | -| HistogramWith5LabelsHotPath | 140 | 297.56 ns | 0.769 ns | 0.682 ns | - | -| HistogramWith7LabelsHotPath | 140 | 349.53 ns | 0.581 ns | 0.515 ns | - | -| HistogramHotPath | 1000 | 85.90 ns | 0.263 ns | 0.246 ns | - | -| HistogramWith1LabelHotPath | 1000 | 136.94 ns | 0.475 ns | 0.444 ns | - | -| HistogramWith3LabelsHotPath | 1000 | 230.74 ns | 0.465 ns | 0.435 ns | - | -| HistogramWith5LabelsHotPath | 1000 | 325.73 ns | 2.040 ns | 1.908 ns | - | -| HistogramWith7LabelsHotPath | 1000 | 379.81 ns | 2.100 ns | 1.964 ns | - | +| Method | BoundCount | Mean | Error | StdDev | +|---------------------------- |----------- |----------:|----------:|----------:| +| HistogramHotPath | 10 | 55.07 ns | 0.664 ns | 1.091 ns | +| HistogramWith1LabelHotPath | 10 | 108.66 ns | 1.324 ns | 1.174 ns | +| HistogramWith3LabelsHotPath | 10 | 193.79 ns | 3.261 ns | 3.349 ns | +| HistogramWith5LabelsHotPath | 10 | 279.44 ns | 4.608 ns | 3.848 ns | +| HistogramWith7LabelsHotPath | 10 | 334.28 ns | 6.650 ns | 5.895 ns | +| HistogramHotPath | 49 | 68.27 ns | 0.744 ns | 0.581 ns | +| HistogramWith1LabelHotPath | 49 | 125.55 ns | 2.265 ns | 2.518 ns | +| HistogramWith3LabelsHotPath | 49 | 207.95 ns | 4.023 ns | 3.951 ns | +| HistogramWith5LabelsHotPath | 49 | 293.45 ns | 5.689 ns | 5.842 ns | +| HistogramWith7LabelsHotPath | 49 | 362.19 ns | 5.610 ns | 6.003 ns | +| HistogramHotPath | 50 | 69.64 ns | 1.422 ns | 1.330 ns | +| HistogramWith1LabelHotPath | 50 | 118.15 ns | 2.040 ns | 1.908 ns | +| HistogramWith3LabelsHotPath | 50 | 250.31 ns | 4.617 ns | 9.326 ns | +| HistogramWith5LabelsHotPath | 50 | 335.31 ns | 3.904 ns | 3.461 ns | +| HistogramWith7LabelsHotPath | 50 | 398.02 ns | 6.815 ns | 6.374 ns | +| HistogramHotPath | 1000 | 94.05 ns | 1.890 ns | 2.100 ns | +| HistogramWith1LabelHotPath | 1000 | 148.57 ns | 2.055 ns | 1.822 ns | +| HistogramWith3LabelsHotPath | 1000 | 661.78 ns | 11.599 ns | 20.314 ns | +| HistogramWith5LabelsHotPath | 1000 | 761.54 ns | 15.049 ns | 16.727 ns | +| HistogramWith7LabelsHotPath | 1000 | 830.14 ns | 16.063 ns | 17.853 ns | */ namespace Benchmarks.Metrics From fb1ad6b2ccc47234f13d23bdb5983373c30eac30 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Thu, 9 Jun 2022 13:45:16 -0700 Subject: [PATCH 042/111] histogram stress test update --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 3 +- .../Program.cs | 36 ++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 9ac390fde2f..38a49be706a 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -103,7 +103,7 @@ internal int FindBucketIndexBinary(double value) Debug.Assert(current != null, "Bucket root was null."); - while (current != null) + do { if (value <= current.LowerBoundExclusive) { @@ -118,6 +118,7 @@ internal int FindBucketIndexBinary(double value) return current.Index; } } + while (current != null); return this.ExplicitBounds.Length; } diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index 8838a1854c9..cecfc984931 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -24,18 +24,15 @@ namespace OpenTelemetry.Tests.Stress; public partial class Program { - private const int ArraySize = 10; - - // Note: Uncomment the below line if you want to run Histogram stress test - // private const int MaxHistogramMeasurement = 1000; + private const int ArraySize = 49; + private const int MaxValue = 1000; private static readonly Meter TestMeter = new(Utils.GetCurrentMethodName()); - private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); private static readonly string[] DimensionValues = new string[ArraySize]; private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random()); - // Note: Uncomment the below line if you want to run Histogram stress test - // private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); + private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); + private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); public static void Main() { @@ -44,6 +41,12 @@ public static void Main() DimensionValues[i] = $"DimValue{i}"; } + var bounds = new double[ArraySize]; + for (int i = 0; i < bounds.Length; i++) + { + bounds[i] = i * MaxValue / bounds.Length; + } + using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusExporter(options => @@ -52,6 +55,7 @@ public static void Main() options.HttpListenerPrefixes = new string[] { $"http://localhost:9185/" }; options.ScrapeResponseCacheDurationMilliseconds = 0; }) + .AddView(TestHistogram.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = bounds }) .Build(); Stress(prometheusPort: 9184); @@ -61,22 +65,12 @@ public static void Main() protected static void Run() { var random = ThreadLocalRandom.Value; - TestCounter.Add( + /*TestCounter.Add( 100, new("DimName1", DimensionValues[random.Next(0, ArraySize)]), new("DimName2", DimensionValues[random.Next(0, ArraySize)]), - new("DimName3", DimensionValues[random.Next(0, ArraySize)])); - } + new("DimName3", DimensionValues[random.Next(0, ArraySize)]));*/ - // Note: Uncomment the below lines if you want to run Histogram stress test - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // protected static void Run() - // { - // var random = ThreadLocalRandom.Value; - // TestHistogram.Record( - // random.Next(MaxHistogramMeasurement), - // new("DimName1", DimensionValues[random.Next(0, ArraySize)]), - // new("DimName2", DimensionValues[random.Next(0, ArraySize)]), - // new("DimName3", DimensionValues[random.Next(0, ArraySize)])); - // } + TestHistogram.Record(random.Next(MaxValue)); + } } From 05cc3c133c1bff19c6dd308ad94d5388607bbbdc Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 28 Jun 2022 15:55:15 -0700 Subject: [PATCH 043/111] fix changelog --- src/OpenTelemetry/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index a77590f915a..18eefd19eff 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -52,7 +52,7 @@ Released 2022-May-16 * Exposed public setters for `LogRecord.State`, `LogRecord.StateValues`, and `LogRecord.FormattedMessage`. - ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) + ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) ## 1.3.0-beta.1 From 15c34641bd91cf6cf4e6f8dbb71225e45b38427c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 28 Jun 2022 15:56:19 -0700 Subject: [PATCH 044/111] spacing fix --- src/OpenTelemetry/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 18eefd19eff..a77590f915a 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -52,7 +52,7 @@ Released 2022-May-16 * Exposed public setters for `LogRecord.State`, `LogRecord.StateValues`, and `LogRecord.FormattedMessage`. - ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) + ([#3217](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217)) ## 1.3.0-beta.1 From e203c2f64b707d1e4de737632b1001a8df3bee5e Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 29 Jun 2022 13:49:28 -0700 Subject: [PATCH 045/111] Fix some (all?) build errors --- src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt | 6 ++++++ .../.publicApi/netstandard2.0/PublicAPI.Unshipped.txt | 1 - .../Metrics/ExplicitBucketHistogramConfiguration.cs | 2 +- test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 43156ee3c3a..359ca7dd185 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -11,5 +11,11 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index da613a718da..8c8fb3951be 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -19,5 +19,4 @@ OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder -~static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogramWithMinMax(this OpenTelemetry.Metrics.MetricType self) -> bool ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index 58bfc245b10..8be618748fc 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -21,7 +21,7 @@ namespace OpenTelemetry.Metrics /// /// Stores configuration for a histogram metric stream with explicit bucket boundaries. /// - public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration + public class ExplicitBucketHistogramConfiguration : HistogramConfiguration { /// /// Gets or sets the optional boundaries of the histogram metric stream. diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 17714fcad8f..b3cecb30f9c 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -1202,7 +1202,8 @@ public void ViewConflict_TwoInstruments_ConflictAvoidedBecauseSecondInstrumentIs [Fact] public void GetHistogramMinThrows() { - var histogramPoint = new MetricPoint(AggregationType.HistogramMinMax, DateTime.Now, null, null, new double[] { 0 }); + AggregatorStore aggregatorStore = new("test", AggregationType.HistogramMinMax, AggregationTemporality.Cumulative, 1024, Metric.DefaultHistogramBounds); + var histogramPoint = new MetricPoint(aggregatorStore, AggregationType.HistogramMinMax, null, null, new double[] { 0 }); var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); Assert.Equal("No values have been recorded yet.", ex.Message); From a13fb6ab0c5c21bcb9f236e1119106116178ee20 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 29 Jun 2022 14:31:27 -0700 Subject: [PATCH 046/111] change already amde --- src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs index d2673eeff2d..8646e37156c 100644 --- a/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderSdk.cs @@ -44,7 +44,7 @@ internal static bool IsValidInstrumentName(string instrumentName) /// /// See specification: . /// The view name. - /// Boolean indicating if the view name is valid. + /// Boolean indicating if the instrument is valid. internal static bool IsValidViewName(string customViewName) { // Only validate the view name in case it's not null. In case it's null, the view name will be the instrument name as per the spec. From acfebca2896611fffe472eb2a265e72df3209491 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 29 Jun 2022 15:35:44 -0700 Subject: [PATCH 047/111] add min and max to otlp exporter --- .../Implementation/MetricItemExtensions.cs | 6 ++++++ src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index fe21b8d058e..515d76d0ab8 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -237,6 +237,7 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: + case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram { @@ -254,6 +255,11 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) AddAttributes(metricPoint.Tags, dataPoint.Attributes); dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); + if (metric.MetricType == MetricType.HistogramWithMinMax) + { + dataPoint.Min = metricPoint.GetHistogramMin(); + dataPoint.Max = metricPoint.GetHistogramMax(); + } foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) { diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 359ca7dd185..b471480fc22 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -17,5 +17,7 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType +static OpenTelemetry.Metrics.Extensions.IsHistogram(this OpenTelemetry.Metrics.AggregationType aggType) -> bool ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file From a2c0e5dbc1da3e3377cfb9c113ca05920038298a Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 1 Jul 2022 15:16:38 -0700 Subject: [PATCH 048/111] sealed bucket class --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 38a49be706a..438f38284ef 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -187,7 +187,7 @@ public bool MoveNext() } } - private class Bucket + private sealed class Bucket { public double UpperBoundInclusive { get; set; } From ef28da0f4e814dd7c3ac61ce499f90a7040732b3 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 1 Jul 2022 15:44:25 -0700 Subject: [PATCH 049/111] ci From 543a6d53be5754d231f656f729c09eb3e476df29 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 5 Jul 2022 12:57:35 -0700 Subject: [PATCH 050/111] double.negative infinity --- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 438f38284ef..11c3f2512b1 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -65,7 +65,7 @@ static Bucket ConstructBalancedTree(double[] values, int min, int max) { Index = median, UpperBoundInclusive = values[median], - LowerBoundExclusive = median > 0 ? values[median - 1] : double.MinValue, + LowerBoundExclusive = median > 0 ? values[median - 1] : double.NegativeInfinity, Left = ConstructBalancedTree(values, min, median), Right = ConstructBalancedTree(values, median + 1, max), }; From f2a20f7f8ed332ed130914dfc3694c2480d49581 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 5 Jul 2022 13:11:53 -0700 Subject: [PATCH 051/111] update order of operations when testing with large MaxValue this would end up having same value bounds --- test/OpenTelemetry.Tests.Stress.Metrics/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index cecfc984931..eba957d42f5 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -26,6 +26,7 @@ public partial class Program { private const int ArraySize = 49; private const int MaxValue = 1000; + private const int MaxValue = int.MaxValue; private static readonly Meter TestMeter = new(Utils.GetCurrentMethodName()); private static readonly string[] DimensionValues = new string[ArraySize]; @@ -44,7 +45,7 @@ public static void Main() var bounds = new double[ArraySize]; for (int i = 0; i < bounds.Length; i++) { - bounds[i] = i * MaxValue / bounds.Length; + bounds[i] = i * (MaxValue / bounds.Length); } using var meterProvider = Sdk.CreateMeterProviderBuilder() From c9f3a3d151aab4e5963165cbeb92f44b9788eb72 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 5 Jul 2022 14:38:31 -0700 Subject: [PATCH 052/111] remove stress test change --- .../Program.cs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index eba957d42f5..8838a1854c9 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -24,16 +24,18 @@ namespace OpenTelemetry.Tests.Stress; public partial class Program { - private const int ArraySize = 49; - private const int MaxValue = 1000; - private const int MaxValue = int.MaxValue; + private const int ArraySize = 10; + + // Note: Uncomment the below line if you want to run Histogram stress test + // private const int MaxHistogramMeasurement = 1000; private static readonly Meter TestMeter = new(Utils.GetCurrentMethodName()); + private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); private static readonly string[] DimensionValues = new string[ArraySize]; private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random()); - private static readonly Counter TestCounter = TestMeter.CreateCounter("TestCounter"); - private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); + // Note: Uncomment the below line if you want to run Histogram stress test + // private static readonly Histogram TestHistogram = TestMeter.CreateHistogram("TestHistogram"); public static void Main() { @@ -42,12 +44,6 @@ public static void Main() DimensionValues[i] = $"DimValue{i}"; } - var bounds = new double[ArraySize]; - for (int i = 0; i < bounds.Length; i++) - { - bounds[i] = i * (MaxValue / bounds.Length); - } - using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusExporter(options => @@ -56,7 +52,6 @@ public static void Main() options.HttpListenerPrefixes = new string[] { $"http://localhost:9185/" }; options.ScrapeResponseCacheDurationMilliseconds = 0; }) - .AddView(TestHistogram.Name, new ExplicitBucketHistogramConfiguration() { Boundaries = bounds }) .Build(); Stress(prometheusPort: 9184); @@ -66,12 +61,22 @@ public static void Main() protected static void Run() { var random = ThreadLocalRandom.Value; - /*TestCounter.Add( + TestCounter.Add( 100, new("DimName1", DimensionValues[random.Next(0, ArraySize)]), new("DimName2", DimensionValues[random.Next(0, ArraySize)]), - new("DimName3", DimensionValues[random.Next(0, ArraySize)]));*/ - - TestHistogram.Record(random.Next(MaxValue)); + new("DimName3", DimensionValues[random.Next(0, ArraySize)])); } + + // Note: Uncomment the below lines if you want to run Histogram stress test + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // protected static void Run() + // { + // var random = ThreadLocalRandom.Value; + // TestHistogram.Record( + // random.Next(MaxHistogramMeasurement), + // new("DimName1", DimensionValues[random.Next(0, ArraySize)]), + // new("DimName2", DimensionValues[random.Next(0, ArraySize)]), + // new("DimName3", DimensionValues[random.Next(0, ArraySize)])); + // } } From a201b86469901438b939fcb326618022f4b6bf51 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 5 Jul 2022 15:49:59 -0700 Subject: [PATCH 053/111] ci From d0d92a773d902734f6ac2a51260f3290f320c603 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 6 Jul 2022 12:39:48 -0700 Subject: [PATCH 054/111] Add histogram binary mode tests --- .../Metrics/AggregatorTest.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs b/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs index 9d40a3bd387..8bc3ab64b57 100644 --- a/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs +++ b/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs @@ -104,6 +104,34 @@ public void HistogramDistributeToAllBucketsCustom() Assert.Equal(boundaries.Length + 1, actualCount); } + [Fact] + public void HistogramBinaryBucketTest() + { + // Arrange + var boundaries = new double[HistogramBuckets.DefaultHistogramCountForBinarySearch]; + for (var i = 0; i < boundaries.Length; i++) + { + boundaries[i] = i; + } + + var histogramPoint = new MetricPoint(this.aggregatorStore, AggregationType.Histogram, null, null, boundaries); + + // Act + histogramPoint.Update(-1); + for (var i = 0.5; i < boundaries.Length; i++) + { + histogramPoint.Update(i); + } + + histogramPoint.TakeSnapshot(true); + + // Assert + foreach (var histogramMeasurement in histogramPoint.GetHistogramBuckets()) + { + Assert.Equal(1, histogramMeasurement.BucketCount); + } + } + [Fact] public void HistogramWithOnlySumCount() { From 7f8d32b605aed89128d1cb0375a4a9f07dded822 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 6 Jul 2022 13:17:20 -0700 Subject: [PATCH 055/111] ci From dbc5f3e5c2a1e2d5e9c22c1b7f5f1afa362ddf11 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 11 Jul 2022 15:59:49 -0700 Subject: [PATCH 056/111] pr review changes --- src/OpenTelemetry/CHANGELOG.md | 2 +- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 24 +++++++++---------- .../Metrics/AggregatorTest.cs | 16 +++++++++++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 31fa3125838..9a557defdc2 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,7 +2,7 @@ ## Unreleased -* Use binary search for histograms with a large amount of buckets. +* Use binary search for histograms with 50 or more supplied boundaries. ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) * `TracerProviderSDK` modified for spans with remote parent. For such spans diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 11c3f2512b1..d45379fbc84 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -26,7 +26,7 @@ namespace OpenTelemetry.Metrics // Note: Does not implement IEnumerable<> to prevent accidental boxing. public class HistogramBuckets { - internal const int DefaultHistogramCountForBinarySearch = 50; + internal const int DefaultBoundaryCountForBinarySearch = 50; internal readonly double[] ExplicitBounds; @@ -40,7 +40,7 @@ public class HistogramBuckets internal int IsCriticalSectionOccupied = 0; - private readonly Bucket root; + private readonly BucketLookupNode bucketLookupTreeRoot; private readonly Func findHistogramBucketIndex; @@ -48,12 +48,12 @@ internal HistogramBuckets(double[] explicitBounds) { this.ExplicitBounds = explicitBounds; this.findHistogramBucketIndex = this.FindBucketIndexLinear; - if (explicitBounds != null && explicitBounds.Length >= DefaultHistogramCountForBinarySearch) + if (explicitBounds != null && explicitBounds.Length >= DefaultBoundaryCountForBinarySearch) { - this.root = ConstructBalancedTree(explicitBounds, 0, explicitBounds.Length); + this.bucketLookupTreeRoot = ConstructBalancedBST(explicitBounds, 0, explicitBounds.Length); this.findHistogramBucketIndex = this.FindBucketIndexBinary; - static Bucket ConstructBalancedTree(double[] values, int min, int max) + static BucketLookupNode ConstructBalancedBST(double[] values, int min, int max) { if (min == max) { @@ -61,13 +61,13 @@ static Bucket ConstructBalancedTree(double[] values, int min, int max) } int median = min + ((max - min) / 2); - return new Bucket + return new BucketLookupNode { Index = median, UpperBoundInclusive = values[median], LowerBoundExclusive = median > 0 ? values[median - 1] : double.NegativeInfinity, - Left = ConstructBalancedTree(values, min, median), - Right = ConstructBalancedTree(values, median + 1, max), + Left = ConstructBalancedBST(values, min, median), + Right = ConstructBalancedBST(values, median + 1, max), }; } } @@ -99,7 +99,7 @@ internal int FindBucketIndex(double value) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal int FindBucketIndexBinary(double value) { - Bucket current = this.root; + BucketLookupNode current = this.bucketLookupTreeRoot; Debug.Assert(current != null, "Bucket root was null."); @@ -187,7 +187,7 @@ public bool MoveNext() } } - private sealed class Bucket + private sealed class BucketLookupNode { public double UpperBoundInclusive { get; set; } @@ -195,9 +195,9 @@ private sealed class Bucket public int Index { get; set; } - public Bucket Left { get; set; } + public BucketLookupNode Left { get; set; } - public Bucket Right { get; set; } + public BucketLookupNode Right { get; set; } } } } diff --git a/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs b/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs index 8bc3ab64b57..0b598d4fa34 100644 --- a/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs +++ b/test/OpenTelemetry.Tests/Metrics/AggregatorTest.cs @@ -108,7 +108,8 @@ public void HistogramDistributeToAllBucketsCustom() public void HistogramBinaryBucketTest() { // Arrange - var boundaries = new double[HistogramBuckets.DefaultHistogramCountForBinarySearch]; + // Bounds = (-Inf, 0] (0, 1], ... (49, +Inf) + var boundaries = new double[HistogramBuckets.DefaultBoundaryCountForBinarySearch]; for (var i = 0; i < boundaries.Length; i++) { boundaries[i] = i; @@ -118,6 +119,8 @@ public void HistogramBinaryBucketTest() // Act histogramPoint.Update(-1); + histogramPoint.Update(boundaries[0]); + histogramPoint.Update(boundaries[boundaries.Length - 1]); for (var i = 0.5; i < boundaries.Length; i++) { histogramPoint.Update(i); @@ -126,9 +129,18 @@ public void HistogramBinaryBucketTest() histogramPoint.TakeSnapshot(true); // Assert + var index = 0; foreach (var histogramMeasurement in histogramPoint.GetHistogramBuckets()) { - Assert.Equal(1, histogramMeasurement.BucketCount); + var expectedCount = 1; + + if (index == 0 || index == boundaries.Length - 1) + { + expectedCount = 2; + } + + Assert.Equal(expectedCount, histogramMeasurement.BucketCount); + index++; } } From 370fb1afb479546869e5084ace55423a416103cd Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 12 Jul 2022 12:11:44 -0700 Subject: [PATCH 057/111] allocated column - hist benchmark --- .../Benchmarks/Metrics/HistogramBenchmarks.cs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index fdab0386ac3..e9a6b94d39d 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -31,28 +31,28 @@ DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT -| Method | BoundCount | Mean | Error | StdDev | -|---------------------------- |----------- |----------:|----------:|----------:| -| HistogramHotPath | 10 | 55.07 ns | 0.664 ns | 1.091 ns | -| HistogramWith1LabelHotPath | 10 | 108.66 ns | 1.324 ns | 1.174 ns | -| HistogramWith3LabelsHotPath | 10 | 193.79 ns | 3.261 ns | 3.349 ns | -| HistogramWith5LabelsHotPath | 10 | 279.44 ns | 4.608 ns | 3.848 ns | -| HistogramWith7LabelsHotPath | 10 | 334.28 ns | 6.650 ns | 5.895 ns | -| HistogramHotPath | 49 | 68.27 ns | 0.744 ns | 0.581 ns | -| HistogramWith1LabelHotPath | 49 | 125.55 ns | 2.265 ns | 2.518 ns | -| HistogramWith3LabelsHotPath | 49 | 207.95 ns | 4.023 ns | 3.951 ns | -| HistogramWith5LabelsHotPath | 49 | 293.45 ns | 5.689 ns | 5.842 ns | -| HistogramWith7LabelsHotPath | 49 | 362.19 ns | 5.610 ns | 6.003 ns | -| HistogramHotPath | 50 | 69.64 ns | 1.422 ns | 1.330 ns | -| HistogramWith1LabelHotPath | 50 | 118.15 ns | 2.040 ns | 1.908 ns | -| HistogramWith3LabelsHotPath | 50 | 250.31 ns | 4.617 ns | 9.326 ns | -| HistogramWith5LabelsHotPath | 50 | 335.31 ns | 3.904 ns | 3.461 ns | -| HistogramWith7LabelsHotPath | 50 | 398.02 ns | 6.815 ns | 6.374 ns | -| HistogramHotPath | 1000 | 94.05 ns | 1.890 ns | 2.100 ns | -| HistogramWith1LabelHotPath | 1000 | 148.57 ns | 2.055 ns | 1.822 ns | -| HistogramWith3LabelsHotPath | 1000 | 661.78 ns | 11.599 ns | 20.314 ns | -| HistogramWith5LabelsHotPath | 1000 | 761.54 ns | 15.049 ns | 16.727 ns | -| HistogramWith7LabelsHotPath | 1000 | 830.14 ns | 16.063 ns | 17.853 ns | +| Method | BoundCount | Mean | Error | StdDev | Allocated | +|---------------------------- |----------- |----------:|----------:|----------:|----------:| +| HistogramHotPath | 10 | 55.07 ns | 0.664 ns | 1.091 ns | - | +| HistogramWith1LabelHotPath | 10 | 108.66 ns | 1.324 ns | 1.174 ns | - | +| HistogramWith3LabelsHotPath | 10 | 193.79 ns | 3.261 ns | 3.349 ns | - | +| HistogramWith5LabelsHotPath | 10 | 279.44 ns | 4.608 ns | 3.848 ns | - | +| HistogramWith7LabelsHotPath | 10 | 334.28 ns | 6.650 ns | 5.895 ns | - | +| HistogramHotPath | 49 | 68.27 ns | 0.744 ns | 0.581 ns | - | +| HistogramWith1LabelHotPath | 49 | 125.55 ns | 2.265 ns | 2.518 ns | - | +| HistogramWith3LabelsHotPath | 49 | 207.95 ns | 4.023 ns | 3.951 ns | - | +| HistogramWith5LabelsHotPath | 49 | 293.45 ns | 5.689 ns | 5.842 ns | - | +| HistogramWith7LabelsHotPath | 49 | 362.19 ns | 5.610 ns | 6.003 ns | - | +| HistogramHotPath | 50 | 69.64 ns | 1.422 ns | 1.330 ns | - | +| HistogramWith1LabelHotPath | 50 | 118.15 ns | 2.040 ns | 1.908 ns | - | +| HistogramWith3LabelsHotPath | 50 | 250.31 ns | 4.617 ns | 9.326 ns | - | +| HistogramWith5LabelsHotPath | 50 | 335.31 ns | 3.904 ns | 3.461 ns | - | +| HistogramWith7LabelsHotPath | 50 | 398.02 ns | 6.815 ns | 6.374 ns | - | +| HistogramHotPath | 1000 | 94.05 ns | 1.890 ns | 2.100 ns | - | +| HistogramWith1LabelHotPath | 1000 | 148.57 ns | 2.055 ns | 1.822 ns | - | +| HistogramWith3LabelsHotPath | 1000 | 661.78 ns | 11.599 ns | 20.314 ns | - | +| HistogramWith5LabelsHotPath | 1000 | 761.54 ns | 15.049 ns | 16.727 ns | - | +| HistogramWith7LabelsHotPath | 1000 | 830.14 ns | 16.063 ns | 17.853 ns | - | */ namespace Benchmarks.Metrics From 3b2f762ed4a8dbccd2e767ef2d75051b2540fbc0 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 26 Jul 2022 11:10:00 -0700 Subject: [PATCH 058/111] CI From 2ff79a9c66dd1a03a036c93d680d8bcb571e1ff9 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 2 Aug 2022 11:52:35 -0700 Subject: [PATCH 059/111] add public api (still borked?) --- src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt | 1 + src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt | 3 +-- .../.publicApi/netstandard2.1/PublicAPI.Unshipped.txt | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index ecaf006aa47..9cf26e801e8 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -11,5 +11,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index b471480fc22..2e87741c127 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -18,6 +18,5 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType -static OpenTelemetry.Metrics.Extensions.IsHistogram(this OpenTelemetry.Metrics.AggregationType aggType) -> bool ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder -~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 43156ee3c3a..3e82430b69b 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -11,5 +11,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder -~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder From 4566b92f473fb05c2f64742e362dfd7e9b516a0b Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Tue, 26 Jul 2022 16:23:31 -0700 Subject: [PATCH 060/111] Exponential Bucket Histogram - part 6 (#3494) --- src/OpenTelemetry/Internal/MathHelper.cs | 12 -- .../Metrics/ExponentialBucketHistogram.cs | 57 +++++- .../Metrics/ExponentialBucketHistogramTest.cs | 167 ++++++++++++------ .../Shared/IEEE754Double.cs | 103 +++++++++++ 4 files changed, 274 insertions(+), 65 deletions(-) create mode 100644 test/OpenTelemetry.Tests/Shared/IEEE754Double.cs diff --git a/src/OpenTelemetry/Internal/MathHelper.cs b/src/OpenTelemetry/Internal/MathHelper.cs index 043fcac6654..a3ffa316e8b 100644 --- a/src/OpenTelemetry/Internal/MathHelper.cs +++ b/src/OpenTelemetry/Internal/MathHelper.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -136,15 +135,4 @@ public static bool IsFinite(double value) return !double.IsInfinity(value) && !double.IsNaN(value); #endif } - - public static string DoubleToString(double value) - { - var repr = Convert.ToString(BitConverter.DoubleToInt64Bits(value), 2); - return new string('0', 64 - repr.Length) + repr; - } - - public static double DoubleFromString(string value) - { - return BitConverter.Int64BitsToDouble(Convert.ToInt64(value, 2)); - } } diff --git a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs index 0c2f2843244..f1670d3ba87 100644 --- a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs +++ b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs @@ -37,7 +37,49 @@ internal class ExponentialBucketHistogram public ExponentialBucketHistogram(int scale, int maxBuckets = 160) { - Guard.ThrowIfOutOfRange(scale, min: -20, max: 20); // TODO: calculate the actual range + /* + The following table is calculated based on [ MapToIndex(double.Epsilon), MapToIndex(double.MaxValue) ]: + + | Scale | Index Range | + | ----- | ------------------------- | + | < -11 | [-1, 0] | + | -11 | [-1, 0] | + | -10 | [-2, 0] | + | -9 | [-3, 1] | + | -8 | [-5, 3] | + | -7 | [-9, 7] | + | -6 | [-17, 15] | + | -5 | [-34, 31] | + | -4 | [-68, 63] | + | -3 | [-135, 127] | + | -2 | [-269, 255] | + | -1 | [-538, 511] | + | 0 | [-1075, 1023] | + | 1 | [-2149, 2047] | + | 2 | [-4297, 4095] | + | 3 | [-8593, 8191] | + | 4 | [-17185, 16383] | + | 5 | [-34369, 32767] | + | 6 | [-68737, 65535] | + | 7 | [-137473, 131071] | + | 8 | [-274945, 262143] | + | 9 | [-549889, 524287] | + | 10 | [-1099777, 1048575] | + | 11 | [-2199553, 2097151] | + | 12 | [-4399105, 4194303] | + | 13 | [-8798209, 8388607] | + | 14 | [-17596417, 16777215] | + | 15 | [-35192833, 33554431] | + | 16 | [-70385665, 67108863] | + | 17 | [-140771329, 134217727] | + | 18 | [-281542657, 268435455] | + | 19 | [-563085313, 536870911] | + | 20 | [-1126170625, 1073741823] | + | 21 | [underflow, 2147483647] | + | > 21 | [underflow, overflow] | + */ + Guard.ThrowIfOutOfRange(scale, min: -11, max: 20); + Guard.ThrowIfOutOfRange(maxBuckets, min: 1); this.Scale = scale; @@ -88,17 +130,26 @@ public int MapToIndex(double value) Debug.Assert(value != 0, "IEEE-754 zero values should be handled by ZeroCount."); Debug.Assert(!double.IsNegative(value), "IEEE-754 negative values should be normalized before calling this method."); + var bits = BitConverter.DoubleToInt64Bits(value); + var fraction = bits & 0xFFFFFFFFFFFFFL /* fraction mask */; + if (this.Scale > 0) { + // TODO: do we really need this given the lookup table is needed for scale>0 anyways? + if (fraction == 0) + { + var exp = (int)((bits & 0x7FF0000000000000L /* exponent mask */) >> 52 /* fraction width */); + return ((exp - 1023 /* exponent bias */) << this.Scale) - 1; + } + // TODO: due to precision issue, the values that are close to the bucket // boundaries should be closely examined to avoid off-by-one. + return (int)Math.Ceiling(Math.Log(value) * this.scalingFactor) - 1; } else { - var bits = BitConverter.DoubleToInt64Bits(value); var exp = (int)((bits & 0x7FF0000000000000L /* exponent mask */) >> 52 /* fraction width */); - var fraction = bits & 0xFFFFFFFFFFFFFL /* fraction mask */; if (exp == 0) { diff --git a/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs b/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs index 7a1ea4708db..1244449f429 100644 --- a/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs +++ b/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs @@ -17,6 +17,7 @@ #if NET6_0_OR_GREATER using System; +using OpenTelemetry.Tests; using Xunit; namespace OpenTelemetry.Metrics.Tests; @@ -40,47 +41,123 @@ public void IndexLookup() // bucket[3]: (8, 16] // ... - var histogram_scale0 = new ExponentialBucketHistogram(0); - - Assert.Equal(-1075, histogram_scale0.MapToIndex(double.Epsilon)); - - Assert.Equal(-1074, histogram_scale0.MapToIndex(double.Epsilon * 2)); - - Assert.Equal(-1073, histogram_scale0.MapToIndex(double.Epsilon * 3)); - Assert.Equal(-1073, histogram_scale0.MapToIndex(double.Epsilon * 4)); - - Assert.Equal(-1072, histogram_scale0.MapToIndex(double.Epsilon * 5)); - Assert.Equal(-1072, histogram_scale0.MapToIndex(double.Epsilon * 6)); - Assert.Equal(-1072, histogram_scale0.MapToIndex(double.Epsilon * 7)); - Assert.Equal(-1072, histogram_scale0.MapToIndex(double.Epsilon * 8)); - - Assert.Equal(-1023, histogram_scale0.MapToIndex(2.2250738585072009E-308)); - Assert.Equal(-1023, histogram_scale0.MapToIndex(2.2250738585072014E-308)); - - Assert.Equal(-3, histogram_scale0.MapToIndex(0.25)); - - Assert.Equal(-2, histogram_scale0.MapToIndex(0.375)); - Assert.Equal(-2, histogram_scale0.MapToIndex(0.5)); - - Assert.Equal(-1, histogram_scale0.MapToIndex(0.75)); - Assert.Equal(-1, histogram_scale0.MapToIndex(1)); - - Assert.Equal(0, histogram_scale0.MapToIndex(1.5)); - Assert.Equal(0, histogram_scale0.MapToIndex(2)); - - Assert.Equal(1, histogram_scale0.MapToIndex(3)); - Assert.Equal(1, histogram_scale0.MapToIndex(4)); - - Assert.Equal(2, histogram_scale0.MapToIndex(5)); - Assert.Equal(2, histogram_scale0.MapToIndex(6)); - Assert.Equal(2, histogram_scale0.MapToIndex(7)); - Assert.Equal(2, histogram_scale0.MapToIndex(8)); + var histogram = new ExponentialBucketHistogram(0); + + Assert.Equal(-1075, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) + Assert.Equal(-1074, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 + Assert.Equal(-1073, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000011"))); // double.Epsilon * 3 + Assert.Equal(-1073, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000100"))); // double.Epsilon * 4 + Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000101"))); // double.Epsilon * 5 + Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 + Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 + Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 + Assert.Equal(-1024, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 + Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) + Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-1022, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 + Assert.Equal(-3, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 + Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000001"))); // ~0.5000000000000001 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000000"))); // 1 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000001"))); // ~1.0000000000000002 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000000 0000000000000000000000000000000000000000000000000000"))); // 2 + Assert.Equal(1, histogram.MapToIndex(IEEE754Double.FromString("0 10000000001 0000000000000000000000000000000000000000000000000000"))); // 4 + Assert.Equal(2, histogram.MapToIndex(IEEE754Double.FromString("0 10000000010 0000000000000000000000000000000000000000000000000000"))); // 8 + Assert.Equal(3, histogram.MapToIndex(IEEE754Double.FromString("0 10000000011 0000000000000000000000000000000000000000000000000000"))); // 16 + Assert.Equal(4, histogram.MapToIndex(IEEE754Double.FromString("0 10000000100 0000000000000000000000000000000000000000000000000000"))); // 32 + Assert.Equal(1022, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000000"))); // ~8.98846567431158E+307 + Assert.Equal(1023, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000001"))); // ~8.988465674311582E+307 + Assert.Equal(1023, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 + Assert.Equal(1023, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) + + // An exponential bucket histogram with scale = -1. + // The base is 2 ^ (2 ^ 1) = 4. + // The buckets are: + // + // ... + // bucket[-3]: (1/64, 1/16] + // bucket[-2]: (1/16, 1/4] + // bucket[-1]: (1/4, 1] + // bucket[0]: (1, 4] + // bucket[1]: (4, 16] + // bucket[2]: (16, 64] + // bucket[3]: (64, 256] + // ... - Assert.Equal(3, histogram_scale0.MapToIndex(9)); - Assert.Equal(3, histogram_scale0.MapToIndex(16)); + histogram = new ExponentialBucketHistogram(-1); + + Assert.Equal(-538, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) + Assert.Equal(-537, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 + Assert.Equal(-537, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000011"))); // double.Epsilon * 3 + Assert.Equal(-537, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000100"))); // double.Epsilon * 4 + Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000101"))); // double.Epsilon * 5 + Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 + Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 + Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-511, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 + Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000001"))); // ~0.5000000000000001 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000000"))); // 1 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000001"))); // ~1.0000000000000002 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000000 0000000000000000000000000000000000000000000000000000"))); // 2 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000001 0000000000000000000000000000000000000000000000000000"))); // 4 + Assert.Equal(1, histogram.MapToIndex(IEEE754Double.FromString("0 10000000010 0000000000000000000000000000000000000000000000000000"))); // 8 + Assert.Equal(1, histogram.MapToIndex(IEEE754Double.FromString("0 10000000011 0000000000000000000000000000000000000000000000000000"))); // 16 + Assert.Equal(2, histogram.MapToIndex(IEEE754Double.FromString("0 10000000100 0000000000000000000000000000000000000000000000000000"))); // 32 + Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000000"))); // ~8.98846567431158E+307 + Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000001"))); // ~8.988465674311582E+307 + Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 + Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) + + // An exponential bucket histogram with scale = -2. + // The base is 2 ^ (2 ^ 2) = 16. + // The buckets are: + // + // ... + // bucket[-3]: (1/4096, 1/256] + // bucket[-2]: (1/256, 1/16] + // bucket[-1]: (1/16, 1] + // bucket[0]: (1, 16] + // bucket[1]: (16, 256] + // bucket[2]: (256, 4096] + // bucket[3]: (4096, 65536] + // ... - Assert.Equal(4, histogram_scale0.MapToIndex(17)); - Assert.Equal(4, histogram_scale0.MapToIndex(32)); + histogram = new ExponentialBucketHistogram(-2); + + Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) + Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 + Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000011"))); // double.Epsilon * 3 + Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000100"))); // double.Epsilon * 4 + Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000101"))); // double.Epsilon * 5 + Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 + Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 + Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000001"))); // ~0.5000000000000001 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000000"))); // 1 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000001"))); // ~1.0000000000000002 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000000 0000000000000000000000000000000000000000000000000000"))); // 2 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000001 0000000000000000000000000000000000000000000000000000"))); // 4 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000010 0000000000000000000000000000000000000000000000000000"))); // 8 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 10000000011 0000000000000000000000000000000000000000000000000000"))); // 16 + Assert.Equal(1, histogram.MapToIndex(IEEE754Double.FromString("0 10000000100 0000000000000000000000000000000000000000000000000000"))); // 32 + Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000000"))); // ~8.98846567431158E+307 + Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 0000000000000000000000000000000000000000000000000001"))); // ~8.988465674311582E+307 + Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 + Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) // An exponential bucket histogram with scale = 1. // The base is 2 ^ (2 ^ -1) = sqrt(2) = 1.41421356237. @@ -96,17 +173,7 @@ public void IndexLookup() // bucket[3]: (2.82842712474, 4] // ... - var histogram_scale1 = new ExponentialBucketHistogram(1); - - Assert.Equal(-3, histogram_scale1.MapToIndex(0.5)); - - Assert.Equal(-2, histogram_scale1.MapToIndex(0.6)); - - Assert.Equal(-1, histogram_scale1.MapToIndex(1)); - - Assert.Equal(1, histogram_scale1.MapToIndex(2)); - - Assert.Equal(3, histogram_scale1.MapToIndex(4)); + histogram = new ExponentialBucketHistogram(1); } } diff --git a/test/OpenTelemetry.Tests/Shared/IEEE754Double.cs b/test/OpenTelemetry.Tests/Shared/IEEE754Double.cs new file mode 100644 index 00000000000..4ae89faaba8 --- /dev/null +++ b/test/OpenTelemetry.Tests/Shared/IEEE754Double.cs @@ -0,0 +1,103 @@ +// +// 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; +using System.Runtime.InteropServices; + +namespace OpenTelemetry.Tests; + +[StructLayout(LayoutKind.Explicit)] +public struct IEEE754Double +{ + [FieldOffset(0)] + public double DoubleValue = 0; + + [FieldOffset(0)] + public long LongValue = 0; + + [FieldOffset(0)] + public ulong ULongValue = 0; + + public IEEE754Double(double value) + { + this.DoubleValue = value; + } + + public static implicit operator double(IEEE754Double value) + { + return value.DoubleValue; + } + + public static IEEE754Double operator ++(IEEE754Double value) + { + value.ULongValue++; + return value; + } + + public static IEEE754Double operator --(IEEE754Double value) + { + value.ULongValue--; + return value; + } + + public static IEEE754Double FromDouble(double value) + { + return new IEEE754Double(value); + } + + public static IEEE754Double FromLong(long value) + { + return new IEEE754Double { LongValue = value }; + } + + public static IEEE754Double FromULong(ulong value) + { + return new IEEE754Double { ULongValue = value }; + } + + public static IEEE754Double FromString(string value) + { + return IEEE754Double.FromLong(Convert.ToInt64(value.Replace(" ", string.Empty), 2)); + } + + public override string ToString() + { + Span chars = stackalloc char[66]; + + var bits = this.ULongValue; + var index = chars.Length - 1; + + for (int i = 0; i < 52; i++) + { + chars[index--] = (char)(bits & 0x01 | 0x30); + bits >>= 1; + } + + chars[index--] = ' '; + + for (int i = 0; i < 11; i++) + { + chars[index--] = (char)(bits & 0x01 | 0x30); + bits >>= 1; + } + + chars[index--] = ' '; + + chars[index--] = (char)(bits & 0x01 | 0x30); + + return $"{chars.ToString()} ({this.DoubleValue})"; + } +} From 7f8801a082391b5005530c51caed3d2703b08223 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Wed, 27 Jul 2022 14:52:46 -0700 Subject: [PATCH 061/111] Minor fixes to Stress Tests (#3496) --- test/OpenTelemetry.Tests.Stress/README.md | 47 ++++++++++++++------- test/OpenTelemetry.Tests.Stress/Skeleton.cs | 12 ++---- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/test/OpenTelemetry.Tests.Stress/README.md b/test/OpenTelemetry.Tests.Stress/README.md index 4b7b10ddb77..a22d7b6788f 100644 --- a/test/OpenTelemetry.Tests.Stress/README.md +++ b/test/OpenTelemetry.Tests.Stress/README.md @@ -43,23 +43,32 @@ Running (concurrency = 1), press to stop... The stress test metrics are exposed via [PrometheusExporter](../../src/OpenTelemetry.Exporter.Prometheus/README.md), which can be accessed via -[http://localhost:9184/metrics/](http://localhost:9184/metrics/): +[http://localhost:9184/metrics/](http://localhost:9184/metrics/). -```text -# TYPE Process_NonpagedSystemMemorySize64 gauge -Process_NonpagedSystemMemorySize64 31651 1637385964580 - -# TYPE Process_PagedSystemMemorySize64 gauge -Process_PagedSystemMemorySize64 238672 1637385964580 - -# TYPE Process_PagedMemorySize64 gauge -Process_PagedMemorySize64 16187392 1637385964580 - -# TYPE Process_WorkingSet64 gauge -Process_WorkingSet64 29753344 1637385964580 +Following shows a section of the metrics exposed in prometheus format: -# TYPE Process_VirtualMemorySize64 gauge -Process_VirtualMemorySize64 2204045848576 1637385964580 +```text +# HELP OpenTelemetry_Tests_Stress_Loops The total number of `Run()` invocations that are completed. +# TYPE OpenTelemetry_Tests_Stress_Loops counter +OpenTelemetry_Tests_Stress_Loops 1844902947 1658950184752 + +# HELP OpenTelemetry_Tests_Stress_LoopsPerSecond The rate of `Run()` invocations based on a small sliding window of few hundreds of milliseconds. +# TYPE OpenTelemetry_Tests_Stress_LoopsPerSecond gauge +OpenTelemetry_Tests_Stress_LoopsPerSecond 9007731.132075472 1658950184752 + +# HELP OpenTelemetry_Tests_Stress_CpuCyclesPerLoop The average CPU cycles for each `Run()` invocation, based on a small sliding window of few hundreds of milliseconds. +# TYPE OpenTelemetry_Tests_Stress_CpuCyclesPerLoop gauge +OpenTelemetry_Tests_Stress_CpuCyclesPerLoop 3008 1658950184752 + +# HELP process_runtime_dotnet_gc_collections_count Number of garbage collections that have occurred since process start. +# TYPE process_runtime_dotnet_gc_collections_count counter +process_runtime_dotnet_gc_collections_count{generation="gen2"} 0 1658950184752 +process_runtime_dotnet_gc_collections_count{generation="gen1"} 0 1658950184752 +process_runtime_dotnet_gc_collections_count{generation="gen0"} 0 1658950184752 + +# HELP process_runtime_dotnet_gc_allocations_size_bytes Count of bytes allocated on the managed GC heap since the process start. .NET objects are allocated from this heap. Object allocations from unmanaged languages such as C/C++ do not use this heap. +# TYPE process_runtime_dotnet_gc_allocations_size_bytes counter +process_runtime_dotnet_gc_allocations_size_bytes 5485192 1658950184752 ``` ## Writing your own stress test @@ -92,6 +101,13 @@ Add the [`Skeleton.cs`](./Skeleton.cs) file to your `*.csproj` file: ``` +Add the following packages to the project: + +```shell +dotnet add package OpenTelemetry.Exporter.Prometheus --prerelease +dotnet add package OpenTelemetry.Instrumentation.Runtime --prerelease +``` + Now you are ready to run your own stress test. Some useful notes: @@ -114,3 +130,4 @@ Some useful notes: sliding window of few hundreds of milliseconds. * `CPU Cycles/Loop` represents the average CPU cycles for each `Run()` invocation, based on a small sliding window of few hundreds of milliseconds. +* `Runaway Time` represents the runaway time (seconds) since the test started. diff --git a/test/OpenTelemetry.Tests.Stress/Skeleton.cs b/test/OpenTelemetry.Tests.Stress/Skeleton.cs index adcf5cbbe22..2ff889d21a3 100644 --- a/test/OpenTelemetry.Tests.Stress/Skeleton.cs +++ b/test/OpenTelemetry.Tests.Stress/Skeleton.cs @@ -63,11 +63,8 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) () => dLoopsPerSecond, description: "The rate of `Run()` invocations based on a small sliding window of few hundreds of milliseconds."); var dCpuCyclesPerLoop = 0D; -#if NET462 - if (Environment.OSVersion.Platform == PlatformID.Win32NT) -#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) -#endif { meter.CreateObservableGauge( "OpenTelemetry.Tests.Stress.CpuCyclesPerLoop", @@ -146,7 +143,7 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) dLoopsPerSecond = (double)nLoops / ((double)watch.ElapsedMilliseconds / 1000.0); dCpuCyclesPerLoop = nLoops == 0 ? 0 : nCpuCycles / nLoops; - output = $"Loops: {cntLoopsTotal:n0}, Loops/Second: {dLoopsPerSecond:n0}, CPU Cycles/Loop: {dCpuCyclesPerLoop:n0}"; + output = $"Loops: {cntLoopsTotal:n0}, Loops/Second: {dLoopsPerSecond:n0}, CPU Cycles/Loop: {dCpuCyclesPerLoop:n0}, RunwayTime (Seconds): {watchForTotal.Elapsed.TotalSeconds:n0} "; Console.Title = output; } }, @@ -169,6 +166,7 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) var cntCpuCyclesTotal = GetCpuCycles(); var cpuCyclesPerLoopTotal = cntLoopsTotal == 0 ? 0 : cntCpuCyclesTotal / cntLoopsTotal; Console.WriteLine("Stopping the stress test..."); + Console.WriteLine($"* Total Runaway Time (seconds) {watchForTotal.Elapsed.TotalSeconds:n0}"); Console.WriteLine($"* Total Loops: {cntLoopsTotal:n0}"); Console.WriteLine($"* Average Loops/Second: {totalLoopsPerSecond:n0}"); Console.WriteLine($"* Average CPU Cycles/Loop: {cpuCyclesPerLoopTotal:n0}"); @@ -180,11 +178,7 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) private static ulong GetCpuCycles() { -#if NET462 - if (Environment.OSVersion.Platform != PlatformID.Win32NT) -#else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) -#endif { return 0; } From 16f1e3f082b93aa2be51f6bac0b37926cc6fbd47 Mon Sep 17 00:00:00 2001 From: Vishwesh Bankwar Date: Wed, 27 Jul 2022 15:27:44 -0700 Subject: [PATCH 062/111] Asp.Net Core Unit test [Activity started in middleware is modified by instrumentation] (#3490) --- .../BasicTests.cs | 56 +++++++++++++++++ .../ActivityMiddleware.cs | 61 +++++++++++++++++++ test/TestApp.AspNetCore.3.1/Startup.cs | 3 + .../ActivityMiddleware.cs | 61 +++++++++++++++++++ test/TestApp.AspNetCore.6.0/Startup.cs | 3 + 5 files changed, 184 insertions(+) create mode 100644 test/TestApp.AspNetCore.3.1/ActivityMiddleware.cs create mode 100644 test/TestApp.AspNetCore.6.0/ActivityMiddleware.cs diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs index 03dc2b9d6e3..208b12da777 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs @@ -550,6 +550,39 @@ void ConfigureTestServices(IServiceCollection services) Assert.Equal(shouldEnrichBeCalled, enrichCalled); } + [Fact(Skip = "Changes pending on instrumentation")] + public async Task ActivitiesStartedInMiddlewareShouldNotBeUpdatedByInstrumentation() + { + var exportedItems = new List(); + + var activitySourceName = "TestMiddlewareActivitySource"; + var activityName = "TestMiddlewareActivity"; + + // Arrange + using (var client = this.factory + .WithWebHostBuilder(builder => + builder.ConfigureTestServices((IServiceCollection services) => + { + services.AddSingleton(new TestActivityMiddlewareImpl(activitySourceName, activityName)); + services.AddOpenTelemetryTracing((builder) => builder.AddAspNetCoreInstrumentation() + .AddSource(activitySourceName) + .AddInMemoryExporter(exportedItems)); + })) + .CreateClient()) + { + var response = await client.GetAsync("/api/values/2"); + response.EnsureSuccessStatusCode(); + WaitForActivityExport(exportedItems, 2); + } + + Assert.Equal(2, exportedItems.Count); + + var middlewareActivity = exportedItems[0]; + + // Middleware activity name should not be changed + Assert.Equal(activityName, middlewareActivity.DisplayName); + } + public void Dispose() { this.tracerProvider?.Dispose(); @@ -661,5 +694,28 @@ public override void OnStopActivity(Activity activity, object payload) this.OnStopActivityCallback?.Invoke(activity, payload); } } + + private class TestActivityMiddlewareImpl : ActivityMiddleware.ActivityMiddlewareImpl + { + private ActivitySource activitySource; + private Activity activity; + private string activityName; + + public TestActivityMiddlewareImpl(string activitySourceName, string activityName) + { + this.activitySource = new ActivitySource(activitySourceName); + this.activityName = activityName; + } + + public override void PreProcess(HttpContext context) + { + this.activity = this.activitySource.StartActivity(this.activityName); + } + + public override void PostProcess(HttpContext context) + { + this.activity?.Stop(); + } + } } } diff --git a/test/TestApp.AspNetCore.3.1/ActivityMiddleware.cs b/test/TestApp.AspNetCore.3.1/ActivityMiddleware.cs new file mode 100644 index 00000000000..44c1eff7d14 --- /dev/null +++ b/test/TestApp.AspNetCore.3.1/ActivityMiddleware.cs @@ -0,0 +1,61 @@ +// +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace TestApp.AspNetCore._3._1 +{ + public class ActivityMiddleware + { + private readonly ActivityMiddlewareImpl impl; + private readonly RequestDelegate next; + + public ActivityMiddleware(RequestDelegate next, ActivityMiddlewareImpl impl) + { + this.next = next; + this.impl = impl; + } + + public async Task InvokeAsync(HttpContext context) + { + if (this.impl != null) + { + this.impl.PreProcess(context); + } + + await this.next(context); + + if (this.impl != null) + { + this.impl.PostProcess(context); + } + } + + public class ActivityMiddlewareImpl + { + public virtual void PreProcess(HttpContext context) + { + // do nothing + } + + public virtual void PostProcess(HttpContext context) + { + // do nothing + } + } + } +} diff --git a/test/TestApp.AspNetCore.3.1/Startup.cs b/test/TestApp.AspNetCore.3.1/Startup.cs index eaf926c8af6..b8d84242aa1 100644 --- a/test/TestApp.AspNetCore.3.1/Startup.cs +++ b/test/TestApp.AspNetCore.3.1/Startup.cs @@ -39,6 +39,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton( new CallbackMiddleware.CallbackMiddlewareImpl()); + services.AddSingleton( + new ActivityMiddleware.ActivityMiddlewareImpl()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -50,6 +52,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) } app.UseMiddleware(); + app.UseMiddleware(); app.UseRouting(); app.UseAuthorization(); diff --git a/test/TestApp.AspNetCore.6.0/ActivityMiddleware.cs b/test/TestApp.AspNetCore.6.0/ActivityMiddleware.cs new file mode 100644 index 00000000000..c45b5e828ab --- /dev/null +++ b/test/TestApp.AspNetCore.6.0/ActivityMiddleware.cs @@ -0,0 +1,61 @@ +// +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace TestApp.AspNetCore._6._0 +{ + public class ActivityMiddleware + { + private readonly ActivityMiddlewareImpl impl; + private readonly RequestDelegate next; + + public ActivityMiddleware(RequestDelegate next, ActivityMiddlewareImpl impl) + { + this.next = next; + this.impl = impl; + } + + public async Task InvokeAsync(HttpContext context) + { + if (this.impl != null) + { + this.impl.PreProcess(context); + } + + await this.next(context); + + if (this.impl != null) + { + this.impl.PostProcess(context); + } + } + + public class ActivityMiddlewareImpl + { + public virtual void PreProcess(HttpContext context) + { + // Do nothing + } + + public virtual void PostProcess(HttpContext context) + { + // Do nothing + } + } + } +} diff --git a/test/TestApp.AspNetCore.6.0/Startup.cs b/test/TestApp.AspNetCore.6.0/Startup.cs index 1da70536444..988ee74706c 100644 --- a/test/TestApp.AspNetCore.6.0/Startup.cs +++ b/test/TestApp.AspNetCore.6.0/Startup.cs @@ -39,6 +39,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton( new CallbackMiddleware.CallbackMiddlewareImpl()); + services.AddSingleton( + new ActivityMiddleware.ActivityMiddlewareImpl()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -50,6 +52,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) } app.UseMiddleware(); + app.UseMiddleware(); app.UseRouting(); app.UseAuthorization(); From 8854de38400ff504125762ac1603576a554f828c Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Wed, 27 Jul 2022 16:21:55 -0700 Subject: [PATCH 063/111] Exponential Bucket Histogram - part 7 (#3499) * hammer out the upper/lower bound of scale * comment --- .../Metrics/ExponentialBucketHistogram.cs | 20 +- .../Metrics/ExponentialBucketHistogramTest.cs | 209 ++++++++++++------ 2 files changed, 161 insertions(+), 68 deletions(-) diff --git a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs index f1670d3ba87..87edd9908b9 100644 --- a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs +++ b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs @@ -35,7 +35,18 @@ internal class ExponentialBucketHistogram private int scale; private double scalingFactor; // 2 ^ scale / log(2) - public ExponentialBucketHistogram(int scale, int maxBuckets = 160) + /// + /// Initializes a new instance of the class. + /// + /// + /// The maximum number of buckets in each of the positive and negative ranges, not counting the special zero bucket. The default value is 160. + /// + public ExponentialBucketHistogram(int maxBuckets = 160) + : this(maxBuckets, 20) + { + } + + internal ExponentialBucketHistogram(int maxBuckets, int scale) { /* The following table is calculated based on [ MapToIndex(double.Epsilon), MapToIndex(double.MaxValue) ]: @@ -80,7 +91,12 @@ The following table is calculated based on [ MapToIndex(double.Epsilon), MapToIn */ Guard.ThrowIfOutOfRange(scale, min: -11, max: 20); - Guard.ThrowIfOutOfRange(maxBuckets, min: 1); + /* + Regardless of the scale, MapToIndex(1) will always be -1, so we need two buckets at minimum: + bucket[-1] = (1/base, 1] + bucket[0] = (1, base] + */ + Guard.ThrowIfOutOfRange(maxBuckets, min: 2); this.Scale = scale; this.PositiveBuckets = new CircularBufferBuckets(maxBuckets); diff --git a/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs b/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs index 1244449f429..59f80ad0984 100644 --- a/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs +++ b/test/OpenTelemetry.Tests/Metrics/ExponentialBucketHistogramTest.cs @@ -27,21 +27,21 @@ public class ExponentialBucketHistogramTest [Fact] public void IndexLookup() { - // An exponential bucket histogram with scale = 0. - // The base is 2 ^ (2 ^ -0) = 2. - // The buckets are: - // - // ... - // bucket[-3]: (1/8, 1/4] - // bucket[-2]: (1/4, 1/2] - // bucket[-1]: (1/2, 1] - // bucket[0]: (1, 2] - // bucket[1]: (2, 4] - // bucket[2]: (4, 8] - // bucket[3]: (8, 16] - // ... - - var histogram = new ExponentialBucketHistogram(0); + /* + An exponential bucket histogram with scale = 0. + The base is 2 ^ (2 ^ 0) = 2. + The buckets are: + ... + bucket[-3]: (1/8, 1/4] + bucket[-2]: (1/4, 1/2] + bucket[-1]: (1/2, 1] + bucket[0]: (1, 2] + bucket[1]: (2, 4] + bucket[2]: (4, 8] + bucket[3]: (8, 16] + ... + */ + var histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: 0); Assert.Equal(-1075, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) Assert.Equal(-1074, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 @@ -51,10 +51,12 @@ public void IndexLookup() Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 Assert.Equal(-1072, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 - Assert.Equal(-1024, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-1025, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000000"))); // ~5.562684646268003E-309 (2 ^ -1024) + Assert.Equal(-1024, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000001"))); // ~5.56268464626801E-309 + Assert.Equal(-1024, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 (2 ^ -1023) Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) - Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-1023, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive, 2 ^ -1022) Assert.Equal(-1022, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 Assert.Equal(-3, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 @@ -71,21 +73,21 @@ public void IndexLookup() Assert.Equal(1023, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 Assert.Equal(1023, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) - // An exponential bucket histogram with scale = -1. - // The base is 2 ^ (2 ^ 1) = 4. - // The buckets are: - // - // ... - // bucket[-3]: (1/64, 1/16] - // bucket[-2]: (1/16, 1/4] - // bucket[-1]: (1/4, 1] - // bucket[0]: (1, 4] - // bucket[1]: (4, 16] - // bucket[2]: (16, 64] - // bucket[3]: (64, 256] - // ... - - histogram = new ExponentialBucketHistogram(-1); + /* + An exponential bucket histogram with scale = -1. + The base is 2 ^ (2 ^ 1) = 4. + The buckets are: + ... + bucket[-3]: (1/64, 1/16] + bucket[-2]: (1/16, 1/4] + bucket[-1]: (1/4, 1] + bucket[0]: (1, 4] + bucket[1]: (4, 16] + bucket[2]: (16, 64] + bucket[3]: (64, 256] + ... + */ + histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: -1); Assert.Equal(-538, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) Assert.Equal(-537, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 @@ -95,10 +97,12 @@ public void IndexLookup() Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 Assert.Equal(-536, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 - Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-513, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000000"))); // ~5.562684646268003E-309 (2 ^ -1024) + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000001"))); // ~5.56268464626801E-309 + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 (2 ^ -1023) Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) - Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-512, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive, 2 ^ -1022) Assert.Equal(-511, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 @@ -115,21 +119,21 @@ public void IndexLookup() Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 Assert.Equal(511, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) - // An exponential bucket histogram with scale = -2. - // The base is 2 ^ (2 ^ 2) = 16. - // The buckets are: - // - // ... - // bucket[-3]: (1/4096, 1/256] - // bucket[-2]: (1/256, 1/16] - // bucket[-1]: (1/16, 1] - // bucket[0]: (1, 16] - // bucket[1]: (16, 256] - // bucket[2]: (256, 4096] - // bucket[3]: (4096, 65536] - // ... - - histogram = new ExponentialBucketHistogram(-2); + /* + An exponential bucket histogram with scale = -2. + The base is 2 ^ (2 ^ 2) = 16. + The buckets are: + ... + bucket[-3]: (1/4096, 1/256] + bucket[-2]: (1/256, 1/16] + bucket[-1]: (1/16, 1] + bucket[0]: (1, 16] + bucket[1]: (16, 256] + bucket[2]: (256, 4096] + bucket[3]: (4096, 65536] + ... + */ + histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: -2); Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) Assert.Equal(-269, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000010"))); // double.Epsilon * 2 @@ -139,10 +143,12 @@ public void IndexLookup() Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000110"))); // double.Epsilon * 6 Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000111"))); // double.Epsilon * 7 Assert.Equal(-268, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000001000"))); // double.Epsilon * 8 - Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 + Assert.Equal(-257, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000000"))); // ~5.562684646268003E-309 (2 ^ -1024) + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000001"))); // ~5.56268464626801E-309 + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000000"))); // ~1.1125369292536007E-308 (2 ^ -1023) Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.112536929253601E-308 Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) - Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive) + Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive, 2 ^ -1022) Assert.Equal(-256, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000001"))); // ~2.225073858507202E-308 Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111101 0000000000000000000000000000000000000000000000000000"))); // 0.25 Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111110 0000000000000000000000000000000000000000000000000000"))); // 0.5 @@ -159,21 +165,92 @@ public void IndexLookup() Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111110"))); // ~1.7976931348623155E+308 Assert.Equal(255, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) - // An exponential bucket histogram with scale = 1. - // The base is 2 ^ (2 ^ -1) = sqrt(2) = 1.41421356237. - // The buckets are: - // - // ... - // bucket[-3]: (0.35355339059, 1/2] - // bucket[-2]: (1/2, 0.70710678118] - // bucket[-1]: (0.70710678118, 1] - // bucket[0]: (1, 1.41421356237] - // bucket[1]: (1.41421356237, 2] - // bucket[2]: (2, 2.82842712474] - // bucket[3]: (2.82842712474, 4] - // ... - - histogram = new ExponentialBucketHistogram(1); + /* + An exponential bucket histogram with scale = -10. + The base is 2 ^ (2 ^ 10) = 2 ^ 1024 = double.MaxValue + 2 ^ -52 (slightly bigger than double.MaxValue). + The buckets are: + bucket[-2]: [double.Epsilon, 2 ^ -1024] + bucket[-1]: (2 ^ -1024, 1] + bucket[0]: (1, double.MaxValue] + */ + histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: -10); + + Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) + Assert.Equal(-2, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000000"))); // ~5.562684646268003E-309 (2 ^ -1024) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0100000000000000000000000000000000000000000000000001"))); // ~5.56268464626801E-309 + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1000000000000000000000000000000000000000000000000001"))); // ~1.1125369292536007E-308 (2 ^ -1023) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive, 2 ^ -1022) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000000"))); // 1 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000001"))); // ~1.0000000000000002 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) + + /* + An exponential bucket histogram with scale = -11. + The base is 2 ^ (2 ^ 11) = 2 ^ 2048 (much bigger than double.MaxValue). + The buckets are: + bucket[-1]: [double.Epsilon, 1] + bucket[0]: (1, double.MaxValue] + */ + histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: -11); + + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000001"))); // ~4.9406564584124654E-324 (minimum subnormal positive, double.Epsilon) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000000 1111111111111111111111111111111111111111111111111111"))); // ~2.2250738585072009E-308 (maximum subnormal positive) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 00000000001 0000000000000000000000000000000000000000000000000000"))); // ~2.2250738585072014E-308 (minimum normal positive, 2 ^ -1022) + Assert.Equal(-1, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000000"))); // 1 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 01111111111 0000000000000000000000000000000000000000000000000001"))); // ~1.0000000000000002 + Assert.Equal(0, histogram.MapToIndex(IEEE754Double.FromString("0 11111111110 1111111111111111111111111111111111111111111111111111"))); // ~1.7976931348623157E+308 (maximum normal positive, double.MaxValue) + + /* + An exponential bucket histogram with scale = 1. + The base is 2 ^ (2 ^ -1) = sqrt(2) = 1.41421356237. + The buckets are: + ... + bucket[-3]: (0.35355339059, 1/2] + bucket[-2]: (1/2, 0.70710678118] + bucket[-1]: (0.70710678118, 1] + bucket[0]: (1, 1.41421356237] + bucket[1]: (1.41421356237, 2] + bucket[2]: (2, 2.82842712474] + bucket[3]: (2.82842712474, 4] + ... + */ + histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: 1); + } + + [Fact] + public void InfinityHandling() + { + var histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: 0); + + histogram.Record(double.PositiveInfinity); + histogram.Record(double.NegativeInfinity); + + Assert.Equal(0, histogram.ZeroCount + histogram.PositiveBuckets.Size + histogram.NegativeBuckets.Size); + } + + [Fact] + public void NaNHandling() + { + var histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: 0); + + histogram.Record(double.NaN); // NaN (language/runtime native) + histogram.Record(IEEE754Double.FromString("0 11111111111 0000000000000000000000000000000000000000000000000001").DoubleValue); // sNaN on x86/64 and ARM + histogram.Record(IEEE754Double.FromString("0 11111111111 1000000000000000000000000000000000000000000000000001").DoubleValue); // qNaN on x86/64 and ARM + histogram.Record(IEEE754Double.FromString("0 11111111111 1111111111111111111111111111111111111111111111111111").DoubleValue); // NaN (alternative encoding) + + Assert.Equal(0, histogram.ZeroCount + histogram.PositiveBuckets.Size + histogram.NegativeBuckets.Size); + } + + [Fact] + public void ZeroHandling() + { + var histogram = new ExponentialBucketHistogram(maxBuckets: 2, scale: 0); + + histogram.Record(IEEE754Double.FromString("0 00000000000 0000000000000000000000000000000000000000000000000000").DoubleValue); // +0 + histogram.Record(IEEE754Double.FromString("1 00000000000 0000000000000000000000000000000000000000000000000000").DoubleValue); // -0 + + Assert.Equal(2, histogram.ZeroCount); } } From 7e65f56ab2a2702581e6d47d9d42ff3ead47413a Mon Sep 17 00:00:00 2001 From: Alan West <3676547+alanwest@users.noreply.github.com> Date: Thu, 28 Jul 2022 07:48:21 -0700 Subject: [PATCH 064/111] OTLP exporter support for limiting activity tags, events, and links (#3376) --- .../Internal/ActivityHelperExtensions.cs | 102 +++++++++++--- .../CHANGELOG.md | 6 + .../EnvironmentVariableConfiguration.cs | 46 ++++++ .../Configuration/SdkConfiguration.cs | 69 +++++++++ .../Implementation/ActivityExtensions.cs | 14 +- src/OpenTelemetry/Internal/TagTransformer.cs | 38 +++-- .../Configuration/SdkConfigurationTests.cs | 133 ++++++++++++++++++ .../OtlpTraceExporterTests.cs | 76 ++++++++++ 8 files changed, 449 insertions(+), 35 deletions(-) create mode 100644 src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs create mode 100644 src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs create mode 100644 test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs diff --git a/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs b/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs index 6cc238b8c23..e3a2c312072 100644 --- a/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs +++ b/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs @@ -44,7 +44,7 @@ public static bool TryGetStatus(this Activity activity, out StatusCode statusCod ActivityStatusTagEnumerator state = default; - ActivityTagsEnumeratorFactory.Enumerate(activity, ref state); + ActivityTagsEnumeratorFactory.Enumerate(activity, ref state, null); if (!state.StatusCode.HasValue) { @@ -72,7 +72,7 @@ public static object GetTagValue(this Activity activity, string tagName) ActivitySingleTagEnumerator state = new ActivitySingleTagEnumerator(tagName); - ActivityTagsEnumeratorFactory.Enumerate(activity, ref state); + ActivityTagsEnumeratorFactory.Enumerate(activity, ref state, null); return state.Value; } @@ -91,7 +91,7 @@ public static bool TryCheckFirstTag(this Activity activity, string tagName, out ActivityFirstTagEnumerator state = new ActivityFirstTagEnumerator(tagName); - ActivityTagsEnumeratorFactory.Enumerate(activity, ref state); + ActivityTagsEnumeratorFactory.Enumerate(activity, ref state, null); if (state.Value == null) { @@ -109,14 +109,15 @@ public static bool TryCheckFirstTag(this Activity activity, string tagName, out /// The struct implementation to use for the enumeration. /// Activity instance. /// Tag enumerator. + /// Maximum number of tags to enumerate. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static void EnumerateTags(this Activity activity, ref T tagEnumerator) + public static void EnumerateTags(this Activity activity, ref T tagEnumerator, int? maxTags = null) where T : struct, IActivityEnumerator> { Debug.Assert(activity != null, "Activity should not be null"); - ActivityTagsEnumeratorFactory.Enumerate(activity, ref tagEnumerator); + ActivityTagsEnumeratorFactory.Enumerate(activity, ref tagEnumerator, maxTags); } /// @@ -125,14 +126,15 @@ public static void EnumerateTags(this Activity activity, ref T tagEnumerator) /// The struct implementation to use for the enumeration. /// Activity instance. /// Link enumerator. + /// Maximum number of links to enumerate. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static void EnumerateLinks(this Activity activity, ref T linkEnumerator) + public static void EnumerateLinks(this Activity activity, ref T linkEnumerator, int? maxLinks = null) where T : struct, IActivityEnumerator { Debug.Assert(activity != null, "Activity should not be null"); - ActivityLinksEnumeratorFactory.Enumerate(activity, ref linkEnumerator); + ActivityLinksEnumeratorFactory.Enumerate(activity, ref linkEnumerator, maxLinks); } /// @@ -141,12 +143,13 @@ public static void EnumerateLinks(this Activity activity, ref T linkEnumerato /// The struct implementation to use for the enumeration. /// ActivityLink instance. /// Tag enumerator. + /// Maximum number of tags to enumerate. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static void EnumerateTags(this ActivityLink activityLink, ref T tagEnumerator) + public static void EnumerateTags(this ActivityLink activityLink, ref T tagEnumerator, int? maxTags = null) where T : struct, IActivityEnumerator> { - ActivityTagsEnumeratorFactory.Enumerate(activityLink, ref tagEnumerator); + ActivityTagsEnumeratorFactory.Enumerate(activityLink, ref tagEnumerator, maxTags); } /// @@ -155,14 +158,15 @@ public static void EnumerateTags(this ActivityLink activityLink, ref T tagEnu /// The struct implementation to use for the enumeration. /// Activity instance. /// Event enumerator. + /// Maximum number of events to enumerate. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static void EnumerateEvents(this Activity activity, ref T eventEnumerator) + public static void EnumerateEvents(this Activity activity, ref T eventEnumerator, int? maxEvents = null) where T : struct, IActivityEnumerator { Debug.Assert(activity != null, "Activity should not be null"); - ActivityEventsEnumeratorFactory.Enumerate(activity, ref eventEnumerator); + ActivityEventsEnumeratorFactory.Enumerate(activity, ref eventEnumerator, maxEvents); } /// @@ -171,12 +175,13 @@ public static void EnumerateEvents(this Activity activity, ref T eventEnumera /// The struct implementation to use for the enumeration. /// ActivityEvent instance. /// Tag enumerator. + /// Maximum number of tags to enumerate. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static void EnumerateTags(this ActivityEvent activityEvent, ref T tagEnumerator) + public static void EnumerateTags(this ActivityEvent activityEvent, ref T tagEnumerator, int? maxTags = null) where T : struct, IActivityEnumerator> { - ActivityTagsEnumeratorFactory.Enumerate(activityEvent, ref tagEnumerator); + ActivityTagsEnumeratorFactory.Enumerate(activityEvent, ref tagEnumerator, maxTags); } private struct ActivitySingleTagEnumerator : IActivityEnumerator> @@ -265,7 +270,7 @@ private static readonly DictionaryEnumerator.AllocationF private static readonly DictionaryEnumerator.ForEachDelegate ForEachTagValueCallbackRef = ForEachTagValueCallback; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Enumerate(Activity activity, ref TState state) + public static void Enumerate(Activity activity, ref TState state, int? maxTags) { var tagObjects = activity.TagObjects; @@ -274,6 +279,12 @@ public static void Enumerate(Activity activity, ref TState state) return; } + if (maxTags.HasValue) + { + SkipAllocationFreeEnumeration(tagObjects, ref state, maxTags.Value); + return; + } + ActivityTagObjectsEnumerator( tagObjects, ref state, @@ -281,7 +292,7 @@ public static void Enumerate(Activity activity, ref TState state) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Enumerate(ActivityLink activityLink, ref TState state) + public static void Enumerate(ActivityLink activityLink, ref TState state, int? maxTags) { var tags = activityLink.Tags; @@ -290,6 +301,12 @@ public static void Enumerate(ActivityLink activityLink, ref TState state) return; } + if (maxTags.HasValue) + { + SkipAllocationFreeEnumeration(tags, ref state, maxTags.Value); + return; + } + ActivityTagsCollectionEnumerator( tags, ref state, @@ -297,7 +314,7 @@ public static void Enumerate(ActivityLink activityLink, ref TState state) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Enumerate(ActivityEvent activityEvent, ref TState state) + public static void Enumerate(ActivityEvent activityEvent, ref TState state, int? maxTags) { var tags = activityEvent.Tags; @@ -306,12 +323,31 @@ public static void Enumerate(ActivityEvent activityEvent, ref TState state) return; } + if (maxTags.HasValue) + { + SkipAllocationFreeEnumeration(tags, ref state, maxTags.Value); + return; + } + ActivityTagsCollectionEnumerator( tags, ref state, ForEachTagValueCallbackRef); } + // TODO: When a limit has been configured an allocation-free enumerator is not used. + // Need to either: + // 1) modify the dynamically generated code to only enumerate up to the max number of items, or + // 2) wait until .NET 7 is released and do this more easily with the new enumerator functions + private static void SkipAllocationFreeEnumeration(IEnumerable> tags, ref TState state, int maxTags) + { + var enumerator = tags.GetEnumerator(); + for (var i = 0; enumerator.MoveNext() && i < maxTags; ++i) + { + state.ForEach(enumerator.Current); + } + } + private static bool ForEachTagValueCallback(ref TState state, KeyValuePair item) => state.ForEach(item); } @@ -328,7 +364,7 @@ private static readonly ListEnumerator.AllocationFreeForEa private static readonly ListEnumerator.ForEachDelegate ForEachLinkCallbackRef = ForEachLinkCallback; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Enumerate(Activity activity, ref TState state) + public static void Enumerate(Activity activity, ref TState state, int? maxLinks) { var activityLinks = activity.Links; @@ -337,6 +373,21 @@ public static void Enumerate(Activity activity, ref TState state) return; } + // TODO: When a limit has been configured an allocation-free enumerator is not used. + // Need to either: + // 1) modify the dynamically generated code to only enumerate up to the max number of items, or + // 2) wait until .NET 7 is released and do this more easily with the new enumerator functions + if (maxLinks.HasValue) + { + var enumerator = activityLinks.GetEnumerator(); + for (var i = 0; enumerator.MoveNext() && i < maxLinks; ++i) + { + state.ForEach(enumerator.Current); + } + + return; + } + ActivityLinksEnumerator( activityLinks, ref state, @@ -359,7 +410,7 @@ private static readonly ListEnumerator.AllocationFreeForE private static readonly ListEnumerator.ForEachDelegate ForEachEventCallbackRef = ForEachEventCallback; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Enumerate(Activity activity, ref TState state) + public static void Enumerate(Activity activity, ref TState state, int? maxEvents) { var activityEvents = activity.Events; @@ -368,6 +419,21 @@ public static void Enumerate(Activity activity, ref TState state) return; } + // TODO: When a limit has been configured an allocation-free enumerator is not used. + // Need to either: + // 1) modify the dynamically generated code to only enumerate up to the max number of items, or + // 2) wait until .NET 7 is released and do this more easily with the new enumerator functions + if (maxEvents.HasValue) + { + var enumerator = activityEvents.GetEnumerator(); + for (var i = 0; enumerator.MoveNext() && i < maxEvents; ++i) + { + state.ForEach(enumerator.Current); + } + + return; + } + ActivityEventsEnumerator( activityEvents, ref state, diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 6199a199208..1a4ae40ade9 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* Adds support for limiting the length and count of attributes exported from + the OTLP exporter. These + [Attribute Limits](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits) + are configured via the environment variables defined in the specification. + ([#3376](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3376)) + * The `MetricReaderOptions` defaults can be overridden using `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` environmental variables as defined in the diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs new file mode 100644 index 00000000000..dd6cbc7ee9e --- /dev/null +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/EnvironmentVariableConfiguration.cs @@ -0,0 +1,46 @@ +// +// 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; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Configuration; + +internal class EnvironmentVariableConfiguration +{ + public static void InitializeDefaultConfigurationFromEnvironment(SdkConfiguration sdkConfiguration) + { + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits + SetIntConfigValue("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => sdkConfiguration.AttributeValueLengthLimit = value); + SetIntConfigValue("OTEL_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.AttributeCountLimit = value); + + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#span-limits + SetIntConfigValue("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", value => sdkConfiguration.SpanAttributeValueLengthLimit = value); + SetIntConfigValue("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.SpanAttributeCountLimit = value); + SetIntConfigValue("OTEL_SPAN_EVENT_COUNT_LIMIT", value => sdkConfiguration.SpanEventCountLimit = value); + SetIntConfigValue("OTEL_SPAN_LINK_COUNT_LIMIT", value => sdkConfiguration.SpanLinkCountLimit = value); + SetIntConfigValue("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.EventAttributeCountLimit = value); + SetIntConfigValue("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", value => sdkConfiguration.LinkAttributeCountLimit = value); + } + + private static void SetIntConfigValue(string key, Action setter) + { + if (EnvironmentVariableHelper.LoadNumeric(key, out var result)) + { + setter(result); + } + } +} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs new file mode 100644 index 00000000000..a7772bcd532 --- /dev/null +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Configuration/SdkConfiguration.cs @@ -0,0 +1,69 @@ +// +// 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. +// + +namespace OpenTelemetry.Configuration; + +internal class SdkConfiguration +{ + private int? spanAttributeValueLengthLimit; + private int? spanAttributeCountLimit; + private int? eventAttributeCountLimit; + private int? linkAttributeCountLimit; + + private SdkConfiguration() + { + EnvironmentVariableConfiguration.InitializeDefaultConfigurationFromEnvironment(this); + } + + public static SdkConfiguration Instance { get; private set; } = new SdkConfiguration(); + + public int? AttributeValueLengthLimit { get; set; } + + public int? AttributeCountLimit { get; set; } + + public int? SpanAttributeValueLengthLimit + { + get => this.spanAttributeValueLengthLimit ?? this.AttributeValueLengthLimit; + set => this.spanAttributeValueLengthLimit = value; + } + + public int? SpanAttributeCountLimit + { + get => this.spanAttributeCountLimit ?? this.AttributeCountLimit; + set => this.spanAttributeCountLimit = value; + } + + public int? SpanEventCountLimit { get; set; } + + public int? SpanLinkCountLimit { get; set; } + + public int? EventAttributeCountLimit + { + get => this.eventAttributeCountLimit ?? this.SpanAttributeCountLimit; + set => this.eventAttributeCountLimit = value; + } + + public int? LinkAttributeCountLimit + { + get => this.linkAttributeCountLimit ?? this.SpanAttributeCountLimit; + set => this.linkAttributeCountLimit = value; + } + + internal static void Reset() + { + Instance = new SdkConfiguration(); + } +} diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index 6e62e19e805..f1e36021513 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -24,6 +24,7 @@ using System.Runtime.CompilerServices; using Google.Protobuf; using Google.Protobuf.Collections; +using OpenTelemetry.Configuration; using OpenTelemetry.Internal; using OpenTelemetry.Trace; using OtlpCollector = Opentelemetry.Proto.Collector.Trace.V1; @@ -154,7 +155,7 @@ internal static OtlpTrace.Span ToOtlpSpan(this Activity activity) }; TagEnumerationState otlpTags = default; - activity.EnumerateTags(ref otlpTags); + activity.EnumerateTags(ref otlpTags, SdkConfiguration.Instance.SpanAttributeCountLimit); if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer) { @@ -181,7 +182,7 @@ internal static OtlpTrace.Span ToOtlpSpan(this Activity activity) otlpSpan.Status = activity.ToOtlpStatus(ref otlpTags); EventEnumerationState otlpEvents = default; - activity.EnumerateEvents(ref otlpEvents); + activity.EnumerateEvents(ref otlpEvents, SdkConfiguration.Instance.SpanEventCountLimit); if (otlpEvents.Created) { otlpSpan.Events.AddRange(otlpEvents.Events); @@ -189,13 +190,14 @@ internal static OtlpTrace.Span ToOtlpSpan(this Activity activity) } LinkEnumerationState otlpLinks = default; - activity.EnumerateLinks(ref otlpLinks); + activity.EnumerateLinks(ref otlpLinks, SdkConfiguration.Instance.SpanLinkCountLimit); if (otlpLinks.Created) { otlpSpan.Links.AddRange(otlpLinks.Links); otlpLinks.Links.Return(); } + // TODO: The drop counts should be set when necessary. // Activity does not limit number of attributes, events, links, etc so drop counts are always zero. return otlpSpan; @@ -259,7 +261,7 @@ private static OtlpTrace.Span.Types.Link ToOtlpLink(ActivityLink activityLink) }; TagEnumerationState otlpTags = default; - activityLink.EnumerateTags(ref otlpTags); + activityLink.EnumerateTags(ref otlpTags, SdkConfiguration.Instance.LinkAttributeCountLimit); if (otlpTags.Created) { otlpLink.Attributes.AddRange(otlpTags.Tags); @@ -279,7 +281,7 @@ private static OtlpTrace.Span.Types.Event ToOtlpEvent(ActivityEvent activityEven }; TagEnumerationState otlpTags = default; - activityEvent.EnumerateTags(ref otlpTags); + activityEvent.EnumerateTags(ref otlpTags, SdkConfiguration.Instance.EventAttributeCountLimit); if (otlpTags.Created) { otlpEvent.Attributes.AddRange(otlpTags.Tags); @@ -355,7 +357,7 @@ public bool ForEach(KeyValuePair activityTag) this.Created = true; } - if (OtlpKeyValueTransformer.Instance.TryTransformTag(activityTag, out var attribute)) + if (OtlpKeyValueTransformer.Instance.TryTransformTag(activityTag, out var attribute, SdkConfiguration.Instance.AttributeValueLengthLimit)) { PooledList.Add(ref this.Tags, attribute); diff --git a/src/OpenTelemetry/Internal/TagTransformer.cs b/src/OpenTelemetry/Internal/TagTransformer.cs index e63ccd623f9..f2a0cee9cc6 100644 --- a/src/OpenTelemetry/Internal/TagTransformer.cs +++ b/src/OpenTelemetry/Internal/TagTransformer.cs @@ -16,12 +16,13 @@ using System; using System.Collections.Generic; +using System.Linq; namespace OpenTelemetry.Internal; internal abstract class TagTransformer { - public bool TryTransformTag(KeyValuePair tag, out T result) + public bool TryTransformTag(KeyValuePair tag, out T result, int? maxLength = null) { if (tag.Value == null) { @@ -33,7 +34,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) { case char: case string: - result = this.TransformStringTag(tag.Key, Convert.ToString(tag.Value)); + result = this.TransformStringTag(tag.Key, TruncateString(Convert.ToString(tag.Value), maxLength)); break; case bool b: result = this.TransformBooleanTag(tag.Key, b); @@ -54,7 +55,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) case Array array: try { - result = this.TransformArrayTagInternal(tag.Key, array); + result = this.TransformArrayTagInternal(tag.Key, array, maxLength); } catch { @@ -77,7 +78,7 @@ public bool TryTransformTag(KeyValuePair tag, out T result) default: try { - result = this.TransformStringTag(tag.Key, tag.Value.ToString()); + result = this.TransformStringTag(tag.Key, TruncateString(tag.Value.ToString(), maxLength)); } catch { @@ -103,13 +104,20 @@ public bool TryTransformTag(KeyValuePair tag, out T result) protected abstract T TransformArrayTag(string key, Array array); - private T TransformArrayTagInternal(string key, Array array) + private static string TruncateString(string value, int? maxLength) + { + return maxLength.HasValue && value?.Length > maxLength + ? value.Substring(0, maxLength.Value) + : value; + } + + private T TransformArrayTagInternal(string key, Array array, int? maxStringValueLength) { // This switch ensures the values of the resultant array-valued tag are of the same type. return array switch { char[] => this.TransformArrayTag(key, array), - string[] => this.TransformArrayTag(key, array), + string[] => this.ConvertToStringArrayThenTransformArrayTag(key, array, maxStringValueLength), bool[] => this.TransformArrayTag(key, array), byte[] => this.TransformArrayTag(key, array), sbyte[] => this.TransformArrayTag(key, array), @@ -120,17 +128,25 @@ private T TransformArrayTagInternal(string key, Array array) long[] => this.TransformArrayTag(key, array), float[] => this.TransformArrayTag(key, array), double[] => this.TransformArrayTag(key, array), - _ => this.ConvertToStringArrayThenTransformArrayTag(key, array), + _ => this.ConvertToStringArrayThenTransformArrayTag(key, array, maxStringValueLength), }; } - private T ConvertToStringArrayThenTransformArrayTag(string key, Array array) + private T ConvertToStringArrayThenTransformArrayTag(string key, Array array, int? maxStringValueLength) { - var stringArray = new string[array.Length]; + string[] stringArray; - for (var i = 0; i < array.Length; ++i) + if (array is string[] arrayAsStringArray && (!maxStringValueLength.HasValue || !arrayAsStringArray.Any(s => s?.Length > maxStringValueLength))) + { + stringArray = arrayAsStringArray; + } + else { - stringArray[i] = array.GetValue(i)?.ToString(); + stringArray = new string[array.Length]; + for (var i = 0; i < array.Length; ++i) + { + stringArray[i] = TruncateString(array.GetValue(i)?.ToString(), maxStringValueLength); + } } return this.TransformArrayTag(key, stringArray); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs new file mode 100644 index 00000000000..dbbc9e43688 --- /dev/null +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Configuration/SdkConfigurationTests.cs @@ -0,0 +1,133 @@ +// +// 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; +using Xunit; + +namespace OpenTelemetry.Configuration.Tests +{ + [Collection("xUnitCollectionPreventingTestsThatDependOnSdkConfigurationFromRunningInParallel")] + public class SdkConfigurationTests : IDisposable + { + public SdkConfigurationTests() + { + ClearEnvVars(); + SdkConfiguration.Reset(); + } + + public void Dispose() + { + ClearEnvVars(); + SdkConfiguration.Reset(); + } + + [Fact] + public void SdkConfigurationDefaults() + { + var config = SdkConfiguration.Instance; + + Assert.Null(config.AttributeValueLengthLimit); + Assert.Null(config.AttributeCountLimit); + Assert.Null(config.SpanAttributeValueLengthLimit); + Assert.Null(config.SpanAttributeCountLimit); + Assert.Null(config.SpanEventCountLimit); + Assert.Null(config.SpanLinkCountLimit); + Assert.Null(config.EventAttributeCountLimit); + Assert.Null(config.LinkAttributeCountLimit); + } + + [Fact] + public void SdkConfigurationIsInitializedFromEnvironment() + { + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "10"); + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_COUNT_LIMIT", "10"); + Environment.SetEnvironmentVariable("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "20"); + Environment.SetEnvironmentVariable("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "20"); + Environment.SetEnvironmentVariable("OTEL_SPAN_EVENT_COUNT_LIMIT", "10"); + Environment.SetEnvironmentVariable("OTEL_SPAN_LINK_COUNT_LIMIT", "10"); + Environment.SetEnvironmentVariable("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", "30"); + Environment.SetEnvironmentVariable("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", "30"); + + SdkConfiguration.Reset(); + var config = SdkConfiguration.Instance; + + Assert.Equal(10, config.AttributeValueLengthLimit); + Assert.Equal(10, config.AttributeCountLimit); + Assert.Equal(20, config.SpanAttributeValueLengthLimit); + Assert.Equal(20, config.SpanAttributeCountLimit); + Assert.Equal(10, config.SpanEventCountLimit); + Assert.Equal(10, config.SpanLinkCountLimit); + Assert.Equal(30, config.EventAttributeCountLimit); + Assert.Equal(30, config.LinkAttributeCountLimit); + } + + [Fact] + public void SpanAttributeValueLengthLimitFallback() + { + var config = SdkConfiguration.Instance; + + config.AttributeValueLengthLimit = 10; + Assert.Equal(10, config.AttributeValueLengthLimit); + Assert.Equal(10, config.SpanAttributeValueLengthLimit); + + config.SpanAttributeValueLengthLimit = 20; + Assert.Equal(10, config.AttributeValueLengthLimit); + Assert.Equal(20, config.SpanAttributeValueLengthLimit); + } + + [Fact] + public void SpanAttributeCountLimitFallback() + { + var config = SdkConfiguration.Instance; + + config.AttributeCountLimit = 10; + Assert.Equal(10, config.AttributeCountLimit); + Assert.Equal(10, config.SpanAttributeCountLimit); + Assert.Equal(10, config.EventAttributeCountLimit); + Assert.Equal(10, config.LinkAttributeCountLimit); + + config.SpanAttributeCountLimit = 20; + Assert.Equal(10, config.AttributeCountLimit); + Assert.Equal(20, config.SpanAttributeCountLimit); + Assert.Equal(20, config.EventAttributeCountLimit); + Assert.Equal(20, config.LinkAttributeCountLimit); + + config.EventAttributeCountLimit = 30; + Assert.Equal(10, config.AttributeCountLimit); + Assert.Equal(20, config.SpanAttributeCountLimit); + Assert.Equal(30, config.EventAttributeCountLimit); + Assert.Equal(20, config.LinkAttributeCountLimit); + + config.LinkAttributeCountLimit = 40; + Assert.Equal(10, config.AttributeCountLimit); + Assert.Equal(20, config.SpanAttributeCountLimit); + Assert.Equal(30, config.EventAttributeCountLimit); + Assert.Equal(40, config.LinkAttributeCountLimit); + } + + private static void ClearEnvVars() + { + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_COUNT_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_SPAN_EVENT_COUNT_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_SPAN_LINK_COUNT_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", null); + Environment.SetEnvironmentVariable("OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", null); + } + } +} diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs index 56a8df672cd..a3a21e45c3f 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpTraceExporterTests.cs @@ -18,8 +18,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Google.Protobuf.Collections; using Microsoft.Extensions.DependencyInjection; using Moq; +using OpenTelemetry.Configuration; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Resources; @@ -33,6 +35,7 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests { + [Collection("xUnitCollectionPreventingTestsThatDependOnSdkConfigurationFromRunningInParallel")] public class OtlpTraceExporterTests : Http2UnencryptedSupportTests { static OtlpTraceExporterTests() @@ -216,6 +219,79 @@ void RunTest(Batch batch) } } + [Fact] + public void SpanLimitsTest() + { + SdkConfiguration.Instance.AttributeValueLengthLimit = 4; + SdkConfiguration.Instance.AttributeCountLimit = 3; + SdkConfiguration.Instance.SpanEventCountLimit = 1; + SdkConfiguration.Instance.SpanLinkCountLimit = 1; + + var tags = new ActivityTagsCollection() + { + new KeyValuePair("TruncatedTag", "12345"), + new KeyValuePair("TruncatedStringArray", new string[] { "12345", "1234", string.Empty, null }), + new KeyValuePair("TruncatedObjectTag", new object()), + new KeyValuePair("OneTagTooMany", 1), + }; + + var links = new[] + { + new ActivityLink(default, tags), + new ActivityLink(default, tags), + }; + + using var activitySource = new ActivitySource(nameof(this.SpanLimitsTest)); + using var activity = activitySource.StartActivity("root", ActivityKind.Server, default(ActivityContext), tags, links); + + var event1 = new ActivityEvent("Event", DateTime.UtcNow, tags); + var event2 = new ActivityEvent("OneEventTooMany", DateTime.Now, tags); + + activity.AddEvent(event1); + activity.AddEvent(event2); + + var otlpSpan = activity.ToOtlpSpan(); + + Assert.NotNull(otlpSpan); + Assert.Equal(3, otlpSpan.Attributes.Count); + Assert.Equal("1234", otlpSpan.Attributes[0].Value.StringValue); + ArrayValueAsserts(otlpSpan.Attributes[1].Value.ArrayValue.Values); + Assert.Equal(new object().ToString().Substring(0, 4), otlpSpan.Attributes[2].Value.StringValue); + + Assert.Single(otlpSpan.Events); + Assert.Equal(3, otlpSpan.Events[0].Attributes.Count); + Assert.Equal("1234", otlpSpan.Events[0].Attributes[0].Value.StringValue); + ArrayValueAsserts(otlpSpan.Events[0].Attributes[1].Value.ArrayValue.Values); + Assert.Equal(new object().ToString().Substring(0, 4), otlpSpan.Events[0].Attributes[2].Value.StringValue); + + Assert.Single(otlpSpan.Links); + Assert.Equal(3, otlpSpan.Links[0].Attributes.Count); + Assert.Equal("1234", otlpSpan.Links[0].Attributes[0].Value.StringValue); + ArrayValueAsserts(otlpSpan.Links[0].Attributes[1].Value.ArrayValue.Values); + Assert.Equal(new object().ToString().Substring(0, 4), otlpSpan.Links[0].Attributes[2].Value.StringValue); + + void ArrayValueAsserts(RepeatedField values) + { + var expectedStringArray = new string[] { "1234", "1234", string.Empty, null }; + for (var i = 0; i < expectedStringArray.Length; ++i) + { + var expectedValue = expectedStringArray[i]; + var expectedValueCase = expectedValue != null + ? OtlpCommon.AnyValue.ValueOneofCase.StringValue + : OtlpCommon.AnyValue.ValueOneofCase.None; + + var actual = values[i]; + Assert.Equal(expectedValueCase, actual.ValueCase); + if (expectedValueCase != OtlpCommon.AnyValue.ValueOneofCase.None) + { + Assert.Equal(expectedValue, actual.StringValue); + } + } + } + + SdkConfiguration.Reset(); + } + [Fact] public void ToOtlpSpanTest() { From df97482f6e1ea9276f26471dd51662bc433e7c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 28 Jul 2022 18:30:33 +0200 Subject: [PATCH 065/111] EnvironmentVariableHelper support for boolean (#3457) --- .../Internal/EnvironmentVariableHelper.cs | 28 ++++++++++++++ .../EnvironmentVariableHelperTests.cs | 38 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs b/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs index df3f89df0aa..f6ea9783590 100644 --- a/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs +++ b/src/OpenTelemetry/Internal/EnvironmentVariableHelper.cs @@ -111,5 +111,33 @@ public static bool LoadUri(string envVarKey, out Uri result) return true; } + + /// + /// Reads an environment variable and parses it as a . + /// + /// The name of the environment variable. + /// The parsed value of the environment variable. + /// + /// Returns true when a non-empty value was read; otherwise, false. + /// + /// + /// Thrown when failed to parse the non-empty value. + /// + public static bool LoadBoolean(string envVarKey, out bool result) + { + result = default; + + if (!LoadString(envVarKey, out string value)) + { + return false; + } + + if (!bool.TryParse(value, out result)) + { + throw new FormatException($"{envVarKey} environment variable has an invalid value: '${value}'"); + } + + return true; + } } } diff --git a/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs b/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs index 290e5ceb77b..738fa27b9b3 100644 --- a/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs +++ b/test/OpenTelemetry.Tests/Internal/EnvironmentVariableHelperTests.cs @@ -55,6 +55,44 @@ public void LoadString_NoValue() Assert.Null(actualValue); } + [Theory] + [InlineData("true", true)] + [InlineData("TRUE", true)] + [InlineData("false", false)] + [InlineData("FALSE", false)] + [InlineData(" true ", true)] + [InlineData(" false ", false)] + public void LoadBoolean(string value, bool expectedValue) + { + Environment.SetEnvironmentVariable(EnvVar, value); + + bool actualBool = EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool actualValue); + + Assert.True(actualBool); + Assert.Equal(expectedValue, actualValue); + } + + [Fact] + public void LoadBoolean_NoValue() + { + bool actualBool = EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool actualValue); + + Assert.False(actualBool); + Assert.False(actualValue); + } + + [Theory] + [InlineData("something")] // non true/false + [InlineData(" ")] // whitespaces + [InlineData("0")] // 0 + [InlineData("1")] // 1 + public void LoadBoolean_Invalid(string value) + { + Environment.SetEnvironmentVariable(EnvVar, value); + + Assert.Throws(() => EnvironmentVariableHelper.LoadBoolean(EnvVar, out bool _)); + } + [Theory] [InlineData("123", 123)] [InlineData("0", 0)] From 4e0dccd527f1354915e94250f0ba90daf3b2e33b Mon Sep 17 00:00:00 2001 From: Mikel Blanchard Date: Thu, 28 Jul 2022 13:11:02 -0700 Subject: [PATCH 066/111] [Logs] Add extension for registering OpenTelemetryLoggerProvider with ILoggingBuilder (#3489) --- .../.publicApi/net462/PublicAPI.Unshipped.txt | 5 + .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 7 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 5 + .../netstandard2.1/PublicAPI.Unshipped.txt | 7 +- src/OpenTelemetry/CHANGELOG.md | 4 + .../Logs/OpenTelemetryLoggingExtensions.cs | 59 ++++- .../OpenTelemetryLoggingExtensionsTests.cs | 211 ++++++++++++++++++ 7 files changed, 294 insertions(+), 4 deletions(-) create mode 100644 test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index ecaf006aa47..791e1c4f84a 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -11,5 +11,10 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 43156ee3c3a..a045a0ffba5 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -11,5 +11,10 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void +*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder -~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index ecaf006aa47..791e1c4f84a 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -11,5 +11,10 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder ~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 43156ee3c3a..a045a0ffba5 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -11,5 +11,10 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void +*REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! +static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure) -> Microsoft.Extensions.Logging.ILoggingBuilder! ~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder -~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +~static OpenTelemetry.Trace.TracerProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index e9943f06bd6..c50635a1d78 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -34,6 +34,10 @@ * Fix exact match of activity source name when `wildcard` is used. ([#3446](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3446)) +* Added AddOpenTelemetry `ILoggingBuilder` extensions which accept + `OpenTelemetryLoggerProvider` directly + ([#3489](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3489)) + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs index 000542b2fbd..9687d32eb1b 100644 --- a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs @@ -32,12 +32,20 @@ namespace Microsoft.Extensions.Logging public static class OpenTelemetryLoggingExtensions { /// - /// Adds a OpenTelemetry logger named 'OpenTelemetry' to the factory. + /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . + /// + /// The to use. + /// The supplied for call chaining. + public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder) + => AddOpenTelemetry(builder, configure: null); + + /// + /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . /// /// The to use. /// Optional configuration action. /// The supplied for call chaining. - public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Action? configure = null) + public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Action? configure) { Guard.ThrowIfNull(builder); @@ -51,5 +59,52 @@ public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Act return builder; } + + /// + /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . + /// + /// + /// Note: The supplied will + /// automatically be disposed when the + /// built from is disposed. + /// + /// The to use. + /// . + /// The supplied for call chaining. + public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, OpenTelemetryLoggerProvider openTelemetryLoggerProvider) + => AddOpenTelemetry(builder, openTelemetryLoggerProvider, disposeProvider: true); + + /// + /// Adds an OpenTelemetry logger named 'OpenTelemetry' to the . + /// + /// The to use. + /// . + /// Controls whether or not the supplied + /// will be disposed when + /// the is disposed. + /// The supplied for call chaining. + public static ILoggingBuilder AddOpenTelemetry( + this ILoggingBuilder builder, + OpenTelemetryLoggerProvider openTelemetryLoggerProvider, + bool disposeProvider) + { + Guard.ThrowIfNull(builder); + Guard.ThrowIfNull(openTelemetryLoggerProvider); + + // Note: Currently if multiple OpenTelemetryLoggerProvider instances + // are added to the same ILoggingBuilder everything after the first + // is silently ignored. + + if (disposeProvider) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(sp => openTelemetryLoggerProvider)); + } + else + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(openTelemetryLoggerProvider)); + } + + return builder; + } } } diff --git a/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs new file mode 100644 index 00000000000..5f07ee7b06f --- /dev/null +++ b/test/OpenTelemetry.Tests/Logs/OpenTelemetryLoggingExtensionsTests.cs @@ -0,0 +1,211 @@ +// +// 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. +// + +#nullable enable + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace OpenTelemetry.Logs.Tests; + +public sealed class OpenTelemetryLoggingExtensionsTests +{ + [Fact] + public void ServiceCollectionAddOpenTelemetryNoParametersTest() + { + bool optionsCallbackInvoked = false; + + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddLogging(configure => + { + configure.AddOpenTelemetry(); + }); + + serviceCollection.Configure(options => + { + optionsCallbackInvoked = true; + }); + + using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); + + ILoggerFactory? loggerFactory = serviceProvider.GetService(); + + Assert.NotNull(loggerFactory); + + Assert.True(optionsCallbackInvoked); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(1, 1)] + [InlineData(5, 5)] + public void ServiceCollectionAddOpenTelemetryConfigureActionTests(int numberOfBuilderRegistrations, int numberOfOptionsRegistrations) + { + int configureCallbackInvocations = 0; + int optionsCallbackInvocations = 0; + OpenTelemetryLoggerOptions? optionsInstance = null; + + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddLogging(configure => + { + for (int i = 0; i < numberOfBuilderRegistrations; i++) + { + configure.AddOpenTelemetry(ConfigureCallback); + } + }); + + for (int i = 0; i < numberOfOptionsRegistrations; i++) + { + serviceCollection.Configure(OptionsCallback); + } + + using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); + + ILoggerFactory? loggerFactory = serviceProvider.GetService(); + + Assert.NotNull(loggerFactory); + + Assert.NotNull(optionsInstance); + + Assert.Equal(numberOfBuilderRegistrations, configureCallbackInvocations); + Assert.Equal(numberOfOptionsRegistrations, optionsCallbackInvocations); + + void ConfigureCallback(OpenTelemetryLoggerOptions options) + { + if (optionsInstance == null) + { + optionsInstance = options; + } + else + { + Assert.Equal(optionsInstance, options); + } + + configureCallbackInvocations++; + } + + void OptionsCallback(OpenTelemetryLoggerOptions options) + { + if (optionsInstance == null) + { + optionsInstance = options; + } + else + { + Assert.Equal(optionsInstance, options); + } + + optionsCallbackInvocations++; + } + } + + [Fact] + public void ServiceCollectionAddOpenTelemetryWithProviderTest() + { + var provider = new WrappedOpenTelemetryLoggerProvider(); + + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddLogging(configure => + { + configure.AddOpenTelemetry(provider); + }); + + using (ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider()) + { + ILoggerFactory? loggerFactory = serviceProvider.GetService(); + + Assert.NotNull(loggerFactory); + + loggerFactory!.Dispose(); + + // Note: Provider disposal does not actually happen until serviceProvider is disposed + Assert.False(provider.Disposed); + } + + Assert.True(provider.Disposed); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ServiceCollectionAddOpenTelemetryWithProviderAndDisposeSpecifiedTests(bool dispose) + { + var provider = new WrappedOpenTelemetryLoggerProvider(); + + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddLogging(configure => + { + configure.AddOpenTelemetry(provider, disposeProvider: dispose); + }); + + using (ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider()) + { + ILoggerFactory? loggerFactory = serviceProvider.GetService(); + + Assert.NotNull(loggerFactory); + + loggerFactory!.Dispose(); + + // Note: Provider disposal does not actually happen until serviceProvider is disposed + Assert.False(provider.Disposed); + } + + Assert.Equal(dispose, provider.Disposed); + + provider.Dispose(); + + Assert.True(provider.Disposed); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void LoggerFactoryCreateAddOpenTelemetryWithProviderAndDisposeSpecifiedTests(bool dispose) + { + var provider = new WrappedOpenTelemetryLoggerProvider(); + + using (var factory = LoggerFactory.Create(configure => + { + configure.AddOpenTelemetry(provider, disposeProvider: dispose); + })) + { + Assert.False(provider.Disposed); + } + + Assert.Equal(dispose, provider.Disposed); + + provider.Dispose(); + + Assert.True(provider.Disposed); + } + + private sealed class WrappedOpenTelemetryLoggerProvider : OpenTelemetryLoggerProvider + { + public bool Disposed { get; private set; } + + protected override void Dispose(bool disposing) + { + this.Disposed = true; + + base.Dispose(disposing); + } + } +} From e3450b2e591e5d590e34d85f69ed3bcc7143d7ab Mon Sep 17 00:00:00 2001 From: Yun-Ting Lin Date: Thu, 28 Jul 2022 16:02:53 -0700 Subject: [PATCH 067/111] [Prometheus] Split up projects based on hosting mechanism. (#3430) --- OpenTelemetry.sln | 48 ++++++-- README.md | 3 +- docs/metrics/customizing-the-sdk/README.md | 3 +- docs/metrics/extending-the-sdk/README.md | 3 +- .../Program.cs | 2 +- .../README.md | 21 ++-- .../getting-started-prometheus-grafana.csproj | 5 +- .../AspNetCore/Examples.AspNetCore.csproj | 2 +- examples/Console/Examples.Console.csproj | 2 +- examples/Console/TestPrometheusExporter.cs | 9 +- .../netcoreapp3.1}/PublicAPI.Shipped.txt | 0 .../netcoreapp3.1/PublicAPI.Unshipped.txt | 26 ++--- .../AssemblyInfo.cs | 23 ++++ .../CHANGELOG.md | 6 + ...etry.Exporter.Prometheus.AspNetCore.csproj | 41 +++++++ ...eusExporterApplicationBuilderExtensions.cs | 7 +- ...sExporterEndpointRouteBuilderExtensions.cs | 7 +- ...sExporterMeterProviderBuilderExtensions.cs | 12 +- .../PrometheusExporterMiddleware.cs | 3 +- .../README.md | 58 +++------- .../.publicApi/net462}/PublicAPI.Shipped.txt | 0 .../.publicApi/net462/PublicAPI.Unshipped.txt | 12 ++ .../netstandard2.0/PublicAPI.Shipped.txt | 0 .../netstandard2.0/PublicAPI.Unshipped.txt | 12 ++ .../CHANGELOG.md | 94 ++++++++++++++++ ...ry.Exporter.Prometheus.HttpListener.csproj | 36 ++++++ ...pListenerMeterProviderBuilderExtensions.cs | 104 ++++++++++++++++++ .../PrometheusHttpListener.cs} | 38 +++---- .../PrometheusHttpListenerOptions.cs | 56 ++++++++++ .../README.md | 72 ++++++++++++ .../.publicApi/net462/PublicAPI.Shipped.txt | 0 .../.publicApi/net462/PublicAPI.Unshipped.txt | 6 + .../netcoreapp3.1/PublicAPI.Shipped.txt | 0 .../netcoreapp3.1/PublicAPI.Unshipped.txt | 6 + .../AssemblyInfo.cs | 4 +- ...lemetry.Exporter.Prometheus.Shared.csproj} | 7 +- .../PrometheusCollectionManager.cs | 2 +- .../PrometheusExporter.cs | 36 +++--- .../PrometheusExporterEventSource.cs | 2 +- .../PrometheusExporterOptions.cs | 52 ++------- .../PrometheusSerializer.cs | 2 +- .../PrometheusSerializerExt.cs | 2 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 18 --- src/OpenTelemetry/AssemblyInfo.cs | 5 +- test/Benchmarks/Benchmarks.csproj | 2 +- .../PrometheusSerializerBenchmarks.cs | 4 +- ...porter.Prometheus.AspNetCore.Tests.csproj} | 13 +-- .../PrometheusCollectionManagerTests.cs | 3 +- .../PrometheusExporterMiddlewareTests.cs | 6 +- ...orter.Prometheus.HttpListener.Tests.csproj | 29 +++++ .../PrometheusExporterHttpListenerTests.cs} | 96 +++++----------- ...ry.Exporter.Prometheus.Shared.Tests.csproj | 32 ++++++ .../PrometheusSerializerTests.cs | 2 +- .../OpenTelemetry.Tests.Stress.Logs.csproj | 2 +- .../OpenTelemetry.Tests.Stress.Metrics.csproj | 2 +- .../Program.cs | 9 +- .../OpenTelemetry.Tests.Stress.csproj | 2 +- test/OpenTelemetry.Tests.Stress/README.md | 2 +- test/OpenTelemetry.Tests.Stress/Skeleton.cs | 9 +- 59 files changed, 737 insertions(+), 323 deletions(-) rename src/{OpenTelemetry.Exporter.Prometheus/.publicApi/net462 => OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1}/PublicAPI.Shipped.txt (100%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt (63%) create mode 100644 src/OpenTelemetry.Exporter.Prometheus.AspNetCore/AssemblyInfo.cs rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/CHANGELOG.md (84%) create mode 100644 src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/PrometheusExporterApplicationBuilderExtensions.cs (96%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/PrometheusExporterEndpointRouteBuilderExtensions.cs (95%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/PrometheusExporterMeterProviderBuilderExtensions.cs (87%) rename src/{OpenTelemetry.Exporter.Prometheus/Implementation => OpenTelemetry.Exporter.Prometheus.AspNetCore}/PrometheusExporterMiddleware.cs (97%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.AspNetCore}/README.md (58%) rename src/{OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1 => OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462}/PublicAPI.Shipped.txt (100%) create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Shipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs rename src/{OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterHttpServer.cs => OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs} (82%) create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs create mode 100644 src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md create mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt create mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.Shared}/AssemblyInfo.cs (78%) rename src/{OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj => OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj} (84%) rename src/{OpenTelemetry.Exporter.Prometheus/Implementation => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusCollectionManager.cs (99%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusExporter.cs (75%) rename src/{OpenTelemetry.Exporter.Prometheus/Implementation => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusExporterEventSource.cs (98%) rename src/{OpenTelemetry.Exporter.Prometheus => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusExporterOptions.cs (52%) rename src/{OpenTelemetry.Exporter.Prometheus/Implementation => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusSerializer.cs (99%) rename src/{OpenTelemetry.Exporter.Prometheus/Implementation => OpenTelemetry.Exporter.Prometheus.Shared}/PrometheusSerializerExt.cs (99%) delete mode 100644 src/OpenTelemetry.Exporter.Prometheus/.publicApi/net462/PublicAPI.Unshipped.txt rename test/{OpenTelemetry.Exporter.Prometheus.Tests/OpenTelemetry.Exporter.Prometheus.Tests.csproj => OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj} (75%) rename test/{OpenTelemetry.Exporter.Prometheus.Tests => OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests}/PrometheusCollectionManagerTests.cs (98%) rename test/{OpenTelemetry.Exporter.Prometheus.Tests => OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests}/PrometheusExporterMiddlewareTests.cs (97%) create mode 100644 test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj rename test/{OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterHttpServerTests.cs => OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs} (63%) create mode 100644 test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj rename test/{OpenTelemetry.Exporter.Prometheus.Tests => OpenTelemetry.Exporter.Prometheus.Shared.Tests}/PrometheusSerializerTests.cs (99%) diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 375d2633837..d345ee94283 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -195,8 +195,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "reporting-exceptions", "doc EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs\trace\customizing-the-sdk\customizing-the-sdk.csproj", "{64E3D8BB-93AB-4571-93F7-ED8D64DFFD06}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus", "src\OpenTelemetry.Exporter.Prometheus\OpenTelemetry.Exporter.Prometheus.csproj", "{52158A12-E7EF-45A1-859F-06F9B17410CB}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "learning-more-instruments", "docs\metrics\learning-more-instruments\learning-more-instruments.csproj", "{E7F491CC-C37E-4A56-9CA7-8F77F59E0614}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "docs\metrics\getting-started\getting-started.csproj", "{EA60B549-F712-4ABE-8E44-FCA83B78C06E}" @@ -209,8 +207,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Tests.Stress", "test\OpenTelemetry.Tests.Stress\OpenTelemetry.Tests.Stress.csproj", "{2770158A-D220-414B-ABC6-179371323579}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.Tests", "test\OpenTelemetry.Exporter.Prometheus.Tests\OpenTelemetry.Exporter.Prometheus.Tests.csproj", "{380EE686-91F1-45B3-AEEB-755F0E5B068F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs", "src\OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs\OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs.csproj", "{6E1A5FA3-E024-4972-9EDC-11E36C5A0D6F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp.AspNetCore.6.0", "test\TestApp.AspNetCore.6.0\TestApp.AspNetCore.6.0.csproj", "{0076C657-564F-4787-9FFF-52D9D55166E8}" @@ -239,6 +235,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Ev EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.EventSource.Tests", "test\OpenTelemetry.Extensions.EventSource.Tests\OpenTelemetry.Extensions.EventSource.Tests.csproj", "{304FCFFF-97DE-484B-8D8C-612C644426E5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.AspNetCore", "src\OpenTelemetry.Exporter.Prometheus.AspNetCore\OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj", "{921CF401-4C2F-4C6D-A750-0B5DC457C1F1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.HttpListener", "src\OpenTelemetry.Exporter.Prometheus.HttpListener\OpenTelemetry.Exporter.Prometheus.HttpListener.csproj", "{6B0232B7-5F29-4FB5-B383-1AA02DFE1089}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.Shared", "src\OpenTelemetry.Exporter.Prometheus.Shared\OpenTelemetry.Exporter.Prometheus.Shared.csproj", "{4AD27517-BAFC-413B-A8F0-988C3CEDC662}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests", "test\OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests\OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj", "{FBD12B0B-6731-4DD4-9C13-86F34593E974}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.HttpListener.Tests", "test\OpenTelemetry.Exporter.Prometheus.HttpListener.Tests\OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj", "{4EF4364F-6E64-43CE-BED1-E6FE01024899}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.Shared.Tests", "test\OpenTelemetry.Exporter.Prometheus.Shared.Tests\OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj", "{8E75AEE2-017B-474F-A96D-035DF76A1C9E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -405,10 +413,6 @@ Global {64E3D8BB-93AB-4571-93F7-ED8D64DFFD06}.Debug|Any CPU.Build.0 = Debug|Any CPU {64E3D8BB-93AB-4571-93F7-ED8D64DFFD06}.Release|Any CPU.ActiveCfg = Release|Any CPU {64E3D8BB-93AB-4571-93F7-ED8D64DFFD06}.Release|Any CPU.Build.0 = Release|Any CPU - {52158A12-E7EF-45A1-859F-06F9B17410CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {52158A12-E7EF-45A1-859F-06F9B17410CB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {52158A12-E7EF-45A1-859F-06F9B17410CB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {52158A12-E7EF-45A1-859F-06F9B17410CB}.Release|Any CPU.Build.0 = Release|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7F491CC-C37E-4A56-9CA7-8F77F59E0614}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -433,10 +437,6 @@ Global {2770158A-D220-414B-ABC6-179371323579}.Debug|Any CPU.Build.0 = Debug|Any CPU {2770158A-D220-414B-ABC6-179371323579}.Release|Any CPU.ActiveCfg = Release|Any CPU {2770158A-D220-414B-ABC6-179371323579}.Release|Any CPU.Build.0 = Release|Any CPU - {380EE686-91F1-45B3-AEEB-755F0E5B068F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {380EE686-91F1-45B3-AEEB-755F0E5B068F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {380EE686-91F1-45B3-AEEB-755F0E5B068F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {380EE686-91F1-45B3-AEEB-755F0E5B068F}.Release|Any CPU.Build.0 = Release|Any CPU {6E1A5FA3-E024-4972-9EDC-11E36C5A0D6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6E1A5FA3-E024-4972-9EDC-11E36C5A0D6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E1A5FA3-E024-4972-9EDC-11E36C5A0D6F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -493,6 +493,30 @@ Global {304FCFFF-97DE-484B-8D8C-612C644426E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {304FCFFF-97DE-484B-8D8C-612C644426E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {304FCFFF-97DE-484B-8D8C-612C644426E5}.Release|Any CPU.Build.0 = Release|Any CPU + {921CF401-4C2F-4C6D-A750-0B5DC457C1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {921CF401-4C2F-4C6D-A750-0B5DC457C1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {921CF401-4C2F-4C6D-A750-0B5DC457C1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {921CF401-4C2F-4C6D-A750-0B5DC457C1F1}.Release|Any CPU.Build.0 = Release|Any CPU + {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Release|Any CPU.Build.0 = Release|Any CPU + {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Release|Any CPU.Build.0 = Release|Any CPU + {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Release|Any CPU.Build.0 = Release|Any CPU + {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Release|Any CPU.Build.0 = Release|Any CPU + {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index f0f027b7478..442df7a4c5f 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,8 @@ libraries](https://github.com/open-telemetry/opentelemetry-specification/blob/ma * [Jaeger](./src/OpenTelemetry.Exporter.Jaeger/README.md) * [OTLP](./src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md) (OpenTelemetry Protocol) -* [Prometheus](./src/OpenTelemetry.Exporter.Prometheus/README.md) +* [Prometheus HttpListener](./src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md) +* [Prometheus AspNetCore](./src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md) * [Zipkin](./src/OpenTelemetry.Exporter.Zipkin/README.md) See the [OpenTelemetry registry](https://opentelemetry.io/registry/?s=net) for diff --git a/docs/metrics/customizing-the-sdk/README.md b/docs/metrics/customizing-the-sdk/README.md index 5491faf1914..eeeb64ef819 100644 --- a/docs/metrics/customizing-the-sdk/README.md +++ b/docs/metrics/customizing-the-sdk/README.md @@ -423,7 +423,8 @@ Refer to the individual exporter docs to learn how to use them: * [In-memory](../../../src/OpenTelemetry.Exporter.InMemory/README.md) * [OTLP](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md) (OpenTelemetry Protocol) -* [Prometheus](../../../src/OpenTelemetry.Exporter.Prometheus/README.md) +* [Prometheus HttpListener](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md) +* [Prometheus AspNetCore](../../../src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md) ### Resource diff --git a/docs/metrics/extending-the-sdk/README.md b/docs/metrics/extending-the-sdk/README.md index 7671bb420ca..0777c8f8f1b 100644 --- a/docs/metrics/extending-the-sdk/README.md +++ b/docs/metrics/extending-the-sdk/README.md @@ -12,7 +12,8 @@ OpenTelemetry .NET SDK has provided the following built-in metric exporters: * [InMemory](../../../src/OpenTelemetry.Exporter.InMemory/README.md) * [Console](../../../src/OpenTelemetry.Exporter.Console/README.md) * [OpenTelemetryProtocol](../../../src/OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md) -* [Prometheus](../../../src/OpenTelemetry.Exporter.Prometheus/README.md) +* [Prometheus HttpListener](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md) +* [Prometheus AspNetCore](../../../src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md) Custom exporters can be implemented to send telemetry data to places which are not covered by the built-in exporters: diff --git a/docs/metrics/getting-started-prometheus-grafana/Program.cs b/docs/metrics/getting-started-prometheus-grafana/Program.cs index 2e176c39f79..32bfa1c65e1 100644 --- a/docs/metrics/getting-started-prometheus-grafana/Program.cs +++ b/docs/metrics/getting-started-prometheus-grafana/Program.cs @@ -31,7 +31,7 @@ public static void Main() { using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter("MyCompany.MyProduct.MyLibrary") - .AddPrometheusExporter(options => { options.StartHttpListener = true; }) + .AddPrometheusHttpListener() .Build(); Console.WriteLine("Press any key to exit"); diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md index e58245a6b04..62953f4f130 100644 --- a/docs/metrics/getting-started-prometheus-grafana/README.md +++ b/docs/metrics/getting-started-prometheus-grafana/README.md @@ -23,10 +23,10 @@ dotnet run ``` Add a reference to [Prometheus -Exporter](../../../src/OpenTelemetry.Exporter.Prometheus/README.md): +Exporter Http Listener](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md): ```sh -dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus +dotnet add package --prerelease OpenTelemetry.Exporter.Prometheus.HttpListener ``` Now, we are going to make some small tweaks to the example in the @@ -46,12 +46,13 @@ And replace the below line: with ```csharp -.AddPrometheusExporter(options => { options.StartHttpListener = true; }) +.AddPrometheusHttpListener() ``` -With `AddPrometheusExporter()`, OpenTelemetry `PrometheusExporter` will export +`PrometheusHttpListener` is a wrapper that contains `PrometheusExporter`. +With `AddPrometheusHttpListener()`, OpenTelemetry `PrometheusExporter` will export data via the endpoint defined by -[PrometheusExporterOptions.HttpListenerPrefixes](../../../src/OpenTelemetry.Exporter.Prometheus/README.md#httplistenerprefixes), +[PrometheusHttpListenerOptions.Prefixes](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md#prefixes), which is `http://localhost:9464/` by default. ```mermaid @@ -60,7 +61,7 @@ graph LR subgraph SDK MeterProvider MetricReader[BaseExportingMetricReader] - PrometheusExporter["PrometheusExporter
(http://localhost:9464/)"] + PrometheusHttpListener["PrometheusHttpListener
(http://localhost:9464/)"] end subgraph API @@ -69,7 +70,7 @@ end Instrument --> | Measurements | MeterProvider -MeterProvider --> | Metrics | MetricReader --> | Pull | PrometheusExporter +MeterProvider --> | Metrics | MetricReader --> | Pull | PrometheusHttpListener ``` Also, for our learning purpose, use a while-loop to keep increasing the counter @@ -99,7 +100,7 @@ web browser: ![Browser UI](https://user-images.githubusercontent.com/17327289/151633547-736c6d91-62d2-4e66-a53f-2e16c44bfabc.png) -Now, we understand how we can configure `PrometheusExporter` to export metrics. +Now, we understand how we can configure `PrometheusHttpListener` to export metrics. Next, we are going to learn about how to use Prometheus to collect the metrics. ## Collect metrics using Prometheus @@ -156,7 +157,7 @@ values we have set in `otel.yml`. Congratulations! Now we know how to configure Prometheus server and deploy OpenTelemetry -`PrometheusExporter` to export our metrics. Next, we are going to explore a tool +`PrometheusHttpListener` to export our metrics. Next, we are going to explore a tool called Grafana, which has powerful visualizations for the metrics. ## Explore metrics using Grafana @@ -201,7 +202,7 @@ subgraph Prometheus PrometheusDatabase end -PrometheusExporter["PrometheusExporter
(listening at #quot;http://localhost:9464/#quot;)"] -->|HTTP GET| PrometheusScraper{{"Prometheus scraper
(polling #quot;http://localhost:9464/metrics#quot; every 10 seconds)"}} +PrometheusHttpListener["PrometheusHttpListener
(listening at #quot;http://localhost:9464/#quot;)"] -->|HTTP GET| PrometheusScraper{{"Prometheus scraper
(polling #quot;http://localhost:9464/metrics#quot; every 10 seconds)"}} PrometheusScraper --> PrometheusDatabase[("Prometheus TSDB (time series database)")] PrometheusDatabase -->|http://localhost:9090/graph| PrometheusUI["Browser
(Prometheus Dashboard)"] PrometheusDatabase -->|http://localhost:9090/api/| Grafana[Grafana Server] diff --git a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj index 4913a024a94..455ed30ceb4 100644 --- a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj +++ b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj @@ -1,5 +1,8 @@ + + netstandard2.0 + - + diff --git a/examples/AspNetCore/Examples.AspNetCore.csproj b/examples/AspNetCore/Examples.AspNetCore.csproj index d92150ac7f8..a1f897d4dcf 100644 --- a/examples/AspNetCore/Examples.AspNetCore.csproj +++ b/examples/AspNetCore/Examples.AspNetCore.csproj @@ -19,7 +19,7 @@ - + diff --git a/examples/Console/Examples.Console.csproj b/examples/Console/Examples.Console.csproj index 830e6dfe32c..8239cd4f5f1 100644 --- a/examples/Console/Examples.Console.csproj +++ b/examples/Console/Examples.Console.csproj @@ -33,7 +33,7 @@ - + diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs index 935e2530000..29fc3879f39 100644 --- a/examples/Console/TestPrometheusExporter.cs +++ b/examples/Console/TestPrometheusExporter.cs @@ -51,12 +51,9 @@ internal static object Run(int port) using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(MyMeter.Name) .AddMeter(MyMeter2.Name) - .AddPrometheusExporter(options => - { - options.StartHttpListener = true; - options.HttpListenerPrefixes = new string[] { $"http://localhost:{port}/" }; - options.ScrapeResponseCacheDurationMilliseconds = 0; - }) + .AddPrometheusHttpListener( + exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, + listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:{port}/" }) .Build(); var process = Process.GetCurrentProcess(); diff --git a/src/OpenTelemetry.Exporter.Prometheus/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt similarity index 100% rename from src/OpenTelemetry.Exporter.Prometheus/.publicApi/net462/PublicAPI.Shipped.txt rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt diff --git a/src/OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt similarity index 63% rename from src/OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt index 0c45b3f187c..f9271183c1c 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt @@ -1,27 +1,17 @@ Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions -OpenTelemetry.Exporter.PrometheusExporter -OpenTelemetry.Exporter.PrometheusExporter.Collect.get -> System.Func -OpenTelemetry.Exporter.PrometheusExporter.Collect.set -> void -OpenTelemetry.Exporter.PrometheusExporter.PrometheusExporter(OpenTelemetry.Exporter.PrometheusExporterOptions options) -> void -OpenTelemetry.Exporter.PrometheusExporterOptions -OpenTelemetry.Exporter.PrometheusExporterOptions.HttpListenerPrefixes.get -> System.Collections.Generic.IReadOnlyCollection -OpenTelemetry.Exporter.PrometheusExporterOptions.HttpListenerPrefixes.set -> void -OpenTelemetry.Exporter.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void -OpenTelemetry.Exporter.PrometheusExporterOptions.StartHttpListener.get -> bool -OpenTelemetry.Exporter.PrometheusExporterOptions.StartHttpListener.set -> void +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions -override OpenTelemetry.Exporter.PrometheusExporter.Dispose(bool disposing) -> void -override OpenTelemetry.Exporter.PrometheusExporter.Export(in OpenTelemetry.Batch metrics) -> OpenTelemetry.ExportResult static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, OpenTelemetry.Metrics.MeterProvider meterProvider, System.Func predicate, string path, System.Action configureBranchedPipeline) -> Microsoft.AspNetCore.Builder.IApplicationBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, string path) -> Microsoft.AspNetCore.Builder.IApplicationBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, System.Func predicate) -> Microsoft.AspNetCore.Builder.IApplicationBuilder -static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder -static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path = null, OpenTelemetry.Metrics.MeterProvider meterProvider = null, System.Action configureBranchedPipeline = null) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder +static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder +static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/AssemblyInfo.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/AssemblyInfo.cs new file mode 100644 index 00000000000..574fd52fb83 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/AssemblyInfo.cs @@ -0,0 +1,23 @@ +// +// 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.Runtime.CompilerServices; + +#if SIGNED +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] +#else +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests")] +#endif diff --git a/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md similarity index 84% rename from src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md index 5787a17c1db..f2df4b1a83b 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +* Split up Prometheus projects based on its hosting mechanism, HttpListener and AspNetCore, + into their own projects and assemblies. The shared code for both hosting mechanism + now lives in the `OpenTelemetry.Exporter.Prometheus.Shared` project and will not + be released. + ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430)) + * Added `IEndpointRouteBuilder` extension methods to help with Prometheus middleware configuration on ASP.NET Core ([#3295](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3295)) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj new file mode 100644 index 00000000000..e7453e0bf52 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj @@ -0,0 +1,41 @@ + + + + + netcoreapp3.1 + AspNetCore middleware for hosting OpenTelemetry .NET Prometheus exporter + $(PackageTags);prometheus;metrics + core- + + + + + false + + + + $(DefineConstants);PROMETHEUS_ASPNETCORE + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterApplicationBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs similarity index 96% rename from src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterApplicationBuilderExtensions.cs rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs index ef96f4722f8..00fe170e6fb 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterApplicationBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs @@ -19,8 +19,7 @@ using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using OpenTelemetry.Exporter; -using OpenTelemetry.Exporter.Prometheus; +using OpenTelemetry.Exporter.Prometheus.AspNetCore; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; @@ -93,8 +92,8 @@ public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint(thi /// The to add /// middleware to. /// Optional - /// containing a otherwise the primary - /// SDK provider will be resolved using application services. + /// containing a Prometheus exporter otherwise the primary SDK provider + /// will be resolved using application services. /// Optional predicate for deciding if a given /// should be branched. If supplied is ignored. diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterEndpointRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs similarity index 95% rename from src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterEndpointRouteBuilderExtensions.cs rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs index 02b58a34201..372a96e8a81 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterEndpointRouteBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs @@ -20,8 +20,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using OpenTelemetry.Exporter; -using OpenTelemetry.Exporter.Prometheus; +using OpenTelemetry.Exporter.Prometheus.AspNetCore; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; @@ -70,8 +69,8 @@ public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint(this IEnd /// If not provided then /// is used. /// Optional - /// containing a otherwise the primary - /// SDK provider will be resolved using application services. + /// containing a Prometheus exporter otherwise the primary SDK provider + /// will be resolved using application services. /// Optional callback to /// configure the branched pipeline. Called before registration of the /// Prometheus middleware. diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs similarity index 87% rename from src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMeterProviderBuilderExtensions.cs rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs index ada7d1c90d1..fd6809d68ee 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs @@ -15,11 +15,15 @@ // using System; -using OpenTelemetry.Exporter; +using OpenTelemetry.Exporter.Prometheus.AspNetCore; +using OpenTelemetry.Exporter.Prometheus.Shared; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics { + /// + /// Extension methods to simplify registering a PrometheusExporter. + /// public static class PrometheusExporterMeterProviderBuilderExtensions { /// @@ -48,8 +52,10 @@ private static MeterProviderBuilder AddPrometheusExporter(MeterProviderBuilder b configure?.Invoke(options); var exporter = new PrometheusExporter(options); - var reader = new BaseExportingMetricReader(exporter); - reader.TemporalityPreference = MetricReaderTemporalityPreference.Cumulative; + var reader = new BaseExportingMetricReader(exporter) + { + TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, + }; return builder.AddReader(reader); } diff --git a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs similarity index 97% rename from src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterMiddleware.cs rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs index 826ca135763..bebf084ce33 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterMiddleware.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs @@ -19,10 +19,11 @@ using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using OpenTelemetry.Exporter.Prometheus.Shared; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus +namespace OpenTelemetry.Exporter.Prometheus.AspNetCore { /// /// ASP.NET Core middleware for exposing a Prometheus metrics scraping endpoint. diff --git a/src/OpenTelemetry.Exporter.Prometheus/README.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md similarity index 58% rename from src/OpenTelemetry.Exporter.Prometheus/README.md rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md index ecac7ad4d41..855c20637a6 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md @@ -1,18 +1,24 @@ -# Prometheus Exporter for OpenTelemetry .NET +# Prometheus Exporter AspNetCore for OpenTelemetry .NET -[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Exporter.Prometheus.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus) -[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Exporter.Prometheus.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus) +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Exporter.Prometheus.AspNetCore.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus.AspNetCore) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Exporter.Prometheus.AspNetCore.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus.AspNetCore) + +An [OpenTelemetry Prometheus exporter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/prometheus.md) +for configuring an ASP.NET Core application with an endpoint for Prometheus +to scrape. ## Prerequisite * [Get Prometheus](https://prometheus.io/docs/introduction/first_steps/) -## Steps to enable OpenTelemetry.Exporter.Prometheus +## Steps to enable OpenTelemetry.Exporter.Prometheus.AspNetCore ### Step 1: Install Package +Install + ```shell -dotnet add package OpenTelemetry.Exporter.Prometheus +dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore ``` ### Step 2: Configure OpenTelemetry MeterProvider @@ -32,14 +38,15 @@ dotnet add package OpenTelemetry.Exporter.Prometheus register the Prometheus exporter. ```csharp - using var meterProvider = Sdk.CreateMeterProviderBuilder() + var meterProvider = Sdk.CreateMeterProviderBuilder() .AddPrometheusExporter() .Build(); + builder.Services.AddSingleton(meterProvider); ``` ### Step 3: Configure Prometheus Scraping Endpoint -* On .NET Core 3.1+ register Prometheus scraping middleware using the +* Register Prometheus scraping middleware using the `UseOpenTelemetryPrometheusScrapingEndpoint` extension: ```csharp @@ -72,46 +79,15 @@ dotnet add package OpenTelemetry.Exporter.Prometheus } ``` -* On .NET Framework an HTTP listener is automatically started which will respond - to scraping requests. See the [Configuration](#configuration) section for - details on the settings available. This may also be turned on in .NET Core (it - is OFF by default) when the ASP.NET Core pipeline is not available for - middleware registration. - ## Configuration The `PrometheusExporter` can be configured using the `PrometheusExporterOptions` -properties. Refer to -[`TestPrometheusExporter.cs`](../../examples/Console/TestPrometheusExporter.cs) -for example use. - -### StartHttpListener - -Set to `true` to start an HTTP listener which will respond to Prometheus scrape -requests using the [HttpListenerPrefixes](#httplistenerprefixes) and -[ScrapeEndpointPath](#scrapeendpointpath) options. - -Defaults: - -* On .NET Framework this is `true` by default. - -* On .NET Core 3.1+ this is `false` by default. Users running ASP.NET Core - should use the `UseOpenTelemetryPrometheusScrapingEndpoint` extension to - register the scraping middleware instead of using the listener. - -### HttpListenerPrefixes - -Defines the prefixes which will be used by the listener when `StartHttpListener` -is `true`. The default value is `["http://localhost:9464/"]`. You may specify -multiple endpoints. - -For details see: -[HttpListenerPrefixCollection.Add(String)](https://docs.microsoft.com/dotnet/api/system.net.httplistenerprefixcollection.add) +properties. ### ScrapeEndpointPath -Defines the path for the Prometheus scrape endpoint for -either the HTTP listener or the middleware registered by +Defines the path for the Prometheus scrape endpoint for the middleware +registered by `UseOpenTelemetryPrometheusScrapingEndpoint`. Default value: `"/metrics"`. ### ScrapeResponseCacheDurationMilliseconds diff --git a/src/OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Shipped.txt similarity index 100% rename from src/OpenTelemetry.Exporter.Prometheus/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Shipped.txt diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..a8f01b6d787 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt @@ -0,0 +1,12 @@ +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions +static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..a8f01b6d787 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -0,0 +1,12 @@ +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions +static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md new file mode 100644 index 00000000000..9f4ac19cfa2 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -0,0 +1,94 @@ +# Changelog + +## Unreleased + +* Split up Prometheus projects based on its hosting mechanism, HttpListener and AspNetCore, + into their own projects and assemblies. The shared code for both hosting mechanism + now lives in the `OpenTelemetry.Exporter.Prometheus.Shared` project and will not + be released. + ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430)) + +## 1.3.0-rc.2 + +Released 2022-June-1 + +## 1.3.0-beta.2 + +Released 2022-May-16 + +## 1.3.0-beta.1 + +Released 2022-Apr-15 + +* Added `IApplicationBuilder` extension methods to help with Prometheus + middleware configuration on ASP.NET Core + ([#3029](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3029)) + +* Changed Prometheus exporter to return 204 No Content and log a warning event + if there are no metrics to collect. + +* Removes .NET Framework 4.6.1. The minimum .NET Framework + version supported is .NET 4.6.2. ([#3190](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3190)) + +## 1.2.0-rc5 + +Released 2022-Apr-12 + +## 1.2.0-rc4 + +Released 2022-Mar-30 + +## 1.2.0-rc3 + +Released 2022-Mar-04 + +## 1.2.0-rc2 + +Released 2022-Feb-02 + +* Update default `httpListenerPrefixes` for PrometheusExporter to be `http://localhost:9464/`. +([#2783](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2783)) + +## 1.2.0-rc1 + +Released 2021-Nov-29 + +* Bug fix for handling Histogram with empty buckets. + ([#2651](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2651)) + +## 1.2.0-beta2 + +Released 2021-Nov-19 + +* Added scrape endpoint response caching feature & + `ScrapeResponseCacheDurationMilliseconds` option + ([#2610](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2610)) + +## 1.2.0-beta1 + +Released 2021-Oct-08 + +## 1.2.0-alpha4 + +Released 2021-Sep-23 + +## 1.2.0-alpha3 + +Released 2021-Sep-13 + +* Bug fixes + ([#2289](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2289)) + ([#2309](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2309)) + +## 1.2.0-alpha2 + +Released 2021-Aug-24 + +* Revamped to support the new Metrics API/SDK. + Supports Counter, Gauge and Histogram. + +## 1.0.0-rc1.1 + +Released 2020-Nov-17 + +* Initial release diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj new file mode 100644 index 00000000000..7769147c0f6 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj @@ -0,0 +1,36 @@ + + + + + netstandard2.0;net462 + Stand-alone HttpListener for hosting OpenTelemetry .NET exporter + $(PackageTags);prometheus;metrics + core- + + + + + false + + + + $(DefineConstants);PROMETHEUS_HTTPLISTENER + + + + + + + + + + + + + + + + + + diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs new file mode 100644 index 00000000000..9ab648b6be0 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs @@ -0,0 +1,104 @@ +// +// 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; +using OpenTelemetry.Exporter.Prometheus.HttpListener; +using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Metrics +{ + /// + /// Extension methods to simplify registering a PrometheusHttpListener. + /// + public static class PrometheusExporterHttpListenerMeterProviderBuilderExtensions + { + /// + /// Adds Prometheus exporter to MeterProviderBuilder. + /// + /// builder to use. + /// Exporter configuration options. + /// HttpListener options. + /// The instance of to chain calls. + public static MeterProviderBuilder AddPrometheusHttpListener( + this MeterProviderBuilder builder, + Action configureExporterOptions = null, + Action configureListenerOptions = null) + { + Guard.ThrowIfNull(builder); + + if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) + { + return deferredMeterProviderBuilder.Configure((sp, builder) => + { + AddPrometheusHttpListener( + builder, + sp.GetOptions(), + sp.GetOptions(), + configureExporterOptions, + configureListenerOptions); + }); + } + + return AddPrometheusHttpListener( + builder, + new PrometheusExporterOptions(), + new PrometheusHttpListenerOptions(), + configureExporterOptions, + configureListenerOptions); + } + + private static MeterProviderBuilder AddPrometheusHttpListener( + MeterProviderBuilder builder, + PrometheusExporterOptions exporterOptions, + PrometheusHttpListenerOptions listenerOptions, + Action configureExporterOptions = null, + Action configureListenerOptions = null) + { + configureExporterOptions?.Invoke(exporterOptions); + configureListenerOptions?.Invoke(listenerOptions); + + var exporter = new PrometheusExporter(exporterOptions); + + var reader = new BaseExportingMetricReader(exporter) + { + TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, + }; + + const string HttpListenerStartFailureExceptionMessage = "PrometheusExporter HttpListener could not be started."; + try + { + var listener = new PrometheusHttpListener(exporter, listenerOptions); + exporter.OnDispose = () => listener.Dispose(); + listener.Start(); + } + catch (Exception ex) + { + try + { + reader.Dispose(); + } + catch + { + } + + throw new InvalidOperationException(HttpListenerStartFailureExceptionMessage, ex); + } + + return builder.AddReader(reader); + } + } +} diff --git a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterHttpServer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs similarity index 82% rename from src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterHttpServer.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index 554f5cf3470..28700603b1b 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterHttpServer.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,37 +18,36 @@ using System.Net; using System.Threading; using System.Threading.Tasks; +using OpenTelemetry.Exporter.Prometheus.Shared; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus +namespace OpenTelemetry.Exporter.Prometheus.HttpListener { - /// - /// An HTTP listener used to expose Prometheus metrics. - /// - internal sealed class PrometheusExporterHttpServer : IDisposable + internal sealed class PrometheusHttpListener : IDisposable { private readonly PrometheusExporter exporter; - private readonly HttpListener httpListener = new(); + private readonly System.Net.HttpListener httpListener = new(); private readonly object syncObject = new(); private CancellationTokenSource tokenSource; private Task workerThread; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The instance. - public PrometheusExporterHttpServer(PrometheusExporter exporter) + /// The exporter instance. + /// The configured HttpListener options. + public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListenerOptions options) { Guard.ThrowIfNull(exporter); - this.exporter = exporter; - if ((exporter.Options.HttpListenerPrefixes?.Count ?? 0) <= 0) + if ((options.Prefixes?.Count ?? 0) <= 0) { - throw new ArgumentException("No HttpListenerPrefixes were specified on PrometheusExporterOptions."); + throw new ArgumentException("No Prefixes were specified on PrometheusHttpListenerOptions."); } - string path = exporter.Options.ScrapeEndpointPath ?? PrometheusExporterOptions.DefaultScrapeEndpointPath; + this.exporter = exporter; + string path = this.exporter.Options.ScrapeEndpointPath ?? PrometheusExporterOptions.DefaultScrapeEndpointPath; if (!path.StartsWith("/")) { path = $"/{path}"; @@ -59,16 +58,16 @@ public PrometheusExporterHttpServer(PrometheusExporter exporter) path = $"{path}/"; } - foreach (string prefix in exporter.Options.HttpListenerPrefixes) + foreach (string prefix in options.Prefixes) { this.httpListener.Prefixes.Add($"{prefix.TrimEnd('/')}{path}"); } } /// - /// Start Http Server. + /// Start the HttpListener. /// - /// An optional that can be used to stop the HTTP server. + /// An optional that can be used to stop the HTTP listener. public void Start(CancellationToken token = default) { lock (this.syncObject) @@ -88,7 +87,7 @@ public void Start(CancellationToken token = default) } /// - /// Stop exporter. + /// Gracefully stop the PrometheusHttpListener. /// public void Stop() { @@ -108,9 +107,10 @@ public void Stop() /// public void Dispose() { + this.Stop(); + if (this.httpListener != null && this.httpListener.IsListening) { - this.Stop(); this.httpListener.Close(); } } diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs new file mode 100644 index 00000000000..264a5f229fd --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs @@ -0,0 +1,56 @@ +// +// 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; +using System.Collections.Generic; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Exporter.Prometheus.HttpListener +{ + /// + /// options. + /// + public class PrometheusHttpListenerOptions + { + private IReadOnlyCollection prefixes = new string[] { "http://localhost:9464/" }; + + /// + /// Gets or sets the prefixes to use for the http listener. + /// Default value: http://localhost:9464/. + /// + public IReadOnlyCollection Prefixes + { + get => this.prefixes; + set + { + Guard.ThrowIfNull(value); + + foreach (string inputUri in value) + { + if (!(Uri.TryCreate(inputUri, UriKind.Absolute, out var uri) && + (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))) + { + throw new ArgumentException( + "Prometheus HttpListener prefix path should be a valid URI with http/https scheme.", + nameof(this.prefixes)); + } + } + + this.prefixes = value; + } + } + } +} diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md new file mode 100644 index 00000000000..8e772a4754e --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md @@ -0,0 +1,72 @@ +# Prometheus Exporter HttpListener for OpenTelemetry .NET + +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Exporter.Prometheus.HttpListener.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus.HttpListener) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Exporter.Prometheus.HttpListener.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus.HttpListener) + +An [OpenTelemetry Prometheus exporter](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/prometheus.md) +that configures an [HttpListener](https://docs.microsoft.com/dotnet/api/system.net.httplistener) +instance for Prometheus to scrape. + +## Prerequisite + +* [Get Prometheus](https://prometheus.io/docs/introduction/first_steps/) + +## Steps to enable OpenTelemetry.Exporter.Prometheus.HttpListener + +### Step 1: Install Package + +Install + +```shell +dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener +``` + +### Step 2: Add PrometheusHttpListener + +Add and configure `PrometheusHttpListener` with `PrometheusExporterOptions` as +the first argument and `PrometheusHttpListenerOptions` as the second argument. + +For example: + +```csharp +using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(MyMeter.Name) + .AddPrometheusHttpListener( + exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, + listenerOptions => listenerOptions.Prefixes = new string[] { "http://localhost:9464/" }) + .Build(); +``` + +### Prefixes + +Defines the prefixes which will be used by the listener. The default value is `["http://localhost:9464/"]`. +You may specify multiple endpoints. + +For details see: +[HttpListenerPrefixCollection.Add(String)](https://docs.microsoft.com/dotnet/api/system.net.httplistenerprefixcollection.add) + +### ScrapeEndpointPath + +Defines the path for the Prometheus scrape endpoint for by +`UseOpenTelemetryPrometheusScrapingEndpoint`. Default value: `"/metrics"`. + +### ScrapeResponseCacheDurationMilliseconds + +Configures scrape endpoint response caching. Multiple scrape requests within the +cache duration time period will receive the same previously generated response. +The default value is `10000` (10 seconds). Set to `0` to disable response +caching. + +## Troubleshooting + +This component uses an +[EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource) +with the name "OpenTelemetry-Exporter-Prometheus" for its internal logging. +Please refer to [SDK +troubleshooting](../OpenTelemetry/README.md#troubleshooting) for instructions on +seeing these internal logs. + +## References + +* [OpenTelemetry Project](https://opentelemetry.io/) +* [Prometheus](https://prometheus.io) diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..d61e4fb9ed9 --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt @@ -0,0 +1,6 @@ +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt new file mode 100644 index 00000000000..539467ab62d --- /dev/null +++ b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt @@ -0,0 +1,6 @@ +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus/AssemblyInfo.cs b/src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs similarity index 78% rename from src/OpenTelemetry.Exporter.Prometheus/AssemblyInfo.cs rename to src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs index 619668af3b4..d4361cf0913 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/AssemblyInfo.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs @@ -18,8 +18,8 @@ #if SIGNED [assembly: InternalsVisibleTo("Benchmarks, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] -[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Shared.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] #else [assembly: InternalsVisibleTo("Benchmarks")] -[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Tests")] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Shared.Tests")] #endif diff --git a/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj b/src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj similarity index 84% rename from src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj rename to src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj index c53448ea4d7..169e97169c4 100644 --- a/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj @@ -3,13 +3,8 @@ netcoreapp3.1;net462 - Prometheus exporter for OpenTelemetry .NET + Prometheus exporter shared code for both Prometheus exporter HttpListener and Prometheus exporter AspNetCore $(PackageTags);prometheus;metrics - core- - - - - $(NoWarn),1591 - net6.0;netcoreapp3.1 - $(TargetFrameworks);net462 + netcoreapp3.1 + + false @@ -19,12 +20,8 @@ - - - - - + diff --git a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusCollectionManagerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs similarity index 98% rename from test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusCollectionManagerTests.cs rename to test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs index 60945c6f997..adeb3ac29c0 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusCollectionManagerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs @@ -21,11 +21,12 @@ #endif using System.Threading; using System.Threading.Tasks; +using OpenTelemetry.Exporter.Prometheus.Shared; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.Tests +namespace OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests { public sealed class PrometheusCollectionManagerTests { diff --git a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterMiddlewareTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs similarity index 97% rename from test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterMiddlewareTests.cs rename to test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs index a11ea430423..ff8b0bdc484 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterMiddlewareTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs @@ -31,7 +31,7 @@ using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.Tests +namespace OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests { public sealed class PrometheusExporterMiddlewareTests { @@ -224,10 +224,6 @@ private static async Task RunPrometheusExporterMiddlewareIntegrationTest( .AddPrometheusExporter(o => { configureOptions?.Invoke(o); - if (o.StartHttpListener) - { - throw new InvalidOperationException("StartHttpListener should be false on .NET Core 3.1+."); - } })); } diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj new file mode 100644 index 00000000000..22b68c4e9ea --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj @@ -0,0 +1,29 @@ + + + Unit test project for Prometheus Exporter HttpListener for OpenTelemetry + + net462 + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + diff --git a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterHttpServerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs similarity index 63% rename from test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterHttpServerTests.cs rename to test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs index 6ba169505d8..d197ffea85a 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusExporterHttpServerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,24 +24,12 @@ using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.Tests +namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Tests { - public class PrometheusExporterHttpServerTests + public class PrometheusExporterHttpListenerTests { private readonly string meterName = Utils.GetCurrentMethodName(); - [Fact] - public async Task PrometheusExporterHttpServerIntegration() - { - await this.RunPrometheusExporterHttpServerIntegrationTest(); - } - - [Fact] - public async Task PrometheusExporterHttpServerIntegration_NoMetrics() - { - await this.RunPrometheusExporterHttpServerIntegrationTest(skipMetrics: true); - } - [Theory] [InlineData("http://example.com")] [InlineData("https://example.com")] @@ -50,10 +38,7 @@ public async Task PrometheusExporterHttpServerIntegration_NoMetrics() public void ServerEndpointSanityCheckPositiveTest(params string[] uris) { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusExporter(opt => - { - opt.HttpListenerPrefixes = uris; - }) + .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = uris) .Build(); } @@ -67,10 +52,7 @@ public void ServerEndpointSanityCheckNegativeTest(params string[] uris) try { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusExporter(opt => - { - opt.HttpListenerPrefixes = uris; - }) + .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = uris) .Build(); } catch (Exception ex) @@ -79,66 +61,45 @@ public void ServerEndpointSanityCheckNegativeTest(params string[] uris) { Assert.Equal("System.ArgumentException", ex.GetType().ToString()); #if NETFRAMEWORK - Assert.Equal("Prometheus server path should be a valid URI with http/https scheme.\r\nParameter name: httpListenerPrefixes", ex.Message); + Assert.Equal("Prometheus HttpListener prefix path should be a valid URI with http/https scheme.\r\nParameter name: prefixes", ex.Message); #else - Assert.Equal("Prometheus server path should be a valid URI with http/https scheme. (Parameter 'httpListenerPrefixes')", ex.Message); + Assert.Equal("Prometheus HttpListener prefix path should be a valid URI with http/https scheme. (Parameter 'prefixes')", ex.Message); #endif } } } + [Fact] + public async Task PrometheusExporterHttpServerIntegration() + { + await this.RunPrometheusExporterHttpServerIntegrationTest(); + } + + [Fact] + public async Task PrometheusExporterHttpServerIntegration_NoMetrics() + { + await this.RunPrometheusExporterHttpServerIntegrationTest(skipMetrics: true); + } + private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetrics = false) { Random random = new Random(); + int retryAttempts = 5; int port = 0; - int retryCount = 5; - MeterProvider provider; string address = null; + MeterProvider provider; using var meter = new Meter(this.meterName); - while (true) + while (retryAttempts-- != 0) { - try - { - port = random.Next(2000, 5000); - provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddPrometheusExporter(o => - { -#if NETFRAMEWORK - bool expectedDefaultState = true; -#else - bool expectedDefaultState = false; -#endif - if (o.StartHttpListener != expectedDefaultState) - { - throw new InvalidOperationException("StartHttpListener value is unexpected."); - } - - if (!o.StartHttpListener) - { - o.StartHttpListener = true; - } + port = random.Next(2000, 5000); + address = $"http://localhost:{port}/"; - address = $"http://localhost:{port}/"; - o.HttpListenerPrefixes = new string[] { address }; - }) - .Build(); - break; - } - catch (Exception ex) - { - if (ex.Message != PrometheusExporter.HttpListenerStartFailureExceptionMessage) - { - throw; - } - - if (retryCount-- <= 0) - { - throw new InvalidOperationException("HttpListener could not be started."); - } - } + provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = new string[] { address }) + .Build(); } var tags = new KeyValuePair[] @@ -155,7 +116,6 @@ private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetri } using HttpClient client = new HttpClient(); - using var response = await client.GetAsync($"{address}metrics").ConfigureAwait(false); if (!skipMetrics) diff --git a/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj new file mode 100644 index 00000000000..640b3541f2e --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj @@ -0,0 +1,32 @@ + + + Unit test project of Prometheus exporter shared code for both Prometheus exporter HttpListener and Prometheus Exporter AspNetCore + + netcoreapp3.1 + $(TargetFrameworks);net462 + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + + diff --git a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs similarity index 99% rename from test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusSerializerTests.cs rename to test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs index cb2ea1d5641..1def2012b8e 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.Tests/PrometheusSerializerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs @@ -21,7 +21,7 @@ using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.Tests +namespace OpenTelemetry.Exporter.Prometheus.Shared.Tests { public sealed class PrometheusSerializerTests { diff --git a/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj b/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj index 8093f8d6d6f..ff88e203fb4 100644 --- a/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj +++ b/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/OpenTelemetry.Tests.Stress.Metrics.csproj b/test/OpenTelemetry.Tests.Stress.Metrics/OpenTelemetry.Tests.Stress.Metrics.csproj index 46fcfb47bd2..49134943927 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/OpenTelemetry.Tests.Stress.Metrics.csproj +++ b/test/OpenTelemetry.Tests.Stress.Metrics/OpenTelemetry.Tests.Stress.Metrics.csproj @@ -14,7 +14,7 @@ - + diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index 8838a1854c9..6a56c5a4bcb 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -46,12 +46,9 @@ public static void Main() using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) - .AddPrometheusExporter(options => - { - options.StartHttpListener = true; - options.HttpListenerPrefixes = new string[] { $"http://localhost:9185/" }; - options.ScrapeResponseCacheDurationMilliseconds = 0; - }) + .AddPrometheusHttpListener( + exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, + listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:9185/" }) .Build(); Stress(prometheusPort: 9184); diff --git a/test/OpenTelemetry.Tests.Stress/OpenTelemetry.Tests.Stress.csproj b/test/OpenTelemetry.Tests.Stress/OpenTelemetry.Tests.Stress.csproj index 32481d41662..73b65c17227 100644 --- a/test/OpenTelemetry.Tests.Stress/OpenTelemetry.Tests.Stress.csproj +++ b/test/OpenTelemetry.Tests.Stress/OpenTelemetry.Tests.Stress.csproj @@ -10,6 +10,6 @@ - + diff --git a/test/OpenTelemetry.Tests.Stress/README.md b/test/OpenTelemetry.Tests.Stress/README.md index a22d7b6788f..0013c573ad6 100644 --- a/test/OpenTelemetry.Tests.Stress/README.md +++ b/test/OpenTelemetry.Tests.Stress/README.md @@ -41,7 +41,7 @@ Running (concurrency = 1), press to stop... ``` The stress test metrics are exposed via -[PrometheusExporter](../../src/OpenTelemetry.Exporter.Prometheus/README.md), +[Prometheus HttpListener](../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md), which can be accessed via [http://localhost:9184/metrics/](http://localhost:9184/metrics/). diff --git a/test/OpenTelemetry.Tests.Stress/Skeleton.cs b/test/OpenTelemetry.Tests.Stress/Skeleton.cs index 2ff889d21a3..e372b108710 100644 --- a/test/OpenTelemetry.Tests.Stress/Skeleton.cs +++ b/test/OpenTelemetry.Tests.Stress/Skeleton.cs @@ -75,12 +75,9 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) using var meterProvider = prometheusPort != 0 ? Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddRuntimeInstrumentation() - .AddPrometheusExporter(options => - { - options.StartHttpListener = true; - options.HttpListenerPrefixes = new string[] { $"http://localhost:{prometheusPort}/" }; - options.ScrapeResponseCacheDurationMilliseconds = 0; - }) + .AddPrometheusHttpListener( + exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, + listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:{prometheusPort}/" }) .Build() : null; var statistics = new long[concurrency]; From 8a4d395452717dba4c3f3636c841c192707f7cbf Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Thu, 28 Jul 2022 18:08:47 -0700 Subject: [PATCH 068/111] Fix nits (#3502) --- .../CHANGELOG.md | 8 +-- src/OpenTelemetry/CHANGELOG.md | 71 ++----------------- 2 files changed, 9 insertions(+), 70 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md index 3766ca848aa..241df1ee7f8 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md @@ -4,18 +4,18 @@ * Metrics instrumentation to correctly populate `http.flavor` tag. (1.1 instead of HTTP/1.1 etc.) - ([3379](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3379)) + ([#3379](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3379)) * Tracing instrumentation to populate `http.flavor` tag. - ([3372](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3372)) + ([#3372](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3372)) * Tracing instrumentation to populate `http.scheme` tag. -([3392](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3392)) + ([#3392](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3392)) ## 1.0.0-rc9.4 Released 2022-Jun-03 * Added additional metric dimensions. - ([3247](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3247)) + ([#3247](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3247)) * Removes net5.0 target as .NET 5.0 is going out of support. The package keeps netstandard2.1 target, so it can still be used with .NET5.0 apps. diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index c50635a1d78..99114364c52 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -9,31 +9,23 @@ activity will be created irrespective of SamplingResult, to maintain context propagation. ([#3329](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3329)) - * Fix issue where a measurement would be dropped when recording it with a null-valued tag. ([#3325](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3325)) - * `CompositeProcessor` will now ensure `ParentProvider` is set on its children ([#3368](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3368)) - * Added `ForceFlush` and helper ctors on `OpenTelemetryLoggerProvider` ([#3364](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3364)) - * `Timestamp`, `TraceId`, `SpanId`, `TraceFlags`, `TraceState`, `CategoryName`, `LogLevel`, `EventId`, & `Exception` properties on `LogRecord` now expose `set` methods ([#3378](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3378)) - * Handle possible exception when initializing the default service name. ([#3405](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3405)) - * `LogRecord` instances are now reused to reduce memory pressure ([#3385](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3385)) - * Fix exact match of activity source name when `wildcard` is used. ([#3446](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3446)) - * Added AddOpenTelemetry `ILoggingBuilder` extensions which accept `OpenTelemetryLoggerProvider` directly ([#3489](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3489)) @@ -70,7 +62,6 @@ Released 2022-Apr-15 * Removes .NET Framework 4.6.1. The minimum .NET Framework version supported is .NET 4.6.2. ([#3190](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3190)) - * Bumped minimum required version of `Microsoft.Extensions.Logging` and `Microsoft.Extensions.Logging.Configuration` to 3.1.0 ([#2582](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3196)) @@ -99,13 +90,11 @@ Released 2022-Apr-12 [DiagnosticSource version 7.0 onwards](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/7.0.0-preview.2.22152.2), they will be aggregated using `AggregationTemporality.Cumulative`. ([#3153](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3153)) - * Fix issue where `ExplicitBucketHistogramConfiguration` could be used to configure metric streams for instruments that are not histograms. Currently, it is not possible to change the aggregation of an instrument with views. This may be possible in the future. ([#3126](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3126)) - * Conformed to the specification to ensure that each view that an instrument matches results in a new metric stream. With this change it is possible for views to introduce conflicting metric streams. Any conflicts encountered will @@ -120,15 +109,12 @@ Released 2022-Mar-30 `ExportIntervalMilliseconds` of `-1` indicating an infinite export interval period. ([#2982](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2982)) - * Fix bug where multiple views selecting a single instrument can result in duplicate updates to a single metric point. ([#3006](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3006)) - * Added the `PeriodicExportingMetricReaderOptions.ExportTimeoutMilliseconds` option. ([#3038](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3038)) - * Removed `MetricReaderType`. This enumeration was previously used when configuring a metric reader with an exporter to configure whether the export cycle would be periodic or manual (i.e., requiring a explicit call to flush @@ -137,11 +123,9 @@ Released 2022-Mar-30 by setting `PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds` to `-1`. ([#3038](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3038)) - * Marked members of the `MetricPoint` `struct` which do not mutate state as `readonly` ([#3065](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3065)) - * [Bug fix] OpenTelemetryLoggerProvider is now unaffected by changes to OpenTelemetryLoggerOptions after the LoggerFactory is built. ([#3055](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3055)) @@ -151,24 +135,18 @@ Released 2022-Mar-30 Released 2022-Mar-04 * Instantiating multiple metric instruments with the same name and also - identical in all other respects - same type, description, and unit - result - in a single metric stream aggregating measurements from all the identical - instruments. - - Instantiating multiple metric instruments with the same name but differ in - some respect - different type, description, or unit - will result in a - separate metric stream for each distinct instrument. - + identical in all other respects - same type, description, and unit - result in + a single metric stream aggregating measurements from all the identical + instruments. Instantiating multiple metric instruments with the same name but + differ in some respect - different type, description, or unit - will result in + a separate metric stream for each distinct instrument. ([#2916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2916)) - * The `Meter` property on `OpenTelemetry.Metrics.Metric` has been removed. It now has `MeterName` and `MeterVersion` properties. ([#2916](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2916)) - * Added support for implementing custom `ResourceDetector`. ([#2949](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2949/) [#2897](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2897)) - * Perf improvement for Histogram and HistogramSumCount by implementing lock-free updates. ([#2951](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2951) @@ -180,14 +158,11 @@ Released 2022-Feb-02 * Make `MetricPoint` of `MetricPointAccessor` readonly. ([#2736](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2736)) - * Fail-fast when using AddView with guaranteed conflict. ([#2751](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2751)) - * Swallow `ObjectDisposedException` from the `BatchExportProcessor` worker thread. ([#2844](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2844)) - * Performance improvement: when emitting metrics, users are strongly advised to provide tags with same Key order, to achieve maximum performance. ([#2805](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2805)) @@ -199,34 +174,27 @@ Released 2021-Nov-29 * Prevent accessing activity Id before sampler runs in case of legacy activities. ([#2659](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2659)) - * Added `ReadOnlyTagCollection` and expose `Tags` on `MetricPoint` instead of `Keys`+`Values` ([#2642](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2642)) - * Refactored `MetricPoint` and added public methods: `GetBucketCounts`, `GetExplicitBounds`, `GetHistogramCount`, and `GetHistogramSum` ([#2657](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2657)) - * Remove MetricStreamConfiguration.Aggregation, as the feature to customize aggregation is not implemented yet. ([#2660](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2660)) - * Removed the public property `HistogramMeasurements` and added a public method `GetHistogramBuckets` instead. Renamed the class `HistogramMeasurements` to `HistogramBuckets` and added an enumerator of type `HistogramBucket` for enumerating `BucketCounts` and `ExplicitBounds`. Removed `GetBucketCounts` and `GetExplicitBounds` methods from `MetricPoint`. ([#2664](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2664)) - * Refactored temporality setting to align with the latest spec. ([#2666](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2666)) - * Removed the public properties `LongValue`, `DoubleValue`, in favor of their counterpart public methods `GetSumLong`, `GetSumDouble`, `GetGaugeLastValueLong`, `GetGaugeLastValueDouble`. ([#2667](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2667)) - * MetricType modified to reserve bits for future types. ([#2693](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2693)) @@ -237,32 +205,23 @@ Released 2021-Nov-19 * Renamed `HistogramConfiguration` to `ExplicitBucketHistogramConfiguration` and changed its member `BucketBounds` to `Boundaries`. ([#2638](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2638)) - * Metrics with the same name but from different meters are allowed. ([#2634](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2634)) - * Metrics SDK will not provide inactive Metrics to delta exporter. ([#2629](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2629)) - * Histogram bounds are validated when added to a View. ([#2573](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2573)) - * Changed `BatchExportActivityProcessorOptions` constructor to throw `FormatException` if it fails to parse any of the supported environment variables. - * Added `BaseExporter.ForceFlush`. ([#2525](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2525)) - * Exposed public `Batch(T[] items, int count)` constructor on `Batch` struct ([#2542](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2542)) - * Added wildcard support for AddMeter. ([#2459](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2459)) - * Add support for multiple Metric readers ([#2596](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2596)) - * Add ability to configure MaxMetricStreams, MaxMetricPointsPerMetricStream ([#2635](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2635)) @@ -272,12 +231,9 @@ Released 2021-Oct-08 * Exception from Observable instrument callbacks does not result in entire metrics being lost. - * SDK is allocation-free on recording of measurements with up to 8 tags. - * TracerProviderBuilder.AddLegacySource now supports wildcard activity names. ([#2183](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2183)) - * Instrument and View names are validated [according with the spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument). ([#2470](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2470)) @@ -301,7 +257,6 @@ Released 2021-Sep-13 * Metrics perf improvements, bug fixes. Replace MetricProcessor with MetricReader. ([#2306](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2306)) - * Add `BatchExportActivityProcessorOptions` which supports field value overriding using `OTEL_BSP_SCHEDULE_DELAY`, `OTEL_BSP_EXPORT_TIMEOUT`, `OTEL_BSP_MAX_QUEUE_SIZE`, `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` environmental @@ -315,19 +270,15 @@ Released 2021-Aug-24 * More Metrics features. All instrument types, push/pull exporters, Delta/Cumulative temporality supported. - * `ResourceBuilder.CreateDefault` has detectors for `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` environment variables so that explicit `AddEnvironmentVariableDetector` call is not needed. ([#2247](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2247)) - * `ResourceBuilder.AddEnvironmentVariableDetector` handles `OTEL_SERVICE_NAME` environmental variable. ([#2209](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2209)) - * Removes upper constraint for Microsoft.Extensions.Logging dependencies. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) - * OpenTelemetryLogger modified to not throw, when the formatter supplied in ILogger.Log call is null. ([#2200](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2200)) @@ -339,7 +290,6 @@ Released 2021-Jul-23 * Add basic Metrics support with a single pipeline, and supporting Counter (sync) instrument. Push and Pull exporters are supported. ([#2174](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2174)) - * Removes .NET Framework 4.5.2, .NET 4.6 support. The minimum .NET Framework version supported is .NET 4.6.1. ([#2138](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2138)) @@ -366,7 +316,6 @@ Released 2021-May-11 * `AddLegacySource()` moved out of `TracerProviderBuilderExtensions` and into public API ([#2019](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2019)) - * Fixed an issue causing inconsistent log scopes when using `BatchLogRecordExportProcessor`. To make parsing scopes easier the `LogRecord.ForEachScope` signature has been changed to receive instances of @@ -389,47 +338,37 @@ Released 2021-Mar-19 * Removed SuppressScope Increment/Decrement from DiagnosticSourceListeners. ([1893](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1893)) - * Added `TracerProviderBuilder.SetErrorStatusOnException` which automatically sets the activity status to `Error` when exception happened. ([#1858](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1858) [#1875](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1875)) - * Added `ForceFlush` to `TracerProvider`. ([#1837](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1837)) - * Added a TracerProviderBuilder extension method called `AddLegacySource` which is used by instrumentation libraries that use DiagnosticSource to get activities processed without ActivitySourceAdapter. [#1836](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1836) [#1860](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1860) - * Added new constructor with optional parameters to allow customization of `ParentBasedSampler` behavior. ([#1727](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1727)) - * The application base directory is now tested after the current directory when searching for the [self diagnostic configuration file](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/README.md#troubleshooting). ([#1865](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1865)) - * Resource Attributes now accept primitive arrays as values. ([#1852](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1852)) - * Fixed [#1846](https://github.com/open-telemetry/opentelemetry-dotnet/issues/1846): `ParentBasedSampler` will no longer explicitly consider Activity links. ([#1851](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1851)) - * Added `IncludeScopes`, `IncludeFormattedMessage`, & `ParseStateValues` on `OpenTelemetryLoggerOptions`. Added `FormattedMessage`, `StateValues`, & `ForEachScope` on `LogRecord`. ([#1869](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1869) & [#1883](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1883)) - * Added `SetResourceBuilder` support to `OpenTelemetryLoggerOptions`. ([#1913](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1913)) - * Added `IDeferredTracerProviderBuilder` and `TracerProviderBuilderBase` to support dependency injection through OpenTelemetry.Extensions.Hosting. ([#1889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1889)) From c475666aeb91ca55aba462aa9172b45d9253bd9b Mon Sep 17 00:00:00 2001 From: liangli Date: Fri, 29 Jul 2022 10:12:28 +0800 Subject: [PATCH 069/111] fix: replace all newtonsoft.json usages (#3478) --- build/Common.nonprod.props | 2 +- .../BasicTests.cs | 10 ++-- .../HttpClientTests.netcore31.cs | 49 ++++++++++--------- .../HttpTestData.cs | 8 ++- .../HttpWebRequestTests.netfx.cs | 43 ++++++++-------- ...elemetry.Instrumentation.Http.Tests.csproj | 2 +- .../http-out-test-cases.json | 16 +++--- .../Controllers/ForwardController.cs | 9 ++-- .../Controllers/ForwardController.cs | 9 ++-- 9 files changed, 75 insertions(+), 73 deletions(-) diff --git a/build/Common.nonprod.props b/build/Common.nonprod.props index 704d4f890fb..4810547d72e 100644 --- a/build/Common.nonprod.props +++ b/build/Common.nonprod.props @@ -41,11 +41,11 @@ [6.0.0,) [6.0.0,) [16.10.0] - [13.0.1,14.0) [4.14.5,5.0) [6.1.0,7.0) [1.0.0-rc.2,2.0) [6.2.3] + 6.0.5 [2.4.3,3.0) [2.4.1,3.0) diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs index 208b12da777..f7eaf9bd213 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/BasicTests.cs @@ -19,6 +19,7 @@ using System.Diagnostics; using System.Linq; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -26,7 +27,6 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Newtonsoft.Json; using OpenTelemetry.Context.Propagation; using OpenTelemetry.Instrumentation.AspNetCore.Implementation; using OpenTelemetry.Tests; @@ -364,7 +364,7 @@ public async Task ExtractContextIrrespectiveOfSamplingDecision(SamplingDecision // Test TraceContext Propagation var request = new HttpRequestMessage(HttpMethod.Get, "/api/GetChildActivityTraceContext"); var response = await client.SendAsync(request); - var childActivityTraceContext = JsonConvert.DeserializeObject>(response.Content.ReadAsStringAsync().Result); + var childActivityTraceContext = JsonSerializer.Deserialize>(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); @@ -376,7 +376,7 @@ public async Task ExtractContextIrrespectiveOfSamplingDecision(SamplingDecision request = new HttpRequestMessage(HttpMethod.Get, "/api/GetChildActivityBaggageContext"); response = await client.SendAsync(request); - var childActivityBaggageContext = JsonConvert.DeserializeObject>(response.Content.ReadAsStringAsync().Result); + var childActivityBaggageContext = JsonSerializer.Deserialize>(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); @@ -431,7 +431,7 @@ public async Task ExtractContextIrrespectiveOfTheFilterApplied() // Ensure that filter was called Assert.True(isFilterCalled); - var childActivityTraceContext = JsonConvert.DeserializeObject>(response.Content.ReadAsStringAsync().Result); + var childActivityTraceContext = JsonSerializer.Deserialize>(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); @@ -443,7 +443,7 @@ public async Task ExtractContextIrrespectiveOfTheFilterApplied() request = new HttpRequestMessage(HttpMethod.Get, "/api/GetChildActivityBaggageContext"); response = await client.SendAsync(request); - var childActivityBaggageContext = JsonConvert.DeserializeObject>(response.Content.ReadAsStringAsync().Result); + var childActivityBaggageContext = JsonSerializer.Deserialize>(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index 27db9e89fba..05c39935426 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -22,9 +22,9 @@ using System.Linq; using System.Net.Http; using System.Reflection; +using System.Text.Json; using System.Threading.Tasks; using Moq; -using Newtonsoft.Json; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; using OpenTelemetry.Trace; @@ -185,29 +185,30 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut [Fact] public async Task DebugIndividualTestAsync() { - var serializer = new JsonSerializer(); - var input = serializer.Deserialize(new JsonTextReader(new StringReader(@" -[ - { - ""name"": ""Response code: 399"", - ""method"": ""GET"", - ""url"": ""http://{host}:{port}/"", - ""responseCode"": 399, - ""responseExpected"": true, - ""spanName"": ""HTTP GET"", - ""spanStatus"": ""UNSET"", - ""spanKind"": ""Client"", - ""spanAttributes"": { - ""http.scheme"": ""http"", - ""http.method"": ""GET"", - ""http.host"": ""{host}:{port}"", - ""http.status_code"": ""399"", - ""http.flavor"": ""2.0"", - ""http.url"": ""http://{host}:{port}/"" - } - } -] -"))); + var input = JsonSerializer.Deserialize( + @" + [ + { + ""name"": ""Response code: 399"", + ""method"": ""GET"", + ""url"": ""http://{host}:{port}/"", + ""responseCode"": 399, + ""responseExpected"": true, + ""spanName"": ""HTTP GET"", + ""spanStatus"": ""UNSET"", + ""spanKind"": ""Client"", + ""spanAttributes"": { + ""http.scheme"": ""http"", + ""http.method"": ""GET"", + ""http.host"": ""{host}:{port}"", + ""http.status_code"": ""399"", + ""http.flavor"": ""2.0"", + ""http.url"": ""http://{host}:{port}/"" + } + } + ] + ", + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); var t = (Task)this.GetType().InvokeMember(nameof(this.HttpOutCallsAreCollectedSuccessfullyAsync), BindingFlags.InvokeMethod, null, this, HttpTestData.GetArgumentsFromTestCaseObject(input).First()); await t; diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpTestData.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpTestData.cs index 38e1dd83391..aa8efe91fbe 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpTestData.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpTestData.cs @@ -14,9 +14,8 @@ // limitations under the License. // using System.Collections.Generic; -using System.IO; using System.Reflection; -using Newtonsoft.Json; +using System.Text.Json; namespace OpenTelemetry.Instrumentation.Http.Tests { @@ -25,9 +24,8 @@ public static class HttpTestData public static IEnumerable ReadTestCases() { var assembly = Assembly.GetExecutingAssembly(); - var serializer = new JsonSerializer(); - var input = serializer.Deserialize(new JsonTextReader(new StreamReader(assembly.GetManifestResourceStream("OpenTelemetry.Instrumentation.Http.Tests.http-out-test-cases.json")))); - + var input = JsonSerializer.Deserialize( + assembly.GetManifestResourceStream("OpenTelemetry.Instrumentation.Http.Tests.http-out-test-cases.json"), new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); return GetArgumentsFromTestCaseObject(input); } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs index 3d3e10a0400..a31ddbaaf43 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs @@ -20,8 +20,8 @@ using System.IO; using System.Linq; using System.Net; +using System.Text.Json; using Moq; -using Newtonsoft.Json; using OpenTelemetry.Tests; using OpenTelemetry.Trace; using Xunit; @@ -137,26 +137,27 @@ public void HttpOutCallsAreCollectedSuccessfully(HttpTestData.HttpOutTestCase tc [Fact] public void DebugIndividualTest() { - var serializer = new JsonSerializer(); - var input = serializer.Deserialize(new JsonTextReader(new StringReader(@" - { - ""name"": ""Http version attribute populated"", - ""method"": ""GET"", - ""url"": ""http://{host}:{port}/"", - ""responseCode"": 200, - ""spanName"": ""HTTP GET"", - ""spanStatus"": ""UNSET"", - ""spanKind"": ""Client"", - ""setHttpFlavor"": true, - ""spanAttributes"": { - ""http.method"": ""GET"", - ""http.host"": ""{host}:{port}"", - ""http.flavor"": ""2.0"", - ""http.status_code"": 200, - ""http.url"": ""http://{host}:{port}/"" - } - } -"))); + var input = JsonSerializer.Deserialize( + @" + { + ""name"": ""Http version attribute populated"", + ""method"": ""GET"", + ""url"": ""http://{host}:{port}/"", + ""responseCode"": 200, + ""spanName"": ""HTTP GET"", + ""spanStatus"": ""UNSET"", + ""spanKind"": ""Client"", + ""setHttpFlavor"": true, + ""spanAttributes"": { + ""http.method"": ""GET"", + ""http.host"": ""{host}:{port}"", + ""http.flavor"": ""2.0"", + ""http.status_code"": ""200"", + ""http.url"": ""http://{host}:{port}/"" + } + } + ", + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); this.HttpOutCallsAreCollectedSuccessfully(input); } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj index a38f1a99cba..35f23f1ba4b 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj @@ -15,9 +15,9 @@ - + all diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json index aeae7bf8ade..3441e152d92 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json @@ -11,7 +11,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/" } }, @@ -27,7 +27,7 @@ "http.method": "POST", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/" } }, @@ -44,7 +44,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource/" } }, @@ -61,7 +61,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource#fragment" } }, @@ -78,7 +78,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/path/to/resource#fragment" } }, @@ -129,7 +129,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/" } }, @@ -146,7 +146,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/" } }, @@ -333,7 +333,7 @@ "http.method": "GET", "http.host": "{host}:{port}", "http.flavor": "2.0", - "http.status_code": 200, + "http.status_code": "200", "http.url": "http://{host}:{port}/" } } diff --git a/test/TestApp.AspNetCore.3.1/Controllers/ForwardController.cs b/test/TestApp.AspNetCore.3.1/Controllers/ForwardController.cs index 31b98f6955c..5b532d3af0e 100644 --- a/test/TestApp.AspNetCore.3.1/Controllers/ForwardController.cs +++ b/test/TestApp.AspNetCore.3.1/Controllers/ForwardController.cs @@ -15,9 +15,10 @@ // using System.Net.Http; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; namespace TestApp.AspNetCore._3._1.Controllers { @@ -44,7 +45,7 @@ public async Task Post([FromBody] Data[] data) var request = new HttpRequestMessage(HttpMethod.Post, argument.Url) { Content = new StringContent( - JsonConvert.SerializeObject(argument.Arguments), + JsonSerializer.Serialize(argument.Arguments), Encoding.UTF8, "application/json"), }; @@ -61,10 +62,10 @@ public async Task Post([FromBody] Data[] data) public class Data { - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } - [JsonProperty("arguments")] + [JsonPropertyName("arguments")] public Data[] Arguments { get; set; } } } diff --git a/test/TestApp.AspNetCore.6.0/Controllers/ForwardController.cs b/test/TestApp.AspNetCore.6.0/Controllers/ForwardController.cs index 36290e144c9..3f1a867186e 100644 --- a/test/TestApp.AspNetCore.6.0/Controllers/ForwardController.cs +++ b/test/TestApp.AspNetCore.6.0/Controllers/ForwardController.cs @@ -16,9 +16,10 @@ using System.Net.Http; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; namespace TestApp.AspNetCore._6._0.Controllers { @@ -45,7 +46,7 @@ public async Task Post([FromBody] Data[] data) var request = new HttpRequestMessage(HttpMethod.Post, argument.Url) { Content = new StringContent( - JsonConvert.SerializeObject(argument.Arguments), + JsonSerializer.Serialize(argument.Arguments), Encoding.UTF8, "application/json"), }; @@ -62,10 +63,10 @@ public async Task Post([FromBody] Data[] data) public class Data { - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } - [JsonProperty("arguments")] + [JsonPropertyName("arguments")] public Data[] Arguments { get; set; } } } From eb49e4d194c66ff6b5bddc1311bcaae2a1fd7ac8 Mon Sep 17 00:00:00 2001 From: nayang7 <107023695+nayang7@users.noreply.github.com> Date: Fri, 29 Jul 2022 13:36:19 +0800 Subject: [PATCH 070/111] Fix Remote IP Address - NULL reference exception (#3481) --- src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md | 2 ++ .../Implementation/HttpInListener.cs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md index 241df1ee7f8..d456038b9b8 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Fix Remote IP Address - NULL reference exception. + ([#3481](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3481)) * Metrics instrumentation to correctly populate `http.flavor` tag. (1.1 instead of HTTP/1.1 etc.) ([#3379](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3379)) diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs index 1ff80acc8b2..a37863ad8b9 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs @@ -360,7 +360,11 @@ private static void AddGrpcAttributes(Activity activity, string grpcMethod, Http activity.DisplayName = grpcMethod.TrimStart('/'); activity.SetTag(SemanticConventions.AttributeRpcSystem, GrpcTagHelper.RpcSystemGrpc); - activity.SetTag(SemanticConventions.AttributeNetPeerIp, context.Connection.RemoteIpAddress.ToString()); + if (context.Connection.RemoteIpAddress != null) + { + activity.SetTag(SemanticConventions.AttributeNetPeerIp, context.Connection.RemoteIpAddress.ToString()); + } + activity.SetTag(SemanticConventions.AttributeNetPeerPort, context.Connection.RemotePort); bool validConversion = GrpcTagHelper.TryGetGrpcStatusCodeFromActivity(activity, out int status); From a3397aadcd280122804955b206a836f7190062f1 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Date: Fri, 29 Jul 2022 14:10:12 -0700 Subject: [PATCH 071/111] improve test coverage: OpenTelemetry.Api `CallerArgumentExpressionAttribute` (#3362) --- src/OpenTelemetry.Api/Internal/Guard.cs | 3 ++ .../OpenTelemetry.Tests/Internal/GuardTest.cs | 43 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/OpenTelemetry.Api/Internal/Guard.cs b/src/OpenTelemetry.Api/Internal/Guard.cs index 1b6348cd83a..f5b4235f1b8 100644 --- a/src/OpenTelemetry.Api/Internal/Guard.cs +++ b/src/OpenTelemetry.Api/Internal/Guard.cs @@ -25,6 +25,9 @@ namespace System.Runtime.CompilerServices /// /// Allows capturing of the expressions passed to a method. /// + /// + /// Borrowed from: . + /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] #pragma warning disable SA1402 // File may only contain a single type #pragma warning disable SA1649 // File name should match first type name diff --git a/test/OpenTelemetry.Tests/Internal/GuardTest.cs b/test/OpenTelemetry.Tests/Internal/GuardTest.cs index 01e23d3d788..30b0ab7b7dd 100644 --- a/test/OpenTelemetry.Tests/Internal/GuardTest.cs +++ b/test/OpenTelemetry.Tests/Internal/GuardTest.cs @@ -15,20 +15,12 @@ // using System; +using System.Runtime.CompilerServices; using System.Threading; using Xunit; namespace OpenTelemetry.Internal.Tests { -#pragma warning disable SA1402 // File may only contain a single type -#pragma warning disable SA1649 // File name should match first type name - public class Thing -#pragma warning restore SA1649 // File name should match first type name -#pragma warning restore SA1402 // File may only contain a single type - { - public string Bar { get; set; } - } - public class GuardTest { [Fact] @@ -171,5 +163,38 @@ public void ZeroTest() Assert.Contains("Must not be zero", ex1.Message); Assert.Equal("0", ex1.ParamName); } + + public class Thing + { + public string Bar { get; set; } + } + +#if !NETCOREAPP3_0_OR_GREATER + /// + /// Borrowed from: . + /// + public class CallerArgumentExpressionAttributeTests + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("paramName")] + public static void Ctor_ParameterName_Roundtrip(string value) + { + var caea = new CallerArgumentExpressionAttribute(value); + Assert.Equal(value, caea.ParameterName); + } + + [Fact] + public static void BasicTest() + { + Assert.Equal("\"hello\"", GetValue("hello")); + Assert.Equal("3 + 2", GetValue(3 + 2)); + Assert.Equal("new object()", GetValue(new object())); + } + + private static string GetValue(object argument, [CallerArgumentExpression("argument")] string expr = null) => expr; + } +#endif } } From ba2986aec0ce21c3cf45d42e33db7fe0da422441 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Fri, 29 Jul 2022 16:26:28 -0700 Subject: [PATCH 072/111] Exponential Bucket Histogram - part 8 (#3505) --- .../Metrics/CircularBufferBuckets.cs | 71 +++++++++---------- .../Metrics/ExponentialBucketHistogram.cs | 49 ++++--------- .../Metrics/CircularBufferBucketsTest.cs | 12 ++-- 3 files changed, 55 insertions(+), 77 deletions(-) diff --git a/src/OpenTelemetry/Metrics/CircularBufferBuckets.cs b/src/OpenTelemetry/Metrics/CircularBufferBuckets.cs index 06d318a25a7..14d5eaddcaf 100644 --- a/src/OpenTelemetry/Metrics/CircularBufferBuckets.cs +++ b/src/OpenTelemetry/Metrics/CircularBufferBuckets.cs @@ -89,50 +89,59 @@ public int TryIncrement(int index, long value = 1) this.begin = index; this.end = index; + this.trait[this.ModuloIndex(index)] += value; + + return 0; } - else if (index > this.end) - { - var diff = index - this.begin; - if (diff >= capacity || diff < 0) - { - return CalculateScaleReduction(diff + 1, capacity); - } + var begin = this.begin; + var end = this.end; - this.end = index; + if (index > end) + { + end = index; } - else if (index < this.begin) + else if (index < begin) { - var diff = this.end - index; + begin = index; + } + else + { + this.trait[this.ModuloIndex(index)] += value; - if (diff >= this.Capacity || diff < 0) - { - return CalculateScaleReduction(diff + 1, capacity); - } + return 0; + } - this.begin = index; + var diff = end - begin; + + if (diff >= capacity || diff < 0) + { + return CalculateScaleReduction(begin, end, capacity); } + this.begin = begin; + this.end = end; + this.trait[this.ModuloIndex(index)] += value; return 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int CalculateScaleReduction(int size, int capacity) + static int CalculateScaleReduction(int begin, int end, int capacity) { - var shift = MathHelper.LeadingZero32(capacity); - - if (size > 0) - { - shift -= MathHelper.LeadingZero32(size); - } + Debug.Assert(capacity >= 2, "The capacity must be at least 2."); - if (size > (capacity << shift)) + var retval = 0; + var diff = end - begin; + while (diff >= capacity || diff < 0) { - shift++; + begin >>= 1; + end >>= 1; + diff = end - begin; + retval++; } - return shift; + return retval; } } @@ -256,18 +265,6 @@ static void Move(long[] array, uint src, uint dst) } } - public override string ToString() - { - return nameof(CircularBufferBuckets) - + "{" - + nameof(this.Capacity) + "=" + this.Capacity + ", " - + nameof(this.Size) + "=" + this.Size + ", " - + nameof(this.begin) + "=" + this.begin + ", " - + nameof(this.end) + "=" + this.end + ", " - + (this.trait == null ? "null" : "{" + string.Join(", ", this.trait) + "}") - + "}"; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private int ModuloIndex(int value) { diff --git a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs index 87edd9908b9..b05a4c4438b 100644 --- a/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs +++ b/src/OpenTelemetry/Metrics/ExponentialBucketHistogram.cs @@ -120,15 +120,6 @@ private set internal CircularBufferBuckets NegativeBuckets { get; } - /// - public override string ToString() - { - return nameof(ExponentialBucketHistogram) - + "{" - + nameof(this.Scale) + "=" + this.Scale - + "}"; - } - /// /// Maps a finite positive IEEE 754 double-precision floating-point /// number to Bucket[index] = ( base ^ index, base ^ (index + 1) ], @@ -189,36 +180,26 @@ public void Record(double value) var c = value.CompareTo(0); - if (c > 0) + if (c == 0) { - var index = this.MapToIndex(value); - var n = this.PositiveBuckets.TryIncrement(index); - - if (n != 0) - { - this.PositiveBuckets.ScaleDown(n); - this.NegativeBuckets.ScaleDown(n); - n = this.PositiveBuckets.TryIncrement(index); - Debug.Assert(n == 0, "Increment should always succeed after scale down."); - } + this.ZeroCount++; + return; } - else if (c < 0) - { - var index = this.MapToIndex(-value); - var n = this.NegativeBuckets.TryIncrement(index); - if (n != 0) - { - this.PositiveBuckets.ScaleDown(n); - this.NegativeBuckets.ScaleDown(n); - n = this.NegativeBuckets.TryIncrement(index); - Debug.Assert(n == 0, "Increment should always succeed after scale down."); - } - } - else + var index = this.MapToIndex(c > 0 ? value : -value); + var buckets = c > 0 ? this.PositiveBuckets : this.NegativeBuckets; + var n = buckets.TryIncrement(index); + + if (n == 0) { - this.ZeroCount++; + return; } + + this.PositiveBuckets.ScaleDown(n); + this.NegativeBuckets.ScaleDown(n); + this.Scale -= n; + n = buckets.TryIncrement(index >> n); + Debug.Assert(n == 0, "Increment should always succeed after scale down."); } } diff --git a/test/OpenTelemetry.Tests/Metrics/CircularBufferBucketsTest.cs b/test/OpenTelemetry.Tests/Metrics/CircularBufferBucketsTest.cs index 68122562250..e83b4bda46c 100644 --- a/test/OpenTelemetry.Tests/Metrics/CircularBufferBucketsTest.cs +++ b/test/OpenTelemetry.Tests/Metrics/CircularBufferBucketsTest.cs @@ -101,18 +101,18 @@ public void NegativeInsertions() [Fact] public void IntegerOverflow() { - var buckets = new CircularBufferBuckets(1); + var buckets = new CircularBufferBuckets(2); Assert.Equal(0, buckets.TryIncrement(int.MaxValue)); Assert.Equal(int.MaxValue, buckets.Offset); Assert.Equal(1, buckets.Size); - Assert.Equal(31, buckets.TryIncrement(1)); - Assert.Equal(31, buckets.TryIncrement(0)); - Assert.Equal(32, buckets.TryIncrement(-1)); - Assert.Equal(32, buckets.TryIncrement(int.MinValue + 1)); - Assert.Equal(32, buckets.TryIncrement(int.MinValue)); + Assert.Equal(30, buckets.TryIncrement(1)); + Assert.Equal(30, buckets.TryIncrement(0)); + Assert.Equal(31, buckets.TryIncrement(-1)); + Assert.Equal(31, buckets.TryIncrement(int.MinValue + 1)); + Assert.Equal(31, buckets.TryIncrement(int.MinValue)); } [Fact] From 7517702f62c6ab2c93450698ce0c06ce4d287339 Mon Sep 17 00:00:00 2001 From: Yun-Ting Lin Date: Fri, 29 Jul 2022 17:16:20 -0700 Subject: [PATCH 073/111] [Prometheus] Remove shared project and move the shared code under listener project (#3503) --- OpenTelemetry.sln | 12 - ...etry.Exporter.Prometheus.AspNetCore.csproj | 12 +- ...sExporterMeterProviderBuilderExtensions.cs | 2 +- .../PrometheusExporterMiddleware.cs | 2 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 14 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 14 +- .../AssemblyInfo.cs | 4 +- ...ry.Exporter.Prometheus.HttpListener.csproj | 10 - ...pListenerMeterProviderBuilderExtensions.cs | 2 +- .../PrometheusHttpListener.cs | 2 +- .../Shared}/PrometheusCollectionManager.cs | 10 +- .../Shared}/PrometheusExporter.cs | 4 +- .../Shared}/PrometheusExporterEventSource.cs | 2 +- .../Shared}/PrometheusExporterOptions.cs | 4 +- .../Shared}/PrometheusSerializer.cs | 2 +- .../Shared}/PrometheusSerializerExt.cs | 2 +- .../.publicApi/net462/PublicAPI.Shipped.txt | 0 .../.publicApi/net462/PublicAPI.Unshipped.txt | 6 - .../netcoreapp3.1/PublicAPI.Shipped.txt | 0 .../netcoreapp3.1/PublicAPI.Unshipped.txt | 6 - ...elemetry.Exporter.Prometheus.Shared.csproj | 29 -- test/Benchmarks/Benchmarks.csproj | 2 +- .../PrometheusSerializerBenchmarks.cs | 2 +- .../PrometheusCollectionManagerTests.cs | 2 +- ...orter.Prometheus.HttpListener.Tests.csproj | 1 + .../PrometheusSerializerTests.cs | 387 ++++++++++++++++++ 26 files changed, 427 insertions(+), 106 deletions(-) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener}/AssemblyInfo.cs (77%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusCollectionManager.cs (96%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusExporter.cs (95%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusExporterEventSource.cs (97%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusExporterOptions.cs (93%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusSerializer.cs (99%) rename src/{OpenTelemetry.Exporter.Prometheus.Shared => OpenTelemetry.Exporter.Prometheus.HttpListener/Shared}/PrometheusSerializerExt.cs (99%) delete mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt delete mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt delete mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt delete mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt delete mode 100644 src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj create mode 100644 test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index d345ee94283..a16555d39ce 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -239,14 +239,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prom EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.HttpListener", "src\OpenTelemetry.Exporter.Prometheus.HttpListener\OpenTelemetry.Exporter.Prometheus.HttpListener.csproj", "{6B0232B7-5F29-4FB5-B383-1AA02DFE1089}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.Shared", "src\OpenTelemetry.Exporter.Prometheus.Shared\OpenTelemetry.Exporter.Prometheus.Shared.csproj", "{4AD27517-BAFC-413B-A8F0-988C3CEDC662}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests", "test\OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests\OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj", "{FBD12B0B-6731-4DD4-9C13-86F34593E974}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.HttpListener.Tests", "test\OpenTelemetry.Exporter.Prometheus.HttpListener.Tests\OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj", "{4EF4364F-6E64-43CE-BED1-E6FE01024899}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Prometheus.Shared.Tests", "test\OpenTelemetry.Exporter.Prometheus.Shared.Tests\OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj", "{8E75AEE2-017B-474F-A96D-035DF76A1C9E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -501,10 +497,6 @@ Global {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B0232B7-5F29-4FB5-B383-1AA02DFE1089}.Release|Any CPU.Build.0 = Release|Any CPU - {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4AD27517-BAFC-413B-A8F0-988C3CEDC662}.Release|Any CPU.Build.0 = Release|Any CPU {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Debug|Any CPU.Build.0 = Debug|Any CPU {FBD12B0B-6731-4DD4-9C13-86F34593E974}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -513,10 +505,6 @@ Global {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Debug|Any CPU.Build.0 = Debug|Any CPU {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Release|Any CPU.ActiveCfg = Release|Any CPU {4EF4364F-6E64-43CE-BED1-E6FE01024899}.Release|Any CPU.Build.0 = Release|Any CPU - {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E75AEE2-017B-474F-A96D-035DF76A1C9E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj index e7453e0bf52..33a00e05f1a 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj @@ -19,12 +19,12 @@ - - - - - - + + + + + + diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs index fd6809d68ee..d230d03d042 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs @@ -16,7 +16,7 @@ using System; using OpenTelemetry.Exporter.Prometheus.AspNetCore; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs index bebf084ce33..d76a85d44d3 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs @@ -19,7 +19,7 @@ using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt index a8f01b6d787..5f48f2c7562 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,12 +1,12 @@ -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions -static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index a8f01b6d787..5f48f2c7562 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,12 +1,12 @@ -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions -static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/AssemblyInfo.cs similarity index 77% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/AssemblyInfo.cs index d4361cf0913..e05d6714457 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/AssemblyInfo.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/AssemblyInfo.cs @@ -17,9 +17,9 @@ using System.Runtime.CompilerServices; #if SIGNED +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.HttpListener.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] [assembly: InternalsVisibleTo("Benchmarks, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] -[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Shared.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] #else +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.HttpListener.Tests")] [assembly: InternalsVisibleTo("Benchmarks")] -[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Shared.Tests")] #endif diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj index 7769147c0f6..ff00ef3db79 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj @@ -14,21 +14,11 @@ false - - $(DefineConstants);PROMETHEUS_HTTPLISTENER - - - - - - - - diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs index 9ab648b6be0..8c53f09837d 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs @@ -16,7 +16,7 @@ using System; using OpenTelemetry.Exporter.Prometheus.HttpListener; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index 28700603b1b..6badb4d5337 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -18,7 +18,7 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; namespace OpenTelemetry.Exporter.Prometheus.HttpListener diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusCollectionManager.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs similarity index 96% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusCollectionManager.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs index 87f3d6bff02..43da102246f 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusCollectionManager.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs @@ -20,7 +20,7 @@ using System.Threading.Tasks; using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared { internal sealed class PrometheusCollectionManager { @@ -91,7 +91,7 @@ public Task EnterCollect() this.ExitGlobalLock(); CollectionResponse response; - bool result = this.ExecuteCollect(); + var result = this.ExecuteCollect(); if (result) { this.previousDataViewGeneratedAtUtc = DateTime.UtcNow; @@ -169,14 +169,14 @@ private void WaitForReadersToComplete() private bool ExecuteCollect() { this.exporter.OnExport = this.onCollectRef; - bool result = this.exporter.Collect(Timeout.Infinite); + var result = this.exporter.Collect(Timeout.Infinite); this.exporter.OnExport = null; return result; } private ExportResult OnCollect(Batch metrics) { - int cursor = 0; + var cursor = 0; try { @@ -191,7 +191,7 @@ private ExportResult OnCollect(Batch metrics) } catch (IndexOutOfRangeException) { - int bufferSize = this.buffer.Length * 2; + var bufferSize = this.buffer.Length * 2; // there are two cases we might run into the following condition: // 1. we have many metrics to be exported - in this case we probably want diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs similarity index 95% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporter.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs index 25cd97c7a4b..ec2dbf0467b 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporter.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs @@ -17,12 +17,10 @@ using System; #if PROMETHEUS_ASPNETCORE using OpenTelemetry.Exporter.Prometheus.AspNetCore; -#elif PROMETHEUS_HTTPLISTENER -using OpenTelemetry.Exporter.Prometheus.HttpListener; #endif using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared { /// /// Exporter of OpenTelemetry metrics to Prometheus. diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterEventSource.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs similarity index 97% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterEventSource.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs index 34f296c4451..6cdbf9a9024 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterEventSource.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs @@ -18,7 +18,7 @@ using System.Diagnostics.Tracing; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared { /// /// EventSource events emitted from the project. diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs similarity index 93% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterOptions.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs index 6c5cbd53db5..4662ee3e263 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs @@ -19,10 +19,8 @@ #if PROMETHEUS_ASPNETCORE namespace OpenTelemetry.Exporter.Prometheus.AspNetCore -#elif PROMETHEUS_HTTPLISTENER -namespace OpenTelemetry.Exporter.Prometheus.HttpListener #else -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared #endif { /// diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializer.cs similarity index 99% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializer.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializer.cs index a8738d1853d..ac8bd042c62 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializer.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializer.cs @@ -22,7 +22,7 @@ using System.Runtime.CompilerServices; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus { /// /// Basic PrometheusSerializer which has no OpenTelemetry dependency. diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializerExt.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializerExt.cs similarity index 99% rename from src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializerExt.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializerExt.cs index 1178c3069b6..805a51a2488 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/PrometheusSerializerExt.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializerExt.cs @@ -16,7 +16,7 @@ using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.Shared +namespace OpenTelemetry.Exporter.Prometheus { /// /// OpenTelemetry additions to the PrometheusSerializer. diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Shipped.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt deleted file mode 100644 index d61e4fb9ed9..00000000000 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/net462/PublicAPI.Unshipped.txt +++ /dev/null @@ -1,6 +0,0 @@ -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Shipped.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt deleted file mode 100644 index 539467ab62d..00000000000 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt +++ /dev/null @@ -1,6 +0,0 @@ -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj b/src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj deleted file mode 100644 index 169e97169c4..00000000000 --- a/src/OpenTelemetry.Exporter.Prometheus.Shared/OpenTelemetry.Exporter.Prometheus.Shared.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - - netcoreapp3.1;net462 - Prometheus exporter shared code for both Prometheus exporter HttpListener and Prometheus exporter AspNetCore - $(PackageTags);prometheus;metrics - - - - - false - - - - - - - - - - - - - - - - diff --git a/test/Benchmarks/Benchmarks.csproj b/test/Benchmarks/Benchmarks.csproj index 3a3cc739d91..20ee4fb7456 100644 --- a/test/Benchmarks/Benchmarks.csproj +++ b/test/Benchmarks/Benchmarks.csproj @@ -29,6 +29,6 @@ - + diff --git a/test/Benchmarks/Exporter/PrometheusSerializerBenchmarks.cs b/test/Benchmarks/Exporter/PrometheusSerializerBenchmarks.cs index efd31fa6f86..c08d069bb50 100644 --- a/test/Benchmarks/Exporter/PrometheusSerializerBenchmarks.cs +++ b/test/Benchmarks/Exporter/PrometheusSerializerBenchmarks.cs @@ -18,7 +18,7 @@ using System.Diagnostics.Metrics; using BenchmarkDotNet.Attributes; using OpenTelemetry; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs index adeb3ac29c0..aa680d6495c 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs @@ -21,7 +21,7 @@ #endif using System.Threading; using System.Threading.Tasks; -using OpenTelemetry.Exporter.Prometheus.Shared; +using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; using Xunit; diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj index 22b68c4e9ea..4588d2168b5 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs new file mode 100644 index 00000000000..e6c0865cc3a --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs @@ -0,0 +1,387 @@ +// +// 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.Generic; +using System.Diagnostics.Metrics; +using System.Text; +using OpenTelemetry.Metrics; +using OpenTelemetry.Tests; +using Xunit; + +namespace OpenTelemetry.Exporter.Prometheus +{ + public sealed class PrometheusSerializerTests + { + [Fact] + public void GaugeZeroDimension() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge("test_gauge", () => 123); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_gauge gauge\n" + + "test_gauge 123 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void GaugeZeroDimensionWithDescription() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge("test_gauge", () => 123, description: "Hello, world!"); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# HELP test_gauge Hello, world!\n" + + "# TYPE test_gauge gauge\n" + + "test_gauge 123 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void GaugeZeroDimensionWithUnit() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge("test_gauge", () => 123, unit: "seconds"); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_gauge_seconds gauge\n" + + "test_gauge_seconds 123 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void GaugeOneDimension() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge( + "test_gauge", + () => new Measurement(123, new KeyValuePair("tagKey", "tagValue"))); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_gauge gauge\n" + + "test_gauge{tagKey='tagValue'} 123 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void GaugeDoubleSubnormal() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + meter.CreateObservableGauge("test_gauge", () => new List> + { + new(double.NegativeInfinity, new("x", "1"), new("y", "2")), + new(double.PositiveInfinity, new("x", "3"), new("y", "4")), + new(double.NaN, new("x", "5"), new("y", "6")), + }); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_gauge gauge\n" + + "test_gauge{x='1',y='2'} -Inf \\d+\n" + + "test_gauge{x='3',y='4'} \\+Inf \\d+\n" + + "test_gauge{x='5',y='6'} Nan \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void SumDoubleInfinites() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var counter = meter.CreateCounter("test_counter"); + counter.Add(1.0E308); + counter.Add(1.0E308); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_counter counter\n" + + "test_counter \\+Inf \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void HistogramZeroDimension() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var histogram = meter.CreateHistogram("test_histogram"); + histogram.Record(18); + histogram.Record(100); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_histogram histogram\n" + + "test_histogram_bucket{le='0'} 0 \\d+\n" + + "test_histogram_bucket{le='5'} 0 \\d+\n" + + "test_histogram_bucket{le='10'} 0 \\d+\n" + + "test_histogram_bucket{le='25'} 1 \\d+\n" + + "test_histogram_bucket{le='50'} 1 \\d+\n" + + "test_histogram_bucket{le='75'} 1 \\d+\n" + + "test_histogram_bucket{le='100'} 2 \\d+\n" + + "test_histogram_bucket{le='250'} 2 \\d+\n" + + "test_histogram_bucket{le='500'} 2 \\d+\n" + + "test_histogram_bucket{le='1000'} 2 \\d+\n" + + "test_histogram_bucket{le='\\+Inf'} 2 \\d+\n" + + "test_histogram_sum 118 \\d+\n" + + "test_histogram_count 2 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void HistogramOneDimension() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var histogram = meter.CreateHistogram("test_histogram"); + histogram.Record(18, new KeyValuePair("x", "1")); + histogram.Record(100, new KeyValuePair("x", "1")); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_histogram histogram\n" + + "test_histogram_bucket{x='1',le='0'} 0 \\d+\n" + + "test_histogram_bucket{x='1',le='5'} 0 \\d+\n" + + "test_histogram_bucket{x='1',le='10'} 0 \\d+\n" + + "test_histogram_bucket{x='1',le='25'} 1 \\d+\n" + + "test_histogram_bucket{x='1',le='50'} 1 \\d+\n" + + "test_histogram_bucket{x='1',le='75'} 1 \\d+\n" + + "test_histogram_bucket{x='1',le='100'} 2 \\d+\n" + + "test_histogram_bucket{x='1',le='250'} 2 \\d+\n" + + "test_histogram_bucket{x='1',le='500'} 2 \\d+\n" + + "test_histogram_bucket{x='1',le='1000'} 2 \\d+\n" + + "test_histogram_bucket{x='1',le='\\+Inf'} 2 \\d+\n" + + "test_histogram_sum{x='1'} 118 \\d+\n" + + "test_histogram_count{x='1'} 2 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void HistogramTwoDimensions() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var histogram = meter.CreateHistogram("test_histogram"); + histogram.Record(18, new("x", "1"), new("y", "2")); + histogram.Record(100, new("x", "1"), new("y", "2")); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_histogram histogram\n" + + "test_histogram_bucket{x='1',y='2',le='0'} 0 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='5'} 0 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='10'} 0 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='25'} 1 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='50'} 1 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='75'} 1 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='100'} 2 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='250'} 2 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='500'} 2 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='1000'} 2 \\d+\n" + + "test_histogram_bucket{x='1',y='2',le='\\+Inf'} 2 \\d+\n" + + "test_histogram_sum{x='1',y='2'} 118 \\d+\n" + + "test_histogram_count{x='1',y='2'} 2 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void HistogramInfinites() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var histogram = meter.CreateHistogram("test_histogram"); + histogram.Record(18); + histogram.Record(double.PositiveInfinity); + histogram.Record(double.PositiveInfinity); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_histogram histogram\n" + + "test_histogram_bucket{le='0'} 0 \\d+\n" + + "test_histogram_bucket{le='5'} 0 \\d+\n" + + "test_histogram_bucket{le='10'} 0 \\d+\n" + + "test_histogram_bucket{le='25'} 1 \\d+\n" + + "test_histogram_bucket{le='50'} 1 \\d+\n" + + "test_histogram_bucket{le='75'} 1 \\d+\n" + + "test_histogram_bucket{le='100'} 1 \\d+\n" + + "test_histogram_bucket{le='250'} 1 \\d+\n" + + "test_histogram_bucket{le='500'} 1 \\d+\n" + + "test_histogram_bucket{le='1000'} 1 \\d+\n" + + "test_histogram_bucket{le='\\+Inf'} 3 \\d+\n" + + "test_histogram_sum \\+Inf \\d+\n" + + "test_histogram_count 3 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + + [Fact] + public void HistogramNaN() + { + var buffer = new byte[85000]; + var metrics = new List(); + + using var meter = new Meter(Utils.GetCurrentMethodName()); + using var provider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddInMemoryExporter(metrics) + .Build(); + + var histogram = meter.CreateHistogram("test_histogram"); + histogram.Record(18); + histogram.Record(double.PositiveInfinity); + histogram.Record(double.NaN); + + provider.ForceFlush(); + + var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); + Assert.Matches( + ("^" + + "# TYPE test_histogram histogram\n" + + "test_histogram_bucket{le='0'} 0 \\d+\n" + + "test_histogram_bucket{le='5'} 0 \\d+\n" + + "test_histogram_bucket{le='10'} 0 \\d+\n" + + "test_histogram_bucket{le='25'} 1 \\d+\n" + + "test_histogram_bucket{le='50'} 1 \\d+\n" + + "test_histogram_bucket{le='75'} 1 \\d+\n" + + "test_histogram_bucket{le='100'} 1 \\d+\n" + + "test_histogram_bucket{le='250'} 1 \\d+\n" + + "test_histogram_bucket{le='500'} 1 \\d+\n" + + "test_histogram_bucket{le='1000'} 1 \\d+\n" + + "test_histogram_bucket{le='\\+Inf'} 3 \\d+\n" + + "test_histogram_sum Nan \\d+\n" + + "test_histogram_count 3 \\d+\n" + + "$").Replace('\'', '"'), + Encoding.UTF8.GetString(buffer, 0, cursor)); + } + } +} From cc5a56e796a750ddc5274da2efa7c1a63823b322 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Mon, 1 Aug 2022 10:33:00 -0700 Subject: [PATCH 074/111] Dust off Prometheus Exporters (#3507) --- .../getting-started-prometheus-grafana.csproj | 3 - examples/Console/TestPrometheusExporter.cs | 3 +- .../netcoreapp3.1/PublicAPI.Unshipped.txt | 14 +- ...etry.Exporter.Prometheus.AspNetCore.csproj | 13 +- ...eusExporterApplicationBuilderExtensions.cs | 2 +- ...sExporterEndpointRouteBuilderExtensions.cs | 2 +- ...sExporterMeterProviderBuilderExtensions.cs | 5 +- .../PrometheusExporterMiddleware.cs | 3 +- .../PrometheusExporterOptions.cs | 10 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 20 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 20 +- .../PrometheusCollectionManager.cs | 10 +- .../PrometheusExporter.cs | 24 +- .../PrometheusExporterEventSource.cs | 2 +- .../PrometheusSerializer.cs | 0 .../PrometheusSerializerExt.cs | 0 ...ry.Exporter.Prometheus.HttpListener.csproj | 2 +- .../PrometheusHttpListener.cs | 5 +- ...ListenerMeterProviderBuilderExtensions.cs} | 45 +- .../PrometheusHttpListenerOptions.cs | 9 +- .../README.md | 13 +- .../PrometheusCollectionManagerTests.cs | 5 +- ...ests.cs => PrometheusHttpListenerTests.cs} | 16 +- .../PrometheusSerializerTests.cs | 2 +- ...ry.Exporter.Prometheus.Shared.Tests.csproj | 32 -- .../PrometheusSerializerTests.cs | 387 ------------------ .../Program.cs | 3 +- test/OpenTelemetry.Tests.Stress/Skeleton.cs | 3 +- 28 files changed, 97 insertions(+), 556 deletions(-) rename src/{OpenTelemetry.Exporter.Prometheus.HttpListener/Shared => OpenTelemetry.Exporter.Prometheus.AspNetCore}/PrometheusExporterOptions.cs (85%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{Shared => Internal}/PrometheusCollectionManager.cs (95%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{Shared => Internal}/PrometheusExporter.cs (74%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{Shared => Internal}/PrometheusExporterEventSource.cs (97%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{Shared => Internal}/PrometheusSerializer.cs (100%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{Shared => Internal}/PrometheusSerializerExt.cs (100%) rename src/OpenTelemetry.Exporter.Prometheus.HttpListener/{PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs => PrometheusHttpListenerMeterProviderBuilderExtensions.cs} (52%) rename test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/{PrometheusExporterHttpListenerTests.cs => PrometheusHttpListenerTests.cs} (88%) delete mode 100644 test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj delete mode 100644 test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs diff --git a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj index 455ed30ceb4..8d59ff99ce3 100644 --- a/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj +++ b/docs/metrics/getting-started-prometheus-grafana/getting-started-prometheus-grafana.csproj @@ -1,7 +1,4 @@ - - netstandard2.0 - diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs index 29fc3879f39..0b1284c4ae0 100644 --- a/examples/Console/TestPrometheusExporter.cs +++ b/examples/Console/TestPrometheusExporter.cs @@ -52,8 +52,7 @@ internal static object Run(int port) .AddMeter(MyMeter.Name) .AddMeter(MyMeter2.Name) .AddPrometheusHttpListener( - exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, - listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:{port}/" }) + options => options.Prefixes = new string[] { $"http://localhost:{port}/" }) .Build(); var process = Process.GetCurrentProcess(); diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt index f9271183c1c..3c9d701eb94 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/netcoreapp3.1/PublicAPI.Unshipped.txt @@ -1,11 +1,11 @@ Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.AspNetCore.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions.PrometheusExporterOptions() -> void +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int +OpenTelemetry.Exporter.Prometheus.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensions.UseOpenTelemetryPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, OpenTelemetry.Metrics.MeterProvider meterProvider, System.Func predicate, string path, System.Action configureBranchedPipeline) -> Microsoft.AspNetCore.Builder.IApplicationBuilder @@ -14,4 +14,4 @@ static Microsoft.AspNetCore.Builder.PrometheusExporterApplicationBuilderExtensio static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path = null, OpenTelemetry.Metrics.MeterProvider meterProvider = null, System.Action configureBranchedPipeline = null) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder static Microsoft.AspNetCore.Builder.PrometheusExporterEndpointRouteBuilderExtensions.MapPrometheusScrapingEndpoint(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string path) -> Microsoft.AspNetCore.Builder.IEndpointConventionBuilder -static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.PrometheusExporterMeterProviderBuilderExtensions.AddPrometheusExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj index 33a00e05f1a..f8f55cb18e3 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj @@ -3,7 +3,7 @@ netcoreapp3.1 - AspNetCore middleware for hosting OpenTelemetry .NET Prometheus exporter + ASP.NET Core middleware for hosting OpenTelemetry .NET Prometheus Exporter $(PackageTags);prometheus;metrics core- @@ -19,14 +19,13 @@ - - - - - - + + + + + diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs index 00fe170e6fb..491e70eac02 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs @@ -19,7 +19,7 @@ using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using OpenTelemetry.Exporter.Prometheus.AspNetCore; +using OpenTelemetry.Exporter.Prometheus; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs index 372a96e8a81..5d260878ffa 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs @@ -20,7 +20,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using OpenTelemetry.Exporter.Prometheus.AspNetCore; +using OpenTelemetry.Exporter.Prometheus; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs index d230d03d042..7039db2a369 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs @@ -15,8 +15,7 @@ // using System; -using OpenTelemetry.Exporter.Prometheus.AspNetCore; -using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; +using OpenTelemetry.Exporter.Prometheus; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics @@ -51,7 +50,7 @@ private static MeterProviderBuilder AddPrometheusExporter(MeterProviderBuilder b { configure?.Invoke(options); - var exporter = new PrometheusExporter(options); + var exporter = new PrometheusExporter(scrapeEndpointPath: options.ScrapeEndpointPath, scrapeResponseCacheDurationMilliseconds: options.ScrapeResponseCacheDurationMilliseconds); var reader = new BaseExportingMetricReader(exporter) { TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs index d76a85d44d3..826ca135763 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs @@ -19,11 +19,10 @@ using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.AspNetCore +namespace OpenTelemetry.Exporter.Prometheus { /// /// ASP.NET Core middleware for exposing a Prometheus metrics scraping endpoint. diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs similarity index 85% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs rename to src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs index 4662ee3e263..bf7576117b1 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs @@ -14,14 +14,9 @@ // limitations under the License. // -using System; using OpenTelemetry.Internal; -#if PROMETHEUS_ASPNETCORE -namespace OpenTelemetry.Exporter.Prometheus.AspNetCore -#else -namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared -#endif +namespace OpenTelemetry.Exporter.Prometheus { /// /// Prometheus exporter options. @@ -29,12 +24,11 @@ namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared public class PrometheusExporterOptions { internal const string DefaultScrapeEndpointPath = "/metrics"; - internal Func GetUtcNowDateTimeOffset = () => DateTimeOffset.UtcNow; private int scrapeResponseCacheDurationMilliseconds = 10 * 1000; /// - /// Gets or sets the path to use for the scraping endpoint. Default value: /metrics. + /// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics". /// public string ScrapeEndpointPath { get; set; } = DefaultScrapeEndpointPath; diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt index 5f48f2c7562..7b61e63513e 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,12 +1,8 @@ -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void -OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions -static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions +static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 5f48f2c7562..7b61e63513e 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,12 +1,8 @@ -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.Prefixes.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.PrometheusExporterOptions() -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.get -> string -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeEndpointPath.set -> void -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.get -> int -OpenTelemetry.Exporter.Prometheus.HttpListener.Shared.PrometheusExporterOptions.ScrapeResponseCacheDurationMilliseconds.set -> void -OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions -static OpenTelemetry.Metrics.PrometheusExporterHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configureExporterOptions = null, System.Action configureListenerOptions = null) -> OpenTelemetry.Metrics.MeterProviderBuilder +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void +OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions +static OpenTelemetry.Metrics.PrometheusHttpListenerMeterProviderBuilderExtensions.AddPrometheusHttpListener(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Action configure = null) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs similarity index 95% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs index 43da102246f..704422b637e 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusCollectionManager.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs @@ -20,12 +20,12 @@ using System.Threading.Tasks; using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared +namespace OpenTelemetry.Exporter.Prometheus { internal sealed class PrometheusCollectionManager { private readonly PrometheusExporter exporter; - private readonly int scrapeResponseCacheDurationInMilliseconds; + private readonly int scrapeResponseCacheDurationMilliseconds; private readonly Func, ExportResult> onCollectRef; private byte[] buffer = new byte[85000]; // encourage the object to live in LOH (large object heap) private int globalLockState; @@ -38,7 +38,7 @@ internal sealed class PrometheusCollectionManager public PrometheusCollectionManager(PrometheusExporter exporter) { this.exporter = exporter; - this.scrapeResponseCacheDurationInMilliseconds = this.exporter.Options.ScrapeResponseCacheDurationMilliseconds; + this.scrapeResponseCacheDurationMilliseconds = this.exporter.ScrapeResponseCacheDurationMilliseconds; this.onCollectRef = this.OnCollect; } @@ -53,8 +53,8 @@ public Task EnterCollect() // If we are within {ScrapeResponseCacheDurationMilliseconds} of the // last successful collect, return the previous view. if (this.previousDataViewGeneratedAtUtc.HasValue - && this.scrapeResponseCacheDurationInMilliseconds > 0 - && this.previousDataViewGeneratedAtUtc.Value.AddMilliseconds(this.scrapeResponseCacheDurationInMilliseconds) >= DateTime.UtcNow) + && this.scrapeResponseCacheDurationMilliseconds > 0 + && this.previousDataViewGeneratedAtUtc.Value.AddMilliseconds(this.scrapeResponseCacheDurationMilliseconds) >= DateTime.UtcNow) { Interlocked.Increment(ref this.readerCount); this.ExitGlobalLock(); diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs similarity index 74% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs index ec2dbf0467b..93514ef4c97 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporter.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs @@ -15,12 +15,10 @@ // using System; -#if PROMETHEUS_ASPNETCORE -using OpenTelemetry.Exporter.Prometheus.AspNetCore; -#endif +using OpenTelemetry.Internal; using OpenTelemetry.Metrics; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared +namespace OpenTelemetry.Exporter.Prometheus { /// /// Exporter of OpenTelemetry metrics to Prometheus. @@ -28,8 +26,6 @@ namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared [ExportModes(ExportModes.Pull)] internal sealed class PrometheusExporter : BaseExporter, IPullMetricExporter { - internal const string HttpListenerStartFailureExceptionMessage = "PrometheusExporter http listener could not be started."; - internal readonly PrometheusExporterOptions Options; private Func funcCollect; private Func, ExportResult> funcExport; private bool disposed = false; @@ -37,10 +33,16 @@ internal sealed class PrometheusExporter : BaseExporter, IPullMetricExpo /// /// Initializes a new instance of the class. /// - /// Options for the exporter. - public PrometheusExporter(PrometheusExporterOptions options) + /// Scraping endpoint. + /// + /// The cache duration in milliseconds for scrape responses. Default value: 0. + /// + public PrometheusExporter(string scrapeEndpointPath = null, int scrapeResponseCacheDurationMilliseconds = 0) { - this.Options = options; + Guard.ThrowIfOutOfRange(scrapeResponseCacheDurationMilliseconds, min: 0); + + this.ScrapeEndpointPath = scrapeEndpointPath ?? "/metrics"; + this.ScrapeResponseCacheDurationMilliseconds = scrapeResponseCacheDurationMilliseconds; this.CollectionManager = new PrometheusCollectionManager(this); } @@ -63,6 +65,10 @@ internal Func, ExportResult> OnExport internal PrometheusCollectionManager CollectionManager { get; } + internal int ScrapeResponseCacheDurationMilliseconds { get; } + + internal string ScrapeEndpointPath { get; } + /// public override ExportResult Export(in Batch metrics) { diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporterEventSource.cs similarity index 97% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporterEventSource.cs index 6cdbf9a9024..b678cb436e2 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusExporterEventSource.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporterEventSource.cs @@ -18,7 +18,7 @@ using System.Diagnostics.Tracing; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Shared +namespace OpenTelemetry.Exporter.Prometheus { /// /// EventSource events emitted from the project. diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs similarity index 100% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializer.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializerExt.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs similarity index 100% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/Shared/PrometheusSerializerExt.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj index ff00ef3db79..e9c46371703 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/OpenTelemetry.Exporter.Prometheus.HttpListener.csproj @@ -3,7 +3,7 @@ netstandard2.0;net462 - Stand-alone HttpListener for hosting OpenTelemetry .NET exporter + Stand-alone HttpListener for hosting OpenTelemetry .NET Prometheus Exporter $(PackageTags);prometheus;metrics core- diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index 6badb4d5337..efd022d79b1 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -18,10 +18,9 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener +namespace OpenTelemetry.Exporter.Prometheus { internal sealed class PrometheusHttpListener : IDisposable { @@ -47,7 +46,7 @@ public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListene } this.exporter = exporter; - string path = this.exporter.Options.ScrapeEndpointPath ?? PrometheusExporterOptions.DefaultScrapeEndpointPath; + string path = this.exporter.ScrapeEndpointPath; if (!path.StartsWith("/")) { path = $"/{path}"; diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs similarity index 52% rename from src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs rename to src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs index 8c53f09837d..6c0b7b75a41 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusExporterHttpListenerMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,8 +15,7 @@ // using System; -using OpenTelemetry.Exporter.Prometheus.HttpListener; -using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; +using OpenTelemetry.Exporter.Prometheus; using OpenTelemetry.Internal; namespace OpenTelemetry.Metrics @@ -24,19 +23,17 @@ namespace OpenTelemetry.Metrics /// /// Extension methods to simplify registering a PrometheusHttpListener. /// - public static class PrometheusExporterHttpListenerMeterProviderBuilderExtensions + public static class PrometheusHttpListenerMeterProviderBuilderExtensions { /// - /// Adds Prometheus exporter to MeterProviderBuilder. + /// Adds PrometheusHttpListener to MeterProviderBuilder. /// /// builder to use. - /// Exporter configuration options. - /// HttpListener options. + /// PrometheusHttpListenerOptions options. /// The instance of to chain calls. public static MeterProviderBuilder AddPrometheusHttpListener( this MeterProviderBuilder builder, - Action configureExporterOptions = null, - Action configureListenerOptions = null) + Action configure = null) { Guard.ThrowIfNull(builder); @@ -44,44 +41,30 @@ public static MeterProviderBuilder AddPrometheusHttpListener( { return deferredMeterProviderBuilder.Configure((sp, builder) => { - AddPrometheusHttpListener( - builder, - sp.GetOptions(), - sp.GetOptions(), - configureExporterOptions, - configureListenerOptions); + AddPrometheusHttpListener(builder, sp.GetOptions(), configure); }); } - return AddPrometheusHttpListener( - builder, - new PrometheusExporterOptions(), - new PrometheusHttpListenerOptions(), - configureExporterOptions, - configureListenerOptions); + return AddPrometheusHttpListener(builder, new PrometheusHttpListenerOptions(), configure); } private static MeterProviderBuilder AddPrometheusHttpListener( MeterProviderBuilder builder, - PrometheusExporterOptions exporterOptions, - PrometheusHttpListenerOptions listenerOptions, - Action configureExporterOptions = null, - Action configureListenerOptions = null) + PrometheusHttpListenerOptions options, + Action configure = null) { - configureExporterOptions?.Invoke(exporterOptions); - configureListenerOptions?.Invoke(listenerOptions); + configure?.Invoke(options); - var exporter = new PrometheusExporter(exporterOptions); + var exporter = new PrometheusExporter(scrapeEndpointPath: options.ScrapeEndpointPath); var reader = new BaseExportingMetricReader(exporter) { TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, }; - const string HttpListenerStartFailureExceptionMessage = "PrometheusExporter HttpListener could not be started."; try { - var listener = new PrometheusHttpListener(exporter, listenerOptions); + var listener = new PrometheusHttpListener(exporter, options); exporter.OnDispose = () => listener.Dispose(); listener.Start(); } @@ -95,7 +78,7 @@ private static MeterProviderBuilder AddPrometheusHttpListener( { } - throw new InvalidOperationException(HttpListenerStartFailureExceptionMessage, ex); + throw new InvalidOperationException("PrometheusExporter HttpListener could not be started.", ex); } return builder.AddReader(reader); diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs index 264a5f229fd..dc1e8e5d9ea 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs @@ -18,7 +18,7 @@ using System.Collections.Generic; using OpenTelemetry.Internal; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener +namespace OpenTelemetry.Exporter.Prometheus { /// /// options. @@ -27,9 +27,14 @@ public class PrometheusHttpListenerOptions { private IReadOnlyCollection prefixes = new string[] { "http://localhost:9464/" }; + /// + /// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics". + /// + public string ScrapeEndpointPath { get; set; } = "/metrics"; + /// /// Gets or sets the prefixes to use for the http listener. - /// Default value: http://localhost:9464/. + /// Default value: ["http://localhost:9464/"]. /// public IReadOnlyCollection Prefixes { diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md index 8e772a4754e..b997b5adecc 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md @@ -23,8 +23,7 @@ dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener ### Step 2: Add PrometheusHttpListener -Add and configure `PrometheusHttpListener` with `PrometheusExporterOptions` as -the first argument and `PrometheusHttpListenerOptions` as the second argument. +Add and configure `PrometheusHttpListener` with `PrometheusHttpListenerOptions`. For example: @@ -32,8 +31,7 @@ For example: using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(MyMeter.Name) .AddPrometheusHttpListener( - exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, - listenerOptions => listenerOptions.Prefixes = new string[] { "http://localhost:9464/" }) + options => options.Prefixes = new string[] { "http://localhost:9464/" }) .Build(); ``` @@ -50,13 +48,6 @@ For details see: Defines the path for the Prometheus scrape endpoint for by `UseOpenTelemetryPrometheusScrapingEndpoint`. Default value: `"/metrics"`. -### ScrapeResponseCacheDurationMilliseconds - -Configures scrape endpoint response caching. Multiple scrape requests within the -cache duration time period will receive the same previously generated response. -The default value is `10000` (10 seconds). Set to `0` to disable response -caching. - ## Troubleshooting This component uses an diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs index aa680d6495c..6f739cbc175 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusCollectionManagerTests.cs @@ -21,12 +21,11 @@ #endif using System.Threading; using System.Threading.Tasks; -using OpenTelemetry.Exporter.Prometheus.HttpListener.Shared; using OpenTelemetry.Metrics; using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests +namespace OpenTelemetry.Exporter.Prometheus.Tests { public sealed class PrometheusCollectionManagerTests { @@ -110,7 +109,7 @@ public async Task EnterExitCollectTest() exporter.CollectionManager.ExitCollect(); } - Thread.Sleep(exporter.Options.ScrapeResponseCacheDurationMilliseconds); + Thread.Sleep(exporter.ScrapeResponseCacheDurationMilliseconds); counter.Add(100); diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs similarity index 88% rename from test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs rename to test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs index d197ffea85a..bfaa2f06f56 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusExporterHttpListenerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,9 +24,9 @@ using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus.HttpListener.Tests +namespace OpenTelemetry.Exporter.Prometheus.Tests { - public class PrometheusExporterHttpListenerTests + public class PrometheusHttpListenerTests { private readonly string meterName = Utils.GetCurrentMethodName(); @@ -38,7 +38,7 @@ public class PrometheusExporterHttpListenerTests public void ServerEndpointSanityCheckPositiveTest(params string[] uris) { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = uris) + .AddPrometheusHttpListener(options => options.Prefixes = uris) .Build(); } @@ -52,7 +52,7 @@ public void ServerEndpointSanityCheckNegativeTest(params string[] uris) try { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = uris) + .AddPrometheusHttpListener(options => options.Prefixes = uris) .Build(); } catch (Exception ex) @@ -97,9 +97,9 @@ private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetri address = $"http://localhost:{port}/"; provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddPrometheusHttpListener(null, listenerOptions => listenerOptions.Prefixes = new string[] { address }) - .Build(); + .AddMeter(meter.Name) + .AddPrometheusHttpListener(options => options.Prefixes = new string[] { address }) + .Build(); } var tags = new KeyValuePair[] diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs index e6c0865cc3a..cb2ea1d5641 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs @@ -21,7 +21,7 @@ using OpenTelemetry.Tests; using Xunit; -namespace OpenTelemetry.Exporter.Prometheus +namespace OpenTelemetry.Exporter.Prometheus.Tests { public sealed class PrometheusSerializerTests { diff --git a/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj deleted file mode 100644 index 640b3541f2e..00000000000 --- a/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/OpenTelemetry.Exporter.Prometheus.Shared.Tests.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - Unit test project of Prometheus exporter shared code for both Prometheus exporter HttpListener and Prometheus Exporter AspNetCore - - netcoreapp3.1 - $(TargetFrameworks);net462 - - false - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - - - - - - - diff --git a/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs deleted file mode 100644 index 1def2012b8e..00000000000 --- a/test/OpenTelemetry.Exporter.Prometheus.Shared.Tests/PrometheusSerializerTests.cs +++ /dev/null @@ -1,387 +0,0 @@ -// -// 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.Generic; -using System.Diagnostics.Metrics; -using System.Text; -using OpenTelemetry.Metrics; -using OpenTelemetry.Tests; -using Xunit; - -namespace OpenTelemetry.Exporter.Prometheus.Shared.Tests -{ - public sealed class PrometheusSerializerTests - { - [Fact] - public void GaugeZeroDimension() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - meter.CreateObservableGauge("test_gauge", () => 123); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_gauge gauge\n" - + "test_gauge 123 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void GaugeZeroDimensionWithDescription() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - meter.CreateObservableGauge("test_gauge", () => 123, description: "Hello, world!"); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# HELP test_gauge Hello, world!\n" - + "# TYPE test_gauge gauge\n" - + "test_gauge 123 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void GaugeZeroDimensionWithUnit() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - meter.CreateObservableGauge("test_gauge", () => 123, unit: "seconds"); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_gauge_seconds gauge\n" - + "test_gauge_seconds 123 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void GaugeOneDimension() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - meter.CreateObservableGauge( - "test_gauge", - () => new Measurement(123, new KeyValuePair("tagKey", "tagValue"))); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_gauge gauge\n" - + "test_gauge{tagKey='tagValue'} 123 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void GaugeDoubleSubnormal() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - meter.CreateObservableGauge("test_gauge", () => new List> - { - new(double.NegativeInfinity, new("x", "1"), new("y", "2")), - new(double.PositiveInfinity, new("x", "3"), new("y", "4")), - new(double.NaN, new("x", "5"), new("y", "6")), - }); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_gauge gauge\n" - + "test_gauge{x='1',y='2'} -Inf \\d+\n" - + "test_gauge{x='3',y='4'} \\+Inf \\d+\n" - + "test_gauge{x='5',y='6'} Nan \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void SumDoubleInfinites() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var counter = meter.CreateCounter("test_counter"); - counter.Add(1.0E308); - counter.Add(1.0E308); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_counter counter\n" - + "test_counter \\+Inf \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void HistogramZeroDimension() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var histogram = meter.CreateHistogram("test_histogram"); - histogram.Record(18); - histogram.Record(100); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_histogram histogram\n" - + "test_histogram_bucket{le='0'} 0 \\d+\n" - + "test_histogram_bucket{le='5'} 0 \\d+\n" - + "test_histogram_bucket{le='10'} 0 \\d+\n" - + "test_histogram_bucket{le='25'} 1 \\d+\n" - + "test_histogram_bucket{le='50'} 1 \\d+\n" - + "test_histogram_bucket{le='75'} 1 \\d+\n" - + "test_histogram_bucket{le='100'} 2 \\d+\n" - + "test_histogram_bucket{le='250'} 2 \\d+\n" - + "test_histogram_bucket{le='500'} 2 \\d+\n" - + "test_histogram_bucket{le='1000'} 2 \\d+\n" - + "test_histogram_bucket{le='\\+Inf'} 2 \\d+\n" - + "test_histogram_sum 118 \\d+\n" - + "test_histogram_count 2 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void HistogramOneDimension() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var histogram = meter.CreateHistogram("test_histogram"); - histogram.Record(18, new KeyValuePair("x", "1")); - histogram.Record(100, new KeyValuePair("x", "1")); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_histogram histogram\n" - + "test_histogram_bucket{x='1',le='0'} 0 \\d+\n" - + "test_histogram_bucket{x='1',le='5'} 0 \\d+\n" - + "test_histogram_bucket{x='1',le='10'} 0 \\d+\n" - + "test_histogram_bucket{x='1',le='25'} 1 \\d+\n" - + "test_histogram_bucket{x='1',le='50'} 1 \\d+\n" - + "test_histogram_bucket{x='1',le='75'} 1 \\d+\n" - + "test_histogram_bucket{x='1',le='100'} 2 \\d+\n" - + "test_histogram_bucket{x='1',le='250'} 2 \\d+\n" - + "test_histogram_bucket{x='1',le='500'} 2 \\d+\n" - + "test_histogram_bucket{x='1',le='1000'} 2 \\d+\n" - + "test_histogram_bucket{x='1',le='\\+Inf'} 2 \\d+\n" - + "test_histogram_sum{x='1'} 118 \\d+\n" - + "test_histogram_count{x='1'} 2 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void HistogramTwoDimensions() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var histogram = meter.CreateHistogram("test_histogram"); - histogram.Record(18, new("x", "1"), new("y", "2")); - histogram.Record(100, new("x", "1"), new("y", "2")); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_histogram histogram\n" - + "test_histogram_bucket{x='1',y='2',le='0'} 0 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='5'} 0 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='10'} 0 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='25'} 1 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='50'} 1 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='75'} 1 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='100'} 2 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='250'} 2 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='500'} 2 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='1000'} 2 \\d+\n" - + "test_histogram_bucket{x='1',y='2',le='\\+Inf'} 2 \\d+\n" - + "test_histogram_sum{x='1',y='2'} 118 \\d+\n" - + "test_histogram_count{x='1',y='2'} 2 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void HistogramInfinites() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var histogram = meter.CreateHistogram("test_histogram"); - histogram.Record(18); - histogram.Record(double.PositiveInfinity); - histogram.Record(double.PositiveInfinity); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_histogram histogram\n" - + "test_histogram_bucket{le='0'} 0 \\d+\n" - + "test_histogram_bucket{le='5'} 0 \\d+\n" - + "test_histogram_bucket{le='10'} 0 \\d+\n" - + "test_histogram_bucket{le='25'} 1 \\d+\n" - + "test_histogram_bucket{le='50'} 1 \\d+\n" - + "test_histogram_bucket{le='75'} 1 \\d+\n" - + "test_histogram_bucket{le='100'} 1 \\d+\n" - + "test_histogram_bucket{le='250'} 1 \\d+\n" - + "test_histogram_bucket{le='500'} 1 \\d+\n" - + "test_histogram_bucket{le='1000'} 1 \\d+\n" - + "test_histogram_bucket{le='\\+Inf'} 3 \\d+\n" - + "test_histogram_sum \\+Inf \\d+\n" - + "test_histogram_count 3 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - - [Fact] - public void HistogramNaN() - { - var buffer = new byte[85000]; - var metrics = new List(); - - using var meter = new Meter(Utils.GetCurrentMethodName()); - using var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(meter.Name) - .AddInMemoryExporter(metrics) - .Build(); - - var histogram = meter.CreateHistogram("test_histogram"); - histogram.Record(18); - histogram.Record(double.PositiveInfinity); - histogram.Record(double.NaN); - - provider.ForceFlush(); - - var cursor = PrometheusSerializer.WriteMetric(buffer, 0, metrics[0]); - Assert.Matches( - ("^" - + "# TYPE test_histogram histogram\n" - + "test_histogram_bucket{le='0'} 0 \\d+\n" - + "test_histogram_bucket{le='5'} 0 \\d+\n" - + "test_histogram_bucket{le='10'} 0 \\d+\n" - + "test_histogram_bucket{le='25'} 1 \\d+\n" - + "test_histogram_bucket{le='50'} 1 \\d+\n" - + "test_histogram_bucket{le='75'} 1 \\d+\n" - + "test_histogram_bucket{le='100'} 1 \\d+\n" - + "test_histogram_bucket{le='250'} 1 \\d+\n" - + "test_histogram_bucket{le='500'} 1 \\d+\n" - + "test_histogram_bucket{le='1000'} 1 \\d+\n" - + "test_histogram_bucket{le='\\+Inf'} 3 \\d+\n" - + "test_histogram_sum Nan \\d+\n" - + "test_histogram_count 3 \\d+\n" - + "$").Replace('\'', '"'), - Encoding.UTF8.GetString(buffer, 0, cursor)); - } - } -} diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index 6a56c5a4bcb..91d5e64a26a 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -47,8 +47,7 @@ public static void Main() using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusHttpListener( - exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, - listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:9185/" }) + options => options.Prefixes = new string[] { $"http://localhost:9185/" }) .Build(); Stress(prometheusPort: 9184); diff --git a/test/OpenTelemetry.Tests.Stress/Skeleton.cs b/test/OpenTelemetry.Tests.Stress/Skeleton.cs index e372b108710..967bcd53a49 100644 --- a/test/OpenTelemetry.Tests.Stress/Skeleton.cs +++ b/test/OpenTelemetry.Tests.Stress/Skeleton.cs @@ -76,8 +76,7 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) .AddMeter(meter.Name) .AddRuntimeInstrumentation() .AddPrometheusHttpListener( - exporterOptions => exporterOptions.ScrapeResponseCacheDurationMilliseconds = 0, - listenerOptions => listenerOptions.Prefixes = new string[] { $"http://localhost:{prometheusPort}/" }) + options => options.Prefixes = new string[] { $"http://localhost:{prometheusPort}/" }) .Build() : null; var statistics = new long[concurrency]; From 365828c4e2a1fa03a34b92da031e096af1939db3 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Mon, 1 Aug 2022 11:09:15 -0700 Subject: [PATCH 075/111] Nit fixed in prometheus for asp.net core (#3510) --- .../OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj index f8f55cb18e3..27c0377af01 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj @@ -14,10 +14,6 @@ false - - $(DefineConstants);PROMETHEUS_ASPNETCORE - - @@ -32,7 +28,7 @@ - + From 61ba0ed7102bd813b7a1278f9f0a6378dd76036a Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Mon, 1 Aug 2022 11:40:12 -0700 Subject: [PATCH 076/111] Nit fixes to prometheus asp.net core (#3511) --- .../PrometheusExporterApplicationBuilderExtensions.cs | 3 --- .../PrometheusExporterEndpointRouteBuilderExtensions.cs | 3 --- .../PrometheusExporterMiddleware.cs | 2 -- 3 files changed, 8 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs index 491e70eac02..100b4d69952 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterApplicationBuilderExtensions.cs @@ -14,8 +14,6 @@ // limitations under the License. // -#if NETCOREAPP3_1_OR_GREATER - using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -150,4 +148,3 @@ public static IApplicationBuilder UseOpenTelemetryPrometheusScrapingEndpoint( } } } -#endif diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs index 5d260878ffa..e24e829aa63 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterEndpointRouteBuilderExtensions.cs @@ -14,8 +14,6 @@ // limitations under the License. // -#if NETCOREAPP3_1_OR_GREATER - using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -108,4 +106,3 @@ public static IEndpointConventionBuilder MapPrometheusScrapingEndpoint( } } } -#endif diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs index 826ca135763..2b2368a60af 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs @@ -14,7 +14,6 @@ // limitations under the License. // -#if NETCOREAPP3_1_OR_GREATER using System; using System.Diagnostics; using System.Threading.Tasks; @@ -102,4 +101,3 @@ public async Task InvokeAsync(HttpContext httpContext) } } } -#endif From 493ab1a9d672a0f3f4cfe03517ad110637ae1bbe Mon Sep 17 00:00:00 2001 From: Yun-Ting Lin Date: Mon, 1 Aug 2022 17:07:42 -0700 Subject: [PATCH 077/111] [Prometheus] Update changelog and minor cleanup. (#3512) --- .../CHANGELOG.md | 15 ++++++++------- .../CHANGELOG.md | 15 ++++++++------- .../PrometheusHttpListener.cs | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md index f2df4b1a83b..ca3dd407279 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md @@ -2,11 +2,12 @@ ## Unreleased -* Split up Prometheus projects based on its hosting mechanism, HttpListener and AspNetCore, - into their own projects and assemblies. The shared code for both hosting mechanism - now lives in the `OpenTelemetry.Exporter.Prometheus.Shared` project and will not - be released. - ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430)) +* Split up Prometheus projects based on its hosting mechanism, + HttpListener and AspNetCore, into their own projects + and assemblies. + ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430) + [#3503](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3503) + [#3507](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3507)) * Added `IEndpointRouteBuilder` extension methods to help with Prometheus middleware configuration on ASP.NET Core @@ -81,8 +82,8 @@ Released 2021-Sep-23 Released 2021-Sep-13 * Bug fixes - ([#2289](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2289)) - ([#2309](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2309)) + ([#2289](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2289) + [#2309](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2309)) ## 1.2.0-alpha2 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md index 9f4ac19cfa2..324932a4262 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -2,11 +2,12 @@ ## Unreleased -* Split up Prometheus projects based on its hosting mechanism, HttpListener and AspNetCore, - into their own projects and assemblies. The shared code for both hosting mechanism - now lives in the `OpenTelemetry.Exporter.Prometheus.Shared` project and will not - be released. - ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430)) +* Split up Prometheus projects based on its hosting mechanism, + HttpListener and AspNetCore, into their own projects + and assemblies. + ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430) + [#3503](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3503) + [#3507](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3507)) ## 1.3.0-rc.2 @@ -77,8 +78,8 @@ Released 2021-Sep-23 Released 2021-Sep-13 * Bug fixes - ([#2289](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2289)) - ([#2309](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2309)) + ([#2289](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2289) + [#2309](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2309)) ## 1.2.0-alpha2 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index efd022d79b1..ce3a5a48ed8 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -25,7 +25,7 @@ namespace OpenTelemetry.Exporter.Prometheus internal sealed class PrometheusHttpListener : IDisposable { private readonly PrometheusExporter exporter; - private readonly System.Net.HttpListener httpListener = new(); + private readonly HttpListener httpListener = new(); private readonly object syncObject = new(); private CancellationTokenSource tokenSource; From 9b0cc13eae1e9cb9350e1b45994725d62bf1f9ea Mon Sep 17 00:00:00 2001 From: Yun-Ting Lin Date: Mon, 1 Aug 2022 17:37:25 -0700 Subject: [PATCH 078/111] Aligning formats for CHANGLOG.md files. (#3513) --- src/OpenTelemetry.Api/CHANGELOG.md | 4 ++-- src/OpenTelemetry.Exporter.Console/CHANGELOG.md | 2 +- src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md | 10 +++++----- .../CHANGELOG.md | 6 +++--- src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md | 4 ++-- src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md | 14 +++++++------- src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md | 3 ++- .../CHANGELOG.md | 2 +- .../CHANGELOG.md | 2 +- src/OpenTelemetry/CHANGELOG.md | 2 +- 10 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index e322f4f5c41..ab6a21171f2 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -163,7 +163,7 @@ Released 2021-Jan-29 the `Status` (otel.status_code) tag (added on `Activity` using the `SetStatus` extension) will now be set as the `UNSET`, `OK`, or `ERROR` string representation instead of the `0`, `1`, or `2` integer representation. - ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579) & + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579) [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620)) * Metrics API/SDK support is in an experimental state and is not recommended for production use. All metric APIs have been marked with the `Obsolete` @@ -266,7 +266,7 @@ Released 2020-08-28 header ([#1048](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1048)) * Removed `DistributedContext` as it is no longer part of the spec - ([#1048](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1048))) + ([#1048](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1048)) * Renaming from `ot` to `otel` ([#1046](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1046)) * Added `RuntimeContext` API diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index 781d1454627..c81c727d695 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -57,7 +57,7 @@ Released 2022-Mar-30 * Added StatusCode, StatusDescription support to `ConsoleActivityExporter`. ([#2929](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2929) - [#3061](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3061)) + [#3061](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3061)) * `AddConsoleExporter` extension method by default sets up exporter to export metrics every 10 seconds. diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 78402461db4..dc7985b864f 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -209,11 +209,11 @@ Released 2021-Jan-29 Simple exporter, and settings for batch exporting properties. * Jaeger will now set the `error` tag when `otel.status_code` is set to `ERROR`. - ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579) & + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579) [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620)) * Jaeger will no longer send the `otel.status_code` tag if the value is `UNSET`. - ([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609) & + ([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609) [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620)) * Span Event.Name will now be populated as the `event` field on Jaeger Logs @@ -265,14 +265,14 @@ Released 2020-Sep-15 Released 2020-08-28 -* Changed `JaegerExporter` to use `BatchExportActivityProcessor` by default +* Changed `JaegerExporter` to use `BatchExportActivityProcessor` by default. ([#1125](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1125)) * Span links will now be sent as `FOLLOWS_FROM` reference type. Previously they were sent as `CHILD_OF`. ([#970](https://github.com/open-telemetry/opentelemetry-dotnet/pull/970)) * Fixed issue when span has both the `net.peer.name` and `net.peer.port` - attributes but did not include `net.peer.port` in the `peer.service` field - ([#1195](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1195)). + attributes but did not include `net.peer.port` in the `peer.service` field. + ([#1195](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1195)) * Renamed extension method from `UseJaegerExporter` to `AddJaegerExporter`. diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 1a4ae40ade9..b04c352c41e 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -31,7 +31,7 @@ Released 2022-May-16 * Support `HttpProtobuf` protocol with logs & added `HttpClientFactory` option -([#3225](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3225)) + ([#3225](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3225)) * Removes net5.0 target and replaced with net6.0 as .NET 5.0 is going out of support. @@ -254,8 +254,8 @@ Released 2021-Apr-23 * Null values in string arrays are preserved according to [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/common.md). - ([#1919](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1919)) and - ([#1945](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1945)). + ([#1919](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1919) + [#1945](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1945)) * When using OpenTelemetry.Extensions.Hosting you can now bind `OtlpExporterOptions` to `IConfiguration` using the `Configure` extension (ex: diff --git a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md index cd272cb8e85..c9330f85220 100644 --- a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md @@ -76,9 +76,9 @@ Released 2020-Sep-15 Released 2020-08-28 -* Renamed extension method from `UseZPagesExporter` to `AddZPagesExporter` +* Renamed extension method from `UseZPagesExporter` to `AddZPagesExporter`. ([#1066](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1066)) -* Changed `ZPagesExporter` to use `ZPagesProcessor` by default +* Changed `ZPagesExporter` to use `ZPagesProcessor` by default. ([#1108](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1108)) ## 0.4.0-beta.2 diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index d62d7bc4efd..4196962db1f 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -192,12 +192,12 @@ Released 2021-Jan-29 * Zipkin will now set the `error` tag to the `Status.Description` value or an empty string when `Status.StatusCode` (`otel.status_code` tag) is set to `ERROR`. - ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579), - [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620), & + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579) + [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620) [#1655](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1655)) * Zipkin will no longer send the `otel.status_code` tag if the value is `UNSET`. - ([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609) & + ([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609) [#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620)) * Zipkin bool tag values will now be sent as `true`/`false` instead of @@ -249,13 +249,13 @@ Released 2020-Sep-15 Released 2020-08-28 -* Renamed extension method from `UseZipkinExporter` to `AddZipkinExporter` +* Renamed extension method from `UseZipkinExporter` to `AddZipkinExporter`. ([#1066](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1066)) -* Changed `ZipkinExporter` to use `BatchExportActivityProcessor` by default +* Changed `ZipkinExporter` to use `BatchExportActivityProcessor` by default. ([#1103](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1103)) * Fixed issue when span has both the `net.peer.name` and `net.peer.port` - attributes but did not include `net.peer.port` in the service address field - ([#1168](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1168)). + attributes but did not include `net.peer.port` in the service address field. + ([#1168](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1168)) ## 0.4.0-beta.2 diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index 799952828e8..93a35a7677d 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -37,7 +37,8 @@ Released 2022-Feb-02 Released 2021-Oct-08 * Removes upper constraint for Microsoft.Extensions.Hosting.Abstractions - dependency. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) + dependency. + ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) * Added `AddOpenTelemetryMetrics` extensions on `IServiceCollection` to register OpenTelemetry `MeterProvider` with application services. Added diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md index d456038b9b8..7e48cbf5487 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md @@ -153,7 +153,7 @@ Released 2020-Sep-15 added by the library are removed from the span. The information from these attributes is contained in other attributes that follow the conventions of OpenTelemetry. - ([#1260](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1260)). + ([#1260](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1260)) ## 0.5.0-beta.2 diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md index 8b25cf20d74..2ca87b172f7 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md @@ -98,7 +98,7 @@ Released 2020-Sep-15 * The `grpc.method` and `grpc.status_code` attributes added by the library are removed from the span. The information from these attributes is contained in other attributes that follow the conventions of OpenTelemetry. - ([#1260](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1260)). + ([#1260](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1260)) ## 0.5.0-beta.2 diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 99114364c52..b62f0338902 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -365,7 +365,7 @@ Released 2021-Mar-19 * Added `IncludeScopes`, `IncludeFormattedMessage`, & `ParseStateValues` on `OpenTelemetryLoggerOptions`. Added `FormattedMessage`, `StateValues`, & `ForEachScope` on `LogRecord`. - ([#1869](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1869) & + ([#1869](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1869) [#1883](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1883)) * Added `SetResourceBuilder` support to `OpenTelemetryLoggerOptions`. ([#1913](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1913)) From fec60fe9ab28e1647a207bd4cebacf907e4177f9 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 2 Aug 2022 11:57:19 -0700 Subject: [PATCH 079/111] ConsoleLogExporter special casing original format (#3516) --- src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs b/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs index c35cf543222..d538c59fb16 100644 --- a/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs +++ b/src/OpenTelemetry.Exporter.Console/ConsoleLogRecordExporter.cs @@ -66,7 +66,7 @@ public override ExportResult Export(in Batch batch) // Special casing {OriginalFormat} // See https://github.com/open-telemetry/opentelemetry-dotnet/pull/3182 // for explanation. - var valueToTransform = logRecord.StateValues[i].Key.Equals("{OriginalValue}") + var valueToTransform = logRecord.StateValues[i].Key.Equals("{OriginalFormat}") ? new KeyValuePair("OriginalFormat (a.k.a Body)", logRecord.StateValues[i].Value) : logRecord.StateValues[i]; From 0244fa024bc7897c35c748344de61ea92e43848f Mon Sep 17 00:00:00 2001 From: Timothy Mothra Date: Tue, 2 Aug 2022 13:10:11 -0700 Subject: [PATCH 080/111] refactor test exporters, use instead `DelegatingTestExporter` (#3486) --- .../IntegrationTests.cs | 53 +++++++++++++------ ...xporter.OpenTelemetryProtocol.Tests.csproj | 2 +- .../Shared/DelegatingExporter.cs | 27 ++++++++++ .../Shared/DelegatingTestExporter.cs | 46 ---------------- 4 files changed, 65 insertions(+), 63 deletions(-) create mode 100644 test/OpenTelemetry.Tests/Shared/DelegatingExporter.cs delete mode 100644 test/OpenTelemetry.Tests/Shared/DelegatingTestExporter.cs diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs index 91466b01299..b8206f03936 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTests.cs @@ -15,6 +15,7 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Metrics; using System.Diagnostics.Tracing; @@ -79,7 +80,8 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo }, }; - DelegatingTestExporter delegatingExporter = null; + DelegatingExporter delegatingExporter = null; + var exportResults = new List(); var activitySourceName = "otlp.collector.test"; @@ -93,7 +95,16 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo serviceProvider: null, configureExporterInstance: otlpExporter => { - delegatingExporter = new DelegatingTestExporter(otlpExporter, onExportAction: () => handle.Set()); + delegatingExporter = new DelegatingExporter + { + OnExportFunc = (batch) => + { + var result = otlpExporter.Export(batch); + exportResults.Add(result); + handle.Set(); + return result; + }, + }; return delegatingExporter; }); @@ -108,21 +119,21 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo if (forceFlush) { Assert.True(tracerProvider.ForceFlush()); - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } else if (exporterOptions.ExportProcessorType == ExportProcessorType.Batch) { Assert.True(handle.WaitOne(ExportIntervalMilliseconds * 2)); - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } } if (!forceFlush && exportProcessorType == ExportProcessorType.Simple) { - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } } @@ -155,7 +166,8 @@ public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endp Protocol = protocol, }; - DelegatingTestExporter delegatingExporter = null; + DelegatingExporter delegatingExporter = null; + var exportResults = new List(); var meterName = "otlp.collector.test"; @@ -174,7 +186,16 @@ public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endp serviceProvider: null, configureExporterInstance: otlpExporter => { - delegatingExporter = new DelegatingTestExporter(otlpExporter, onExportAction: () => handle.Set()); + delegatingExporter = new DelegatingExporter + { + OnExportFunc = (batch) => + { + var result = otlpExporter.Export(batch); + exportResults.Add(result); + handle.Set(); + return result; + }, + }; return delegatingExporter; }); @@ -191,21 +212,21 @@ public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endp if (forceFlush) { Assert.True(meterProvider.ForceFlush()); - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } else if (!useManualExport) { Assert.True(handle.WaitOne(ExportIntervalMilliseconds * 2)); - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } } if (!forceFlush && useManualExport) { - Assert.Single(delegatingExporter.ExportResults); - Assert.Equal(ExportResult.Success, delegatingExporter.ExportResults[0]); + Assert.Single(exportResults); + Assert.Equal(ExportResult.Success, exportResults[0]); } } diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj index 2ddffb5be2a..271f7649e84 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj @@ -27,7 +27,7 @@ - + diff --git a/test/OpenTelemetry.Tests/Shared/DelegatingExporter.cs b/test/OpenTelemetry.Tests/Shared/DelegatingExporter.cs new file mode 100644 index 00000000000..13cef6924d9 --- /dev/null +++ b/test/OpenTelemetry.Tests/Shared/DelegatingExporter.cs @@ -0,0 +1,27 @@ +// +// 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; + +namespace OpenTelemetry.Tests; + +internal sealed class DelegatingExporter : BaseExporter + where T : class +{ + public Func, ExportResult> OnExportFunc { get; set; } = (batch) => default; + + public override ExportResult Export(in Batch batch) => this.OnExportFunc(batch); +} diff --git a/test/OpenTelemetry.Tests/Shared/DelegatingTestExporter.cs b/test/OpenTelemetry.Tests/Shared/DelegatingTestExporter.cs deleted file mode 100644 index 10800369105..00000000000 --- a/test/OpenTelemetry.Tests/Shared/DelegatingTestExporter.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// 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; -using System.Collections.Generic; - -namespace OpenTelemetry.Tests -{ - public class DelegatingTestExporter : BaseExporter - where T : class - { - private readonly BaseExporter exporter; - private readonly Action onExportAction; - - public DelegatingTestExporter( - BaseExporter exporter, - Action onExportAction = null) - { - this.exporter = exporter; - this.onExportAction = onExportAction; - } - - public List ExportResults { get; } = new(); - - public override ExportResult Export(in Batch batch) - { - var result = this.exporter.Export(batch); - this.ExportResults.Add(result); - this.onExportAction?.Invoke(); - return result; - } - } -} From 59ed0334f8e2bb440ddbda192147c8db184b6595 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Tue, 2 Aug 2022 15:39:41 -0700 Subject: [PATCH 081/111] Improve PrometheusHttpListener options (#3521) --- .../README.md | 6 +- examples/Console/TestPrometheusExporter.cs | 2 +- .../.publicApi/net462/PublicAPI.Unshipped.txt | 4 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 4 +- .../CHANGELOG.md | 4 ++ .../PrometheusHttpListener.cs | 12 ++-- .../PrometheusHttpListenerOptions.cs | 20 +++---- .../README.md | 22 +++---- .../PrometheusHttpListenerTests.cs | 58 +++++++++++-------- .../Program.cs | 2 +- test/OpenTelemetry.Tests.Stress/Skeleton.cs | 2 +- 11 files changed, 68 insertions(+), 68 deletions(-) diff --git a/docs/metrics/getting-started-prometheus-grafana/README.md b/docs/metrics/getting-started-prometheus-grafana/README.md index 62953f4f130..1e2f2e35e99 100644 --- a/docs/metrics/getting-started-prometheus-grafana/README.md +++ b/docs/metrics/getting-started-prometheus-grafana/README.md @@ -49,10 +49,10 @@ with .AddPrometheusHttpListener() ``` -`PrometheusHttpListener` is a wrapper that contains `PrometheusExporter`. -With `AddPrometheusHttpListener()`, OpenTelemetry `PrometheusExporter` will export +`PrometheusHttpListener` is a wrapper that contains `PrometheusExporter`. With +`AddPrometheusHttpListener()`, OpenTelemetry `PrometheusExporter` will export data via the endpoint defined by -[PrometheusHttpListenerOptions.Prefixes](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md#prefixes), +[PrometheusHttpListenerOptions.UriPrefixes](../../../src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md#uriprefixes), which is `http://localhost:9464/` by default. ```mermaid diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs index 0b1284c4ae0..befb0e5d4e9 100644 --- a/examples/Console/TestPrometheusExporter.cs +++ b/examples/Console/TestPrometheusExporter.cs @@ -52,7 +52,7 @@ internal static object Run(int port) .AddMeter(MyMeter.Name) .AddMeter(MyMeter2.Name) .AddPrometheusHttpListener( - options => options.Prefixes = new string[] { $"http://localhost:{port}/" }) + options => options.UriPrefixes = new string[] { $"http://localhost:{port}/" }) .Build(); var process = Process.GetCurrentProcess(); diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt index 7b61e63513e..e05aa673ed4 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,6 +1,6 @@ OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions -OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection -OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.UriPrefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.UriPrefixes.set -> void OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 7b61e63513e..e05aa673ed4 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,6 +1,6 @@ OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions -OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.get -> System.Collections.Generic.IReadOnlyCollection -OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.Prefixes.set -> void +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.UriPrefixes.get -> System.Collections.Generic.IReadOnlyCollection +OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.UriPrefixes.set -> void OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string OpenTelemetry.Exporter.Prometheus.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md index 324932a4262..9d516152808 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -8,6 +8,10 @@ ([#3430](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3430) [#3503](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3503) [#3507](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3507)) +* Fixed bug + [#2840](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2840) by + allowing `+` and `*` to be used in the URI prefixes (e.g. `"http://*:9184"`). + ([#3521](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3521)) ## 1.3.0-rc.2 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index ce3a5a48ed8..3bd122a7732 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -39,14 +39,12 @@ internal sealed class PrometheusHttpListener : IDisposable public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListenerOptions options) { Guard.ThrowIfNull(exporter); - - if ((options.Prefixes?.Count ?? 0) <= 0) - { - throw new ArgumentException("No Prefixes were specified on PrometheusHttpListenerOptions."); - } + Guard.ThrowIfNull(options); this.exporter = exporter; + string path = this.exporter.ScrapeEndpointPath; + if (!path.StartsWith("/")) { path = $"/{path}"; @@ -57,9 +55,9 @@ public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListene path = $"{path}/"; } - foreach (string prefix in options.Prefixes) + foreach (string uriPrefix in options.UriPrefixes) { - this.httpListener.Prefixes.Add($"{prefix.TrimEnd('/')}{path}"); + this.httpListener.Prefixes.Add($"{uriPrefix.TrimEnd('/')}{path}"); } } diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs index dc1e8e5d9ea..68f88c16424 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs @@ -25,7 +25,7 @@ namespace OpenTelemetry.Exporter.Prometheus /// public class PrometheusHttpListenerOptions { - private IReadOnlyCollection prefixes = new string[] { "http://localhost:9464/" }; + private IReadOnlyCollection uriPrefixes = new string[] { "http://localhost:9464/" }; /// /// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics". @@ -33,28 +33,22 @@ public class PrometheusHttpListenerOptions public string ScrapeEndpointPath { get; set; } = "/metrics"; /// - /// Gets or sets the prefixes to use for the http listener. + /// Gets or sets the URI (Uniform Resource Identifier) prefixes to use for the http listener. /// Default value: ["http://localhost:9464/"]. /// - public IReadOnlyCollection Prefixes + public IReadOnlyCollection UriPrefixes { - get => this.prefixes; + get => this.uriPrefixes; set { Guard.ThrowIfNull(value); - foreach (string inputUri in value) + if (value.Count == 0) { - if (!(Uri.TryCreate(inputUri, UriKind.Absolute, out var uri) && - (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))) - { - throw new ArgumentException( - "Prometheus HttpListener prefix path should be a valid URI with http/https scheme.", - nameof(this.prefixes)); - } + throw new ArgumentException("Empty list provided.", nameof(this.UriPrefixes)); } - this.prefixes = value; + this.uriPrefixes = value; } } } diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md index b997b5adecc..b97cb0bd258 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md @@ -15,38 +15,32 @@ instance for Prometheus to scrape. ### Step 1: Install Package -Install - ```shell dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener ``` ### Step 2: Add PrometheusHttpListener -Add and configure `PrometheusHttpListener` with `PrometheusHttpListenerOptions`. - -For example: - ```csharp -using var meterProvider = Sdk.CreateMeterProviderBuilder() +var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(MyMeter.Name) .AddPrometheusHttpListener( - options => options.Prefixes = new string[] { "http://localhost:9464/" }) + options => options.UriPrefixes = new string[] { "http://localhost:9464/" }) .Build(); ``` -### Prefixes +### UriPrefixes -Defines the prefixes which will be used by the listener. The default value is `["http://localhost:9464/"]`. -You may specify multiple endpoints. +Defines one or more URI (Uniform Resource Identifier) prefixes which will be +used by the HTTP listener. The default value is `["http://localhost:9464/"]`. -For details see: +Refer to [HttpListenerPrefixCollection.Add(String)](https://docs.microsoft.com/dotnet/api/system.net.httplistenerprefixcollection.add) +for more details. ### ScrapeEndpointPath -Defines the path for the Prometheus scrape endpoint for by -`UseOpenTelemetryPrometheusScrapingEndpoint`. Default value: `"/metrics"`. +Defines the Prometheus scrape endpoint path. Default value: `"/metrics"`. ## Troubleshooting diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs index bfaa2f06f56..fb281a3563f 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs @@ -31,42 +31,52 @@ public class PrometheusHttpListenerTests private readonly string meterName = Utils.GetCurrentMethodName(); [Theory] - [InlineData("http://example.com")] + [InlineData("http://+:9184")] + [InlineData("http://*:9184")] + [InlineData("http://+:9184/")] + [InlineData("http://*:9184/")] [InlineData("https://example.com")] [InlineData("http://127.0.0.1")] [InlineData("http://example.com", "https://example.com", "http://127.0.0.1")] - public void ServerEndpointSanityCheckPositiveTest(params string[] uris) + [InlineData("http://example.com")] + public void UriPrefixesPositiveTest(params string[] uriPrefixes) { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusHttpListener(options => options.Prefixes = uris) + .AddPrometheusHttpListener(options => options.UriPrefixes = uriPrefixes) .Build(); } - [Theory] - [InlineData("")] - [InlineData(null)] - [InlineData("ftp://example.com")] - [InlineData("http://example.com", "https://example.com", "ftp://example.com")] - public void ServerEndpointSanityCheckNegativeTest(params string[] uris) + [Fact] + public void UriPrefixesNull() { - try + Assert.Throws(() => { using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() - .AddPrometheusHttpListener(options => options.Prefixes = uris) + .AddPrometheusHttpListener(options => options.UriPrefixes = null) .Build(); - } - catch (Exception ex) + }); + } + + [Fact] + public void UriPrefixesEmptyList() + { + Assert.Throws(() => { - if (ex is not ArgumentNullException) - { - Assert.Equal("System.ArgumentException", ex.GetType().ToString()); -#if NETFRAMEWORK - Assert.Equal("Prometheus HttpListener prefix path should be a valid URI with http/https scheme.\r\nParameter name: prefixes", ex.Message); -#else - Assert.Equal("Prometheus HttpListener prefix path should be a valid URI with http/https scheme. (Parameter 'prefixes')", ex.Message); -#endif - } - } + using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() + .AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { }) + .Build(); + }); + } + + [Fact] + public void UriPrefixesInvalid() + { + Assert.Throws(() => + { + using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder() + .AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "ftp://example.com" }) + .Build(); + }); } [Fact] @@ -98,7 +108,7 @@ private async Task RunPrometheusExporterHttpServerIntegrationTest(bool skipMetri provider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) - .AddPrometheusHttpListener(options => options.Prefixes = new string[] { address }) + .AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { address }) .Build(); } diff --git a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs index 91d5e64a26a..da3215aee79 100644 --- a/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs +++ b/test/OpenTelemetry.Tests.Stress.Metrics/Program.cs @@ -47,7 +47,7 @@ public static void Main() using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(TestMeter.Name) .AddPrometheusHttpListener( - options => options.Prefixes = new string[] { $"http://localhost:9185/" }) + options => options.UriPrefixes = new string[] { $"http://localhost:9185/" }) .Build(); Stress(prometheusPort: 9184); diff --git a/test/OpenTelemetry.Tests.Stress/Skeleton.cs b/test/OpenTelemetry.Tests.Stress/Skeleton.cs index 967bcd53a49..c69e2543a1a 100644 --- a/test/OpenTelemetry.Tests.Stress/Skeleton.cs +++ b/test/OpenTelemetry.Tests.Stress/Skeleton.cs @@ -76,7 +76,7 @@ public static void Stress(int concurrency = 0, int prometheusPort = 0) .AddMeter(meter.Name) .AddRuntimeInstrumentation() .AddPrometheusHttpListener( - options => options.Prefixes = new string[] { $"http://localhost:{prometheusPort}/" }) + options => options.UriPrefixes = new string[] { $"http://localhost:{prometheusPort}/" }) .Build() : null; var statistics = new long[concurrency]; From 08463091ca859202d4d1c3aeb154c90bb533c322 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Tue, 2 Aug 2022 17:10:00 -0700 Subject: [PATCH 082/111] Minor improvements to Prometheus Exporter (ASP.NET Core) (#3522) --- .../PrometheusExporterOptions.cs | 4 ++-- .../README.md | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs index bf7576117b1..248b991f4c5 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterOptions.cs @@ -25,7 +25,7 @@ public class PrometheusExporterOptions { internal const string DefaultScrapeEndpointPath = "/metrics"; - private int scrapeResponseCacheDurationMilliseconds = 10 * 1000; + private int scrapeResponseCacheDurationMilliseconds = 300; /// /// Gets or sets the path to use for the scraping endpoint. Default value: "/metrics". @@ -33,7 +33,7 @@ public class PrometheusExporterOptions public string ScrapeEndpointPath { get; set; } = DefaultScrapeEndpointPath; /// - /// Gets or sets the cache duration in milliseconds for scrape responses. Default value: 10,000 (10 seconds). + /// Gets or sets the cache duration in milliseconds for scrape responses. Default value: 300. /// /// /// Note: Specify 0 to disable response caching. diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md index 855c20637a6..d9cb8bfdc1a 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md @@ -15,15 +15,15 @@ to scrape. ### Step 1: Install Package -Install - ```shell dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore ``` ### Step 2: Configure OpenTelemetry MeterProvider -* When using OpenTelemetry.Extensions.Hosting package on .NET Core 3.1+: +* When using + [OpenTelemetry.Extensions.Hosting](../OpenTelemetry.Extensions.Hosting/README.md) + package on .NET Core 3.1+: ```csharp services.AddOpenTelemetryMetrics(builder => @@ -34,7 +34,7 @@ dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore * Or configure directly: - Call the `AddPrometheusExporter` `MeterProviderBuilder` extension to + Call the `MeterProviderBuilder.AddPrometheusExporter` extension to register the Prometheus exporter. ```csharp @@ -94,8 +94,7 @@ registered by Configures scrape endpoint response caching. Multiple scrape requests within the cache duration time period will receive the same previously generated response. -The default value is `10000` (10 seconds). Set to `0` to disable response -caching. +The default value is `300`. Set to `0` to disable response caching. ## Troubleshooting From 436211580f0f11175781557ae7a4909ef02910f2 Mon Sep 17 00:00:00 2001 From: Paulo Janotti Date: Tue, 2 Aug 2022 17:38:10 -0700 Subject: [PATCH 083/111] Fix OpenTracing shim under legacy AspNetCore activities (#3506) --- .../CHANGELOG.md | 4 +++ .../SpanBuilderShim.cs | 19 +------------ .../SpanBuilderShimTests.cs | 28 +++++++++++++++++-- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md index 30a4b655820..aff4eaa3b30 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md +++ b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* Fix: Handling of OpenTracing spans when used in conjunction + with legacy "Microsoft.AspNetCore.Hosting.HttpRequestIn" activities. + ([#3509](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3506)) + ## 1.0.0-rc9.4 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs index 483549e8f97..5cdbe55e85d 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs +++ b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using OpenTelemetry.Internal; using OpenTelemetry.Trace; using OpenTracing; @@ -50,14 +49,6 @@ internal sealed class SpanBuilderShim : ISpanBuilder /// private readonly List> attributes = new(); - /// - /// The set of operation names for System.Diagnostics.Activity based automatic instrumentations that indicate a root span. - /// - private readonly IList rootOperationNamesForActivityBasedAutoInstrumentations = new List - { - "Microsoft.AspNetCore.Hosting.HttpRequestIn", - }; - /// /// The parent as an TelemetrySpan, if any. /// @@ -79,7 +70,7 @@ internal sealed class SpanBuilderShim : ISpanBuilder private bool error; - public SpanBuilderShim(Tracer tracer, string spanName, IList rootOperationNamesForActivityBasedAutoInstrumentations = null) + public SpanBuilderShim(Tracer tracer, string spanName) { Guard.ThrowIfNull(tracer); Guard.ThrowIfNull(spanName); @@ -87,7 +78,6 @@ public SpanBuilderShim(Tracer tracer, string spanName, IList rootOperati this.tracer = tracer; this.spanName = spanName; this.ScopeManager = new ScopeManagerShim(this.tracer); - this.rootOperationNamesForActivityBasedAutoInstrumentations = rootOperationNamesForActivityBasedAutoInstrumentations ?? this.rootOperationNamesForActivityBasedAutoInstrumentations; } private IScopeManager ScopeManager { get; } @@ -172,13 +162,6 @@ public ISpan Start() { span = this.tracer.StartSpan(this.spanName, this.spanKind, this.parentSpanContext, default, this.links, this.explicitStartTime ?? default); } - else if (this.parentSpan == null && !this.parentSpanContext.IsValid && Activity.Current != null && Activity.Current.IdFormat == ActivityIdFormat.W3C) - { - if (this.rootOperationNamesForActivityBasedAutoInstrumentations.Contains(Activity.Current.OperationName)) - { - span = Tracer.CurrentSpan; - } - } if (span == null) { diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs index c149928d78a..27f9cc11cd3 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs @@ -127,13 +127,13 @@ public void Start_ActivityOperationRootSpanChecks() // matching root operation name var tracer = TracerProvider.Default.GetTracer(TracerName); - var shim = new SpanBuilderShim(tracer, "foo", new List { "foo" }); + var shim = new SpanBuilderShim(tracer, "foo"); var spanShim1 = (SpanShim)shim.Start(); Assert.Equal("foo", spanShim1.Span.Activity.OperationName); // mis-matched root operation name - shim = new SpanBuilderShim(tracer, "foo", new List { "bar" }); + shim = new SpanBuilderShim(tracer, "foo"); var spanShim2 = (SpanShim)shim.Start(); Assert.Equal("foo", spanShim2.Span.Activity.OperationName); @@ -330,5 +330,29 @@ public void Start() Assert.NotNull(span); Assert.Equal("foo", span.Span.Activity.OperationName); } + + [Fact] + public void Start_UnderAspNetCoreInstrumentation() + { + // Simulate a span from AspNetCore instrumentation as parent. + using var source = new ActivitySource("Microsoft.AspNetCore.Hosting.HttpRequestIn"); + using var parentSpan = source.StartActivity("OTelParent"); + Assert.NotNull(parentSpan); + + // Start the OpenTracing span. + var tracer = TracerProvider.Default.GetTracer(TracerName); + var builderShim = new SpanBuilderShim(tracer, "foo"); + var spanShim = builderShim.StartActive().Span as SpanShim; + Assert.NotNull(spanShim); + + var telemetrySpan = spanShim.Span; + Assert.Same(telemetrySpan.Activity, Activity.Current); + Assert.Same(parentSpan, telemetrySpan.Activity.Parent); + + // Dispose the spanShim.Span and ensure correct state for Activity.Current + spanShim.Span.Dispose(); + + Assert.Same(parentSpan, Activity.Current); + } } } From 15e2e0a4f3560b25523e7afd52877be070e7ba66 Mon Sep 17 00:00:00 2001 From: Utkarsh Umesan Pillai Date: Tue, 2 Aug 2022 18:28:08 -0700 Subject: [PATCH 084/111] Update CHANGELOG for 1.4.0-alpha.1 release (#3523) --- src/OpenTelemetry.Api/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Console/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md | 4 ++++ .../CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md | 4 ++++ src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md | 4 ++++ src/OpenTelemetry/CHANGELOG.md | 4 ++++ 16 files changed, 64 insertions(+) diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index ab6a21171f2..d17ef3eb0e3 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * Add `Activity.RecordException` overload accepting additional attributes to add to the `ActivityEvent`. [#3433](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3433) diff --git a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md index c81c727d695..fde2a3c421d 100644 --- a/src/OpenTelemetry.Exporter.Console/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Console/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * The `MetricReaderOptions` defaults can be overridden using `OTEL_METRIC_EXPORT_INTERVAL` and `OTEL_METRIC_EXPORT_TIMEOUT` environmental variables as defined in the diff --git a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md index 20be374518e..9cd73b34aa2 100644 --- a/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * `InMemoryExporter` will now buffer scopes when exporting `LogRecord` ([#3360](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3360)) diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index dc7985b864f..b136e59c426 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md index 8a0a3f260ff..22bad645336 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + ## 1.3.0-rc.2 Released 2022-June-1 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index b04c352c41e..a68b5b9494a 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * Adds support for limiting the length and count of attributes exported from the OTLP exporter. These [Attribute Limits](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits) diff --git a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md index c9330f85220..97f7a2abd16 100644 --- a/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.ZPages/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + ## 1.0.0-rc9.4 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index 4196962db1f..d07671b0809 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + ## 1.3.0 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md index 93a35a7677d..76d47d93281 100644 --- a/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Hosting/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + ## 1.0.0-rc9.4 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md index b8ded0360f5..d4a09cab221 100644 --- a/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md +++ b/src/OpenTelemetry.Extensions.Propagators/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * Add `JaegerPropagator`. ([1881](https://github.com/open-telemetry/opentelemetry-dotnet/issues/1881)) diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md index 7e48cbf5487..7dd26e20f5d 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + * Fix Remote IP Address - NULL reference exception. ([#3481](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3481)) * Metrics instrumentation to correctly populate `http.flavor` tag. diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md index 2ca87b172f7..843828f26cb 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + ## 1.0.0-rc9.4 Released 2022-Jun-03 diff --git a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md index 1a5041471bc..20fb945c219 100644 --- a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + * Added `http.scheme` tag to tracing instrumentation. ([#3464](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3464)) diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md index 015fcd8f5b4..3f0e444a328 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + * Update the `ActivitySource.Name` from "OpenTelemetry.SqlClient" to "OpenTelemetry.Instrumentation.SqlClient". ([#3435](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3435)) diff --git a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md index aff4eaa3b30..4affe1b02a0 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md +++ b/src/OpenTelemetry.Shims.OpenTracing/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 1.0.0-rc9.5 + +Released 2022-Aug-02 + * Fix: Handling of OpenTracing spans when used in conjunction with legacy "Microsoft.AspNetCore.Hosting.HttpRequestIn" activities. ([#3509](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3506)) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index b62f0338902..fe70f994bad 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -5,6 +5,10 @@ * Use binary search for histograms with 50 or more supplied boundaries. ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) +## 1.4.0-alpha.1 + +Released 2022-Aug-02 + * `TracerProviderSDK` modified for spans with remote parent. For such spans activity will be created irrespective of SamplingResult, to maintain context propagation. From b5190727eb10ee7b75992753f28d55bcedfba0b8 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Tue, 2 Aug 2022 20:29:55 -0700 Subject: [PATCH 085/111] Nit cleanup (#3518) --- .../OpenTelemetry.Tests.Stress.Logs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj b/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj index ff88e203fb4..45c21139ba3 100644 --- a/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj +++ b/test/OpenTelemetry.Tests.Stress.Logs/OpenTelemetry.Tests.Stress.Logs.csproj @@ -3,7 +3,7 @@ Exe - net6.0;net5.0;netcoreapp3.1;net462 + net6.0;netcoreapp3.1;net462 From dad7f999b275a4e8f478a1baf6389b9bb21ad5bc Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Wed, 3 Aug 2022 10:16:31 -0700 Subject: [PATCH 086/111] Nit internal fixes for PrometheusExporter (#3525) --- .../PrometheusExporterMeterProviderBuilderExtensions.cs | 2 +- .../Internal/PrometheusExporter.cs | 6 +----- .../PrometheusHttpListener.cs | 2 +- .../PrometheusHttpListenerMeterProviderBuilderExtensions.cs | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs index 7039db2a369..25189d1aa37 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMeterProviderBuilderExtensions.cs @@ -50,7 +50,7 @@ private static MeterProviderBuilder AddPrometheusExporter(MeterProviderBuilder b { configure?.Invoke(options); - var exporter = new PrometheusExporter(scrapeEndpointPath: options.ScrapeEndpointPath, scrapeResponseCacheDurationMilliseconds: options.ScrapeResponseCacheDurationMilliseconds); + var exporter = new PrometheusExporter(scrapeResponseCacheDurationMilliseconds: options.ScrapeResponseCacheDurationMilliseconds); var reader = new BaseExportingMetricReader(exporter) { TemporalityPreference = MetricReaderTemporalityPreference.Cumulative, diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs index 93514ef4c97..b0d5a5eb7db 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusExporter.cs @@ -33,15 +33,13 @@ internal sealed class PrometheusExporter : BaseExporter, IPullMetricExpo /// /// Initializes a new instance of the class. /// - /// Scraping endpoint. /// /// The cache duration in milliseconds for scrape responses. Default value: 0. /// - public PrometheusExporter(string scrapeEndpointPath = null, int scrapeResponseCacheDurationMilliseconds = 0) + public PrometheusExporter(int scrapeResponseCacheDurationMilliseconds = 0) { Guard.ThrowIfOutOfRange(scrapeResponseCacheDurationMilliseconds, min: 0); - this.ScrapeEndpointPath = scrapeEndpointPath ?? "/metrics"; this.ScrapeResponseCacheDurationMilliseconds = scrapeResponseCacheDurationMilliseconds; this.CollectionManager = new PrometheusCollectionManager(this); } @@ -67,8 +65,6 @@ internal Func, ExportResult> OnExport internal int ScrapeResponseCacheDurationMilliseconds { get; } - internal string ScrapeEndpointPath { get; } - /// public override ExportResult Export(in Batch metrics) { diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs index 3bd122a7732..24707794140 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListener.cs @@ -43,7 +43,7 @@ public PrometheusHttpListener(PrometheusExporter exporter, PrometheusHttpListene this.exporter = exporter; - string path = this.exporter.ScrapeEndpointPath; + string path = options.ScrapeEndpointPath; if (!path.StartsWith("/")) { diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs index 6c0b7b75a41..e6fd9f82258 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs @@ -55,7 +55,7 @@ private static MeterProviderBuilder AddPrometheusHttpListener( { configure?.Invoke(options); - var exporter = new PrometheusExporter(scrapeEndpointPath: options.ScrapeEndpointPath); + var exporter = new PrometheusExporter(); var reader = new BaseExportingMetricReader(exporter) { From e60763cff020f8453f115570a4f47cd20fcfcae0 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 3 Aug 2022 15:27:54 -0700 Subject: [PATCH 087/111] Add Min and Max to Histograms --- .../Implementation/MetricItemExtensions.cs | 6 + .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 2 + src/OpenTelemetry/CHANGELOG.md | 4 + src/OpenTelemetry/Metrics/AggregationType.cs | 31 ++- .../ExplicitBucketHistogramConfiguration.cs | 2 +- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 8 +- src/OpenTelemetry/Metrics/Metric.cs | 19 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 222 ++++++++++++------ src/OpenTelemetry/Metrics/MetricReaderExt.cs | 6 +- src/OpenTelemetry/Metrics/MetricType.cs | 7 +- .../MetricTests.cs | 2 +- .../HttpClientTests.netcore31.cs | 2 +- .../Metrics/MetricTestData.cs | 16 ++ .../Metrics/MetricViewTests.cs | 73 ++++++ 14 files changed, 303 insertions(+), 97 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index fe21b8d058e..515d76d0ab8 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -237,6 +237,7 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: + case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram { @@ -254,6 +255,11 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) AddAttributes(metricPoint.Tags, dataPoint.Attributes); dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); + if (metric.MetricType == MetricType.HistogramWithMinMax) + { + dataPoint.Min = metricPoint.GetHistogramMin(); + dataPoint.Max = metricPoint.GetHistogramMax(); + } foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) { diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index a045a0ffba5..af7f98c1dca 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -12,6 +12,8 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index fe70f994bad..da136e377d0 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -5,6 +5,10 @@ * Use binary search for histograms with 50 or more supplied boundaries. ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) +* Make recording of `Min` and `Max` for histograms configurable, enabled by + default. + ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) + ## 1.4.0-alpha.1 Released 2022-Aug-02 diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index bd87c9e5b4f..104d04bf706 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using OpenTelemetry.Metrics; + namespace OpenTelemetry.Metrics { internal enum AggregationType @@ -54,13 +56,36 @@ internal enum AggregationType DoubleGauge = 5, /// - /// Histogram. + /// Histogram with sum, count, buckets. /// Histogram = 6, /// - /// Histogram with sum, count only. + /// Histogram with sum, count, min, max, buckets. + /// + HistogramMinMax = 7, + + /// + /// Histogram with sum, count. + /// + HistogramSumCount = 8, + + /// + /// Histogram with sum, count, min, max. /// - HistogramSumCount = 7, + HistogramSumCountMinMax = 9, + } +} + +#pragma warning disable SA1649 // File name should match first type name +internal static class AggregationTypeMethods +#pragma warning restore SA1649 // File name should match first type name +{ + public static bool IsHistogram(this AggregationType aggType) + { + return aggType == AggregationType.Histogram + || aggType == AggregationType.HistogramMinMax + || aggType == AggregationType.HistogramSumCount + || aggType == AggregationType.HistogramSumCountMinMax; } } diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index 58bfc245b10..8be618748fc 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -21,7 +21,7 @@ namespace OpenTelemetry.Metrics /// /// Stores configuration for a histogram metric stream with explicit bucket boundaries. /// - public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration + public class ExplicitBucketHistogramConfiguration : HistogramConfiguration { /// /// Gets or sets the optional boundaries of the histogram metric stream. diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index d45379fbc84..905877a6467 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -31,13 +31,17 @@ public class HistogramBuckets internal readonly double[] ExplicitBounds; internal readonly long[] RunningBucketCounts; - internal readonly long[] SnapshotBucketCounts; internal double RunningSum; - internal double SnapshotSum; + internal double RunningMin = double.PositiveInfinity; + internal double SnapshotMin; + + internal double RunningMax = double.NegativeInfinity; + internal double SnapshotMax; + internal int IsCriticalSectionOccupied = 0; private readonly BucketLookupNode bucketLookupTreeRoot; diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 61443173f70..83afa754176 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -34,7 +34,8 @@ internal Metric( AggregationTemporality temporality, int maxMetricPointsPerMetricStream, double[] histogramBounds = null, - string[] tagKeysInteresting = null) + string[] tagKeysInteresting = null, + bool histogramRecordMinMax = true) { this.InstrumentIdentity = instrumentIdentity; @@ -88,17 +89,11 @@ internal Metric( || instrumentIdentity.InstrumentType == typeof(Histogram) || instrumentIdentity.InstrumentType == typeof(Histogram)) { - this.MetricType = MetricType.Histogram; - - if (histogramBounds != null - && histogramBounds.Length == 0) - { - aggType = AggregationType.HistogramSumCount; - } - else - { - aggType = AggregationType.Histogram; - } + this.MetricType = histogramRecordMinMax ? MetricType.HistogramWithMinMax : MetricType.Histogram; + + aggType = histogramBounds != null && histogramBounds.Length == 0 + ? (histogramRecordMinMax ? AggregationType.HistogramSumCountMinMax : AggregationType.HistogramSumCount) + : (histogramRecordMinMax ? AggregationType.HistogramMinMax : AggregationType.Histogram); } else { diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 149f20bc8f8..c0b6ebba278 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -58,11 +58,13 @@ internal MetricPoint( this.deltaLastValue = default; this.MetricPointStatus = MetricPointStatus.NoCollectPending; - if (this.aggType == AggregationType.Histogram) + if (this.aggType == AggregationType.Histogram || + this.aggType == AggregationType.HistogramMinMax) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); } - else if (this.aggType == AggregationType.HistogramSumCount) + else if (this.aggType == AggregationType.HistogramSumCount || + this.aggType == AggregationType.HistogramSumCountMinMax) { this.histogramBuckets = new HistogramBuckets(null); } @@ -187,7 +189,7 @@ public readonly double GetGaugeLastValueDouble() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long GetHistogramCount() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (!this.aggType.IsHistogram()) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramCount)); } @@ -205,7 +207,7 @@ public readonly long GetHistogramCount() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetHistogramSum() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (!this.aggType.IsHistogram()) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramSum)); } @@ -223,7 +225,7 @@ public readonly double GetHistogramSum() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly HistogramBuckets GetHistogramBuckets() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (!this.aggType.IsHistogram()) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } @@ -231,6 +233,44 @@ public readonly HistogramBuckets GetHistogramBuckets() return this.histogramBuckets; } + /// + /// Gets the minimum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Minimum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMin() + { + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); + } + + return this.histogramBuckets.SnapshotMin; + } + + /// + /// Gets the maximum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Maximum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMax() + { + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); + } + + return this.histogramBuckets.SnapshotMax; + } + internal readonly MetricPoint Copy() { MetricPoint copy = this; @@ -261,7 +301,9 @@ internal void Update(long number) } case AggregationType.Histogram: + case AggregationType.HistogramMinMax: case AggregationType.HistogramSumCount: + case AggregationType.HistogramSumCountMinMax: { this.Update((double)number); break; @@ -324,50 +366,25 @@ internal void Update(double number) case AggregationType.Histogram: { - int i = this.histogramBuckets.FindBucketIndex(number); - - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - unchecked - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - this.histogramBuckets.RunningBucketCounts[i]++; - } - - this.histogramBuckets.IsCriticalSectionOccupied = 0; - break; - } - - sw.SpinOnce(); - } + this.HistogramUpdate(number, true, false); + break; + } + case AggregationType.HistogramMinMax: + { + this.HistogramUpdate(number, true, true); break; } case AggregationType.HistogramSumCount: { - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - unchecked - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - } - - this.histogramBuckets.IsCriticalSectionOccupied = 0; - break; - } - - sw.SpinOnce(); - } + this.HistogramUpdate(number, false, false); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramUpdate(number, false, true); break; } } @@ -487,46 +504,25 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - lock (this.histogramBuckets.LockObject) - { - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) - { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) - { - this.histogramBuckets.RunningBucketCounts[i] = 0; - } - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - } + this.HistogramSnapshot(outputDelta, true, false); + break; + } + case AggregationType.HistogramMinMax: + { + this.HistogramSnapshot(outputDelta, true, true); break; } case AggregationType.HistogramSumCount: { - lock (this.histogramBuckets.LockObject) - { - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - } + this.HistogramSnapshot(outputDelta, false, false); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramSnapshot(outputDelta, false, true); break; } } @@ -537,5 +533,81 @@ private readonly void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void HistogramUpdate(double number, bool hasBuckets, bool hasMinMax) + { + int i = hasBuckets + ? this.histogramBuckets.FindBucketIndex(number) + : 0; + + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + if (hasBuckets) + { + this.histogramBuckets.RunningBucketCounts[i]++; + } + + if (hasMinMax) + { + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + } + + this.histogramBuckets.IsCriticalSectionOccupied = 0; + break; + } + + sw.SpinOnce(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax) + { + lock (this.histogramBuckets.LockObject) + { + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + if (hasMinMax) + { + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + } + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + if (hasMinMax) + { + this.histogramBuckets.RunningMin = 0; + this.histogramBuckets.RunningMax = 0; + } + } + + if (hasBuckets) + { + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + } + } } } diff --git a/src/OpenTelemetry/Metrics/MetricReaderExt.cs b/src/OpenTelemetry/Metrics/MetricReaderExt.cs index c8cb0db0a0e..6d7342b597a 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderExt.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderExt.cs @@ -157,7 +157,11 @@ internal List AddMetricsListWithViews(Instrument instrument, List Histogram = 0x40, + + /// + /// Histogram with minimum and maximum values. + /// + HistogramWithMinMax = 0x50, } } diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 53bac48facc..b2dfc036d28 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -80,7 +80,7 @@ public async Task RequestMetricIsCaptured() var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index 05c39935426..94d2ab171ca 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -142,7 +142,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 0664dc18c00..f1a2b517a93 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -49,5 +49,21 @@ public static IEnumerable InvalidHistogramBoundaries new object[] { new double[] { 0, 1, 1, 2 } }, new object[] { new double[] { 0, 1, 2, -1 } }, }; + + public static IEnumerable ValidHistogramMinMax + => new List + { + new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, + new object[] { new double[] { double.NegativeInfinity, 0, double.PositiveInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.PositiveInfinity }, + new object[] { new double[] { 1 }, new HistogramConfiguration(), 1, 1 }, + new object[] { new double[] { 5, 100, 4, 101, -2, 97 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } }, -2, 101 }, + }; + + public static IEnumerable InvalidHistogramMinMax + => new List + { + new object[] { new double[] { 1 }, new HistogramConfiguration() { RecordMinMax = false } }, + new object[] { new double[] { 1 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, RecordMinMax = false } }, + }; } } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 3a12cd4ac05..323c87abaf2 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -572,6 +572,79 @@ public void ViewToProduceCustomHistogramBound() Assert.Equal(boundaries.Length + 1, actualCount); } + [Theory] + [MemberData(nameof(MetricTestData.ValidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView(histogram.Name, histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + Assert.Single(exportedItems); + var metric1 = exportedItems[0]; + + Assert.Equal("MyHistogram", metric1.Name); + + var metricPoints = new List(); + foreach (ref readonly var mp in metric1.GetMetricPoints()) + { + metricPoints.Add(mp); + } + + Assert.Single(metricPoints); + var metricPoint = metricPoints[0]; + + Assert.Equal(expectedMin, metricPoint.GetHistogramMin()); + Assert.Equal(expectedMax, metricPoint.GetHistogramMax()); + } + + [Theory] + [MemberData(nameof(MetricTestData.InvalidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView(histogram.Name, histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + var metricPoints = new List(); + foreach (ref readonly var mp in exportedItems[0].GetMetricPoints()) + { + metricPoints.Add(mp); + } + + var histogramPoint = metricPoints[0]; + + var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMin)} is not supported for this metric type.", ex.Message); + + ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMax)} is not supported for this metric type.", ex.Message); + } + [Fact] public void ViewToSelectTagKeys() { From 9693e39e94bc2bb4232253c44d28ba5ae43ff7c2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 3 Aug 2022 15:28:51 -0700 Subject: [PATCH 088/111] Forgot HistogramConfiguration.cs file --- .../Metrics/HistogramConfiguration.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/OpenTelemetry/Metrics/HistogramConfiguration.cs diff --git a/src/OpenTelemetry/Metrics/HistogramConfiguration.cs b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs new file mode 100644 index 00000000000..37980098937 --- /dev/null +++ b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs @@ -0,0 +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. +// + +namespace OpenTelemetry.Metrics; + +public class HistogramConfiguration : MetricStreamConfiguration +{ + /// + /// Gets or sets a value indicating whether Min, Max + /// should be collected. + /// + public bool RecordMinMax { get; set; } = true; +} From efb9aea2ec07a981dbba775aee47ff5766383827 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 3 Aug 2022 17:30:57 -0700 Subject: [PATCH 089/111] publicApi --- .../.publicApi/net462/PublicAPI.Unshipped.txt | 7 +++++++ .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 5 +++++ .../.publicApi/netstandard2.0/PublicAPI.Unshipped.txt | 7 +++++++ .../.publicApi/netstandard2.1/PublicAPI.Unshipped.txt | 7 +++++++ 4 files changed, 26 insertions(+) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 791e1c4f84a..2ac9779135e 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -11,6 +11,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index af7f98c1dca..419bbd9a289 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -12,8 +12,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, bool disposeProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 791e1c4f84a..2ac9779135e 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -11,6 +11,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMillisecond OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index a045a0ffba5..ef547e28ab4 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -11,6 +11,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType *REMOVED*static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, System.Action? configure = null) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder) -> Microsoft.Extensions.Logging.ILoggingBuilder! static Microsoft.Extensions.Logging.OpenTelemetryLoggingExtensions.AddOpenTelemetry(this Microsoft.Extensions.Logging.ILoggingBuilder! builder, OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider) -> Microsoft.Extensions.Logging.ILoggingBuilder! From 4e58feffcbf95bd3ad120ce250a989f813b7b9d7 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 2 Sep 2022 12:40:54 -0700 Subject: [PATCH 090/111] bump --- src/OpenTelemetry/Metrics/MetricPoint.cs | 52 ++---------------------- src/OpenTelemetry/Metrics/MetricType.cs | 2 +- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index f5eb6676287..c52b5eed536 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -215,54 +215,6 @@ public readonly double GetHistogramSum() return this.histogramBuckets.SnapshotSum; } - /// - /// Gets the minimum value of the histogram associated with the metric point. - /// - /// - /// Applies to metric type. - /// - /// Minimum value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public double GetHistogramMin() - { - if (this.aggType != AggregationType.HistogramMinMax && - this.aggType != AggregationType.HistogramSumCountMinMax) - { - this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); - } - - if (this.runningValue.AsLong == 0) - { - throw new InvalidOperationException("No values have been recorded yet."); - } - - return this.histogramBuckets.SnapshotMin; - } - - /// - /// Gets the maximum value of the histogram associated with the metric point. - /// - /// - /// Applies to metric type. - /// - /// Maximum value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public double GetHistogramMax() - { - if (this.aggType != AggregationType.HistogramMinMax && - this.aggType != AggregationType.HistogramSumCountMinMax) - { - this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); - } - - if (this.runningValue.AsLong == 0) - { - throw new InvalidOperationException("No values have been recorded yet."); - } - - return this.histogramBuckets.SnapshotMax; - } - /// /// Gets the buckets of the histogram associated with the metric point. /// @@ -419,6 +371,7 @@ internal void Update(double number) this.HistogramUpdate(number, true, false); break; } + case AggregationType.HistogramMinMax: { this.HistogramUpdate(number, true, true); @@ -430,6 +383,7 @@ internal void Update(double number) this.HistogramUpdate(number, false, false); break; } + case AggregationType.HistogramSumCountMinMax: { this.HistogramUpdate(number, false, true); @@ -555,6 +509,7 @@ internal void TakeSnapshot(bool outputDelta) this.HistogramSnapshot(outputDelta, true, false); break; } + case AggregationType.HistogramMinMax: { this.HistogramSnapshot(outputDelta, true, true); @@ -566,6 +521,7 @@ internal void TakeSnapshot(bool outputDelta) this.HistogramSnapshot(outputDelta, false, false); break; } + case AggregationType.HistogramSumCountMinMax: { this.HistogramSnapshot(outputDelta, false, true); diff --git a/src/OpenTelemetry/Metrics/MetricType.cs b/src/OpenTelemetry/Metrics/MetricType.cs index b200399d6f2..dbf759f0d49 100644 --- a/src/OpenTelemetry/Metrics/MetricType.cs +++ b/src/OpenTelemetry/Metrics/MetricType.cs @@ -75,7 +75,7 @@ public enum MetricType : byte /// HistogramWithMinMax = 0x50, - /// + /// /// Non-monotonic Sum of Long type. /// LongSumNonMonotonic = 0x8a, From 87dd2990add4698db14965a8d386174b0da88322 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 2 Sep 2022 12:52:04 -0700 Subject: [PATCH 091/111] Delete PublicAPI.Unshipped.txt --- .../.publicApi/net461/PublicAPI.Unshipped.txt | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100644 src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt diff --git a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt deleted file mode 100644 index b8e5a0156c7..00000000000 --- a/src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt +++ /dev/null @@ -1,149 +0,0 @@ -OpenTelemetry.BaseExporter.ForceFlush(int timeoutMilliseconds = -1) -> bool -OpenTelemetry.Batch.Batch(T[] items, int count) -> void -OpenTelemetry.Batch.Count.get -> long -OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.AggregationTemporality.Cumulative = 1 -> OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.AggregationTemporality.Delta = 2 -> OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.AggregationTemporalityAttribute -OpenTelemetry.Metrics.AggregationTemporalityAttribute.AggregationTemporalityAttribute(OpenTelemetry.Metrics.AggregationTemporality temporality) -> void -OpenTelemetry.Metrics.AggregationTemporalityAttribute.Temporality.get -> OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.BaseExportingMetricReader -OpenTelemetry.Metrics.BaseExportingMetricReader.BaseExportingMetricReader(OpenTelemetry.BaseExporter exporter) -> void -OpenTelemetry.Metrics.BaseExportingMetricReader.SupportedExportModes.get -> OpenTelemetry.Metrics.ExportModes -OpenTelemetry.Metrics.HistogramBucket -OpenTelemetry.Metrics.HistogramBucket.BucketCount.get -> long -OpenTelemetry.Metrics.HistogramBucket.ExplicitBound.get -> double -OpenTelemetry.Metrics.HistogramBucket.HistogramBucket() -> void -OpenTelemetry.Metrics.HistogramBuckets -OpenTelemetry.Metrics.HistogramBuckets.Enumerator -OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Current.get -> OpenTelemetry.Metrics.HistogramBucket -OpenTelemetry.Metrics.HistogramBuckets.Enumerator.Enumerator() -> void -OpenTelemetry.Metrics.HistogramBuckets.Enumerator.MoveNext() -> bool -OpenTelemetry.Metrics.HistogramBuckets.GetEnumerator() -> OpenTelemetry.Metrics.HistogramBuckets.Enumerator -OpenTelemetry.Metrics.HistogramConfiguration -OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void -OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool -OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.EndTime.get -> System.DateTimeOffset -OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double -OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double -OpenTelemetry.Metrics.MetricPoint.GetSumDouble() -> double -OpenTelemetry.Metrics.MetricPoint.GetSumLong() -> long -OpenTelemetry.Metrics.MetricPoint.GetGaugeLastValueDouble() -> double -OpenTelemetry.Metrics.MetricPoint.GetGaugeLastValueLong() -> long -OpenTelemetry.Metrics.MetricPoint.GetHistogramBuckets() -> OpenTelemetry.Metrics.HistogramBuckets -OpenTelemetry.Metrics.MetricPoint.StartTime.get -> System.DateTimeOffset -OpenTelemetry.Metrics.MetricPointsAccessor -OpenTelemetry.Metrics.MetricPointsAccessor.MetricPointsAccessor() -> void -OpenTelemetry.Metrics.MetricPointsAccessor.Enumerator -OpenTelemetry.Metrics.MetricPointsAccessor.Enumerator.Current.get -> OpenTelemetry.Metrics.MetricPoint -OpenTelemetry.Metrics.MetricPointsAccessor.Enumerator.Enumerator() -> void -OpenTelemetry.Metrics.MetricPointsAccessor.Enumerator.MoveNext() -> bool -OpenTelemetry.Metrics.MetricPointsAccessor.GetEnumerator() -> OpenTelemetry.Metrics.MetricPointsAccessor.Enumerator -OpenTelemetry.Metrics.ExportModes -OpenTelemetry.Metrics.ExportModes.Pull = 2 -> OpenTelemetry.Metrics.ExportModes -OpenTelemetry.Metrics.ExportModes.Push = 1 -> OpenTelemetry.Metrics.ExportModes -OpenTelemetry.Metrics.ExportModesAttribute -OpenTelemetry.Metrics.ExportModesAttribute.ExportModesAttribute(OpenTelemetry.Metrics.ExportModes supported) -> void -OpenTelemetry.Metrics.ExportModesAttribute.Supported.get -> OpenTelemetry.Metrics.ExportModes -OpenTelemetry.Metrics.ExplicitBucketHistogramConfiguration -OpenTelemetry.Metrics.ExplicitBucketHistogramConfiguration.Boundaries.get -> double[] -OpenTelemetry.Metrics.ExplicitBucketHistogramConfiguration.Boundaries.set -> void -OpenTelemetry.Metrics.ExplicitBucketHistogramConfiguration.ExplicitBucketHistogramConfiguration() -> void -OpenTelemetry.Metrics.IPullMetricExporter -OpenTelemetry.Metrics.IPullMetricExporter.Collect.get -> System.Func -OpenTelemetry.Metrics.IPullMetricExporter.Collect.set -> void -OpenTelemetry.Metrics.MeterProviderBuilderBase -OpenTelemetry.Metrics.MeterProviderBuilderBase.Build() -> OpenTelemetry.Metrics.MeterProvider -OpenTelemetry.Metrics.MeterProviderBuilderBase.MeterProviderBuilderBase() -> void -OpenTelemetry.Metrics.MeterProviderBuilderExtensions -OpenTelemetry.Metrics.MeterProviderExtensions -OpenTelemetry.Metrics.Metric -OpenTelemetry.Metrics.Metric.Description.get -> string -OpenTelemetry.Metrics.Metric.GetMetricPoints() -> OpenTelemetry.Metrics.MetricPointsAccessor -OpenTelemetry.Metrics.Metric.Meter.get -> System.Diagnostics.Metrics.Meter -OpenTelemetry.Metrics.Metric.MetricType.get -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.Metric.Name.get -> string -OpenTelemetry.Metrics.Metric.Temporality.get -> OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.Metric.Unit.get -> string -OpenTelemetry.Metrics.MetricPoint -OpenTelemetry.Metrics.MetricPoint.GetHistogramCount() -> long -OpenTelemetry.Metrics.MetricPoint.GetHistogramSum() -> double -OpenTelemetry.Metrics.MetricPoint.MetricPoint() -> void -OpenTelemetry.Metrics.MetricPoint.Tags.get -> OpenTelemetry.ReadOnlyTagCollection -OpenTelemetry.Metrics.MetricReader -OpenTelemetry.Metrics.MetricReader.Collect(int timeoutMilliseconds = -1) -> bool -OpenTelemetry.Metrics.MetricReader.Dispose() -> void -OpenTelemetry.Metrics.MetricReader.MetricReader() -> void -OpenTelemetry.Metrics.MetricReader.Shutdown(int timeoutMilliseconds = -1) -> bool -OpenTelemetry.Metrics.MetricReader.Temporality.get -> OpenTelemetry.Metrics.AggregationTemporality -OpenTelemetry.Metrics.MetricReader.Temporality.set -> void -OpenTelemetry.Metrics.MetricReaderType -OpenTelemetry.Metrics.MetricReaderType.Manual = 0 -> OpenTelemetry.Metrics.MetricReaderType -OpenTelemetry.Metrics.MetricReaderType.Periodic = 1 -> OpenTelemetry.Metrics.MetricReaderType -OpenTelemetry.Metrics.MetricStreamConfiguration -OpenTelemetry.Metrics.MetricStreamConfiguration.Description.get -> string -OpenTelemetry.Metrics.MetricStreamConfiguration.Description.set -> void -OpenTelemetry.Metrics.MetricStreamConfiguration.MetricStreamConfiguration() -> void -OpenTelemetry.Metrics.MetricStreamConfiguration.Name.get -> string -OpenTelemetry.Metrics.MetricStreamConfiguration.Name.set -> void -OpenTelemetry.Metrics.MetricStreamConfiguration.TagKeys.get -> string[] -OpenTelemetry.Metrics.MetricStreamConfiguration.TagKeys.set -> void -OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.DoubleGauge = 45 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.DoubleSum = 29 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.Histogram = 64 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.LongGauge = 42 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricType.LongSum = 26 -> OpenTelemetry.Metrics.MetricType -OpenTelemetry.Metrics.MetricTypeExtensions -OpenTelemetry.Metrics.PeriodicExportingMetricReader -OpenTelemetry.Metrics.PeriodicExportingMetricReader.PeriodicExportingMetricReader(OpenTelemetry.BaseExporter exporter, int exportIntervalMilliseconds = 60000, int exportTimeoutMilliseconds = 30000) -> void -OpenTelemetry.Metrics.PeriodicExportingMetricReaderOptions -OpenTelemetry.Metrics.PeriodicExportingMetricReaderOptions.PeriodicExportingMetricReaderOptions() -> void -OpenTelemetry.Metrics.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds.get -> int -OpenTelemetry.Metrics.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds.set -> void -OpenTelemetry.ReadOnlyTagCollection -OpenTelemetry.ReadOnlyTagCollection.Count.get -> int -OpenTelemetry.ReadOnlyTagCollection.Enumerator -OpenTelemetry.ReadOnlyTagCollection.Enumerator.Current.get -> System.Collections.Generic.KeyValuePair -OpenTelemetry.ReadOnlyTagCollection.Enumerator.Enumerator() -> void -OpenTelemetry.ReadOnlyTagCollection.Enumerator.MoveNext() -> bool -OpenTelemetry.ReadOnlyTagCollection.GetEnumerator() -> OpenTelemetry.ReadOnlyTagCollection.Enumerator -OpenTelemetry.ReadOnlyTagCollection.ReadOnlyTagCollection() -> void -OpenTelemetry.Resources.IResourceDetector -OpenTelemetry.Resources.IResourceDetector.Detect() -> OpenTelemetry.Resources.Resource -OpenTelemetry.Trace.BatchExportActivityProcessorOptions -OpenTelemetry.Trace.BatchExportActivityProcessorOptions.BatchExportActivityProcessorOptions() -> void -override OpenTelemetry.BaseExportProcessor.OnForceFlush(int timeoutMilliseconds) -> bool -override OpenTelemetry.BatchExportProcessor.Dispose(bool disposing) -> void -override OpenTelemetry.Metrics.BaseExportingMetricReader.Dispose(bool disposing) -> void -override OpenTelemetry.Metrics.BaseExportingMetricReader.OnCollect(int timeoutMilliseconds) -> bool -override OpenTelemetry.Metrics.BaseExportingMetricReader.OnShutdown(int timeoutMilliseconds) -> bool -override OpenTelemetry.Metrics.MeterProviderBuilderBase.AddInstrumentation(System.Func instrumentationFactory) -> OpenTelemetry.Metrics.MeterProviderBuilder -override OpenTelemetry.Metrics.MeterProviderBuilderBase.AddMeter(params string[] names) -> OpenTelemetry.Metrics.MeterProviderBuilder -override OpenTelemetry.Metrics.PeriodicExportingMetricReader.Dispose(bool disposing) -> void -override OpenTelemetry.Metrics.PeriodicExportingMetricReader.OnShutdown(int timeoutMilliseconds) -> bool -readonly OpenTelemetry.Metrics.BaseExportingMetricReader.exporter -> OpenTelemetry.BaseExporter -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddReader(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, OpenTelemetry.Metrics.MetricReader reader) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, string instrumentName, OpenTelemetry.Metrics.MetricStreamConfiguration metricStreamConfiguration) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, string instrumentName, string name) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Func viewConfig) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Build(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProvider -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricPointsPerMetricStream(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricStreams(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricStreams) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.MeterProviderExtensions.ForceFlush(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool -static OpenTelemetry.Metrics.MeterProviderExtensions.Shutdown(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool -static OpenTelemetry.Metrics.MeterProviderExtensions.TryFindExporter(this OpenTelemetry.Metrics.MeterProvider provider, out T exporter) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsDouble(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsGauge(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsHistogram(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsLong(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Metrics.MetricTypeExtensions.IsSum(this OpenTelemetry.Metrics.MetricType self) -> bool -static OpenTelemetry.Sdk.CreateMeterProviderBuilder() -> OpenTelemetry.Metrics.MeterProviderBuilder -static readonly OpenTelemetry.Metrics.MetricStreamConfiguration.Drop -> OpenTelemetry.Metrics.MetricStreamConfiguration -virtual OpenTelemetry.BaseExporter.OnForceFlush(int timeoutMilliseconds) -> bool -virtual OpenTelemetry.Metrics.MetricReader.Dispose(bool disposing) -> void -virtual OpenTelemetry.Metrics.MetricReader.OnCollect(int timeoutMilliseconds) -> bool -virtual OpenTelemetry.Metrics.MetricReader.OnShutdown(int timeoutMilliseconds) -> bool From 24dceb82556962bcb9757b1b82f0c5e50c69e910 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 2 Sep 2022 14:30:41 -0700 Subject: [PATCH 092/111] undo --- src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt | 1 - src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt | 1 - src/OpenTelemetry/Metrics/MetricTypeExtensions.cs | 2 +- test/Benchmarks/Metrics/HistogramBenchmarks.cs | 1 + 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 2c4a0dc2ee2..3030905636c 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -20,7 +20,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BasePr OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 3030905636c..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -19,7 +19,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool diff --git a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs index 6ee8a9db3bf..595886e6cfd 100644 --- a/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs +++ b/src/OpenTelemetry/Metrics/MetricTypeExtensions.cs @@ -26,7 +26,7 @@ public static class MetricTypeExtensions internal const MetricType METRIC_TYPE_MONOTONIC_SUM = (MetricType)0x10; internal const MetricType METRIC_TYPE_GAUGE = (MetricType)0x20; - /* internal const MetricType METRIC_TYPE_SUMMARY = 0x30; // not used */ + /* internal const byte METRIC_TYPE_SUMMARY = 0x30; // not used */ internal const MetricType METRIC_TYPE_HISTOGRAM = (MetricType)0x40; internal const MetricType METRIC_TYPE_NON_MONOTONIC_SUM = (MetricType)0x80; diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 97d95df6317..1b88fdd53ba 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -30,6 +30,7 @@ [Host] : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT DefaultJob : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT + | Method | BoundCount | Mean | Error | StdDev | |---------------------------- |----------- |----------:|----------:|----------:| | HistogramHotPath | 10 | 45.19 ns | 0.321 ns | 0.285 ns | From d1221983760460f89d56983290df16635d671011 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 2 Sep 2022 15:41:47 -0700 Subject: [PATCH 093/111] fix --- .../netstandard2.1/PublicAPI.Unshipped.txt | 1 - test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 3030905636c..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -19,7 +19,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index b3cecb30f9c..f419759d036 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -1198,18 +1198,5 @@ public void ViewConflict_TwoInstruments_ConflictAvoidedBecauseSecondInstrumentIs Assert.Equal("othername", exportedItems[0].Name); Assert.Equal(10, GetLongSum(metric1)); } - - [Fact] - public void GetHistogramMinThrows() - { - AggregatorStore aggregatorStore = new("test", AggregationType.HistogramMinMax, AggregationTemporality.Cumulative, 1024, Metric.DefaultHistogramBounds); - var histogramPoint = new MetricPoint(aggregatorStore, AggregationType.HistogramMinMax, null, null, new double[] { 0 }); - - var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); - Assert.Equal("No values have been recorded yet.", ex.Message); - - ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); - Assert.Equal("No values have been recorded yet.", ex.Message); - } } } From f834a90d7d9d06ec970a920c310b76680a75140e Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 2 Sep 2022 17:27:16 -0700 Subject: [PATCH 094/111] Update PublicAPI.Unshipped.txt --- src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 3030905636c..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -19,7 +19,6 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool From 637225f2df3fa89dacf8ddc6d08975af011b62f4 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 6 Sep 2022 11:05:10 -0700 Subject: [PATCH 095/111] Update MetricPoint.cs --- src/OpenTelemetry/Metrics/MetricPoint.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index c52b5eed536..ddf0e69e926 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -585,6 +585,12 @@ private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax // Lock acquired this.snapshotValue.AsLong = this.runningValue.AsLong; this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + if (hasMinMax) + { + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + } + if (outputDelta) { this.runningValue.AsLong = 0; @@ -596,12 +602,6 @@ private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax } } - if (hasMinMax) - { - this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; - this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; - } - if (hasBuckets) { for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) From 922d19ab8d20be1636ea70cfaf870ce62a73d6fc Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 7 Sep 2022 14:58:22 -0700 Subject: [PATCH 096/111] Initial upload --- .../Implementation/MetricItemExtensions.cs | 6 + .../.publicApi/net462/PublicAPI.Unshipped.txt | 7 + .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 7 + .../netstandard2.0/PublicAPI.Unshipped.txt | 7 + .../netstandard2.1/PublicAPI.Unshipped.txt | 7 + src/OpenTelemetry/CHANGELOG.md | 3 + src/OpenTelemetry/Metrics/AggregationType.cs | 14 +- .../ExplicitBucketHistogramConfiguration.cs | 2 +- src/OpenTelemetry/Metrics/HistogramBuckets.cs | 6 + src/OpenTelemetry/Metrics/Metric.cs | 9 +- src/OpenTelemetry/Metrics/MetricPoint.cs | 271 +++++++++++------- src/OpenTelemetry/Metrics/MetricReaderExt.cs | 4 +- src/OpenTelemetry/Metrics/MetricType.cs | 7 +- .../MetricTests.cs | 2 +- .../HttpClientTests.cs | 2 +- .../Metrics/MetricTestData.cs | 16 ++ .../Metrics/MetricViewTests.cs | 69 +++++ 17 files changed, 326 insertions(+), 113 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 4933871e7b2..8f472c537ec 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -239,6 +239,7 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: + case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram { @@ -256,6 +257,11 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) AddAttributes(metricPoint.Tags, dataPoint.Attributes); dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); + if (metric.MetricType == MetricType.HistogramWithMinMax) + { + dataPoint.Min = metricPoint.GetHistogramMin(); + dataPoint.Max = metricPoint.GetHistogramMax(); + } foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) { diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 9463e1c3aaf..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -19,6 +19,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string traceStateString) -> void ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable> attributes, string traceStateString) -> void diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 9463e1c3aaf..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -19,6 +19,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string traceStateString) -> void ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable> attributes, string traceStateString) -> void diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index f6977a98165..454a660e3e2 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -19,6 +19,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BasePr OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string traceStateString) -> void ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable> attributes, string traceStateString) -> void diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 9463e1c3aaf..c9c357345cf 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -19,6 +19,13 @@ OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void +OpenTelemetry.Metrics.HistogramConfiguration +OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool +OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType ~OpenTelemetry.Trace.SamplingResult.TraceStateString.get -> string ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, string traceStateString) -> void ~OpenTelemetry.Trace.SamplingResult.SamplingResult(OpenTelemetry.Trace.SamplingDecision decision, System.Collections.Generic.IEnumerable> attributes, string traceStateString) -> void diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 3c83f2bb6be..ae0d13ffe36 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Recording `Min` and `Max` for histograms is configurable, enabled by default. + ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) + * Use binary search for histograms with 50 or more supplied boundaries. ([#3252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3252)) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index bd87c9e5b4f..beec3fe6966 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -54,13 +54,23 @@ internal enum AggregationType DoubleGauge = 5, /// - /// Histogram. + /// Histogram with sum, count, buckets. /// Histogram = 6, /// - /// Histogram with sum, count only. + /// Histogram with sum, count. /// HistogramSumCount = 7, + + /// + /// Histogram with sum, count, min, max, buckets. + /// + HistogramMinMax = 8, + + /// + /// Histogram with sum, count, min, max. + /// + HistogramSumCountMinMax = 9, } } diff --git a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs index 58bfc245b10..8be618748fc 100644 --- a/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs +++ b/src/OpenTelemetry/Metrics/ExplicitBucketHistogramConfiguration.cs @@ -21,7 +21,7 @@ namespace OpenTelemetry.Metrics /// /// Stores configuration for a histogram metric stream with explicit bucket boundaries. /// - public class ExplicitBucketHistogramConfiguration : MetricStreamConfiguration + public class ExplicitBucketHistogramConfiguration : HistogramConfiguration { /// /// Gets or sets the optional boundaries of the histogram metric stream. diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 2a2149b31b0..4f481c61f4c 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -38,6 +38,12 @@ public class HistogramBuckets internal double SnapshotSum; + internal double RunningMin = double.PositiveInfinity; + internal double SnapshotMin; + + internal double RunningMax = double.NegativeInfinity; + internal double SnapshotMax; + internal int IsCriticalSectionOccupied = 0; private readonly BucketLookupNode bucketLookupTreeRoot; diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 51e8df9b7ac..595c67f3213 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -34,7 +34,8 @@ internal Metric( AggregationTemporality temporality, int maxMetricPointsPerMetricStream, double[] histogramBounds = null, - string[] tagKeysInteresting = null) + string[] tagKeysInteresting = null, + bool histogramRecordMinMax = true) { this.InstrumentIdentity = instrumentIdentity; @@ -116,16 +117,16 @@ internal Metric( || instrumentIdentity.InstrumentType == typeof(Histogram) || instrumentIdentity.InstrumentType == typeof(Histogram)) { - this.MetricType = MetricType.Histogram; + this.MetricType = histogramRecordMinMax ? MetricType.HistogramWithMinMax : MetricType.Histogram; if (histogramBounds != null && histogramBounds.Length == 0) { - aggType = AggregationType.HistogramSumCount; + aggType = histogramRecordMinMax ? AggregationType.HistogramSumCountMinMax : AggregationType.HistogramSumCount; } else { - aggType = AggregationType.Histogram; + aggType = histogramRecordMinMax ? AggregationType.HistogramMinMax : AggregationType.Histogram; } } else diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 55abb65b9c5..fbcd0c7b785 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -58,11 +58,13 @@ internal MetricPoint( this.deltaLastValue = default; this.MetricPointStatus = MetricPointStatus.NoCollectPending; - if (this.aggType == AggregationType.Histogram) + if (this.aggType == AggregationType.Histogram || + this.aggType == AggregationType.HistogramMinMax) { this.histogramBuckets = new HistogramBuckets(histogramExplicitBounds); } - else if (this.aggType == AggregationType.HistogramSumCount) + else if (this.aggType == AggregationType.HistogramSumCount || + this.aggType == AggregationType.HistogramSumCountMinMax) { this.histogramBuckets = new HistogramBuckets(null); } @@ -187,7 +189,10 @@ public readonly double GetGaugeLastValueDouble() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly long GetHistogramCount() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramCount)); } @@ -205,7 +210,10 @@ public readonly long GetHistogramCount() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly double GetHistogramSum() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramSum)); } @@ -223,7 +231,10 @@ public readonly double GetHistogramSum() [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly HistogramBuckets GetHistogramBuckets() { - if (this.aggType != AggregationType.Histogram && this.aggType != AggregationType.HistogramSumCount) + if (this.aggType != AggregationType.Histogram && + this.aggType != AggregationType.HistogramSumCount && + this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) { this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramBuckets)); } @@ -231,6 +242,44 @@ public readonly HistogramBuckets GetHistogramBuckets() return this.histogramBuckets; } + /// + /// Gets the minimum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Minimum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMin() + { + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); + } + + return this.histogramBuckets.SnapshotMin; + } + + /// + /// Gets the maximum value of the histogram associated with the metric point. + /// + /// + /// Applies to metric type. + /// + /// Maximum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double GetHistogramMax() + { + if (this.aggType != AggregationType.HistogramMinMax && + this.aggType != AggregationType.HistogramSumCountMinMax) + { + this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); + } + + return this.histogramBuckets.SnapshotMax; + } + internal readonly MetricPoint Copy() { MetricPoint copy = this; @@ -262,6 +311,8 @@ internal void Update(long number) case AggregationType.Histogram: case AggregationType.HistogramSumCount: + case AggregationType.HistogramMinMax: + case AggregationType.HistogramSumCountMinMax: { this.Update((double)number); @@ -326,54 +377,25 @@ internal void Update(double number) case AggregationType.Histogram: { - int i = this.histogramBuckets.FindBucketIndex(number); - - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - unchecked - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - this.histogramBuckets.RunningBucketCounts[i]++; - } - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } - - sw.SpinOnce(); - } - + this.HistogramUpdate(number, true, false); break; } case AggregationType.HistogramSumCount: { - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - unchecked - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - } - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } + this.HistogramUpdate(number, false, false); + break; + } - sw.SpinOnce(); - } + case AggregationType.HistogramMinMax: + { + this.HistogramUpdate(number, true, true); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramUpdate(number, false, true); break; } } @@ -493,68 +515,25 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) - { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) - { - this.histogramBuckets.RunningBucketCounts[i] = 0; - } - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } - - sw.SpinOnce(); - } - + this.HistogramSnapshot(outputDelta, true, false); break; } case AggregationType.HistogramSumCount: { - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (outputDelta) - { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - } - - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } + this.HistogramSnapshot(outputDelta, false, false); + break; + } - sw.SpinOnce(); - } + case AggregationType.HistogramMinMax: + { + this.HistogramSnapshot(outputDelta, true, true); + break; + } + case AggregationType.HistogramSumCountMinMax: + { + this.HistogramSnapshot(outputDelta, false, true); break; } } @@ -565,5 +544,95 @@ private readonly void ThrowNotSupportedMetricTypeException(string methodName) { throw new NotSupportedException($"{methodName} is not supported for this metric type."); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void HistogramUpdate(double number, bool hasBuckets, bool hasMinMax) + { + int i = hasBuckets + ? this.histogramBuckets.FindBucketIndex(number) + : 0; + + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + if (hasBuckets) + { + this.histogramBuckets.RunningBucketCounts[i]++; + } + + if (hasMinMax) + { + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + } + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax) + { + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + if (hasMinMax) + { + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + } + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + + if (hasMinMax) + { + this.histogramBuckets.RunningMin = 0; + this.histogramBuckets.RunningMax = 0; + } + } + + if (hasBuckets) + { + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + } } } diff --git a/src/OpenTelemetry/Metrics/MetricReaderExt.cs b/src/OpenTelemetry/Metrics/MetricReaderExt.cs index c8cb0db0a0e..064e3e3df04 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderExt.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderExt.cs @@ -156,8 +156,8 @@ internal List AddMetricsListWithViews(Instrument instrument, List Histogram = 0x40, + /// + /// Histogram with minimum and maximum values. + /// + HistogramWithMinMax = 0x50, + /// /// Non-monotonic Sum of Long type. /// diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 2b597048008..183bf4fd77d 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -74,7 +74,7 @@ public async Task RequestMetricIsCaptured() var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs index 7407e134527..2d802d40955 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs @@ -139,7 +139,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.Histogram); + Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index 0664dc18c00..f1a2b517a93 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -49,5 +49,21 @@ public static IEnumerable InvalidHistogramBoundaries new object[] { new double[] { 0, 1, 1, 2 } }, new object[] { new double[] { 0, 1, 2, -1 } }, }; + + public static IEnumerable ValidHistogramMinMax + => new List + { + new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, + new object[] { new double[] { double.NegativeInfinity, 0, double.PositiveInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.PositiveInfinity }, + new object[] { new double[] { 1 }, new HistogramConfiguration(), 1, 1 }, + new object[] { new double[] { 5, 100, 4, 101, -2, 97 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } }, -2, 101 }, + }; + + public static IEnumerable InvalidHistogramMinMax + => new List + { + new object[] { new double[] { 1 }, new HistogramConfiguration() { RecordMinMax = false } }, + new object[] { new double[] { 1 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, RecordMinMax = false } }, + }; } } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 3a12cd4ac05..f419759d036 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -572,6 +572,75 @@ public void ViewToProduceCustomHistogramBound() Assert.Equal(boundaries.Length + 1, actualCount); } + [Theory] + [MemberData(nameof(MetricTestData.ValidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMax(double[] values, HistogramConfiguration histogramConfiguration, double expectedMin, double expectedMax) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView(histogram.Name, histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + var metricPoints = new List(); + foreach (ref readonly var mp in exportedItems[0].GetMetricPoints()) + { + metricPoints.Add(mp); + } + + var histogramPoint = metricPoints[0]; + var min = histogramPoint.GetHistogramMin(); + var max = histogramPoint.GetHistogramMax(); + + Assert.Equal(expectedMin, min); + Assert.Equal(expectedMax, max); + } + + [Theory] + [MemberData(nameof(MetricTestData.InvalidHistogramMinMax), MemberType = typeof(MetricTestData))] + public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) + { + using var meter = new Meter(Utils.GetCurrentMethodName()); + var histogram = meter.CreateHistogram("MyHistogram"); + var exportedItems = new List(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(meter.Name) + .AddView(histogram.Name, histogramConfiguration) + .AddInMemoryExporter(exportedItems) + .Build(); + + for (var i = 0; i < values.Length; i++) + { + histogram.Record(values[i]); + } + + meterProvider.ForceFlush(MaxTimeToAllowForFlush); + + var metricPoints = new List(); + foreach (ref readonly var mp in exportedItems[0].GetMetricPoints()) + { + metricPoints.Add(mp); + } + + var histogramPoint = metricPoints[0]; + + var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMin)} is not supported for this metric type.", ex.Message); + + ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); + Assert.Contains($"{nameof(histogramPoint.GetHistogramMax)} is not supported for this metric type.", ex.Message); + } + [Fact] public void ViewToSelectTagKeys() { From aa94f897975d0f4a6e19db501f73cd9a36283a5c Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 7 Sep 2022 14:58:39 -0700 Subject: [PATCH 097/111] Add HistogramConfiguration.cs --- .../Metrics/HistogramConfiguration.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/OpenTelemetry/Metrics/HistogramConfiguration.cs diff --git a/src/OpenTelemetry/Metrics/HistogramConfiguration.cs b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs new file mode 100644 index 00000000000..37980098937 --- /dev/null +++ b/src/OpenTelemetry/Metrics/HistogramConfiguration.cs @@ -0,0 +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. +// + +namespace OpenTelemetry.Metrics; + +public class HistogramConfiguration : MetricStreamConfiguration +{ + /// + /// Gets or sets a value indicating whether Min, Max + /// should be collected. + /// + public bool RecordMinMax { get; set; } = true; +} From 0760c358b2dce10d620bc169cbe1f55f40bf5588 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 26 Sep 2022 13:16:21 -0700 Subject: [PATCH 098/111] mention MetricType.HistogramWithMinMax in changelog --- src/OpenTelemetry/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index 1601c2357d1..96f65063ba3 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased * Make recording of `Min` and `Max` for histograms configurable, enabled by - default. + default. Adds a new `MetricType` named `HistogramWithMinMax`. ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) * Use binary search for histograms with 50 or more supplied boundaries. From f1f0a3f25f1fb4c0e4a94eff32da476bc5d89525 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Mon, 26 Sep 2022 13:16:44 -0700 Subject: [PATCH 099/111] reset running values to -/+ inf --- src/OpenTelemetry/Metrics/MetricPoint.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index ddf0e69e926..f6a20c1fb9e 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -597,8 +597,8 @@ private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax this.histogramBuckets.RunningSum = 0; if (hasMinMax) { - this.histogramBuckets.RunningMin = 0; - this.histogramBuckets.RunningMax = 0; + this.histogramBuckets.RunningMin = double.PositiveInfinity; + this.histogramBuckets.RunningMax = double.NegativeInfinity; } } From d182298e8620b80a3b0628955cc70648d04d0c55 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 27 Sep 2022 10:13:54 -0700 Subject: [PATCH 100/111] Update AggregationType.cs --- src/OpenTelemetry/Metrics/AggregationType.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/OpenTelemetry/Metrics/AggregationType.cs b/src/OpenTelemetry/Metrics/AggregationType.cs index 40f22c08e09..eff60b2d91d 100644 --- a/src/OpenTelemetry/Metrics/AggregationType.cs +++ b/src/OpenTelemetry/Metrics/AggregationType.cs @@ -14,8 +14,6 @@ // limitations under the License. // -using OpenTelemetry.Metrics; - namespace OpenTelemetry.Metrics { internal enum AggregationType From e3e96e655bfcefdb6b1c1ac0294b4f6be565f20d Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 28 Sep 2022 10:05:02 -0700 Subject: [PATCH 101/111] Update CHANGELOG.md --- src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 6b96dfa8588..34dec786905 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Recording `Min` and `Max` for histograms is configurable, enabled by default. + ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) + * Added overloads which accept a name to the `MeterProviderBuilder` `AddOtlpExporter` extension to allow for more fine-grained options management ([#3648](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3648)) From c8fb75ccbe5c1eb2762630c57d0bd9dd51593c21 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 7 Oct 2022 14:10:38 -0700 Subject: [PATCH 102/111] undo addition of histogramwithminmax metrictype --- .../CHANGELOG.md | 3 ++- .../Implementation/MetricItemExtensions.cs | 14 ++++++++++---- .../.publicApi/net462/PublicAPI.Unshipped.txt | 1 - .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 1 - .../netstandard2.0/PublicAPI.Unshipped.txt | 1 - .../netstandard2.1/PublicAPI.Unshipped.txt | 1 - src/OpenTelemetry/CHANGELOG.md | 2 +- src/OpenTelemetry/Metrics/Metric.cs | 2 +- src/OpenTelemetry/Metrics/MetricType.cs | 7 +------ .../MetricTests.cs | 2 +- .../HttpClientTests.cs | 2 +- 11 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 34dec786905..b8385560005 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -2,7 +2,8 @@ ## Unreleased -* Recording `Min` and `Max` for histograms is configurable, enabled by default. +* OTLP histogram data points will now include `Min` and `Max` values when + they are present. ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) * Added overloads which accept a name to the `MeterProviderBuilder` diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 8f472c537ec..878e24009ea 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -239,7 +239,6 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) } case MetricType.Histogram: - case MetricType.HistogramWithMinMax: { var histogram = new OtlpMetrics.Histogram { @@ -257,10 +256,17 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) AddAttributes(metricPoint.Tags, dataPoint.Attributes); dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); - if (metric.MetricType == MetricType.HistogramWithMinMax) + + var max = metricPoint.GetHistogramMax(); + if (!double.IsNegativeInfinity(max)) + { + dataPoint.Max = max; + } + + var min = metricPoint.GetHistogramMin(); + if (!double.IsPositiveInfinity(min)) { - dataPoint.Min = metricPoint.GetHistogramMin(); - dataPoint.Max = metricPoint.GetHistogramMax(); + dataPoint.Min = min; } foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 5d08565fffd..69b05311d96 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -40,7 +40,6 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 5d08565fffd..69b05311d96 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -40,7 +40,6 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index e58fa30c641..507ba457434 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -40,7 +40,6 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 5d08565fffd..69b05311d96 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -40,7 +40,6 @@ OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double -OpenTelemetry.Metrics.MetricType.HistogramWithMinMax = 80 -> OpenTelemetry.Metrics.MetricType static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md index b12fd3ecb15..0cbefc342dc 100644 --- a/src/OpenTelemetry/CHANGELOG.md +++ b/src/OpenTelemetry/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased * Make recording of `Min` and `Max` for histograms configurable, enabled by - default. Adds a new `MetricType` named `HistogramWithMinMax`. + default. ([#2735](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2735)) * Use binary search for histograms with 50 or more supplied boundaries. diff --git a/src/OpenTelemetry/Metrics/Metric.cs b/src/OpenTelemetry/Metrics/Metric.cs index 090087bc8a1..161d470df9f 100644 --- a/src/OpenTelemetry/Metrics/Metric.cs +++ b/src/OpenTelemetry/Metrics/Metric.cs @@ -117,7 +117,7 @@ internal Metric( || instrumentIdentity.InstrumentType == typeof(Histogram) || instrumentIdentity.InstrumentType == typeof(Histogram)) { - this.MetricType = histogramRecordMinMax ? MetricType.HistogramWithMinMax : MetricType.Histogram; + this.MetricType = MetricType.Histogram; aggType = histogramBounds != null && histogramBounds.Length == 0 ? (histogramRecordMinMax ? AggregationType.HistogramSumCountMinMax : AggregationType.HistogramSumCount) diff --git a/src/OpenTelemetry/Metrics/MetricType.cs b/src/OpenTelemetry/Metrics/MetricType.cs index dbf759f0d49..c5f1b375b29 100644 --- a/src/OpenTelemetry/Metrics/MetricType.cs +++ b/src/OpenTelemetry/Metrics/MetricType.cs @@ -27,7 +27,7 @@ public enum MetricType : byte 0x20: Gauge 0x30: Summary (reserved) 0x40: Histogram - 0x50: HistogramWithMinMax + 0x50: HistogramWithMinMax (reserved) 0x60: ExponentialHistogram (reserved) 0x70: ExponentialHistogramWithMinMax (reserved) 0x80: SumNonMonotonic @@ -70,11 +70,6 @@ public enum MetricType : byte /// Histogram = 0x40, - /// - /// Histogram with minimum and maximum values. - /// - HistogramWithMinMax = 0x50, - /// /// Non-monotonic Sum of Long type. /// diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 183bf4fd77d..2b597048008 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -74,7 +74,7 @@ public async Task RequestMetricIsCaptured() var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); + Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs index 2d802d40955..7407e134527 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs @@ -139,7 +139,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var metric = requestMetrics[0]; Assert.NotNull(metric); - Assert.True(metric.MetricType == MetricType.HistogramWithMinMax); + Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); foreach (var p in metric.GetMetricPoints()) From d9bdf1b35b47f4034ee7d5c87957c462f9207fc0 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 7 Oct 2022 15:50:56 -0700 Subject: [PATCH 103/111] unfold hist update and snapshot --- src/OpenTelemetry/Metrics/MetricPoint.cs | 311 ++++++++++++++++------- 1 file changed, 214 insertions(+), 97 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index f68e4a49149..c06251ca2ec 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -377,25 +377,111 @@ internal void Update(double number) case AggregationType.Histogram: { - this.HistogramUpdate(number, true, false); + int i = this.histogramBuckets.FindBucketIndex(number); + + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningBucketCounts[i]++; + } + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + break; } case AggregationType.HistogramSumCount: { - this.HistogramUpdate(number, false, false); + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + } + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + break; } case AggregationType.HistogramMinMax: { - this.HistogramUpdate(number, true, true); + int i = this.histogramBuckets.FindBucketIndex(number); + + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningBucketCounts[i]++; + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + break; } case AggregationType.HistogramSumCountMinMax: { - this.HistogramUpdate(number, false, true); + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + unchecked + { + this.runningValue.AsLong++; + this.histogramBuckets.RunningSum += number; + this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); + this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + } + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); + } + break; } } @@ -515,125 +601,156 @@ internal void TakeSnapshot(bool outputDelta) case AggregationType.Histogram: { - this.HistogramSnapshot(outputDelta, true, false); - break; - } + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + } + + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } - case AggregationType.HistogramSumCount: - { - this.HistogramSnapshot(outputDelta, false, false); - break; - } + sw.SpinOnce(); + } - case AggregationType.HistogramMinMax: - { - this.HistogramSnapshot(outputDelta, true, true); break; } - case AggregationType.HistogramSumCountMinMax: + case AggregationType.HistogramSumCount: { - this.HistogramSnapshot(outputDelta, false, true); - break; - } - } - } + var sw = default(SpinWait); + while (true) + { + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - [MethodImpl(MethodImplOptions.NoInlining)] - private readonly void ThrowNotSupportedMetricTypeException(string methodName) - { - throw new NotSupportedException($"{methodName} is not supported for this metric type."); - } + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void HistogramUpdate(double number, bool hasBuckets, bool hasMinMax) - { - int i = hasBuckets - ? this.histogramBuckets.FindBucketIndex(number) - : 0; + this.MetricPointStatus = MetricPointStatus.NoCollectPending; - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - unchecked - { - this.runningValue.AsLong++; - this.histogramBuckets.RunningSum += number; - if (hasBuckets) - { - this.histogramBuckets.RunningBucketCounts[i]++; - } + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } - if (hasMinMax) - { - this.histogramBuckets.RunningMin = Math.Min(this.histogramBuckets.RunningMin, number); - this.histogramBuckets.RunningMax = Math.Max(this.histogramBuckets.RunningMax, number); + sw.SpinOnce(); } - } - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } - sw.SpinOnce(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void HistogramSnapshot(bool outputDelta, bool hasBuckets, bool hasMinMax) - { - var sw = default(SpinWait); - while (true) - { - if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) - { - // Lock acquired - this.snapshotValue.AsLong = this.runningValue.AsLong; - this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; - if (hasMinMax) - { - this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; - this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + break; } - if (outputDelta) + case AggregationType.HistogramMinMax: { - this.runningValue.AsLong = 0; - this.histogramBuckets.RunningSum = 0; - if (hasMinMax) + var sw = default(SpinWait); + while (true) { - this.histogramBuckets.RunningMin = double.PositiveInfinity; - this.histogramBuckets.RunningMax = double.NegativeInfinity; + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) + { + // Lock acquired + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + this.histogramBuckets.RunningMin = double.PositiveInfinity; + this.histogramBuckets.RunningMax = double.NegativeInfinity; + } + + for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + { + this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; + if (outputDelta) + { + this.histogramBuckets.RunningBucketCounts[i] = 0; + } + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; + } + + sw.SpinOnce(); } + + break; } - if (hasBuckets) + case AggregationType.HistogramSumCountMinMax: { - for (int i = 0; i < this.histogramBuckets.RunningBucketCounts.Length; i++) + var sw = default(SpinWait); + while (true) { - this.histogramBuckets.SnapshotBucketCounts[i] = this.histogramBuckets.RunningBucketCounts[i]; - if (outputDelta) + if (Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 1) == 0) { - this.histogramBuckets.RunningBucketCounts[i] = 0; + // Lock acquired + this.snapshotValue.AsLong = this.runningValue.AsLong; + this.histogramBuckets.SnapshotSum = this.histogramBuckets.RunningSum; + this.histogramBuckets.SnapshotMin = this.histogramBuckets.RunningMin; + this.histogramBuckets.SnapshotMax = this.histogramBuckets.RunningMax; + + if (outputDelta) + { + this.runningValue.AsLong = 0; + this.histogramBuckets.RunningSum = 0; + this.histogramBuckets.RunningMin = double.PositiveInfinity; + this.histogramBuckets.RunningMax = double.NegativeInfinity; + } + + this.MetricPointStatus = MetricPointStatus.NoCollectPending; + + // Release lock + Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); + break; } - } - } - this.MetricPointStatus = MetricPointStatus.NoCollectPending; - - // Release lock - Interlocked.Exchange(ref this.histogramBuckets.IsCriticalSectionOccupied, 0); - break; - } + sw.SpinOnce(); + } - sw.SpinOnce(); + break; + } } } + + [MethodImpl(MethodImplOptions.NoInlining)] + private readonly void ThrowNotSupportedMetricTypeException(string methodName) + { + throw new NotSupportedException($"{methodName} is not supported for this metric type."); + } } } - - From fea3c654cfc8d1791fcf6d21445892fb4c3ebfe2 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 11 Oct 2022 12:02:30 -0700 Subject: [PATCH 104/111] move recordminmax to metricstreamidentity --- src/OpenTelemetry/Metrics/MetricReaderExt.cs | 3 +-- src/OpenTelemetry/Metrics/MetricStreamIdentity.cs | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricReaderExt.cs b/src/OpenTelemetry/Metrics/MetricReaderExt.cs index 064e3e3df04..8d15cd68f91 100644 --- a/src/OpenTelemetry/Metrics/MetricReaderExt.cs +++ b/src/OpenTelemetry/Metrics/MetricReaderExt.cs @@ -156,8 +156,7 @@ internal List AddMetricsListWithViews(Instrument instrument, List metricIdentity1.Equals(metricIdentity2); public static bool operator !=(MetricStreamIdentity metricIdentity1, MetricStreamIdentity metricIdentity2) => !metricIdentity1.Equals(metricIdentity2); @@ -99,6 +102,7 @@ public bool Equals(MetricStreamIdentity other) && this.Unit == other.Unit && this.Description == other.Description && this.ViewId == other.ViewId + && this.HistogramRecordMinMax == other.HistogramRecordMinMax && StringArrayComparer.Equals(this.TagKeys, other.TagKeys) && HistogramBoundsEqual(this.HistogramBucketBounds, other.HistogramBucketBounds); } From 3bad254d35c7d789a44ec086d63221aeeea71cda Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 11 Oct 2022 12:06:50 -0700 Subject: [PATCH 105/111] remove logs publicapi --- .../.publicApi/netstandard2.1/PublicAPI.Unshipped.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 26e0f6f92a4..1ad859bcae0 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,15 +1,5 @@ Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions -OpenTelemetry.Logs.LogRecord.CategoryName.set -> void -OpenTelemetry.Logs.LogRecord.EventId.set -> void -OpenTelemetry.Logs.LogRecord.Exception.set -> void -OpenTelemetry.Logs.LogRecord.LogLevel.set -> void -OpenTelemetry.Logs.LogRecord.SpanId.set -> void -OpenTelemetry.Logs.LogRecord.Timestamp.set -> void -OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void -OpenTelemetry.Logs.LogRecord.TraceId.set -> void -OpenTelemetry.Logs.LogRecord.TraceState.set -> void -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool From 1ad4a54526dd1e46a773e62aec63060c10a1dcc4 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Tue, 11 Oct 2022 12:08:11 -0700 Subject: [PATCH 106/111] this one --- .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 8 -------- .../.publicApi/netstandard2.1/PublicAPI.Unshipped.txt | 10 ++++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 74ba2610481..26e0f6f92a4 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -10,14 +10,6 @@ OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void OpenTelemetry.Logs.LogRecord.TraceId.set -> void OpenTelemetry.Logs.LogRecord.TraceState.set -> void OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureServices(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.SetIncludeFormattedMessage(bool enabled) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.SetIncludeScopes(bool enabled) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! -OpenTelemetry.Logs.OpenTelemetryLoggerOptions.SetParseStateValues(bool enabled) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! -OpenTelemetry.Logs.OpenTelemetryLoggerOptionsExtensions -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.AddProcessor(OpenTelemetry.BaseProcessor! processor) -> OpenTelemetry.Logs.OpenTelemetryLoggerProvider! -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool -OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 1ad859bcae0..26e0f6f92a4 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -1,5 +1,15 @@ Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions Microsoft.Extensions.DependencyInjection.TracerProviderBuilderServiceCollectionExtensions +OpenTelemetry.Logs.LogRecord.CategoryName.set -> void +OpenTelemetry.Logs.LogRecord.EventId.set -> void +OpenTelemetry.Logs.LogRecord.Exception.set -> void +OpenTelemetry.Logs.LogRecord.LogLevel.set -> void +OpenTelemetry.Logs.LogRecord.SpanId.set -> void +OpenTelemetry.Logs.LogRecord.Timestamp.set -> void +OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void +OpenTelemetry.Logs.LogRecord.TraceId.set -> void +OpenTelemetry.Logs.LogRecord.TraceState.set -> void +OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions! OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool From fe853f39570744e5b380049a128e2b4b826c7fba Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Oct 2022 11:01:37 -0700 Subject: [PATCH 107/111] TryGetHistogram Min/Max --- .../Implementation/MetricItemExtensions.cs | 6 ++--- .../.publicApi/net462/PublicAPI.Unshipped.txt | 4 +-- .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 4 +-- .../netstandard2.0/PublicAPI.Unshipped.txt | 4 +-- .../netstandard2.1/PublicAPI.Unshipped.txt | 4 +-- src/OpenTelemetry/Metrics/MetricPoint.cs | 26 ++++++++++++------- .../Metrics/MetricStreamIdentity.cs | 1 + .../Metrics/MetricViewTests.cs | 14 +++++----- 8 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index 878e24009ea..a68de629d9a 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -257,14 +257,12 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); - var max = metricPoint.GetHistogramMax(); - if (!double.IsNegativeInfinity(max)) + if (metricPoint.TryGetHistogramMax(out var max)) { dataPoint.Max = max; } - var min = metricPoint.GetHistogramMin(); - if (!double.IsPositiveInfinity(min)) + if (metricPoint.TryGetHistogramMin(out var min)) { dataPoint.Min = min; } diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index 26e0f6f92a4..e46a7c54e93 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -14,8 +14,8 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double -OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index 26e0f6f92a4..e46a7c54e93 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -14,8 +14,8 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double -OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 26e0f6f92a4..e46a7c54e93 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -14,8 +14,8 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double -OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index 26e0f6f92a4..e46a7c54e93 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -14,8 +14,8 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double -OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool +OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index c06251ca2ec..49d50a1ef72 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -243,41 +243,47 @@ public readonly HistogramBuckets GetHistogramBuckets() } /// - /// Gets the minimum value of the histogram associated with the metric point. + /// Gets the minimum value of the histogram associated with the metric + /// point if present. /// + /// Output variable for the minimum value. /// /// Applies to metric type. /// - /// Minimum value. + /// A minimum value exists. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public double GetHistogramMin() + public bool TryGetHistogramMin(out double min) { if (this.aggType != AggregationType.HistogramMinMax && this.aggType != AggregationType.HistogramSumCountMinMax) { - this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMin)); + this.ThrowNotSupportedMetricTypeException(nameof(this.TryGetHistogramMin)); } - return this.histogramBuckets.SnapshotMin; + min = this.histogramBuckets.SnapshotMin; + return !double.IsPositiveInfinity(min); } /// - /// Gets the maximum value of the histogram associated with the metric point. + /// Gets the maximum value of the histogram associated with the metric + /// point if present. /// + /// Output variable for the maximum value. /// /// Applies to metric type. /// - /// Maximum value. + /// A maximum value exists. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public double GetHistogramMax() + public bool TryGetHistogramMax(out double max) { if (this.aggType != AggregationType.HistogramMinMax && this.aggType != AggregationType.HistogramSumCountMinMax) { - this.ThrowNotSupportedMetricTypeException(nameof(this.GetHistogramMax)); + this.ThrowNotSupportedMetricTypeException(nameof(this.TryGetHistogramMax)); } - return this.histogramBuckets.SnapshotMax; + max = this.histogramBuckets.SnapshotMax; + return !double.IsNegativeInfinity(max); } internal readonly MetricPoint Copy() diff --git a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs index 8c31a43d518..9039aa7612c 100644 --- a/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs +++ b/src/OpenTelemetry/Metrics/MetricStreamIdentity.cs @@ -45,6 +45,7 @@ public MetricStreamIdentity(Instrument instrument, MetricStreamConfiguration met hash = (hash * 31) + this.MeterName.GetHashCode(); hash = (hash * 31) + this.MeterVersion.GetHashCode(); hash = (hash * 31) + this.InstrumentName.GetHashCode(); + hash = (hash * 31) + this.HistogramRecordMinMax.GetHashCode(); hash = this.Unit == null ? hash : (hash * 31) + this.Unit.GetHashCode(); hash = this.Description == null ? hash : (hash * 31) + this.Description.GetHashCode(); hash = !this.ViewId.HasValue ? hash : (hash * 31) + this.ViewId.Value; diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index f419759d036..961b68c0826 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -599,9 +599,11 @@ public void HistogramMinMax(double[] values, HistogramConfiguration histogramCon } var histogramPoint = metricPoints[0]; - var min = histogramPoint.GetHistogramMin(); - var max = histogramPoint.GetHistogramMax(); + var hasMin = histogramPoint.TryGetHistogramMin(out var min); + var hasMax = histogramPoint.TryGetHistogramMax(out var max); + Assert.True(hasMin); + Assert.True(hasMax); Assert.Equal(expectedMin, min); Assert.Equal(expectedMax, max); } @@ -634,11 +636,11 @@ public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histog var histogramPoint = metricPoints[0]; - var ex = Assert.Throws(() => histogramPoint.GetHistogramMin()); - Assert.Contains($"{nameof(histogramPoint.GetHistogramMin)} is not supported for this metric type.", ex.Message); + var ex = Assert.Throws(() => histogramPoint.TryGetHistogramMin(out var min)); + Assert.Contains($"{nameof(histogramPoint.TryGetHistogramMin)} is not supported for this metric type.", ex.Message); - ex = Assert.Throws(() => histogramPoint.GetHistogramMax()); - Assert.Contains($"{nameof(histogramPoint.GetHistogramMax)} is not supported for this metric type.", ex.Message); + ex = Assert.Throws(() => histogramPoint.TryGetHistogramMax(out var max)); + Assert.Contains($"{nameof(histogramPoint.TryGetHistogramMax)} is not supported for this metric type.", ex.Message); } [Fact] From 3a868ae0ff88935ba235c2e0c33fd753ec47b4d6 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Oct 2022 14:27:36 -0700 Subject: [PATCH 108/111] Do not throw for minmax histogram --- src/OpenTelemetry/Metrics/MetricPoint.cs | 22 +++++++------------ .../Metrics/MetricViewTests.cs | 9 +++----- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 49d50a1ef72..a20ee341fce 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -254,14 +254,11 @@ public readonly HistogramBuckets GetHistogramBuckets() [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetHistogramMin(out double min) { - if (this.aggType != AggregationType.HistogramMinMax && - this.aggType != AggregationType.HistogramSumCountMinMax) - { - this.ThrowNotSupportedMetricTypeException(nameof(this.TryGetHistogramMin)); - } - min = this.histogramBuckets.SnapshotMin; - return !double.IsPositiveInfinity(min); + + return !double.IsPositiveInfinity(min) && + (this.aggType == AggregationType.HistogramMinMax || + this.aggType == AggregationType.HistogramSumCountMinMax); } /// @@ -276,14 +273,11 @@ public bool TryGetHistogramMin(out double min) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetHistogramMax(out double max) { - if (this.aggType != AggregationType.HistogramMinMax && - this.aggType != AggregationType.HistogramSumCountMinMax) - { - this.ThrowNotSupportedMetricTypeException(nameof(this.TryGetHistogramMax)); - } - max = this.histogramBuckets.SnapshotMax; - return !double.IsNegativeInfinity(max); + + return !double.IsNegativeInfinity(max) && + (this.aggType == AggregationType.HistogramMinMax || + this.aggType == AggregationType.HistogramSumCountMinMax); } internal readonly MetricPoint Copy() diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 961b68c0826..962dba7658c 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -610,7 +610,7 @@ public void HistogramMinMax(double[] values, HistogramConfiguration histogramCon [Theory] [MemberData(nameof(MetricTestData.InvalidHistogramMinMax), MemberType = typeof(MetricTestData))] - public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histogramConfiguration) + public void HistogramMinMaxNotPresent(double[] values, HistogramConfiguration histogramConfiguration) { using var meter = new Meter(Utils.GetCurrentMethodName()); var histogram = meter.CreateHistogram("MyHistogram"); @@ -636,11 +636,8 @@ public void HistogramMinMaxThrows(double[] values, HistogramConfiguration histog var histogramPoint = metricPoints[0]; - var ex = Assert.Throws(() => histogramPoint.TryGetHistogramMin(out var min)); - Assert.Contains($"{nameof(histogramPoint.TryGetHistogramMin)} is not supported for this metric type.", ex.Message); - - ex = Assert.Throws(() => histogramPoint.TryGetHistogramMax(out var max)); - Assert.Contains($"{nameof(histogramPoint.TryGetHistogramMax)} is not supported for this metric type.", ex.Message); + Assert.False(histogramPoint.TryGetHistogramMin(out var min)); + Assert.False(histogramPoint.TryGetHistogramMax(out var max)); } [Fact] From cb744d735e0b34ecb474f2294bcec247426492db Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Oct 2022 16:34:25 -0700 Subject: [PATCH 109/111] hasminmax strategy --- .../Implementation/MetricItemExtensions.cs | 10 ++--- .../.publicApi/net462/PublicAPI.Unshipped.txt | 5 ++- .../.publicApi/net6.0/PublicAPI.Unshipped.txt | 5 ++- .../netstandard2.0/PublicAPI.Unshipped.txt | 5 ++- .../netstandard2.1/PublicAPI.Unshipped.txt | 5 ++- src/OpenTelemetry/Metrics/MetricPoint.cs | 39 +++++++++++-------- .../Metrics/MetricTestData.cs | 1 + .../Metrics/MetricViewTests.cs | 12 +++--- 8 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs index a68de629d9a..50ad352ddfc 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/MetricItemExtensions.cs @@ -257,14 +257,10 @@ internal static OtlpMetrics.Metric ToOtlpMetric(this Metric metric) dataPoint.Count = (ulong)metricPoint.GetHistogramCount(); dataPoint.Sum = metricPoint.GetHistogramSum(); - if (metricPoint.TryGetHistogramMax(out var max)) + if (metricPoint.HasMinMax()) { - dataPoint.Max = max; - } - - if (metricPoint.TryGetHistogramMin(out var min)) - { - dataPoint.Min = min; + dataPoint.Min = metricPoint.GetHistogramMin(); + dataPoint.Max = metricPoint.GetHistogramMax(); } foreach (var histogramMeasurement in metricPoint.GetHistogramBuckets()) diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt index e46a7c54e93..eedd81fc086 100644 --- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt @@ -14,8 +14,9 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt index e46a7c54e93..eedd81fc086 100644 --- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -14,8 +14,9 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index e46a7c54e93..eedd81fc086 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -14,8 +14,9 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt index e46a7c54e93..eedd81fc086 100644 --- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt @@ -14,8 +14,9 @@ OpenTelemetry.Metrics.HistogramConfiguration OpenTelemetry.Metrics.HistogramConfiguration.HistogramConfiguration() -> void OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.get -> bool OpenTelemetry.Metrics.HistogramConfiguration.RecordMinMax.set -> void -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMax(out double max) -> bool -OpenTelemetry.Metrics.MetricPoint.TryGetHistogramMin(out double min) -> bool +OpenTelemetry.Metrics.MetricPoint.GetHistogramMax() -> double +OpenTelemetry.Metrics.MetricPoint.GetHistogramMin() -> double +OpenTelemetry.Metrics.MetricPoint.HasMinMax() -> bool static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.MeterProviderBuilderServiceCollectionExtensions.ConfigureOpenTelemetryMetrics(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configure) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder! diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index a20ee341fce..74607c893c3 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -244,40 +244,45 @@ public readonly HistogramBuckets GetHistogramBuckets() /// /// Gets the minimum value of the histogram associated with the metric - /// point if present. + /// point if present. Check by using . /// - /// Output variable for the minimum value. /// /// Applies to metric type. /// - /// A minimum value exists. + /// A histogram's maximum value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetHistogramMin(out double min) + public double GetHistogramMin() { - min = this.histogramBuckets.SnapshotMin; - - return !double.IsPositiveInfinity(min) && - (this.aggType == AggregationType.HistogramMinMax || - this.aggType == AggregationType.HistogramSumCountMinMax); + return this.histogramBuckets.SnapshotMin; } /// /// Gets the maximum value of the histogram associated with the metric - /// point if present. + /// point if present. Check by using . /// - /// Output variable for the maximum value. /// /// Applies to metric type. /// - /// A maximum value exists. + /// A histogram's maximum value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetHistogramMax(out double max) + public double GetHistogramMax() { - max = this.histogramBuckets.SnapshotMax; + return this.histogramBuckets.SnapshotMax; + } - return !double.IsNegativeInfinity(max) && - (this.aggType == AggregationType.HistogramMinMax || - this.aggType == AggregationType.HistogramSumCountMinMax); + /// + /// Gets whether the histogram has a valid Min and Max value. + /// Should be used before + /// and to + /// ensure a valid value is returned. + /// + /// A minimum and maximum value exist. + public bool HasMinMax() + { + return (this.aggType == AggregationType.HistogramMinMax || + this.aggType == AggregationType.HistogramSumCountMinMax) && + this.histogramBuckets.RunningMin != double.PositiveInfinity && + this.histogramBuckets.RunningMax != double.NegativeInfinity; } internal readonly MetricPoint Copy() diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs index f1a2b517a93..c4b8fdf944a 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestData.cs @@ -54,6 +54,7 @@ public static IEnumerable ValidHistogramMinMax => new List { new object[] { new double[] { -10, 0, 1, 9, 10, 11, 19 }, new HistogramConfiguration(), -10, 19 }, + new object[] { new double[] { double.NegativeInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.NegativeInfinity }, new object[] { new double[] { double.NegativeInfinity, 0, double.PositiveInfinity }, new HistogramConfiguration(), double.NegativeInfinity, double.PositiveInfinity }, new object[] { new double[] { 1 }, new HistogramConfiguration(), 1, 1 }, new object[] { new double[] { 5, 100, 4, 101, -2, 97 }, new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } }, -2, 101 }, diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 962dba7658c..70bda2660cb 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -599,11 +599,12 @@ public void HistogramMinMax(double[] values, HistogramConfiguration histogramCon } var histogramPoint = metricPoints[0]; - var hasMin = histogramPoint.TryGetHistogramMin(out var min); - var hasMax = histogramPoint.TryGetHistogramMax(out var max); + var hasMinMax = histogramPoint.HasMinMax(); + Assert.True(hasMinMax); + + var min = histogramPoint.GetHistogramMin(); + var max = histogramPoint.GetHistogramMax(); - Assert.True(hasMin); - Assert.True(hasMax); Assert.Equal(expectedMin, min); Assert.Equal(expectedMax, max); } @@ -636,8 +637,7 @@ public void HistogramMinMaxNotPresent(double[] values, HistogramConfiguration hi var histogramPoint = metricPoints[0]; - Assert.False(histogramPoint.TryGetHistogramMin(out var min)); - Assert.False(histogramPoint.TryGetHistogramMax(out var max)); + Assert.False(histogramPoint.HasMinMax()); } [Fact] From a3dcdef49be8a859f3d98ec163278654733d7d97 Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Wed, 12 Oct 2022 16:44:09 -0700 Subject: [PATCH 110/111] fix logic --- src/OpenTelemetry/Metrics/MetricPoint.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 74607c893c3..218fa88f834 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -281,8 +281,8 @@ public bool HasMinMax() { return (this.aggType == AggregationType.HistogramMinMax || this.aggType == AggregationType.HistogramSumCountMinMax) && - this.histogramBuckets.RunningMin != double.PositiveInfinity && - this.histogramBuckets.RunningMax != double.NegativeInfinity; + !(this.histogramBuckets.RunningMin == double.PositiveInfinity && + this.histogramBuckets.RunningMax == double.NegativeInfinity); } internal readonly MetricPoint Copy() From 7169a98ba68f3c9d32d58ea2814dd0260885c03e Mon Sep 17 00:00:00 2001 From: Michael Maxwell Date: Fri, 14 Oct 2022 10:56:51 -0700 Subject: [PATCH 111/111] only aggtype for hasminmax --- src/OpenTelemetry/Metrics/MetricPoint.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry/Metrics/MetricPoint.cs b/src/OpenTelemetry/Metrics/MetricPoint.cs index 218fa88f834..50dc46d1135 100644 --- a/src/OpenTelemetry/Metrics/MetricPoint.cs +++ b/src/OpenTelemetry/Metrics/MetricPoint.cs @@ -279,10 +279,8 @@ public double GetHistogramMax() /// A minimum and maximum value exist. public bool HasMinMax() { - return (this.aggType == AggregationType.HistogramMinMax || - this.aggType == AggregationType.HistogramSumCountMinMax) && - !(this.histogramBuckets.RunningMin == double.PositiveInfinity && - this.histogramBuckets.RunningMax == double.NegativeInfinity); + return this.aggType == AggregationType.HistogramMinMax || + this.aggType == AggregationType.HistogramSumCountMinMax; } internal readonly MetricPoint Copy()