From 04aed2fd27051f7546e5b89380bcfd79dc63a948 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 18:10:12 +0000 Subject: [PATCH 1/6] Use separate action descriptor types --- .../ActionListExecutorTests.cs | 2 +- .../ActionsServiceCollectionExtensions.cs | 4 +-- .../CollectionRules/Actions/CallbackAction.cs | 15 +++++++++++ .../Actions/PassThroughAction.cs | 9 +++++++ .../ActionDependencyAnalyzerTests.cs | 12 ++++----- .../Actions/CollectDumpAction.cs | 8 ++++++ .../Actions/CollectExceptionsAction.cs | 8 ++++++ .../Actions/CollectGCDumpAction.cs | 8 ++++++ .../Actions/CollectLiveMetricsAction.cs | 8 ++++++ .../Actions/CollectLogsAction.cs | 8 ++++++ .../Actions/CollectStacksAction.cs | 8 ++++++ .../Actions/CollectTraceAction.cs | 8 ++++++ .../CollectionRules/Actions/ExecuteAction.cs | 8 ++++++ .../Actions/GetEnvironmentVariableAction.cs | 8 ++++++ .../Actions/LoadProfilerAction.cs | 8 ++++++ .../Actions/SetEnvironmentVariableAction.cs | 8 ++++++ .../CollectionRuleActionDescriptor.cs | 24 ----------------- .../ServiceCollectionExtensions.cs | 27 ++++++++++--------- 18 files changed, 135 insertions(+), 46 deletions(-) delete mode 100644 src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleActionDescriptor.cs diff --git a/src/Tests/CollectionRuleActions.UnitTests/ActionListExecutorTests.cs b/src/Tests/CollectionRuleActions.UnitTests/ActionListExecutorTests.cs index 417612e9baa..be6564186dd 100644 --- a/src/Tests/CollectionRuleActions.UnitTests/ActionListExecutorTests.cs +++ b/src/Tests/CollectionRuleActions.UnitTests/ActionListExecutorTests.cs @@ -186,7 +186,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => Assert.Throws(() => host.Services.GetRequiredService>().Get(DefaultRuleName)); }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/ActionsServiceCollectionExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/ActionsServiceCollectionExtensions.cs index 488893a7f6d..5ffb31ba8e1 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/ActionsServiceCollectionExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/ActionsServiceCollectionExtensions.cs @@ -14,7 +14,7 @@ internal static class ActionsServiceCollectionExtensions public static IServiceCollection RegisterTestAction(this IServiceCollection services, CallbackActionService callback) { services.AddSingleton(callback); - services.RegisterCollectionRuleAction(CallbackAction.ActionName); + services.RegisterCollectionRuleAction(); return services; } @@ -22,7 +22,7 @@ public static IServiceCollection RegisterTestAction(this IServiceCollection serv public static IServiceCollection RegisterDelayedTestAction(this IServiceCollection services, CallbackActionService callback) { services.AddSingleton(callback); - services.RegisterCollectionRuleAction(DelayedCallbackAction.ActionName); + services.RegisterCollectionRuleAction(); return services; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs index d3fa485312b..9ab847a8ee8 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using System; using System.Collections.Generic; @@ -73,6 +74,13 @@ public ICollectionRuleAction Create(IProcessInfo processInfo, BaseRecordOptions } } + internal sealed class CallbackActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => CallbackAction.ActionName; + public Type OptionsType => typeof(BaseRecordOptions); + public Type FactoryType => typeof(CallbackActionFactory); + } + internal sealed class DelayedCallbackAction : ICollectionRuleAction { public const string ActionName = nameof(DelayedCallbackAction); @@ -111,6 +119,13 @@ public Task WaitForCompletionAsync(CancellationToken } } + internal sealed class DelayedCallbackActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => DelayedCallbackAction.ActionName; + public Type OptionsType => typeof(BaseRecordOptions); + public Type FactoryType => typeof(DelayedCallbackActionFactory); + } + internal sealed class CallbackActionService { public TimeProvider TimeProvider { get; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs index 182df3dfb90..d5bd00da1e7 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs @@ -3,7 +3,9 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -53,6 +55,13 @@ public Task WaitForCompletionAsync(CancellationToken } } + internal sealed class PassThroughActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => nameof(PassThroughAction); + public Type OptionsType => typeof(PassThroughOptions); + public Type FactoryType => typeof(PassThroughActionFactory); + } + internal sealed record class PassThroughOptions : BaseRecordOptions { [ActionOptionsDependencyProperty] diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs index 003a036ec8f..5e55d62eecf 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ActionDependencyAnalyzerTests.cs @@ -135,7 +135,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => Assert.Equal("Output a1input3 trail", a2output3); }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } @@ -174,7 +174,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } @@ -211,7 +211,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => }, serviceCollection => { serviceCollection.AddSingleton(); - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } @@ -254,7 +254,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }, loggingBuilder => { loggingBuilder.AddProvider(new TestLoggerProvider(record)); @@ -290,7 +290,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } @@ -352,7 +352,7 @@ await TestHostHelper.CreateCollectionRulesHost(_outputHelper, rootOptions => Assert.Equal("Output a1input3 trail", a2output3); }, serviceCollection => { - serviceCollection.RegisterCollectionRuleAction(nameof(PassThroughAction)); + serviceCollection.RegisterCollectionRuleAction(); }); } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs index ac740410b20..706816008f6 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Monitoring.WebApi.Models; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Extensions.DependencyInjection; using System; @@ -66,4 +67,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat } } } + + internal sealed class CollectDumpActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectDump; + public Type FactoryType => typeof(CollectDumpActionFactory); + public Type OptionsType => typeof(CollectDumpOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs index efc8f2150ce..0cc81f403be 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.ComponentModel.DataAnnotations; @@ -55,4 +56,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat return egressOperation; } } + + internal sealed class CollectExceptionsActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectExceptions; + public Type FactoryType => typeof(CollectExceptionsActionFactory); + public Type OptionsType => typeof(CollectExceptionsOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs index 21157f86952..67941439175 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs @@ -7,6 +7,7 @@ using System; using System.ComponentModel.DataAnnotations; using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Actions { @@ -59,4 +60,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat } } } + + internal sealed class CollectGCDumpActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectGCDump; + public Type FactoryType => typeof(CollectGCDumpActionFactory); + public Type OptionsType => typeof(CollectGCDumpOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs index 9ba039edc59..4c95de29d10 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Monitoring.WebApi.Models; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; @@ -95,4 +96,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat } } } + + internal sealed class CollectLiveMetricsActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectLiveMetrics; + public Type FactoryType => typeof(CollectLiveMetricsActionFactory); + public Type OptionsType => typeof(CollectLiveMetricsOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs index 41546ca8182..7e2408a3e40 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.Options; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; @@ -83,4 +84,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat } } } + + internal sealed class CollectLogsActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectLogs; + public Type FactoryType => typeof(CollectLogsActionFactory); + public Type OptionsType => typeof(CollectLogsOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs index 5c9c53c2d67..0a77c7064dd 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.ComponentModel.DataAnnotations; @@ -71,4 +72,11 @@ private static StackFormat MapCallStackFormat(CallStackFormat format) => _ => throw new InvalidOperationException() }; } + + internal sealed class CollectStacksActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectStacks; + public Type FactoryType => typeof(CollectStacksActionFactory); + public Type OptionsType => typeof(CollectStacksOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs index cd5d6c1540c..0f0f00613d6 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Monitoring.WebApi.Models; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; @@ -107,4 +108,11 @@ protected override EgressOperation CreateArtifactOperation(CollectionRuleMetadat } } } + + internal sealed class CollectTraceActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.CollectTrace; + public Type FactoryType => typeof(CollectTraceActionFactory); + public Type OptionsType => typeof(CollectTraceOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs index eb77d0c0926..f21ee2f7a9d 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.EventPipe; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -105,4 +106,11 @@ internal static void ValidateExitCode(bool ignoreExitCode, int exitCode) } } } + + internal sealed class ExecuteActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.Execute; + public Type FactoryType => typeof(ExecuteActionFactory); + public Type OptionsType => typeof(ExecuteOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs index a75d576916b..662cbbb6176 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.NETCore.Client; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Extensions.Logging; using System; @@ -83,4 +84,11 @@ protected override async Task ExecuteCoreAsync( } } } + + internal sealed class GetEnvironmentVariableActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.GetEnvironmentVariable; + public Type OptionsType => typeof(GetEnvironmentVariableOptions); + public Type FactoryType => typeof(GetEnvironmentVariableActionFactory); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs index d3338bd8520..c5a0e5a384e 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Logging; using System; using System.ComponentModel.DataAnnotations; @@ -68,4 +69,11 @@ protected override async Task ExecuteCoreAsync( } } } + + internal sealed class LoadProfilerActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.LoadProfiler; + public Type FactoryType => typeof(LoadProfilerActionFactory); + public Type OptionsType => typeof(LoadProfilerOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs index edd4298089c..c64bf229317 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Logging; using System; using System.ComponentModel.DataAnnotations; @@ -68,4 +69,11 @@ protected override async Task ExecuteCoreAsync( } } } + + internal sealed class SetEnvironmentVariableActionDescriptor : ICollectionRuleActionDescriptor + { + public string ActionName => KnownCollectionRuleActions.SetEnvironmentVariable; + public Type FactoryType => typeof(SetEnvironmentVariableActionFactory); + public Type OptionsType => typeof(SetEnvironmentVariableOptions); + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleActionDescriptor.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleActionDescriptor.cs deleted file mode 100644 index b032176db15..00000000000 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleActionDescriptor.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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.Tools.Monitor.CollectionRules.Actions; -using System; - -namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration -{ - internal sealed class CollectionRuleActionDescriptor : - ICollectionRuleActionDescriptor - where TFactory : ICollectionRuleActionFactory - { - public CollectionRuleActionDescriptor(string actionName) - { - ActionName = actionName; - } - - public string ActionName { get; } - - public Type FactoryType => typeof(TFactory); - - public Type OptionsType => typeof(TOptions); - } -} diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 2a3683477b6..898612024d4 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -140,17 +140,17 @@ public static AuthenticationBuilder ConfigureMonitorApiKeyAuthentication(this IS public static IServiceCollection ConfigureCollectionRules(this IServiceCollection services) { - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectDump); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectExceptions); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectGCDump); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectLiveMetrics); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectLogs); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectStacks); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.CollectTrace); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.Execute); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.LoadProfiler); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.SetEnvironmentVariable); - services.RegisterCollectionRuleAction(KnownCollectionRuleActions.GetEnvironmentVariable); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); + services.RegisterCollectionRuleAction(); services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.AspNetRequestCount); services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.AspNetRequestDuration); @@ -196,13 +196,14 @@ public static IServiceCollection ConfigureCollectionRules(this IServiceCollectio return services; } - public static IServiceCollection RegisterCollectionRuleAction(this IServiceCollection services, string actionName) + public static IServiceCollection RegisterCollectionRuleAction(this IServiceCollection services) where TFactory : class, ICollectionRuleActionFactory where TOptions : BaseRecordOptions, new() + where TDescriptor : class, ICollectionRuleActionDescriptor, new() { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton>(sp => new CollectionRuleActionDescriptor(actionName)); + services.AddSingleton(sp => new TDescriptor()); // NOTE: When opening collection rule actions for extensibility, this should not be added for all registered actions. // Each action should register its own IValidateOptions<> implementation (if it needs one). services.AddSingleton, DataAnnotationValidateOptions>(); From 65f601ac71b5736ae1e463cf438953fcdb046107 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 18:30:15 +0000 Subject: [PATCH 2/6] Move BindOptions to action descriptors --- .../CollectionRules/Actions/CallbackAction.cs | 15 +++++++++++++++ .../CollectionRules/Actions/PassThroughAction.cs | 8 ++++++++ .../CollectionRules/Actions/CollectDumpAction.cs | 8 ++++++++ .../Actions/CollectExceptionsAction.cs | 8 ++++++++ .../Actions/CollectGCDumpAction.cs | 8 ++++++++ .../Actions/CollectLiveMetricsAction.cs | 8 ++++++++ .../CollectionRules/Actions/CollectLogsAction.cs | 8 ++++++++ .../Actions/CollectStacksAction.cs | 8 ++++++++ .../CollectionRules/Actions/CollectTraceAction.cs | 8 ++++++++ .../Actions/CollectionRuleActionOperations.cs | 7 +++++-- .../CollectionRules/Actions/ExecuteAction.cs | 8 ++++++++ .../Actions/GetEnvironmentVariableAction.cs | 8 ++++++++ .../Actions/ICollectionRuleActionOperations.cs | 4 +++- .../CollectionRules/Actions/LoadProfilerAction.cs | 8 ++++++++ .../Actions/SetEnvironmentVariableAction.cs | 8 ++++++++ .../Configuration/CollectionRuleBindingHelper.cs | 6 +----- .../ICollectionRuleActionDescriptor.cs | 3 +++ 17 files changed, 123 insertions(+), 8 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs index 9ab847a8ee8..4e2c28bfc82 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/CallbackAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Threading; @@ -79,6 +80,13 @@ internal sealed class CallbackActionDescriptor : ICollectionRuleActionDescriptor public string ActionName => CallbackAction.ActionName; public Type OptionsType => typeof(BaseRecordOptions); public Type FactoryType => typeof(CallbackActionFactory); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + BaseRecordOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } internal sealed class DelayedCallbackAction : ICollectionRuleAction @@ -124,6 +132,13 @@ internal sealed class DelayedCallbackActionDescriptor : ICollectionRuleActionDes public string ActionName => DelayedCallbackAction.ActionName; public Type OptionsType => typeof(BaseRecordOptions); public Type FactoryType => typeof(DelayedCallbackActionFactory); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + BaseRecordOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } internal sealed class CallbackActionService diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs index d5bd00da1e7..f8b350b6bda 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTestCommon/CollectionRules/Actions/PassThroughAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Threading; @@ -60,6 +61,13 @@ internal sealed class PassThroughActionDescriptor : ICollectionRuleActionDescrip public string ActionName => nameof(PassThroughAction); public Type OptionsType => typeof(PassThroughOptions); public Type FactoryType => typeof(PassThroughActionFactory); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + PassThroughOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } internal sealed record class PassThroughOptions : BaseRecordOptions diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs index 706816008f6..e4a3debe39a 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectDumpAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi.Models; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.ComponentModel.DataAnnotations; @@ -73,5 +74,12 @@ internal sealed class CollectDumpActionDescriptor : ICollectionRuleActionDescrip public string ActionName => KnownCollectionRuleActions.CollectDump; public Type FactoryType => typeof(CollectDumpActionFactory); public Type OptionsType => typeof(CollectDumpOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectDumpOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs index 0cc81f403be..f9156e83d77 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectExceptionsAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities; @@ -62,5 +63,12 @@ internal sealed class CollectExceptionsActionDescriptor : ICollectionRuleActionD public string ActionName => KnownCollectionRuleActions.CollectExceptions; public Type FactoryType => typeof(CollectExceptionsActionFactory); public Type OptionsType => typeof(CollectExceptionsOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectExceptionsOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs index 67941439175..b2ab4445160 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectGCDumpAction.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.ComponentModel.DataAnnotations; @@ -66,5 +67,12 @@ internal sealed class CollectGCDumpActionDescriptor : ICollectionRuleActionDescr public string ActionName => KnownCollectionRuleActions.CollectGCDump; public Type FactoryType => typeof(CollectGCDumpActionFactory); public Type OptionsType => typeof(CollectGCDumpOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectGCDumpOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs index 4c95de29d10..26200990c76 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLiveMetricsAction.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi.Models; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; @@ -102,5 +103,12 @@ internal sealed class CollectLiveMetricsActionDescriptor : ICollectionRuleAction public string ActionName => KnownCollectionRuleActions.CollectLiveMetrics; public Type FactoryType => typeof(CollectLiveMetricsActionFactory); public Type OptionsType => typeof(CollectLiveMetricsOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectLiveMetricsOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs index 7e2408a3e40..c76deac2531 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectLogsAction.cs @@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -90,5 +91,12 @@ internal sealed class CollectLogsActionDescriptor : ICollectionRuleActionDescrip public string ActionName => KnownCollectionRuleActions.CollectLogs; public Type FactoryType => typeof(CollectLogsActionFactory); public Type OptionsType => typeof(CollectLogsOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectLogsOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs index 0a77c7064dd..8001d0e99d7 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectStacksAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities; @@ -78,5 +79,12 @@ internal sealed class CollectStacksActionDescriptor : ICollectionRuleActionDescr public string ActionName => KnownCollectionRuleActions.CollectStacks; public Type FactoryType => typeof(CollectStacksActionFactory); public Type OptionsType => typeof(CollectStacksOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectStacksOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs index 0f0f00613d6..92b7f9c43f4 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectTraceAction.cs @@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using Utils = Microsoft.Diagnostics.Monitoring.WebApi.Utilities; @@ -114,5 +115,12 @@ internal sealed class CollectTraceActionDescriptor : ICollectionRuleActionDescri public string ActionName => KnownCollectionRuleActions.CollectTrace; public Type FactoryType => typeof(CollectTraceActionFactory); public Type OptionsType => typeof(CollectTraceOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + CollectTraceOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectionRuleActionOperations.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectionRuleActionOperations.cs index aea65cae497..746af4f906a 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectionRuleActionOperations.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/CollectionRuleActionOperations.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -59,13 +60,15 @@ public bool TryCreateFactory( } /// - public bool TryCreateOptions( + public bool TryBindOptions( string actionName, + IConfigurationSection actionSection, out object options) { if (_map.TryGetValue(actionName, out ICollectionRuleActionDescriptor descriptor)) { - options = Activator.CreateInstance(descriptor.OptionsType); + IConfigurationSection settingsSection = actionSection.GetSection(nameof(CollectionRuleActionOptions.Settings)); + descriptor.BindOptions(settingsSection, out options); return true; } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs index f21ee2f7a9d..000120179a0 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/ExecuteAction.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -112,5 +113,12 @@ internal sealed class ExecuteActionDescriptor : ICollectionRuleActionDescriptor public string ActionName => KnownCollectionRuleActions.Execute; public Type FactoryType => typeof(ExecuteActionFactory); public Type OptionsType => typeof(ExecuteOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + ExecuteOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs index 662cbbb6176..b7a8fe7d44f 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/GetEnvironmentVariableAction.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -90,5 +91,12 @@ internal sealed class GetEnvironmentVariableActionDescriptor : ICollectionRuleAc public string ActionName => KnownCollectionRuleActions.GetEnvironmentVariable; public Type OptionsType => typeof(GetEnvironmentVariableOptions); public Type FactoryType => typeof(GetEnvironmentVariableActionFactory); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + GetEnvironmentVariableOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs index e6168312093..21260ebccb2 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs @@ -3,6 +3,7 @@ #nullable disable +using Microsoft.Extensions.Configuration; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -25,8 +26,9 @@ bool TryCreateFactory( /// Attempts to create an options instance of the options type /// associated with the registered action name. /// - bool TryCreateOptions( + bool TryBindOptions( string actionName, + IConfigurationSection actionSection, out object options); /// diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs index c5a0e5a384e..7f9770c9428 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/LoadProfilerAction.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using System.Threading; @@ -75,5 +76,12 @@ internal sealed class LoadProfilerActionDescriptor : ICollectionRuleActionDescri public string ActionName => KnownCollectionRuleActions.LoadProfiler; public Type FactoryType => typeof(LoadProfilerActionFactory); public Type OptionsType => typeof(LoadProfilerOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + LoadProfilerOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs index c64bf229317..b40b78a4041 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/SetEnvironmentVariableAction.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Actions; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using System.Threading; @@ -75,5 +76,12 @@ internal sealed class SetEnvironmentVariableActionDescriptor : ICollectionRuleAc public string ActionName => KnownCollectionRuleActions.SetEnvironmentVariable; public Type FactoryType => typeof(SetEnvironmentVariableActionFactory); public Type OptionsType => typeof(SetEnvironmentVariableOptions); + + public void BindOptions(IConfigurationSection settingsSection, out object settings) + { + SetEnvironmentVariableOptions options = new(); + settingsSection.Bind(options); + settings = options; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs index 548c4bd3cc6..a549120d117 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs @@ -13,12 +13,8 @@ internal static class CollectionRuleBindingHelper public static void BindActionSettings(IConfigurationSection actionSection, CollectionRuleActionOptions actionOptions, ICollectionRuleActionOperations actionOperations) { if (null != actionOptions && - actionOperations.TryCreateOptions(actionOptions.Type, out object actionSettings)) + actionOperations.TryBindOptions(actionOptions.Type, actionSection, out object actionSettings)) { - IConfigurationSection settingsSection = actionSection.GetSection(nameof(CollectionRuleActionOptions.Settings)); - - settingsSection.Bind(actionSettings); - actionOptions.Settings = actionSettings; } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs index 9f31a727d10..561c005c697 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using Microsoft.Extensions.Configuration; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration { @@ -12,5 +13,7 @@ internal interface ICollectionRuleActionDescriptor Type FactoryType { get; } Type OptionsType { get; } + + void BindOptions(IConfigurationSection settingsSection, out object settings); } } From 0792fafce093cbc0dab1864890f6d637150b3545 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 18:45:01 +0000 Subject: [PATCH 3/6] Use separate trigger descriptor types --- .../CollectionRules/Triggers/ManualTrigger.cs | 8 ++++ .../TriggersServiceCollectionExtensions.cs | 2 +- .../CollectionRuleTriggerDescriptor.cs | 40 ------------------- .../AspNetRequestCountTriggerFactory.cs | 8 ++++ .../AspNetRequestDurationTriggerFactory.cs | 8 ++++ .../AspNetResponseStatusTriggerFactory.cs | 8 ++++ .../Triggers/EventCounterTriggerFactory.cs | 8 ++++ .../Triggers/EventMeterTriggerFactory.cs | 8 ++++ .../Triggers/StartupTriggerFactory.cs | 8 ++++ .../ServiceCollectionExtensions.cs | 30 +++++++------- 10 files changed, 72 insertions(+), 56 deletions(-) delete mode 100644 src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleTriggerDescriptor.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs index cce2bd81f53..8401663b704 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.Monitoring.WebApi; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers; using System; using System.Threading; @@ -59,6 +60,13 @@ private void NotifyHandler(object sender, EventArgs args) } } + internal sealed class ManualTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public string TriggerName => ManualTrigger.TriggerName; + public Type FactoryType => typeof(ManualTriggerFactory); + public Type OptionsType => null; + } + internal sealed class ManualTriggerService { public event EventHandler NotifyStarted; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/TriggersServiceCollectionExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/TriggersServiceCollectionExtensions.cs index 6511462a1c9..17c3d961270 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/TriggersServiceCollectionExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/TriggersServiceCollectionExtensions.cs @@ -11,7 +11,7 @@ internal static class TriggersServiceCollectionExtensions public static IServiceCollection RegisterManualTrigger(this IServiceCollection services, ManualTriggerService service) { services.AddSingleton(service); - return services.RegisterCollectionRuleTrigger(ManualTrigger.TriggerName); + return services.RegisterCollectionRuleTrigger(); } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleTriggerDescriptor.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleTriggerDescriptor.cs deleted file mode 100644 index ab9b7a87a82..00000000000 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleTriggerDescriptor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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.Tools.Monitor.CollectionRules.Triggers; -using System; - -namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration -{ - internal sealed class CollectionRuleTriggerDescriptor : - ICollectionRuleTriggerDescriptor - where TFactory : ICollectionRuleTriggerFactory - { - public CollectionRuleTriggerDescriptor(string triggerName) - { - TriggerName = triggerName; - } - - public Type FactoryType => typeof(TFactory); - - public Type? OptionsType => null; - - public string TriggerName { get; } - } - - internal sealed class CollectionRuleTriggerProvider : - ICollectionRuleTriggerDescriptor - where TFactory : ICollectionRuleTriggerFactory - { - public CollectionRuleTriggerProvider(string triggerName) - { - TriggerName = triggerName; - } - - public Type FactoryType => typeof(TFactory); - - public Type OptionsType => typeof(TOptions); - - public string TriggerName { get; } - } -} diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs index 25b4aa8e0d5..d43a121427b 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.AspNet; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using System; using System.Globalization; @@ -44,4 +45,11 @@ public ICollectionRuleTrigger Create(IEndpointInfo endpointInfo, Action callback return EventPipeTriggerFactory.Create(endpointInfo, aspnetTriggerSourceConfiguration, _traceEventTriggerFactory, settings, callback); } } + + internal sealed class AspNetRequestCountTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(AspNetRequestCountTriggerFactory); + public Type? OptionsType => typeof(AspNetRequestCountOptions); + public string TriggerName => KnownCollectionRuleTriggers.AspNetRequestCount; + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs index 616862cf5ed..8d3a06fe652 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.AspNet; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; using System; using System.Globalization; @@ -50,4 +51,11 @@ public ICollectionRuleTrigger Create(IEndpointInfo endpointInfo, Action callback return EventPipeTriggerFactory.Create(endpointInfo, aspnetTriggerSourceConfiguration, _traceEventTriggerFactory, settings, callback); } } + + internal sealed class AspNetRequestDurationTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(AspNetRequestDurationTriggerFactory); + public Type? OptionsType => typeof(AspNetRequestDurationOptions); + public string TriggerName => KnownCollectionRuleTriggers.AspNetRequestDuration; + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs index 4ab82c90c34..d71c2502df8 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.AspNet; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using System; using System.Globalization; using System.Linq; @@ -59,4 +60,11 @@ private static StatusCodeRange ParseRange(string range) return new StatusCodeRange(min, max); } } + + internal sealed class AspNetResponseStatusTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(AspNetResponseStatusTriggerFactory); + public Type? OptionsType => typeof(AspNetResponseStatusOptions); + public string TriggerName => KnownCollectionRuleTriggers.AspNetResponseStatus; + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs index 309bfa90933..565d2d254db 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers.EventCounterShortcuts; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; using System; @@ -109,4 +110,11 @@ internal static EventCounterOptions ToEventCounterOptions(IEventCounterShortcuts }; } } + + internal sealed class EventCounterTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(EventCounterTriggerFactory); + public Type? OptionsType => typeof(EventCounterOptions); + public string TriggerName => KnownCollectionRuleTriggers.EventCounter; + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs index 46502ad63b5..9f813ffda64 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.SystemDiagnosticsMetrics; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; using System; @@ -55,4 +56,11 @@ public ICollectionRuleTrigger Create(IEndpointInfo endpointInfo, Action callback callback); } } + + internal sealed class EventMeterTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(EventMeterTriggerFactory); + public Type? OptionsType => typeof(EventMeterOptions); + public string TriggerName => KnownCollectionRuleTriggers.EventMeter; + } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs index c17ad90fc7c..84a0141df4a 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.Monitoring.WebApi; +using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers @@ -18,4 +19,11 @@ public ICollectionRuleTrigger Create(IEndpointInfo endpointInfo, Action callback return new StartupTrigger(callback); } } + + internal sealed class StartupTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(StartupTriggerFactory); + public Type? OptionsType => null; + public string TriggerName => KnownCollectionRuleTriggers.Startup; + } } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 898612024d4..233c8420bde 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -152,15 +152,15 @@ public static IServiceCollection ConfigureCollectionRules(this IServiceCollectio services.RegisterCollectionRuleAction(); services.RegisterCollectionRuleAction(); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.AspNetRequestCount); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.AspNetRequestDuration); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.AspNetResponseStatus); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.EventCounter); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.CPUUsage); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.GCHeapSize); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.ThreadpoolQueueLength); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.Startup); - services.RegisterCollectionRuleTrigger(KnownCollectionRuleTriggers.EventMeter); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); services.AddSingleton(); services.AddSingleton, Monitoring.EventPipe.Triggers.EventCounter.EventCounterTriggerFactory>(); @@ -210,24 +210,24 @@ public static IServiceCollection RegisterCollectionRuleAction(this IServiceCollection services, string triggerName) + public static IServiceCollection RegisterCollectionRuleTrigger(this IServiceCollection services) where TFactory : class, ICollectionRuleTriggerFactory + where TDescriptor : class, ICollectionRuleTriggerDescriptor, new() { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton>( - sp => new CollectionRuleTriggerDescriptor(triggerName)); + services.AddSingleton(sp => new TDescriptor()); return services; } - public static IServiceCollection RegisterCollectionRuleTrigger(this IServiceCollection services, string triggerName) + public static IServiceCollection RegisterCollectionRuleTrigger(this IServiceCollection services) where TFactory : class, ICollectionRuleTriggerFactory where TOptions : class, new() + where TDescriptor : class, ICollectionRuleTriggerDescriptor, new() { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton>( - sp => new CollectionRuleTriggerProvider(triggerName)); + services.AddSingleton(sp => new TDescriptor()); // NOTE: When opening collection rule triggers for extensibility, this should not be added for all registered triggers. // Each trigger should register its own IValidateOptions<> implementation (if it needs one). services.AddSingleton, DataAnnotationValidateOptions>(); From 9120678357b2757cc9f90d0e1b32eae8aefa98f3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 19:00:40 +0000 Subject: [PATCH 4/6] Move binding to trigger descriptors --- .../CollectionRules/Triggers/ManualTrigger.cs | 7 +++++++ .../Actions/ICollectionRuleActionOperations.cs | 2 +- .../Configuration/CollectionRuleBindingHelper.cs | 6 +----- .../Configuration/ICollectionRuleActionDescriptor.cs | 2 +- .../Configuration/ICollectionRuleTriggerDescriptor.cs | 3 +++ .../Triggers/AspNetRequestCountTriggerFactory.cs | 9 +++++++++ .../Triggers/AspNetRequestDurationTriggerFactory.cs | 9 +++++++++ .../Triggers/AspNetResponseStatusTriggerFactory.cs | 9 +++++++++ .../Triggers/CollectionRuleTriggerOperations.cs | 11 ++++++----- .../Triggers/EventCounterTriggerFactory.cs | 9 +++++++++ .../Triggers/EventMeterTriggerFactory.cs | 9 +++++++++ .../Triggers/ICollectionRuleTriggerOperations.cs | 6 ++++-- .../CollectionRules/Triggers/StartupTriggerFactory.cs | 7 +++++++ 13 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs index 8401663b704..f02a2e1cde9 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/CollectionRules/Triggers/ManualTrigger.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers; +using Microsoft.Extensions.Configuration; using System; using System.Threading; using System.Threading.Tasks; @@ -65,6 +66,12 @@ internal sealed class ManualTriggerDescriptor : ICollectionRuleTriggerDescriptor public string TriggerName => ManualTrigger.TriggerName; public Type FactoryType => typeof(ManualTriggerFactory); public Type OptionsType => null; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object settings) + { + settings = null; + return false; + } } internal sealed class ManualTriggerService diff --git a/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs b/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs index 21260ebccb2..075f3195f0c 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Actions/ICollectionRuleActionOperations.cs @@ -23,7 +23,7 @@ bool TryCreateFactory( out ICollectionRuleActionFactoryProxy action); /// - /// Attempts to create an options instance of the options type + /// Attempts to bind an options instance of the options type /// associated with the registered action name. /// bool TryBindOptions( diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs index a549120d117..7e4ec3aca29 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Configuration/CollectionRuleBindingHelper.cs @@ -22,12 +22,8 @@ public static void BindActionSettings(IConfigurationSection actionSection, Colle public static void BindTriggerSettings(IConfigurationSection triggerSection, CollectionRuleTriggerOptions triggerOptions, ICollectionRuleTriggerOperations triggerOperations) { if (null != triggerOptions && - triggerOperations.TryCreateOptions(triggerOptions.Type, out object triggerSettings)) + triggerOperations.TryBindOptions(triggerOptions.Type, triggerSection, out object triggerSettings)) { - IConfigurationSection settingsSection = triggerSection.GetSection(nameof(CollectionRuleTriggerOptions.Settings)); - - settingsSection.Bind(triggerSettings); - triggerOptions.Settings = triggerSettings; } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs index 561c005c697..7003561ffc7 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleActionDescriptor.cs @@ -1,8 +1,8 @@ // 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 Microsoft.Extensions.Configuration; +using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration { diff --git a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleTriggerDescriptor.cs b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleTriggerDescriptor.cs index 48846c97c29..aa167eddc2a 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleTriggerDescriptor.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Configuration/ICollectionRuleTriggerDescriptor.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Configuration; using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration @@ -12,5 +13,7 @@ interface ICollectionRuleTriggerDescriptor Type? OptionsType { get; } string TriggerName { get; } + + bool TryBindOptions(IConfigurationSection settingsSection, out object? settings); } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs index d43a121427b..21ba4514f99 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestCountTriggerFactory.cs @@ -7,6 +7,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; +using Microsoft.Extensions.Configuration; using System; using System.Globalization; @@ -51,5 +52,13 @@ internal sealed class AspNetRequestCountTriggerDescriptor : ICollectionRuleTrigg public Type FactoryType => typeof(AspNetRequestCountTriggerFactory); public Type? OptionsType => typeof(AspNetRequestCountOptions); public string TriggerName => KnownCollectionRuleTriggers.AspNetRequestCount; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new AspNetRequestCountOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs index 8d3a06fe652..6df9c51a904 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetRequestDurationTriggerFactory.cs @@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Configuration; using System; using System.Globalization; @@ -57,5 +58,13 @@ internal sealed class AspNetRequestDurationTriggerDescriptor : ICollectionRuleTr public Type FactoryType => typeof(AspNetRequestDurationTriggerFactory); public Type? OptionsType => typeof(AspNetRequestDurationOptions); public string TriggerName => KnownCollectionRuleTriggers.AspNetRequestDuration; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new AspNetRequestDurationOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs index d71c2502df8..b912e7e0411 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/AspNetResponseStatusTriggerFactory.cs @@ -7,6 +7,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; +using Microsoft.Extensions.Configuration; using System; using System.Globalization; using System.Linq; @@ -66,5 +67,13 @@ internal sealed class AspNetResponseStatusTriggerDescriptor : ICollectionRuleTri public Type FactoryType => typeof(AspNetResponseStatusTriggerFactory); public Type? OptionsType => typeof(AspNetResponseStatusOptions); public string TriggerName => KnownCollectionRuleTriggers.AspNetResponseStatus; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new AspNetResponseStatusOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/CollectionRuleTriggerOperations.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/CollectionRuleTriggerOperations.cs index 1b1dfac9460..efdf694c883 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/CollectionRuleTriggerOperations.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/CollectionRuleTriggerOperations.cs @@ -5,6 +5,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -71,16 +72,16 @@ public bool TryCreateFactory( } /// - public bool TryCreateOptions( + public bool TryBindOptions( string triggerName, + IConfigurationSection triggerSection, out object options) { // Check that the trigger is registered and has options - if (_map.TryGetValue(triggerName, out ICollectionRuleTriggerDescriptor descriptor) && - null != descriptor.OptionsType) + if (_map.TryGetValue(triggerName, out ICollectionRuleTriggerDescriptor descriptor)) { - options = Activator.CreateInstance(descriptor.OptionsType); - return true; + IConfigurationSection settingsSection = triggerSection.GetSection(nameof(CollectionRuleTriggerOptions.Settings)); + return descriptor.TryBindOptions(settingsSection, out options); } options = null; diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs index 565d2d254db..6affc5f5cf1 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs @@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers.EventCounterShortcuts; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Configuration; using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers @@ -116,5 +117,13 @@ internal sealed class EventCounterTriggerDescriptor : ICollectionRuleTriggerDesc public Type FactoryType => typeof(EventCounterTriggerFactory); public Type? OptionsType => typeof(EventCounterOptions); public string TriggerName => KnownCollectionRuleTriggers.EventCounter; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new EventCounterOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs index 9f813ffda64..3453f845ee9 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventMeterTriggerFactory.cs @@ -7,6 +7,7 @@ using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Options.Triggers; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Configuration; using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers @@ -62,5 +63,13 @@ internal sealed class EventMeterTriggerDescriptor : ICollectionRuleTriggerDescri public Type FactoryType => typeof(EventMeterTriggerFactory); public Type? OptionsType => typeof(EventMeterOptions); public string TriggerName => KnownCollectionRuleTriggers.EventMeter; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new EventMeterOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } } } diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTriggerOperations.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTriggerOperations.cs index 083adf8dd5d..610321cde6c 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTriggerOperations.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/ICollectionRuleTriggerOperations.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Extensions.Configuration; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -20,11 +21,12 @@ bool TryCreateFactory( out ICollectionRuleTriggerFactoryProxy factory); /// - /// Attempts to create an options instance of the options type + /// Attempts to bind an options instance of the options type /// associated with the registered trigger name. /// - bool TryCreateOptions( + bool TryBindOptions( string triggerName, + IConfigurationSection triggerSection, out object options); /// diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs index 84a0141df4a..f28fc8dfa60 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/StartupTriggerFactory.cs @@ -3,6 +3,7 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Configuration; +using Microsoft.Extensions.Configuration; using System; namespace Microsoft.Diagnostics.Tools.Monitor.CollectionRules.Triggers @@ -25,5 +26,11 @@ internal sealed class StartupTriggerDescriptor : ICollectionRuleTriggerDescripto public Type FactoryType => typeof(StartupTriggerFactory); public Type? OptionsType => null; public string TriggerName => KnownCollectionRuleTriggers.Startup; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + settings = null; + return false; + } } } From 401f162fd2a735add22fb6ec64cde89c4c12dfdb Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 20:27:58 +0000 Subject: [PATCH 5/6] Fix EventCounter descriptors --- .../Triggers/EventCounterTriggerFactory.cs | 45 +++++++++++++++++++ .../ServiceCollectionExtensions.cs | 18 ++++---- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs index 6affc5f5cf1..778b7d60a14 100644 --- a/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs +++ b/src/Tools/dotnet-monitor/CollectionRules/Triggers/EventCounterTriggerFactory.cs @@ -126,4 +126,49 @@ public bool TryBindOptions(IConfigurationSection settingsSection, out object? se return true; } } + + internal sealed class CPUUsageTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(EventCounterTriggerFactory); + public Type? OptionsType => typeof(CPUUsageOptions); + public string TriggerName => KnownCollectionRuleTriggers.CPUUsage; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new CPUUsageOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } + } + + internal sealed class GCHeapSizeTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(EventCounterTriggerFactory); + public Type? OptionsType => typeof(GCHeapSizeOptions); + public string TriggerName => KnownCollectionRuleTriggers.GCHeapSize; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new GCHeapSizeOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } + } + + internal sealed class ThreadpoolQueueLengthTriggerDescriptor : ICollectionRuleTriggerDescriptor + { + public Type FactoryType => typeof(EventCounterTriggerFactory); + public Type? OptionsType => typeof(ThreadpoolQueueLengthOptions); + public string TriggerName => KnownCollectionRuleTriggers.ThreadpoolQueueLength; + + public bool TryBindOptions(IConfigurationSection settingsSection, out object? settings) + { + var options = new ThreadpoolQueueLengthOptions(); + settingsSection.Bind(options); + settings = options; + return true; + } + } } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 233c8420bde..7c14cfc747e 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -152,15 +152,15 @@ public static IServiceCollection ConfigureCollectionRules(this IServiceCollectio services.RegisterCollectionRuleAction(); services.RegisterCollectionRuleAction(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); - services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); + services.RegisterCollectionRuleTrigger(); services.AddSingleton(); services.AddSingleton, Monitoring.EventPipe.Triggers.EventCounter.EventCounterTriggerFactory>(); From b13cb280fac2231a05903bf615247fb1e9936146 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 18 Apr 2025 22:53:24 +0000 Subject: [PATCH 6/6] PR feedback - Don't construct descriptors explicitly --- .../dotnet-monitor/ServiceCollectionExtensions.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 7c14cfc747e..ea8cb23f561 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -199,11 +199,11 @@ public static IServiceCollection ConfigureCollectionRules(this IServiceCollectio public static IServiceCollection RegisterCollectionRuleAction(this IServiceCollection services) where TFactory : class, ICollectionRuleActionFactory where TOptions : BaseRecordOptions, new() - where TDescriptor : class, ICollectionRuleActionDescriptor, new() + where TDescriptor : class, ICollectionRuleActionDescriptor { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton(sp => new TDescriptor()); + services.AddSingleton(); // NOTE: When opening collection rule actions for extensibility, this should not be added for all registered actions. // Each action should register its own IValidateOptions<> implementation (if it needs one). services.AddSingleton, DataAnnotationValidateOptions>(); @@ -212,22 +212,22 @@ public static IServiceCollection RegisterCollectionRuleAction(this IServiceCollection services) where TFactory : class, ICollectionRuleTriggerFactory - where TDescriptor : class, ICollectionRuleTriggerDescriptor, new() + where TDescriptor : class, ICollectionRuleTriggerDescriptor { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton(sp => new TDescriptor()); + services.AddSingleton(); return services; } public static IServiceCollection RegisterCollectionRuleTrigger(this IServiceCollection services) where TFactory : class, ICollectionRuleTriggerFactory where TOptions : class, new() - where TDescriptor : class, ICollectionRuleTriggerDescriptor, new() + where TDescriptor : class, ICollectionRuleTriggerDescriptor { services.AddSingleton(); services.AddSingleton>(); - services.AddSingleton(sp => new TDescriptor()); + services.AddSingleton(); // NOTE: When opening collection rule triggers for extensibility, this should not be added for all registered triggers. // Each trigger should register its own IValidateOptions<> implementation (if it needs one). services.AddSingleton, DataAnnotationValidateOptions>();