From ac98dd42d409cfff73632c292124a24f43af8806 Mon Sep 17 00:00:00 2001 From: Julian Mathias Kock Date: Mon, 24 Feb 2025 14:34:44 +0100 Subject: [PATCH 1/5] Change to early return of OS instead of throwing This will make sure that the executed code only works in scenarios that are supported, which is Windows and Linux. This is particularly important for teams working on different operating systems, and running the code without containerization. --- .../ResourceMonitoringServiceCollectionExtensions.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs index c09e4c85b75..3bca037f3a3 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs @@ -63,6 +63,12 @@ private static IServiceCollection AddResourceMonitoringInternal( this IServiceCollection services, Action configure) { + bool isSupportedOs = OperatingSystem.IsWindows() || OperatingSystem.IsLinux(); + if (!isSupportedOs) + { + return services; + } + var builder = new ResourceMonitorBuilder(services); _ = services.AddMetrics(); @@ -78,10 +84,6 @@ private static IServiceCollection AddResourceMonitoringInternal( { _ = builder.AddLinuxProvider(); } - else - { - throw new PlatformNotSupportedException(); - } #endif configure.Invoke(builder); From 1d171e312c0fbd2903a586fe2f0e18305d33fa07 Mon Sep 17 00:00:00 2001 From: Julian Mathias Kock Date: Tue, 4 Mar 2025 06:57:39 +0100 Subject: [PATCH 2/5] fix: only use OperatingSystem when available --- .../ResourceMonitoringServiceCollectionExtensions.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs index 3bca037f3a3..e23d82b3c6b 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs @@ -63,19 +63,17 @@ private static IServiceCollection AddResourceMonitoringInternal( this IServiceCollection services, Action configure) { + _ = services.AddMetrics(); + var builder = new ResourceMonitorBuilder(services); +#if NETFRAMEWORK + _ = builder.AddWindowsProvider(); +#else bool isSupportedOs = OperatingSystem.IsWindows() || OperatingSystem.IsLinux(); if (!isSupportedOs) { return services; } - var builder = new ResourceMonitorBuilder(services); - - _ = services.AddMetrics(); - -#if NETFRAMEWORK - _ = builder.AddWindowsProvider(); -#else if (OperatingSystem.IsWindows()) { _ = builder.AddWindowsProvider(); From ca55453b2ec4aa3c0d9f7f3955cf64d18c045a5a Mon Sep 17 00:00:00 2001 From: evgenyfedorov2 Date: Fri, 27 Jun 2025 22:53:34 +0200 Subject: [PATCH 3/5] Remove ExcludeFromCodeCoverage attribute --- .../ResourceMonitoringServiceCollectionExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs index e23d82b3c6b..1ea5e668a9a 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/ResourceMonitoringServiceCollectionExtensions.cs @@ -57,8 +57,6 @@ public static IServiceCollection AddResourceMonitoring( return services.AddResourceMonitoringInternal(configure); } - // can't easily test the exception throwing case - [ExcludeFromCodeCoverage] private static IServiceCollection AddResourceMonitoringInternal( this IServiceCollection services, Action configure) From 892b4b6c2523a30bcf8b0ddb81e258dec389a681 Mon Sep 17 00:00:00 2001 From: evgenyfedorov2 Date: Sun, 29 Jun 2025 22:27:31 +0200 Subject: [PATCH 4/5] More tests --- .../ResourceMonitoringExtensionsTests.cs | 52 ++++++++++++++++++- .../XUnit/OSSkipConditionAttribute.cs | 2 +- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs index 995afb65c62..23384433b94 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs @@ -16,9 +16,9 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test; -[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] public sealed class ResourceMonitoringExtensionsTests { + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void Throw_Null_When_Registration_Ingredients_Null() { @@ -30,6 +30,7 @@ public void Throw_Null_When_Registration_Ingredients_Null() Assert.Throws(() => services.AddResourceMonitoring((b) => b.ConfigureMonitor((Action)null!))); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void AddsResourceMonitoringService_ToServicesCollection() { @@ -50,6 +51,7 @@ public void AddsResourceMonitoringService_ToServicesCollection() Assert.IsAssignableFrom(trackerService); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void AddsResourceMonitoringService_ToServicesCollection_NoArgs() { @@ -66,6 +68,7 @@ public void AddsResourceMonitoringService_ToServicesCollection_NoArgs() Assert.IsAssignableFrom(trackerService); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void AddsResourceMonitoringService_AsHostedService() { @@ -87,6 +90,7 @@ public void AddsResourceMonitoringService_AsHostedService() Assert.IsAssignableFrom(trackerService); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void ConfigureResourceUtilization_InitializeTrackerProperly() { @@ -113,6 +117,7 @@ public void ConfigureResourceUtilization_InitializeTrackerProperly() Assert.NotNull(publisher); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void ConfigureMonitor_GivenOptionsDelegate_InitializeTrackerWithOptionsProperly() { @@ -141,6 +146,7 @@ public void ConfigureMonitor_GivenOptionsDelegate_InitializeTrackerWithOptionsPr Assert.Equal(TimeSpan.FromSeconds(CalculationPeriodValue), options!.Value.PublishingWindow); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void ConfigureMonitor_GivenIConfigurationSection_InitializeTrackerWithOptionsProperly() { @@ -182,6 +188,7 @@ public void ConfigureMonitor_GivenIConfigurationSection_InitializeTrackerWithOpt Assert.Equal(TimeSpan.FromSeconds(CalculationPeriod), options!.Value.PublishingWindow); } + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void Registering_Resource_Utilization_Adds_Only_One_Object_Of_Type_ResourceUtilizationService_To_DI_Container() { @@ -204,4 +211,47 @@ public void Registering_Resource_Utilization_Adds_Only_One_Object_Of_Type_Resour Assert.IsAssignableFrom(background); Assert.Same(tracker as ResourceMonitorService, background as ResourceMonitorService); } + + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.Windows, SkipReason = "For MacOs only.")] + [ConditionalFact] + public void AddResourceMonitoringInternal_WhenMacOs_ReturnsSameServiceCollection() + { + var services = new ServiceCollection(); + + // Act + IServiceCollection result = services.AddResourceMonitoring(); + + // Assert + Assert.Same(services, result); + Assert.DoesNotContain(services, s => s.ServiceType == typeof(ISnapshotProvider)); + } + + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] + [ConditionalFact] + public void AddResourceMonitoring_AddsISnapshotProvider() + { + var services = new ServiceCollection(); + + // Act + IServiceCollection result = services.AddResourceMonitoring(); + + // Assert + Assert.Same(services, result); + Assert.Contains(services, s => s.ServiceType == typeof(ISnapshotProvider)); + } + + + [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] + [ConditionalFact] + public void AddResourceMonitoringInternal_CallsConfigureDelegate() + { + var services = new ServiceCollection(); + bool delegateCalled = false; + + // Act + services.AddResourceMonitoring(_ => delegateCalled = true); + + // Assert + Assert.True(delegateCalled); + } } diff --git a/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs b/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs index 143cd7005ad..586b53d3fcb 100644 --- a/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs +++ b/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs @@ -60,7 +60,7 @@ private static OperatingSystems GetCurrentOS() throw new PlatformNotSupportedException(); #else - // RuntimeInformation API is only avaialble in .NET Framework 4.7.1+ + // RuntimeInformation API is only available in .NET Framework 4.7.1+ // .NET Framework 4.7 and below can only run on Windows. return OperatingSystems.Windows; #endif From 1d547bd5ace7438eb42ac245a96379898b0540f3 Mon Sep 17 00:00:00 2001 From: evgenyfedorov2 Date: Sun, 29 Jun 2025 22:41:29 +0200 Subject: [PATCH 5/5] Update Readme --- .../README.md | 6 +++++- .../ResourceMonitoringExtensionsTests.cs | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/README.md b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/README.md index ae20ab0297e..41f91b7df44 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/README.md +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/README.md @@ -1,6 +1,10 @@ # Microsoft.Extensions.Diagnostics.ResourceMonitoring -Measures and reports processor and memory usage. This library utilizes control groups (cgroups) in Linux to monitor system resources. Both cgroups v1 and v2 are supported. +Measures and reports processor and memory usage. To monitor system resources, this library: + +- Utilizes control groups (cgroups) in Linux. Both cgroups v1 and v2 are supported. +- Utilized Job Objects in Windows. +- Mac OS is not supported. ## Install the package diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs index 23384433b94..875fbb67158 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs @@ -240,7 +240,6 @@ public void AddResourceMonitoring_AddsISnapshotProvider() Assert.Contains(services, s => s.ServiceType == typeof(ISnapshotProvider)); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] [ConditionalFact] public void AddResourceMonitoringInternal_CallsConfigureDelegate()