Skip to content

Commit

Permalink
Some refactoring, fixed broken test and added coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
kkeirstead committed Mar 3, 2025
1 parent b98e3f6 commit b934d90
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 68 deletions.
29 changes: 8 additions & 21 deletions src/Microsoft.Diagnostics.Monitoring.Options/MonitorCapability.cs
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;

namespace Microsoft.Diagnostics.Monitoring.Options
{
public class MonitorCapability : IMonitorCapability
public class MonitorCapability
{
public const string Exceptions = "exceptions";
public const string ParameterCapturing = "parameters";
public const string CallStacks = "callstacks";
public const string Metrics = "metrics";
public const string HttpEgress = "http_egress";

public string Name { get; }
[Required]
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;

[JsonPropertyName("enabled")]
public bool Enabled { get; set; }
public MonitorCapability(string name)
{
Name = name;
}

public MonitorCapability(string name, bool enabled)
{
Name = name;
Enabled = enabled;
}
}

public interface IMonitorCapability
{
string Name { get; }
bool Enabled
{
get; set;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public partial class DiagController : DiagnosticsControllerBase
private readonly ICaptureParametersOperationFactory _captureParametersFactory;
private readonly IGCDumpOperationFactory _gcdumpOperationFactory;
private readonly IStacksOperationFactory _stacksOperationFactory;
private readonly IEnumerable<IMonitorCapability> _monitorCapabilities;
private readonly IEnumerable<MonitorCapability> _monitorCapabilities;
public DiagController(IServiceProvider serviceProvider, ILogger<DiagController> logger)
: base(serviceProvider.GetRequiredService<IDiagnosticServices>(), serviceProvider.GetRequiredService<IEgressOperationStore>(), logger)
{
Expand All @@ -65,7 +65,7 @@ public DiagController(IServiceProvider serviceProvider, ILogger<DiagController>
_captureParametersFactory = serviceProvider.GetRequiredService<ICaptureParametersOperationFactory>();
_gcdumpOperationFactory = serviceProvider.GetRequiredService<IGCDumpOperationFactory>();
_stacksOperationFactory = serviceProvider.GetRequiredService<IStacksOperationFactory>();
_monitorCapabilities = serviceProvider.GetRequiredService<IEnumerable<IMonitorCapability>>();
_monitorCapabilities = serviceProvider.GetRequiredService<IEnumerable<MonitorCapability>>();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ public class DotnetMonitorInfo
/// The capabilities provided by dotnet-monitor.
/// </summary>
[JsonPropertyName("capabilities")]
public required IMonitorCapability[] Capabilities { get; set; }
public required MonitorCapability[] Capabilities { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using Microsoft.Diagnostics.Monitoring.TestCommon;
using Microsoft.Diagnostics.Monitoring.TestCommon.Options;
using Microsoft.Diagnostics.Monitoring.TestCommon.Runners;
using Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.Fixtures;
using Microsoft.Diagnostics.Monitoring.Tool.FunctionalTests.HttpApi;
Expand All @@ -10,6 +12,7 @@
using Microsoft.Diagnostics.Monitoring.WebApi.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
Expand All @@ -34,9 +37,9 @@ public InfoTests(ITestOutputHelper outputHelper, ServiceProviderFixture serviceP
/// Tests that the info endpoint provides the expected output.
/// </summary>
[Theory]
[InlineData(DiagnosticPortConnectionMode.Connect)]
[InlineData(DiagnosticPortConnectionMode.Listen)]
public Task InfoEndpointValidationTest(DiagnosticPortConnectionMode mode)
[InlineData(DiagnosticPortConnectionMode.Connect, false)]
[InlineData(DiagnosticPortConnectionMode.Listen, true)]
public Task InfoEndpointValidationTest(DiagnosticPortConnectionMode mode, bool enableInProcessFeatures)
{
return ScenarioRunner.SingleTarget(
_outputHelper,
Expand Down Expand Up @@ -67,7 +70,27 @@ public Task InfoEndpointValidationTest(DiagnosticPortConnectionMode mode)
Assert.Equal(runner.DiagnosticPortPath, info.DiagnosticPortName);
}

Assert.Equal(5, info.Capabilities.Length); // Update if capabilities change
Assert.Contains(info.Capabilities, capability => capability.Name == MonitorCapability.Exceptions);
Assert.Contains(info.Capabilities, capability => capability.Name == MonitorCapability.ParameterCapturing);
Assert.Contains(info.Capabilities, capability => capability.Name == MonitorCapability.Metrics);
Assert.Contains(info.Capabilities, capability => capability.Name == MonitorCapability.CallStacks);
Assert.Contains(info.Capabilities, capability => capability.Name == MonitorCapability.HttpEgress);
Assert.True(info.Capabilities.First(c => c.Name == MonitorCapability.HttpEgress).Enabled);
Assert.True(info.Capabilities.First(c => c.Name == MonitorCapability.Metrics).Enabled);
Assert.Equal(enableInProcessFeatures, info.Capabilities.First(c => c.Name == MonitorCapability.Exceptions).Enabled);
Assert.Equal(enableInProcessFeatures, info.Capabilities.First(c => c.Name == MonitorCapability.ParameterCapturing).Enabled);
Assert.Equal(enableInProcessFeatures, info.Capabilities.First(c => c.Name == MonitorCapability.CallStacks).Enabled);

await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
},
configureTool: runner =>
{
if (enableInProcessFeatures)
{
runner.ConfigurationFromEnvironment.EnableInProcessFeatures();
runner.ConfigurationFromEnvironment.EnableParameterCapturing();
}
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ public static RootOptions EnableExceptions(this RootOptions options)
return options;
}

public static RootOptions EnableParameterCapturing(this RootOptions options)
{
options.GetOrCreateInProcessFeaturesOptions().GetOrCreateParameterCapturingOptions().Enabled = true;

return options;
}

private static ExceptionsOptions GetOrCreateExceptionsOptions(this InProcessFeaturesOptions options)
{
ExceptionsOptions exceptionsOptions = options.Exceptions;
Expand All @@ -101,6 +108,17 @@ private static ExceptionsOptions GetOrCreateExceptionsOptions(this InProcessFeat
return exceptionsOptions;
}

private static ParameterCapturingOptions GetOrCreateParameterCapturingOptions(this InProcessFeaturesOptions options)
{
ParameterCapturingOptions parameterOptions = options.ParameterCapturing;
if (null == parameterOptions)
{
parameterOptions = new ParameterCapturingOptions();
options.ParameterCapturing = parameterOptions;
}
return parameterOptions;
}

public static RootOptions SetExceptionFiltering(this RootOptions options, ExceptionsConfiguration configuration)
{
options.GetOrCreateInProcessFeaturesOptions().GetOrCreateExceptionsOptions().CollectionFilters = configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.Monitoring
{
public class CallStacksCapabilityPostConfigureOptions : CapabilityPostConfigureOptions<CallStacksOptions>
{
public CallStacksCapabilityPostConfigureOptions(IEnumerable<MonitorCapability> capabilities)
: base(capabilities.First(c => c.Name == MonitorCapability.CallStacks))
{
}

public override void PostConfigure(string? _, CallStacksOptions options)
{
PostConfigure(options.Enabled ?? false);
}
}
}
41 changes: 9 additions & 32 deletions src/Tools/dotnet-monitor/CapabilitiesPostConfigureOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,27 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using Microsoft.Diagnostics.Monitoring.WebApi;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.Monitoring
{
public class CapabilityPostConfigureOptions :
IPostConfigureOptions<CallStacksOptions>,
IPostConfigureOptions<ExceptionsOptions>,
IPostConfigureOptions<ParameterCapturingOptions>,
IPostConfigureOptions<MetricsOptions>
public abstract class CapabilityPostConfigureOptions<T> : IPostConfigureOptions<T> where T : class
{
private readonly List<IMonitorCapability> _capabilities;
private readonly Dictionary<Type, string> _capabilityMap;
private MonitorCapability? _capability;

public CapabilityPostConfigureOptions(IEnumerable<IMonitorCapability> capabilities)
public CapabilityPostConfigureOptions(MonitorCapability? capability)
{
_capabilities = capabilities.ToList();
_capabilityMap = new Dictionary<Type, string>
{
{ typeof(CallStacksOptions), MonitorCapability.CallStacks },
{ typeof(ExceptionsOptions), MonitorCapability.Exceptions },
{ typeof(ParameterCapturingOptions), MonitorCapability.ParameterCapturing },
{ typeof(MetricsOptions), MonitorCapability.Metrics }
};
_capability = capability;
}

public void PostConfigure<TOptions>(bool isEnabled) where TOptions : class
public abstract void PostConfigure(string? name, T options);

public void PostConfigure(bool isEnabled)
{
if (_capabilityMap.TryGetValue(typeof(TOptions), out string? capabilityName))
if (_capability != null)
{
IMonitorCapability? capability = _capabilities.FirstOrDefault(c => c.Name == capabilityName);
if (capability != null)
{
capability.Enabled = isEnabled;
}
_capability.Enabled = isEnabled;
}
}

public void PostConfigure(string? _, CallStacksOptions options) => PostConfigure<CallStacksOptions>(options.Enabled ?? false);
public void PostConfigure(string? _, ExceptionsOptions options) => PostConfigure<ExceptionsOptions>(options.Enabled ?? false);
public void PostConfigure(string? _, ParameterCapturingOptions options) => PostConfigure<ParameterCapturingOptions>(options.Enabled ?? false);
public void PostConfigure(string? _, MetricsOptions options) => PostConfigure<MetricsOptions>(options.Enabled ?? false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.Monitoring
{
public class ExceptionsCapabilityPostConfigureOptions : CapabilityPostConfigureOptions<ExceptionsOptions>
{
public ExceptionsCapabilityPostConfigureOptions(IEnumerable<MonitorCapability> capabilities)
: base(capabilities.First(c => c.Name == MonitorCapability.Exceptions))
{
}

public override void PostConfigure(string? _, ExceptionsOptions options)
{
PostConfigure(options.Enabled ?? false);
}
}
}
23 changes: 23 additions & 0 deletions src/Tools/dotnet-monitor/MetricsCapabilityPostConfigureOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using Microsoft.Diagnostics.Monitoring.WebApi;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.Monitoring
{
public class MetricsCapabilityPostConfigureOptions : CapabilityPostConfigureOptions<MetricsOptions>
{
public MetricsCapabilityPostConfigureOptions(IEnumerable<MonitorCapability> capabilities)
: base(capabilities.First(c => c.Name == MonitorCapability.Metrics))
{
}

public override void PostConfigure(string? _, MetricsOptions options)
{
PostConfigure(options.Enabled ?? false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Diagnostics.Monitoring.Options;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.Monitoring
{
public class ParametersCapabilityPostConfigureOptions : CapabilityPostConfigureOptions<ParameterCapturingOptions>
{
public ParametersCapabilityPostConfigureOptions(IEnumerable<MonitorCapability> capabilities)
: base(capabilities.First(c => c.Name == MonitorCapability.ParameterCapturing))
{
}

public override void PostConfigure(string? _, ParameterCapturingOptions options)
{
PostConfigure(options.Enabled ?? false);
}
}
}
18 changes: 9 additions & 9 deletions src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,19 @@ public static IServiceCollection ConfigureStorage(this IServiceCollection servic

public static IServiceCollection ConfigureCapabilities(this IServiceCollection services, bool noHttpEgress)
{
services.AddSingleton<IMonitorCapability>(new MonitorCapability(MonitorCapability.Metrics));
services.AddSingleton<IPostConfigureOptions<MetricsOptions>, CapabilityPostConfigureOptions>();
services.AddSingleton(new MonitorCapability() { Name = MonitorCapability.Metrics });
services.AddSingleton<IPostConfigureOptions<MetricsOptions>, MetricsCapabilityPostConfigureOptions>();

services.AddSingleton<IMonitorCapability>(new MonitorCapability(MonitorCapability.Exceptions));
services.AddSingleton<IPostConfigureOptions<ExceptionsOptions>, CapabilityPostConfigureOptions>();
services.AddSingleton(new MonitorCapability() { Name = MonitorCapability.Exceptions });
services.AddSingleton<IPostConfigureOptions<ExceptionsOptions>, ExceptionsCapabilityPostConfigureOptions>();

services.AddSingleton<IMonitorCapability>(new MonitorCapability(MonitorCapability.CallStacks));
services.AddSingleton<IPostConfigureOptions<CallStacksOptions>, CapabilityPostConfigureOptions>();
services.AddSingleton(new MonitorCapability() { Name = MonitorCapability.CallStacks });
services.AddSingleton<IPostConfigureOptions<CallStacksOptions>, CallStacksCapabilityPostConfigureOptions>();

services.AddSingleton<IMonitorCapability>(new MonitorCapability(MonitorCapability.ParameterCapturing));
services.AddSingleton<IPostConfigureOptions<ParameterCapturingOptions>, CapabilityPostConfigureOptions>();
services.AddSingleton(new MonitorCapability() { Name = MonitorCapability.ParameterCapturing });
services.AddSingleton<IPostConfigureOptions<ParameterCapturingOptions>, ParametersCapabilityPostConfigureOptions>();

services.AddSingleton<IMonitorCapability>(new MonitorCapability(MonitorCapability.HttpEgress, !noHttpEgress));
services.AddSingleton(new MonitorCapability() { Name = MonitorCapability.HttpEgress, Enabled = !noHttpEgress });

return services;
}
Expand Down

0 comments on commit b934d90

Please sign in to comment.