diff --git a/.github/workflows/package-Instrumentation.Runtime.yml b/.github/workflows/package-Instrumentation.Runtime.yml new file mode 100644 index 0000000000..e5ff3f4966 --- /dev/null +++ b/.github/workflows/package-Instrumentation.Runtime.yml @@ -0,0 +1,49 @@ +name: Pack OpenTelemetry.Contrib.Instrumentation.Runtime + +on: + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: true + default: 'warning' + push: + tags: + - 'Instrumentation.Runtime-*' # trigger when we create a tag with prefix "Instrumentation.Runtime-" + +jobs: + build-test-pack: + runs-on: ${{ matrix.os }} + env: + PROJECT: OpenTelemetry.Contrib.Instrumentation.Runtime + + strategy: + matrix: + os: [windows-latest] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # fetching all + + - name: Install dependencies + run: dotnet restore + + - name: dotnet build ${{env.PROJECT}} + run: dotnet build src/${{env.PROJECT}} --configuration Release --no-restore -p:Deterministic=true + + - name: dotnet test ${{env.PROJECT}} + run: dotnet test test/${{env.PROJECT}}.Tests + + - name: dotnet pack ${{env.PROJECT}} + run: dotnet pack src/${{env.PROJECT}} --configuration Release --no-build + + - name: Publish Artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{env.PROJECT}}-packages + path: '**/${{env.PROJECT}}/bin/**/*.*nupkg' + + - name: Publish Nuget + run: | + nuget push **/${{env.PROJECT}}/bin/**/*.nupkg -Source https://api.nuget.org/v3/index.json -ApiKey ${{ secrets.NUGET_TOKEN }} -SymbolApiKey ${{ secrets.NUGET_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml index 5e7f20e319..ed3e8af464 100644 --- a/.github/workflows/pr_build.yml +++ b/.github/workflows/pr_build.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false # ensures the entire test matrix is run, even if one permutation fails matrix: os: [windows-latest,ubuntu-latest] - version: [net461,netcoreapp3.1,net5.0] + version: [net461,netcoreapp3.1,net5.0,net6.0] exclude: - os: ubuntu-latest version: net461 diff --git a/opentelemetry-dotnet-contrib.sln b/opentelemetry-dotnet-contrib.sln index 11ea786c81..0d7d416698 100644 --- a/opentelemetry-dotnet-contrib.sln +++ b/opentelemetry-dotnet-contrib.sln @@ -156,6 +156,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Contrib.Exten EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Contrib.Extensions.PersistentStorage.Tests", "test\OpenTelemetry.Contrib.Extensions.PersistentStorage.Tests\OpenTelemetry.Contrib.Extensions.PersistentStorage.Tests.csproj", "{72EBA81D-2933-417C-8F21-D4CFFD72F530}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Contrib.Instrumentation.Runtime", "src\OpenTelemetry.Contrib.Instrumentation.Runtime\OpenTelemetry.Contrib.Instrumentation.Runtime.csproj", "{F01E8C75-2791-4DBE-BD7A-5510871EBF56}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Contrib.Instrumentation.Runtime.Tests", "test\OpenTelemetry.Contrib.Instrumentation.Runtime.Tests\OpenTelemetry.Contrib.Instrumentation.Runtime.Tests.csproj", "{FB907DF7-F3F3-4A07-885D-E5FECAE36BDA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -306,6 +310,14 @@ Global {72EBA81D-2933-417C-8F21-D4CFFD72F530}.Debug|Any CPU.Build.0 = Debug|Any CPU {72EBA81D-2933-417C-8F21-D4CFFD72F530}.Release|Any CPU.ActiveCfg = Release|Any CPU {72EBA81D-2933-417C-8F21-D4CFFD72F530}.Release|Any CPU.Build.0 = Release|Any CPU + {F01E8C75-2791-4DBE-BD7A-5510871EBF56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F01E8C75-2791-4DBE-BD7A-5510871EBF56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F01E8C75-2791-4DBE-BD7A-5510871EBF56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F01E8C75-2791-4DBE-BD7A-5510871EBF56}.Release|Any CPU.Build.0 = Release|Any CPU + {FB907DF7-F3F3-4A07-885D-E5FECAE36BDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB907DF7-F3F3-4A07-885D-E5FECAE36BDA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB907DF7-F3F3-4A07-885D-E5FECAE36BDA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB907DF7-F3F3-4A07-885D-E5FECAE36BDA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -353,6 +365,8 @@ Global {D52558C8-B7BF-4F59-A0FA-9AA629E68012} = {2097345F-4DD3-477D-BC54-A922F9B2B402} {433C59A3-D535-421E-BA7F-9BCE0D4A3D25} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} {72EBA81D-2933-417C-8F21-D4CFFD72F530} = {2097345F-4DD3-477D-BC54-A922F9B2B402} + {F01E8C75-2791-4DBE-BD7A-5510871EBF56} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} + {FB907DF7-F3F3-4A07-885D-E5FECAE36BDA} = {2097345F-4DD3-477D-BC54-A922F9B2B402} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B0816796-CDB3-47D7-8C3C-946434DE3B66} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/AssemblyInfo.cs b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/AssemblyInfo.cs new file mode 100644 index 0000000000..82ef8df4ab --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/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.Contrib.Instrumentation.Runtime.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")] +#else +[assembly: InternalsVisibleTo("OpenTelemetry.Contrib.Instrumentation.Runtime.Tests")] +#endif diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/MeterProviderBuilderExtensions.cs new file mode 100644 index 0000000000..7bc2e24aef --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/MeterProviderBuilderExtensions.cs @@ -0,0 +1,50 @@ +// +// 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.Contrib.Instrumentation.Runtime; + +namespace OpenTelemetry.Metrics +{ + /// + /// Extension methods to simplify registering of dependency instrumentation. + /// + public static class MeterProviderBuilderExtensions + { + /// + /// Enables runtime instrumentation. + /// + /// being configured. + /// Runtime metrics options. + /// The instance of to chain the calls. + public static MeterProviderBuilder AddRuntimeMetrics( + this MeterProviderBuilder builder, + Action configure = null) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + var options = new RuntimeMetricsOptions(); + configure?.Invoke(options); + + var instrumentation = new RuntimeMetrics(options); + builder.AddMeter(RuntimeMetrics.InstrumentationName); + return builder.AddInstrumentation(() => instrumentation); + } + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/OpenTelemetry.Contrib.Instrumentation.Runtime.csproj b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/OpenTelemetry.Contrib.Instrumentation.Runtime.csproj new file mode 100644 index 0000000000..c6b246f127 --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/OpenTelemetry.Contrib.Instrumentation.Runtime.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0;net461;netcoreapp3.1;net6.0 + dotnet runtime instrumentation for OpenTelemetry .NET + $(PackageTags);OpenTelemetry;runtime + Instrumentation.Runtime- + + + + + + + diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/README.md b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/README.md new file mode 100644 index 0000000000..c80f7c713b --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/README.md @@ -0,0 +1,88 @@ +# DotNet Runtime Instrumentation for OpenTelemetry .NET + +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Contrib.Instrumentation.Runtime.svg)](https://www.nuget.org/packages/OpenTelemetry.Contrib.Instrumentation.Runtime) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Contrib.Instrumentation.Runtime.svg)](https://www.nuget.org/packages/OpenTelemetry.Contrib.Instrumentation.Runtime) + +This is an [Instrumentation +Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), +which instruments [.NET Runtime](https://docs.microsoft.com/dotnet) and +collect telemetry about runtime behavior. + +## Steps to enable OpenTelemetry.Contrib.Instrumentation.Runtime + +### Step 1: Install Package + +Add a reference to the +[`OpenTelemetry.Contrib.Instrumentation.Runtime`](https://www.nuget.org/packages/OpenTelemetry.Contrib.Instrumentation.Runtime) +package. Also, add any other instrumentations & exporters you will need. + +```shell +dotnet add package OpenTelemetry.Contrib.Instrumentation.Runtime +``` + +### Step 2: Enable Runtime Instrumentation at application startup + +Runtime instrumentation must be enabled at application startup. This is +typically done in the `ConfigureServices` of your `Startup` class. The example +below enables this instrumentation by using an extension method on +`IServiceCollection`. This extension method requires adding the package +[`OpenTelemetry.Extensions.Hosting`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Extensions.Hosting/README.md) +to the application. This ensures the instrumentation is disposed when the host +is shutdown. + +Additionally, this examples sets up the OpenTelemetry Prometheus exporter, which +requires adding the package +[`OpenTelemetry.Exporter.Prometheus`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Prometheus/README.md) +to the application. + +```csharp +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Metrics; + +public void ConfigureServices(IServiceCollection services) +{ + services.AddOpenTelemetryMetrics((builder) => builder + .AddRuntimeMetrics() + .AddPrometheusExporter() + ); +} +``` + +Or configure directly: + +```csharp +using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddRuntimeMetrics() + .Build(); +``` + +## Advanced configuration + +By default all available runtime metrics will be added. It's also possible to +specify only the required metrics: + +```csharp +using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddRuntimeMetrics(options => options + { + options.GcEnabled = true; + options.ThreadingEnabled = true; + options.MemoryEnabled = true; + }) + .Build(); +``` + +## Troubleshooting + +This component uses an +[EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource) +with the name "OpenTelemetry-Instrumentation-Runtime" for its internal +logging. Please refer to [SDK +troubleshooting](https://github.com/open-telemetry/opentelemetry-dotnet/tree/main/src/OpenTelemetry#troubleshooting) +for instructions on seeing these internal logs. + +## References + +* [Introduction to ASP.NET + Core](https://docs.microsoft.com/aspnet/core/introduction-to-aspnet-core) +* [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetrics.cs b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetrics.cs new file mode 100644 index 0000000000..0fe2926d08 --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetrics.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 System.Diagnostics.Metrics; +using System.Reflection; +using System.Threading; + +namespace OpenTelemetry.Contrib.Instrumentation.Runtime +{ + /// + /// .NET runtime instrumentation. + /// + internal class RuntimeMetrics : IDisposable + { + internal static readonly AssemblyName AssemblyName = typeof(RuntimeMetrics).Assembly.GetName(); + internal static readonly string InstrumentationName = AssemblyName.Name; + internal static readonly string InstrumentationVersion = AssemblyName.Version.ToString(); + + private readonly Meter meter; + + /// + /// Initializes a new instance of the class. + /// + /// The options to define the metrics. + public RuntimeMetrics(RuntimeMetricsOptions options) + { + this.meter = new Meter(InstrumentationName, InstrumentationVersion); + + if (options.IsGcEnabled) + { + this.meter.CreateObservableGauge($"{options.MetricPrefix}gc.heap", () => GC.GetTotalMemory(false), "B", "GC Heap Size"); + this.meter.CreateObservableGauge($"{options.MetricPrefix}gen_0-gc.count", () => GC.CollectionCount(0), description: "Gen 0 GC Count"); + this.meter.CreateObservableGauge($"{options.MetricPrefix}gen_1-gc.count", () => GC.CollectionCount(1), description: "Gen 1 GC Count"); + this.meter.CreateObservableGauge($"{options.MetricPrefix}gen_2-gc.count", () => GC.CollectionCount(2), description: "Gen 2 GC Count"); +#if NETCOREAPP3_1_OR_GREATER + this.meter.CreateObservableCounter($"{options.MetricPrefix}alloc.rate", () => GC.GetTotalAllocatedBytes(), "B", "Allocation Rate"); + this.meter.CreateObservableCounter($"{options.MetricPrefix}gc.fragmentation", GetFragmentation, description: "GC Fragmentation"); +#endif + +#if NET6_0_OR_GREATER + this.meter.CreateObservableCounter($"{options.MetricPrefix}gc.committed", () => (double)(GC.GetGCMemoryInfo().TotalCommittedBytes / 1_000_000), "MB", description: "GC Committed Bytes"); +#endif + } + +#if NET6_0_OR_GREATER + if (options.IsJitEnabled) + { + this.meter.CreateObservableCounter($"{options.MetricPrefix}il.bytes.jitted", () => System.Runtime.JitInfo.GetCompiledILBytes(), "B", description: "IL Bytes Jitted"); + this.meter.CreateObservableCounter($"{options.MetricPrefix}methods.jitted.count", () => System.Runtime.JitInfo.GetCompiledMethodCount(), description: "Number of Methods Jitted"); + this.meter.CreateObservableGauge($"{options.MetricPrefix}time.in.jit", () => System.Runtime.JitInfo.GetCompilationTime().TotalMilliseconds, "ms", description: "Time spent in JIT"); + } +#endif + +#if NETCOREAPP3_1_OR_GREATER + if (options.IsThreadingEnabled) + { + this.meter.CreateObservableGauge($"{options.MetricPrefix}monitor.lock.contention.count", () => Monitor.LockContentionCount, description: "Monitor Lock Contention Count"); + this.meter.CreateObservableCounter($"{options.MetricPrefix}threadpool.thread.count", () => ThreadPool.ThreadCount, description: "ThreadPool Thread Count"); + this.meter.CreateObservableGauge($"{options.MetricPrefix}threadpool.completed.items.count", () => ThreadPool.CompletedWorkItemCount, description: "ThreadPool Completed Work Item Count"); + this.meter.CreateObservableCounter($"{options.MetricPrefix}threadpool.queue.length", () => ThreadPool.PendingWorkItemCount, description: "ThreadPool Queue Length"); + this.meter.CreateObservableCounter($"{options.MetricPrefix}active.timer.count", () => Timer.ActiveCount, description: "Number of Active Timers"); + } +#endif + + if (options.IsMemoryEnabled) + { + this.meter.CreateObservableGauge($"{options.MetricPrefix}memory.usage", () => (double)(Environment.WorkingSet / 1_000_000), "MB", "Working Set"); + } + + if (options.IsAssembliesEnabled) + { + this.meter.CreateObservableCounter($"{options.MetricPrefix}assembly.count", () => AppDomain.CurrentDomain.GetAssemblies().Length, description: "Number of Assemblies Loaded"); + } + } + + /// + public void Dispose() + { + this.meter?.Dispose(); + } + +#if NETCOREAPP3_1_OR_GREATER + private static double GetFragmentation() + { + var gcInfo = GC.GetGCMemoryInfo(); + return gcInfo.HeapSizeBytes != 0 ? gcInfo.FragmentedBytes * 100d / gcInfo.HeapSizeBytes : 0; + } +#endif + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetricsOptions.cs b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetricsOptions.cs new file mode 100644 index 0000000000..08f8576a97 --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.Runtime/RuntimeMetricsOptions.cs @@ -0,0 +1,100 @@ +// +// 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.Contrib.Instrumentation.Runtime +{ + /// + /// Options to define the runtime metrics. + /// + public class RuntimeMetricsOptions + { + /// + /// Gets a prefix used for the metric names. + /// + public string MetricPrefix { get; } = "process.runtime.dotnet."; + + /// + /// Gets or sets a value indicating whether garbage collection metrics should be collected. + /// + public bool? GcEnabled { get; set; } + +#if NET6_0_OR_GREATER + /// + /// Gets or sets a value indicating whether jitter metrics should be collected. + /// + public bool? JitEnabled { get; set; } +#endif + +#if NETCOREAPP3_1_OR_GREATER + /// + /// Gets or sets a value indicating whether threading metrics should be collected. + /// + public bool? ThreadingEnabled { get; set; } +#endif + + /// + /// Gets or sets a value indicating whether memory metrics should be collected. + /// + public bool? MemoryEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether assembly metrics should be collected. + /// + public bool? AssembliesEnabled { get; set; } + + /// + /// Gets a value indicating whether all metrics are enabled. + /// + internal bool IsAllEnabled => this.GcEnabled == null +#if NET6_0_OR_GREATER + && this.JitEnabled == null +#endif +#if NETCOREAPP3_1_OR_GREATER + && this.ThreadingEnabled == null +#endif + && this.MemoryEnabled == null + && this.AssembliesEnabled == null; + + /// + /// Gets a value indicating whether garbage collection metrics is enabled. + /// + internal bool IsGcEnabled => this.GcEnabled == true || this.IsAllEnabled; + +#if NET6_0_OR_GREATER + /// + /// Gets a value indicating whether jitter metrics is enabled. + /// + internal bool IsJitEnabled => this.JitEnabled == true || this.IsAllEnabled; +#endif + +#if NETCOREAPP3_1_OR_GREATER + /// + /// Gets a value indicating whether threading metrics is enabled. + /// + internal bool IsThreadingEnabled => this.ThreadingEnabled == true || this.IsAllEnabled; +#endif + + /// + /// Gets a value indicating whether memory metrics is enabled. + /// + internal bool IsMemoryEnabled => this.MemoryEnabled == true || this.IsAllEnabled; + + /// + /// Gets a value indicating whether assembly metrics is enabled. + /// + internal bool IsAssembliesEnabled => this.AssembliesEnabled == true || this.IsAllEnabled; + } +} diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests.csproj b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests.csproj new file mode 100644 index 0000000000..3b801c40fa --- /dev/null +++ b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp3.1;net6.0 + $(TargetFrameworks);net461 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsOptionsTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsOptionsTests.cs new file mode 100644 index 0000000000..e8942649a7 --- /dev/null +++ b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsOptionsTests.cs @@ -0,0 +1,140 @@ +// +// 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 Xunit; + +namespace OpenTelemetry.Contrib.Instrumentation.Runtime.Tests +{ + public class RuntimeMetricsOptionsTests + { + [Fact] + public void Enable_All_If_Nothing_Was_Defined() + { + var options = new RuntimeMetricsOptions(); + + Assert.True(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.True(options.IsJitEnabled); +#endif +#if NETCOREAPP3_1_OR_GREATER + Assert.True(options.IsThreadingEnabled); +#endif + Assert.True(options.IsMemoryEnabled); + Assert.True(options.IsAssembliesEnabled); + Assert.True(options.IsAllEnabled); + } + + [Fact] + public void Enable_Gc_Only() + { + var options = new RuntimeMetricsOptions { GcEnabled = true }; + + Assert.True(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.False(options.IsJitEnabled); +#endif +#if NETCOREAPP3_1_OR_GREATER + Assert.False(options.IsThreadingEnabled); +#endif + Assert.False(options.IsMemoryEnabled); + Assert.False(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } + +#if NET6_0_OR_GREATER + [Fact] + public void Enable_Jit_Only() + { + var options = new RuntimeMetricsOptions { JitEnabled = true }; + + Assert.False(options.IsGcEnabled); + Assert.True(options.IsJitEnabled); + Assert.False(options.IsThreadingEnabled); + Assert.False(options.IsMemoryEnabled); + Assert.False(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } +#endif + +#if NETCOREAPP3_1_OR_GREATER + [Fact] + public void Enable_Threading_Only() + { + var options = new RuntimeMetricsOptions { ThreadingEnabled = true }; + + Assert.False(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.False(options.IsJitEnabled); +#endif + Assert.True(options.IsThreadingEnabled); + Assert.False(options.IsMemoryEnabled); + Assert.False(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } +#endif + + [Fact] + public void Enable_Memory_Only() + { + var options = new RuntimeMetricsOptions { MemoryEnabled = true }; + + Assert.False(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.False(options.IsJitEnabled); +#endif +#if NETCOREAPP3_1_OR_GREATER + Assert.False(options.IsThreadingEnabled); +#endif + Assert.True(options.IsMemoryEnabled); + Assert.False(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } + + [Fact] + public void Enable_Assemblies_Only() + { + var options = new RuntimeMetricsOptions { AssembliesEnabled = true }; + + Assert.False(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.False(options.IsJitEnabled); +#endif +#if NETCOREAPP3_1_OR_GREATER + Assert.False(options.IsThreadingEnabled); +#endif + Assert.False(options.IsMemoryEnabled); + Assert.True(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } + + [Fact] + public void Enable_Multiple() + { + var options = new RuntimeMetricsOptions { GcEnabled = true, MemoryEnabled = true }; + + Assert.True(options.IsGcEnabled); +#if NET6_0_OR_GREATER + Assert.False(options.IsJitEnabled); +#endif +#if NETCOREAPP3_1_OR_GREATER + Assert.False(options.IsThreadingEnabled); +#endif + Assert.True(options.IsMemoryEnabled); + Assert.False(options.IsAssembliesEnabled); + Assert.False(options.IsAllEnabled); + } + } +} diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsTests.cs new file mode 100644 index 0000000000..4da53cbb5e --- /dev/null +++ b/test/OpenTelemetry.Contrib.Instrumentation.Runtime.Tests/RuntimeMetricsTests.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; +using System.Collections.Generic; +using System.Threading.Tasks; +using OpenTelemetry.Exporter; +using OpenTelemetry.Metrics; +using Xunit; + +namespace OpenTelemetry.Contrib.Instrumentation.Runtime.Tests +{ + public class RuntimeMetricsTests + { + private MeterProvider meterProvider = null; + + [Fact] + public async Task RequestMetricIsCaptured() + { + var metricItems = new List(); + var metricExporter = new InMemoryExporter(metricItems); + + var metricReader = new PeriodicExportingMetricReader(metricExporter, 500); + + this.meterProvider = Sdk.CreateMeterProviderBuilder() + .AddRuntimeMetrics(options => + { + options.GcEnabled = true; +#if NETCOREAPP3_1_OR_GREATER + options.ThreadingEnabled = true; +#endif + options.MemoryEnabled = true; +#if NET6_0_OR_GREATER + + options.JitEnabled = true; +#endif + options.AssembliesEnabled = true; + }) + .AddReader(metricReader) + .Build(); + + await Task.Delay(TimeSpan.FromSeconds(2)); + this.meterProvider.Dispose(); + + Assert.True(metricItems.Count > 1); + } + } +}