|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring;
#if !NETFRAMEWORK
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Network;
#endif
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Interop;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Network;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Lets you configure and register resource monitoring components.
/// </summary>
public static class ResourceMonitoringServiceCollectionExtensions
{
/// <summary>
/// Configures and adds an <see cref="IResourceMonitor"/> implementation to a service collection.
/// </summary>
/// <param name="services">The dependency injection container to add the monitor to.</param>
/// <returns>The value of <paramref name="services" />.</returns>
/// <exception cref="ArgumentNullException"><paramref name="services"/> is <see langword="null"/>.</exception>
public static IServiceCollection AddResourceMonitoring(
this IServiceCollection services)
{
_ = Throw.IfNull(services);
return services.AddResourceMonitoringInternal(o => { });
}
/// <summary>
/// Configures and adds an <see cref="IResourceMonitor"/> implementation to a service collection.
/// </summary>
/// <param name="services">The dependency injection container to add the monitor to.</param>
/// <param name="configure">Delegate to configure <see cref="IResourceMonitorBuilder"/>.</param>
/// <returns>The value of <paramref name="services" />.</returns>
/// <exception cref="ArgumentNullException">Either <paramref name="services"/> or <paramref name="configure"/> is <see langword="null"/>.</exception>
public static IServiceCollection AddResourceMonitoring(
this IServiceCollection services,
Action<IResourceMonitorBuilder> configure)
{
_ = Throw.IfNull(services);
_ = Throw.IfNull(configure);
return services.AddResourceMonitoringInternal(configure);
}
// can't easily test the exception throwing case
[ExcludeFromCodeCoverage]
private static IServiceCollection AddResourceMonitoringInternal(
this IServiceCollection services,
Action<IResourceMonitorBuilder> configure)
{
var builder = new ResourceMonitorBuilder(services);
_ = services.AddMetrics();
#if NETFRAMEWORK
_ = builder.AddWindowsProvider();
#else
if (OperatingSystem.IsWindows())
{
_ = builder.AddWindowsProvider();
}
else if (OperatingSystem.IsLinux())
{
_ = builder.AddLinuxProvider();
}
else
{
throw new PlatformNotSupportedException();
}
#endif
configure.Invoke(builder);
return services;
}
private static ResourceMonitorBuilder AddWindowsProvider(this ResourceMonitorBuilder builder)
{
builder.PickWindowsSnapshotProvider();
_ = builder.Services
.AddActivatedSingleton<WindowsNetworkMetrics>()
.AddActivatedSingleton<ITcpStateInfoProvider, WindowsTcpStateInfo>();
return builder;
}
[ExcludeFromCodeCoverage]
private static void PickWindowsSnapshotProvider(this ResourceMonitorBuilder builder)
{
if (JobObjectInfo.SafeJobHandle.IsProcessInJob())
{
builder.Services.TryAddSingleton<ISnapshotProvider, WindowsContainerSnapshotProvider>();
}
else
{
builder.Services.TryAddSingleton<ISnapshotProvider, WindowsSnapshotProvider>();
}
}
#if !NETFRAMEWORK
private static ResourceMonitorBuilder AddLinuxProvider(this ResourceMonitorBuilder builder)
{
_ = Throw.IfNull(builder);
builder.Services.TryAddActivatedSingleton<ISnapshotProvider, LinuxUtilizationProvider>();
builder.Services.TryAddSingleton<IFileSystem, OSFileSystem>();
builder.Services.TryAddSingleton<IUserHz, UserHz>();
builder.PickLinuxParser();
_ = builder.Services
.AddActivatedSingleton<LinuxNetworkUtilizationParser>()
.AddActivatedSingleton<LinuxNetworkMetrics>()
.AddActivatedSingleton<ITcpStateInfoProvider, LinuxTcpStateInfo>();
return builder;
}
[ExcludeFromCodeCoverage]
private static void PickLinuxParser(this ResourceMonitorBuilder builder)
{
var injectParserV2 = ResourceMonitoringLinuxCgroupVersion.GetCgroupType();
if (injectParserV2)
{
builder.Services.TryAddSingleton<ILinuxUtilizationParser, LinuxUtilizationParserCgroupV2>();
}
else
{
builder.Services.TryAddSingleton<ILinuxUtilizationParser, LinuxUtilizationParserCgroupV1>();
}
}
#endif
}
|