From a24916a69380c6660eb6b92128f8ce9aac296c60 Mon Sep 17 00:00:00 2001 From: Joe Schmitt Date: Mon, 1 Jul 2024 09:40:32 -0700 Subject: [PATCH 1/5] Enable nullable context in WebApi --- .../ActionContextExtensions.cs | 8 +-- .../AssemblyExtensions.cs | 4 +- .../Controllers/ControllerExtensions.cs | 4 +- .../Controllers/DiagController.Metrics.cs | 12 ++-- .../Controllers/DiagController.cs | 72 ++++++++++--------- .../Controllers/DiagnosticsControllerBase.cs | 22 +++--- .../Controllers/ExceptionsController.cs | 12 ++-- .../Controllers/MetricsController.cs | 2 + .../Controllers/OperationsController.cs | 4 +- .../DiagProcessFilter.cs | 2 +- .../DiagnosticServices.cs | 9 +-- .../DumpService.cs | 2 +- .../EndpointInfo/IEndpointInfoSource.cs | 16 ++--- .../ExceptionsConfigurationSettings.cs | 18 ++--- .../Exceptions/IExceptionInstance.cs | 4 +- .../IDiagnosticServices.cs | 2 +- .../IEgressService.cs | 2 +- .../LoggingExtensions.cs | 26 +++---- .../Metrics/MetricsService.cs | 4 +- .../Metrics/MetricsSettingsFactory.cs | 4 +- .../Metrics/MetricsStore.cs | 6 +- .../Metrics/PrometheusDataModel.cs | 8 +-- .../Metrics/StreamingCounterLogger.cs | 2 + ...osoft.Diagnostics.Monitoring.WebApi.csproj | 1 + .../Models/CallStackResults.cs | 8 +-- .../Models/CollectionRuleDescription.cs | 2 +- .../Models/DotnetMonitorInfo.cs | 6 +- .../Models/EgressOperationStatus.cs | 16 ++--- .../Models/EventMetricsConfiguration.cs | 15 ++-- .../Models/EventPipeConfiguration.cs | 2 +- .../Models/EventPipeProvider.cs | 9 ++- .../Models/LogsConfiguration.cs | 2 +- .../Models/ProcessIdentifier.cs | 2 +- .../Models/ProcessInfo.cs | 8 +-- .../Models/SpeedScopeStackResults.cs | 18 ++--- .../Operation/EgressOperation.cs | 2 +- .../Operation/EgressOperationStore.cs | 27 ++++--- .../Operation/HttpResponseEgressOperation.cs | 4 +- .../Operation/IEgressOperation.cs | 2 +- .../Operation/IEgressOperationStore.cs | 2 +- .../OutputStreamResult.cs | 6 +- .../CapturedParametersTextFormatter.cs | 2 +- .../ParameterCapturing/ICapturedParameters.cs | 2 +- .../ProcessInfoImpl.cs | 16 ++--- .../ProcessKey.cs | 8 +-- .../Stacks/CallStackData.cs | 2 +- .../Stacks/EventStacksPipeline.cs | 4 +- .../Stacks/SpeedScopeStacksFormatter.cs | 2 +- .../Stacks/StacksFormatter.cs | 2 +- .../Stacks/TextStacksFormatter.cs | 2 +- .../StreamingLogger.cs | 18 +++-- .../TaskCompletionSourceExtensions.cs | 2 + .../Utilities/StackUtilities.cs | 4 +- .../Utilities/TraceUtilities.cs | 2 +- .../Utilities/Utilities.cs | 4 +- .../Validation/CounterValidator.cs | 5 +- .../Validation/IntegerOrHexStringAttribute.cs | 7 +- 57 files changed, 244 insertions(+), 215 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs index edbe885d5d0..257a8318b86 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs @@ -17,9 +17,9 @@ public sealed class ExecutionResult { private static readonly ExecutionResult _empty = new ExecutionResult(); - public Exception Exception { get; private set; } - public T Result { get; private set; } - public ProblemDetails ProblemDetails { get; private set; } + public Exception? Exception { get; private set; } + public T? Result { get; private set; } + public ProblemDetails? ProblemDetails { get; private set; } private ExecutionResult() { } @@ -95,7 +95,7 @@ internal static class ActionContextExtensions { public static Task ProblemAsync(this ActionContext context, BadRequestObjectResult result) { - if (context.HttpContext.Features.Get().HasStarted) + if (context.HttpContext.Features.Get()?.HasStarted == true) { // If already started writing response, do not rewrite // as this will throw an InvalidOperationException. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/AssemblyExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/AssemblyExtensions.cs index 56dacdad7fa..ef0236a77fd 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/AssemblyExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/AssemblyExtensions.cs @@ -7,7 +7,7 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class AssemblyExtensions { - public static string GetInformationalVersionString(this Assembly assembly) + public static string? GetInformationalVersionString(this Assembly assembly) { if (assembly.GetCustomAttribute() is AssemblyInformationalVersionAttribute assemblyVersionAttribute) @@ -16,7 +16,7 @@ public static string GetInformationalVersionString(this Assembly assembly) } else { - return assembly.GetName().Version.ToString(); + return assembly.GetName().Version?.ToString(); } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ControllerExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ControllerExtensions.cs index 86cdf7c4ec0..16f207cbc2b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ControllerExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ControllerExtensions.cs @@ -35,7 +35,7 @@ public static ActionResult InvokeService(this ControllerBase controller, Func //and then safely convert back. - return controller.InvokeService(() => serviceCall(), logger).Result; + return controller.InvokeService(() => serviceCall(), logger).Result!; } public static ActionResult InvokeService(this ControllerBase controller, Func> serviceCall, ILogger logger) @@ -50,7 +50,7 @@ public static async Task InvokeService(this ControllerBase control //Task -> Task> //Then unwrap the result back to ActionResult ActionResult result = await controller.InvokeService(async () => await serviceCall(), logger); - return result.Result; + return result.Result!; } public static async Task> InvokeService(this ControllerBase controller, Func>> serviceCall, ILogger logger) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.Metrics.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.Metrics.cs index f6ba02a6eed..0c99f193dc8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.Metrics.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.Metrics.cs @@ -33,13 +33,13 @@ public Task CaptureMetrics( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -83,13 +83,13 @@ public Task CaptureMetricsCustom( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index b6dcd12e890..fa207571b08 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -35,7 +35,9 @@ public partial class DiagController : DiagnosticsControllerBase { private const TraceProfile DefaultTraceProfiles = TraceProfile.Cpu | TraceProfile.Http | TraceProfile.Metrics | TraceProfile.GcCollect; +#nullable disable private readonly IOptions _diagnosticPortOptions; +#nullable enable private readonly IOptions _callStacksOptions; private readonly IOptions _parameterCapturingOptions; private readonly IOptionsMonitor _counterOptions; @@ -77,7 +79,7 @@ public Task>> GetProcesses() { return this.InvokeService(async () => { - IProcessInfo defaultProcessInfo = null; + IProcessInfo? defaultProcessInfo = null; try { defaultProcessInfo = await DiagnosticServices.GetProcessAsync(null, HttpContext.RequestAborted); @@ -127,7 +129,7 @@ public Task>> GetProcesses() [FromQuery] Guid? uid = null, [FromQuery] - string name = null) + string? name = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -165,7 +167,7 @@ public Task>> GetProcessEnvironment( [FromQuery] Guid? uid = null, [FromQuery] - string name = null) + string? name = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -213,13 +215,13 @@ public Task CaptureDump( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] Models.DumpType type = Models.DumpType.WithHeap, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -257,11 +259,11 @@ public Task CaptureGcDump( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -300,15 +302,15 @@ public Task CaptureTrace( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] TraceProfile profile = DefaultTraceProfiles, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -348,13 +350,13 @@ public Task CaptureTraceCustom( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -363,7 +365,7 @@ public Task CaptureTraceCustom( foreach (Models.EventPipeProvider provider in configuration.Providers) { if (!CounterValidator.ValidateProvider(_counterOptions.CurrentValue, - provider, out string errorMessage)) + provider, out string? errorMessage)) { throw new ValidationException(errorMessage); } @@ -399,15 +401,15 @@ public Task CaptureLogs( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] LogLevel? level = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -459,13 +461,13 @@ public Task CaptureLogsCustom( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); @@ -495,7 +497,7 @@ public ActionResult GetInfo() { return this.InvokeService(() => { - string version = Assembly.GetExecutingAssembly().GetInformationalVersionString(); + string? version = Assembly.GetExecutingAssembly().GetInformationalVersionString(); string runtimeVersion = Environment.Version.ToString(); DiagnosticPortConnectionMode diagnosticPortMode = _diagnosticPortOptions.Value.GetConnectionMode(); string diagnosticPortName = GetDiagnosticPortName(); @@ -528,7 +530,7 @@ public Task>> GetColl [FromQuery] Guid? uid = null, [FromQuery] - string name = null) + string? name = null) { return InvokeForProcess>(processInfo => { @@ -554,7 +556,7 @@ public Task> GetCollectionRuleDe [FromQuery] Guid? uid = null, [FromQuery] - string name = null) + string? name = null) { return InvokeForProcess(processInfo => { @@ -579,11 +581,11 @@ public async Task CaptureParameters( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { if (!_parameterCapturingOptions.Value.GetEnabled()) { @@ -621,11 +623,11 @@ public Task CaptureStacks( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { if (!_callStacksOptions.Value.GetEnabled()) { @@ -660,8 +662,8 @@ private Task StartTrace( IProcessInfo processInfo, MonitoringSourceConfiguration configuration, TimeSpan duration, - string egressProvider, - string tags) + string? egressProvider, + string? tags) { IArtifactOperation traceOperation = _traceOperationFactory.Create( processInfo.EndpointInfo, @@ -679,8 +681,8 @@ private Task StartTrace( private Task StartLogs( IProcessInfo processInfo, EventLogsPipelineSettings settings, - string egressProvider, - string tags) + string? egressProvider, + string? tags) { LogFormat? format = ComputeLogFormat(Request.GetTypedHeaders().Accept); if (null == format) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagnosticsControllerBase.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagnosticsControllerBase.cs index e73ea81359b..fbebd9b9786 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagnosticsControllerBase.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagnosticsControllerBase.cs @@ -22,7 +22,7 @@ private protected DiagnosticsControllerBase(IDiagnosticServices diagnosticServic Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - protected Task InvokeForProcess(Func func, ProcessKey? processKey, string artifactType = null) + protected Task InvokeForProcess(Func func, ProcessKey? processKey, string? artifactType = null) { Func> asyncFunc = processInfo => Task.FromResult(func(processInfo)); @@ -30,21 +30,21 @@ protected Task InvokeForProcess(Func f return InvokeForProcess(asyncFunc, processKey, artifactType); } - protected async Task InvokeForProcess(Func> func, ProcessKey? processKey, string artifactType) + protected async Task InvokeForProcess(Func> func, ProcessKey? processKey, string? artifactType) { ActionResult result = await InvokeForProcess(async processInfo => await func(processInfo), processKey, artifactType); - return result.Result; + return result.Result!; } - protected Task> InvokeForProcess(Func> func, ProcessKey? processKey, string artifactType = null) + protected Task> InvokeForProcess(Func> func, ProcessKey? processKey, string? artifactType = null) { return InvokeForProcess(processInfo => Task.FromResult(func(processInfo)), processKey, artifactType); } - protected async Task> InvokeForProcess(Func>> func, ProcessKey? processKey, string artifactType = null) + protected async Task> InvokeForProcess(Func>> func, ProcessKey? processKey, string? artifactType = null) { - IDisposable artifactTypeRegistration = null; + IDisposable? artifactTypeRegistration = null; if (!string.IsNullOrEmpty(artifactType)) { KeyValueLogScope artifactTypeScope = new KeyValueLogScope(); @@ -75,10 +75,10 @@ protected async Task> InvokeForProcess(Func Result( string artifactType, - string providerName, + string? providerName, IArtifactOperation operation, IProcessInfo processInfo, - string tags, + string? tags, bool asAttachment = true) { KeyValueLogScope scope = Utilities.CreateArtifactScope(artifactType, processInfo.EndpointInfo); @@ -103,7 +103,7 @@ protected async Task Result( } } - private async Task RegisterCurrentHttpResponseAsOperation(IProcessInfo processInfo, string artifactType, string tags, IArtifactOperation operation) + private async Task RegisterCurrentHttpResponseAsOperation(IProcessInfo processInfo, string artifactType, string? tags, IArtifactOperation operation) { // While not strictly a Location redirect, use the same header as externally egressed operations for consistency. HttpContext.Response.Headers["Location"] = await RegisterOperation( @@ -111,7 +111,7 @@ private async Task RegisterCurrentHttpResponseAsOperation(IProcessInfo processIn limitKey: artifactType); } - private async Task RegisterOperation(IEgressOperation egressOperation, string limitKey) + private async Task RegisterOperation(IEgressOperation egressOperation, string limitKey) { // Will throw TooManyRequestsException if there are too many concurrent operations. Guid operationId = await OperationStore.AddOperation(egressOperation, limitKey); @@ -123,7 +123,7 @@ private async Task RegisterOperation(IEgressOperation egressOperation, s private async Task SendToEgress(IEgressOperation egressOperation, string limitKey) { - string operationUrl = await RegisterOperation(egressOperation, limitKey); + string? operationUrl = await RegisterOperation(egressOperation, limitKey); return Accepted(operationUrl); } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ExceptionsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ExceptionsController.cs index 3af23c32b16..84023a6960a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ExceptionsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/ExceptionsController.cs @@ -55,11 +55,11 @@ public Task GetExceptions( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { if (!_options.Value.GetEnabled()) { @@ -107,11 +107,11 @@ public Task CaptureExceptionsCustom( [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string egressProvider = null, + string? egressProvider = null, [FromQuery] - string tags = null) + string? tags = null) { if (!_options.Value.GetEnabled()) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs index ecb3c2fc0cb..70f3b0e747f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs @@ -21,7 +21,9 @@ public class MetricsController : ControllerBase private const string ArtifactType_Metrics = "metrics"; private readonly ILogger _logger; + #nullable disable private readonly MetricsStoreService _metricsStore; + #nullable enable private readonly MetricsOptions _metricsOptions; public MetricsController(ILogger logger, diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs index 9c52a10f02b..9d6c9a3c570 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs @@ -45,9 +45,9 @@ public OperationsController(ILogger logger, IServiceProvid [FromQuery] Guid? uid = null, [FromQuery] - string name = null, + string? name = null, [FromQuery] - string tags = null) + string? tags = null) { ProcessKey? processKey = Utilities.GetProcessKey(pid, uid, name); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs index 19c9f5637fa..09159e22762 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs @@ -130,7 +130,7 @@ internal sealed class DiagProcessFilterEntry { public DiagProcessFilterCriteria Criteria { get; set; } - public string Value { get; set; } + public string Value { get; set; } = string.Empty; public DiagProcessFilterMatchType MatchType { get; set; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs index 4d1f3814c08..c3ae701723b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs @@ -26,14 +26,14 @@ public DiagnosticServices(IEndpointInfoSource endpointInfoSource, _logger = logger; } - public async Task> GetProcessesAsync(DiagProcessFilter processFilterConfig, CancellationToken token) + public async Task> GetProcessesAsync(DiagProcessFilter? processFilterConfig, CancellationToken token) { - IEnumerable processes = null; + IEnumerable? processes = null; try { using CancellationTokenSource extendedInfoCancellation = CancellationTokenSource.CreateLinkedTokenSource(token); - IList> processInfoTasks = new List>(); + IList> processInfoTasks = new List>(); foreach (IEndpointInfo endpointInfo in await _endpointInfoSource.GetEndpointInfoAsync(token)) { // CONSIDER: Can this processing be pushed into the IEndpointInfoSource implementation and cached @@ -71,7 +71,8 @@ public async Task> GetProcessesAsync(DiagProcessFilter processes = processInfoTasks .Where(t => t.Result != null) - .Select(t => t.Result); + .Select(t => t.Result) + .Cast(); } catch (UnauthorizedAccessException) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DumpService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DumpService.cs index 876e91526ff..337ff58c6a6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DumpService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DumpService.cs @@ -47,7 +47,7 @@ public async Task DumpAsync(IEndpointInfo endpointInfo, Models.DumpType string dumpFilePath = Path.Combine(dumpTempFolder, FormattableString.Invariant($"{Guid.NewGuid()}_{endpointInfo.ProcessId}")); DumpType dumpType = MapDumpType(mode); - IDisposable operationRegistration = null; + IDisposable? operationRegistration = null; // Only track operation status for endpoints from a listening server because: // 1) Each process only ever has a single instance of an IEndpointInfo // 2) Only the listening server will query the dump service for the operation status of an endpoint. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs index 1d17af1f986..a20fe3326bb 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs @@ -17,13 +17,13 @@ public interface IEndpointInfo Guid RuntimeInstanceCookie { get; } - string CommandLine { get; } + string? CommandLine { get; } - string OperatingSystem { get; } + string? OperatingSystem { get; } - string ProcessArchitecture { get; } + string? ProcessArchitecture { get; } - Version RuntimeVersion { get; } + Version? RuntimeVersion { get; } IServiceProvider ServiceProvider { get; } } @@ -42,11 +42,11 @@ public virtual IpcEndpoint Endpoint public abstract int ProcessId { get; protected set; } public abstract Guid RuntimeInstanceCookie { get; protected set; } - public abstract string CommandLine { get; protected set; } - public abstract string OperatingSystem { get; protected set; } - public abstract string ProcessArchitecture { get; protected set; } + public abstract string? CommandLine { get; protected set; } + public abstract string? OperatingSystem { get; protected set; } + public abstract string? ProcessArchitecture { get; protected set; } - public abstract Version RuntimeVersion { get; protected set; } + public abstract Version? RuntimeVersion { get; protected set; } public abstract IServiceProvider ServiceProvider { get; protected set; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/ExceptionsConfigurationSettings.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/ExceptionsConfigurationSettings.cs index 786faab5f90..08cd89d7a2e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/ExceptionsConfigurationSettings.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/ExceptionsConfigurationSettings.cs @@ -14,7 +14,7 @@ internal sealed class ExceptionsConfigurationSettings public List Exclude { get; set; } = new(); - private static bool CheckConfiguration(IExceptionInstance exception, List filterList, Func evaluateFilterList) + private static bool CheckConfiguration(IExceptionInstance exception, List filterList, Func evaluateFilterList) { var topFrame = exception.CallStack?.Frames.FirstOrDefault(); @@ -31,7 +31,7 @@ private static bool CheckConfiguration(IExceptionInstance exception, List evaluateFilterList = (configuration, topFrame) => + Func evaluateFilterList = (configuration, topFrame) => { bool include = true; if (topFrame != null) @@ -51,7 +51,7 @@ internal bool ShouldInclude(IExceptionInstance exception) internal bool ShouldExclude(IExceptionInstance exception) { - Func evaluateFilterList = (configuration, topFrame) => + Func evaluateFilterList = (configuration, topFrame) => { bool? exclude = null; if (topFrame != null) @@ -72,7 +72,7 @@ internal bool ShouldExclude(IExceptionInstance exception) return CheckConfiguration(exception, Exclude, evaluateFilterList); } - private static void CompareIncludeValues(string configurationValue, string actualValue, ref bool include) + private static void CompareIncludeValues(string? configurationValue, string actualValue, ref bool include) { if (include && !string.IsNullOrEmpty(configurationValue)) { @@ -80,7 +80,7 @@ private static void CompareIncludeValues(string configurationValue, string actua } } - private static void CompareExcludeValues(string configurationValue, string actualValue, ref bool? exclude) + private static void CompareExcludeValues(string? configurationValue, string actualValue, ref bool? exclude) { if (exclude != false && !string.IsNullOrEmpty(configurationValue)) { @@ -96,12 +96,12 @@ private static bool CompareValues(string configurationValue, string actualValue) internal sealed class ExceptionFilterSettings { - public string MethodName { get; set; } + public string? MethodName { get; set; } - public string ExceptionType { get; set; } + public string? ExceptionType { get; set; } - public string TypeName { get; set; } + public string? TypeName { get; set; } - public string ModuleName { get; set; } + public string? ModuleName { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/IExceptionInstance.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/IExceptionInstance.cs index 47fe2351621..5b178bc477a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/IExceptionInstance.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Exceptions/IExceptionInstance.cs @@ -19,11 +19,11 @@ internal interface IExceptionInstance DateTime Timestamp { get; } - CallStack CallStack { get; } + CallStack? CallStack { get; } ulong[] InnerExceptionIds { get; } - public string ActivityId { get; } + public string? ActivityId { get; } public ActivityIdFormat ActivityIdFormat { get; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs index 5f4d732395f..b82beb50fee 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs @@ -16,7 +16,7 @@ internal interface IDiagnosticServices /// /// Returns running processes, optionally based on filter criteria. /// - Task> GetProcessesAsync(DiagProcessFilter processFilter, CancellationToken token); + Task> GetProcessesAsync(DiagProcessFilter? processFilter, CancellationToken token); /// /// Returns a process based on a key. If no key is specified, the DefaultProcess configuration is used. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs index 5f32326355b..38319aa6a94 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs @@ -18,7 +18,7 @@ Task EgressAsync( string fileName, string contentType, IEndpointInfo source, - CollectionRuleMetadata collectionRuleMetadata, + CollectionRuleMetadata? collectionRuleMetadata, CancellationToken token); Task ValidateProviderOptionsAsync( diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs index fc73bcc8737..288bf6752a7 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs @@ -15,31 +15,31 @@ internal static class LoggingExtensions logLevel: LogLevel.Error, formatString: Strings.LogFormatString_RequestFailed); - private static readonly Action _requestCanceled = + private static readonly Action _requestCanceled = LoggerMessage.Define( eventId: new EventId(2, "RequestCanceled"), logLevel: LogLevel.Information, formatString: Strings.LogFormatString_RequestCanceled); - private static readonly Action _resolvedTargetProcess = + private static readonly Action _resolvedTargetProcess = LoggerMessage.Define( eventId: new EventId(3, "ResolvedTargetProcess"), logLevel: LogLevel.Debug, formatString: Strings.LogFormatString_ResolvedTargetProcess); - private static readonly Action _egressedArtifact = + private static readonly Action _egressedArtifact = LoggerMessage.Define( eventId: new EventId(4, "EgressedArtifact"), logLevel: LogLevel.Information, formatString: Strings.LogFormatString_EgressedArtifact); - private static readonly Action _writtenToHttpStream = + private static readonly Action _writtenToHttpStream = LoggerMessage.Define( eventId: new EventId(5, "WrittenToHttpStream"), logLevel: LogLevel.Information, formatString: Strings.LogFormatString_WrittenToHttpStream); - private static readonly Action _throttledEndpoint = + private static readonly Action _throttledEndpoint = LoggerMessage.Define( eventId: new EventId(6, "ThrottledEndpoint"), logLevel: LogLevel.Warning, @@ -51,13 +51,13 @@ internal static class LoggingExtensions logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_DefaultProcessUnexpectedFailure); - private static readonly Action _stoppingTraceEventHit = + private static readonly Action _stoppingTraceEventHit = LoggerMessage.Define( eventId: new EventId(8, "StoppingTraceEventHit"), logLevel: LogLevel.Debug, formatString: Strings.LogFormatString_StoppingTraceEventHit); - private static readonly Action _stoppingTraceEventPayloadFilterMismatch = + private static readonly Action _stoppingTraceEventPayloadFilterMismatch = LoggerMessage.Define( eventId: new EventId(9, "StoppingTraceEventPayloadFilterMismatch"), logLevel: LogLevel.Warning, @@ -75,7 +75,7 @@ internal static class LoggingExtensions logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_StopOperationFailed); - private static readonly Action _metricsDropped = + private static readonly Action _metricsDropped = LoggerMessage.Define( eventId: new EventId(12, "MetricsDropped"), logLevel: LogLevel.Warning, @@ -87,31 +87,31 @@ internal static class LoggingExtensions logLevel: LogLevel.Error, formatString: Strings.LogFormatString_MetricsWriteFailed); - private static readonly Action _metricsAbandonCompletion = + private static readonly Action _metricsAbandonCompletion = LoggerMessage.Define( eventId: new EventId(14, "MetricsAbandonCompletion"), logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_MetricsAbandonCompletion); - private static readonly Action _metricsUnprocessed = + private static readonly Action _metricsUnprocessed = LoggerMessage.Define( eventId: new EventId(15, "MetricsUnprocessed"), logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_MetricsUnprocessed); - private static readonly Action _counterEndedPayload = + private static readonly Action _counterEndedPayload = LoggerMessage.Define( eventId: new EventId(16, "CounterEndedPayload"), logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_CounterEndedPayload); - private static readonly Action _errorPayload = + private static readonly Action _errorPayload = LoggerMessage.Define( eventId: new EventId(17, "ErrorPayload"), logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_ErrorPayload); - private static readonly Action _generatedInProcessArtifact = + private static readonly Action _generatedInProcessArtifact = LoggerMessage.Define( eventId: new EventId(18, "GeneratedInProcessArtifact"), logLevel: LogLevel.Information, diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsService.cs index eb88449451b..61c40b9d755 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsService.cs @@ -17,7 +17,7 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi /// internal sealed class MetricsService : BackgroundService { - private MetricsPipeline _counterPipeline; + private MetricsPipeline? _counterPipeline; private readonly IDiagnosticServices _services; private readonly MetricsStoreService _store; private IOptionsMonitor _optionsMonitor; @@ -55,7 +55,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) using var optionsTokenSource = new CancellationTokenSource(); //If metric options change, we need to cancel the existing metrics pipeline and restart with the new settings. - using IDisposable monitorListener = _optionsMonitor.OnChange((_, _) => optionsTokenSource.SafeCancel()); + using IDisposable? monitorListener = _optionsMonitor.OnChange((_, _) => optionsTokenSource.SafeCancel()); MetricsPipelineSettings counterSettings = MetricsSettingsFactory.CreateSettings(counterOptions, Timeout.Infinite, options); counterSettings.UseSharedSession = pi.EndpointInfo.RuntimeVersion?.Major >= 8; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsSettingsFactory.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsSettingsFactory.cs index 856605f7fb7..06cbe409fa4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsSettingsFactory.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsSettingsFactory.cs @@ -70,7 +70,7 @@ private static MetricsPipelineSettings CreateSettings(bool includeDefaults, foreach (EventPipeCounterGroup counterGroup in eventPipeCounterGroups) { - if (intervalMap.TryGetValue(counterGroup.ProviderName, out GlobalProviderOptions providerInterval)) + if (intervalMap.TryGetValue(counterGroup.ProviderName, out GlobalProviderOptions? providerInterval)) { Debug.Assert(counterGroup.IntervalSeconds == null, "Unexpected value for provider interval"); counterGroup.IntervalSeconds = providerInterval.IntervalSeconds; @@ -120,7 +120,7 @@ private static List ConvertCounterGroups(IList ConvertCounterGroups(IList providers, IList meters) + private static List ConvertCounterGroups(IList? providers, IList? meters) { List counterGroups = new(); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsStore.cs index 35981911621..5011bd3caf1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/MetricsStore.cs @@ -35,7 +35,7 @@ public override int GetHashCode() return code.ToHashCode(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is MetricKey metricKey) { @@ -99,7 +99,7 @@ public void AddMetric(ICounterPayload metric) lock (_allMetrics) { var metricKey = new MetricKey(metric); - if (!_allMetrics.TryGetValue(metricKey, out Queue metrics)) + if (!_allMetrics.TryGetValue(metricKey, out Queue? metrics)) { metrics = new Queue(); _allMetrics.Add(metricKey, metrics); @@ -120,7 +120,7 @@ public void AddMetric(ICounterPayload metric) public async Task SnapshotMetrics(Stream outputStream, CancellationToken token) { - Dictionary> copy = null; + Dictionary>? copy = null; lock (_allMetrics) { copy = new Dictionary>(); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/PrometheusDataModel.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/PrometheusDataModel.cs index 59ff2fe06f2..dc3d86f856a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/PrometheusDataModel.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/PrometheusDataModel.cs @@ -28,22 +28,20 @@ internal static class PrometheusDataModel public static string GetPrometheusNormalizedName(string metricProvider, string metric, string unit) { - string baseUnit = null; + string? baseUnit = null; if ((unit != null) && (!KnownUnits.TryGetValue(unit, out baseUnit))) { baseUnit = unit; } - bool hasUnit = !string.IsNullOrEmpty(baseUnit); - //The +1's account for separators //CONSIDER Can we optimize with Span/stackalloc here instead of using StringBuilder? - StringBuilder builder = new StringBuilder(metricProvider.Length + metric.Length + (hasUnit ? baseUnit.Length + 1 : 0) + 1); + StringBuilder builder = new StringBuilder(metricProvider.Length + metric.Length + (!string.IsNullOrEmpty(baseUnit) ? baseUnit.Length + 1 : 0) + 1); NormalizeString(builder, metricProvider, isProvider: true); builder.Append(SeparatorChar); NormalizeString(builder, metric, isProvider: false); - if (hasUnit) + if (!string.IsNullOrEmpty(baseUnit)) { builder.Append(SeparatorChar); NormalizeString(builder, baseUnit, isProvider: false); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/StreamingCounterLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/StreamingCounterLogger.cs index 4a6e0e56e1b..39d4f4b7490 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/StreamingCounterLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Metrics/StreamingCounterLogger.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable disable + using Microsoft.Diagnostics.Monitoring.EventPipe; using Microsoft.Extensions.Logging; using System; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj index c7c5ff56ded..29ec888bfe6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj @@ -15,6 +15,7 @@ $(Description) true Library + enable diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CallStackResults.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CallStackResults.cs index 3d410000a49..87a29455177 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CallStackResults.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CallStackResults.cs @@ -10,16 +10,16 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi.Models public class CallStackFrame { [JsonPropertyName("methodName")] - public string MethodName { get; set; } + public string MethodName { get; set; } = string.Empty; [JsonPropertyName("methodToken")] public uint MethodToken { get; set; } [JsonPropertyName("typeName")] - public string TypeName { get; set; } + public string TypeName { get; set; } = string.Empty; [JsonPropertyName("moduleName")] - public string ModuleName { get; set; } + public string ModuleName { get; set; } = string.Empty; [JsonPropertyName("moduleVersionId")] public Guid ModuleVersionId { get; set; } @@ -46,7 +46,7 @@ public class CallStack public uint ThreadId { get; set; } [JsonPropertyName("threadName")] - public string ThreadName { get; set; } + public string ThreadName { get; set; } = string.Empty; [JsonPropertyName("frames")] public IList Frames { get; set; } = new List(); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CollectionRuleDescription.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CollectionRuleDescription.cs index 0129e79c155..141163004d5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CollectionRuleDescription.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/CollectionRuleDescription.cs @@ -17,6 +17,6 @@ public record class CollectionRuleDescription /// Human-readable explanation for the current state of the collection rule. /// [JsonPropertyName("stateReason")] - public string StateReason { get; set; } + public string? StateReason { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs index 331078012a9..ef5d7287fc4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs @@ -11,13 +11,13 @@ public class DotnetMonitorInfo /// The dotnet monitor version. /// [JsonPropertyName("version")] - public string Version { get; set; } + public string? Version { get; set; } /// /// The dotnet runtime version. /// [JsonPropertyName("runtimeVersion")] - public string RuntimeVersion { get; set; } + public string? RuntimeVersion { get; set; } /// /// Indicates whether dotnet monitor is in 'connect' mode or 'listen' mode. @@ -29,6 +29,6 @@ public class DotnetMonitorInfo /// The name of the named pipe or unix domain socket to use for connecting to the diagnostic server. /// [JsonPropertyName("diagnosticPortName")] - public string DiagnosticPortName { get; set; } + public string? DiagnosticPortName { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs index 8e0a2f230b3..30c3b78e0d3 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs @@ -22,16 +22,16 @@ public class OperationSummary public OperationState Status { get; set; } [JsonPropertyName("process")] - public OperationProcessInfo Process { get; set; } + public OperationProcessInfo? Process { get; set; } [JsonPropertyName("egressProviderName")] - public string EgressProviderName { get; set; } + public string? EgressProviderName { get; set; } [JsonPropertyName("isStoppable")] public bool IsStoppable { get; set; } [JsonPropertyName("tags")] - public ISet Tags { get; set; } + public ISet? Tags { get; set; } } /// @@ -46,7 +46,7 @@ public class OperationProcessInfo public Guid Uid { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } } /// @@ -58,11 +58,11 @@ public class OperationStatus : OperationSummary //Success cases [JsonPropertyName("resourceLocation")] - public string ResourceLocation { get; set; } + public string? ResourceLocation { get; set; } //Failure cases [JsonPropertyName("error")] - public OperationError Error { get; set; } + public OperationError? Error { get; set; } } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -79,9 +79,9 @@ public enum OperationState public class OperationError { [JsonPropertyName("code")] - public string Code { get; set; } + public string? Code { get; set; } [JsonPropertyName("message")] - public string Message { get; set; } + public string? Message { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventMetricsConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventMetricsConfiguration.cs index 2b5d78fbd01..fad168e9380 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventMetricsConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventMetricsConfiguration.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// Imported by Microsoft.Diagnostics.Monitoring.ConfigurationSchema +#nullable enable + using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; @@ -13,29 +16,29 @@ public class EventMetricsConfiguration public bool IncludeDefaultProviders { get; set; } = true; [JsonPropertyName("providers")] - public EventMetricsProvider[] Providers { get; set; } + public EventMetricsProvider[]? Providers { get; set; } [JsonPropertyName("meters")] - public EventMetricsMeter[] Meters { get; set; } + public EventMetricsMeter[]? Meters { get; set; } } public class EventMetricsProvider { [Required] [JsonPropertyName("providerName")] - public string ProviderName { get; set; } + public string ProviderName { get; set; } = string.Empty; [JsonPropertyName("counterNames")] - public string[] CounterNames { get; set; } + public string[]? CounterNames { get; set; } } public class EventMetricsMeter { [Required] [JsonPropertyName("meterName")] - public string MeterName { get; set; } + public string MeterName { get; set; } = string.Empty; [JsonPropertyName("instrumentNames")] - public string[] InstrumentNames { get; set; } + public string[]? InstrumentNames { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs index 614f8f78022..5bc7ef29662 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs @@ -10,7 +10,7 @@ public class EventPipeConfiguration { [JsonPropertyName("providers")] [Required, MinLength(1)] - public EventPipeProvider[] Providers { get; set; } + public EventPipeProvider[] Providers { get; set; } = []; [JsonPropertyName("requestRundown")] public bool RequestRundown { get; set; } = true; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs index 9f1c23452a6..c631eca410b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// Imported by Microsoft.Diagnostics.Monitoring.ConfigurationSchema +#nullable enable + #if !SCHEMAGEN using Microsoft.Diagnostics.Monitoring.WebApi.Validation; #endif @@ -15,19 +18,19 @@ public class EventPipeProvider { [JsonPropertyName("name")] [Required] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; [JsonPropertyName("keywords")] #if !SCHEMAGEN [IntegerOrHexString] #endif - public string Keywords { get; set; } = "0x" + EventKeywords.All.ToString("X"); + public string? Keywords { get; set; } = "0x" + EventKeywords.All.ToString("X"); [JsonPropertyName("eventLevel")] [EnumDataType(typeof(EventLevel))] public EventLevel EventLevel { get; set; } = EventLevel.Verbose; [JsonPropertyName("arguments")] - public IDictionary Arguments { get; set; } + public IDictionary? Arguments { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs index 2f3ae659fdd..523378abd76 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs @@ -22,7 +22,7 @@ public class LogsConfiguration /// The logger categories and levels at which logs are collected. Setting the log level to null will have logs collected from the corresponding category at the level set in the LogLevel property. /// [JsonPropertyName("filterSpecs")] - public Dictionary FilterSpecs { get; set; } + public Dictionary? FilterSpecs { get; set; } /// /// Set to true to collect logs at the application-defined categories and levels. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs index 9065463d7a3..75246a5cf34 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs @@ -15,7 +15,7 @@ public class ProcessIdentifier public Guid Uid { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonPropertyName("isDefault")] public bool IsDefault { get; set; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs index 54fe8bdac3d..a1f74572870 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs @@ -15,15 +15,15 @@ public class ProcessInfo public Guid Uid { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonPropertyName("commandLine")] - public string CommandLine { get; set; } + public string? CommandLine { get; set; } [JsonPropertyName("operatingSystem")] - public string OperatingSystem { get; set; } + public string? OperatingSystem { get; set; } [JsonPropertyName("processArchitecture")] - public string ProcessArchitecture { get; set; } + public string? ProcessArchitecture { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/SpeedScopeStackResults.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/SpeedScopeStackResults.cs index e44bb0bf47d..ecff5fa32b1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/SpeedScopeStackResults.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/SpeedScopeStackResults.cs @@ -9,10 +9,10 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi.Models public class SpeedscopeResult { [JsonPropertyName("exporter")] - public string Exporter { get; set; } + public string? Exporter { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonPropertyName("activeProfileIndex")] public int ActiveProfileIndex { get; set; } @@ -21,22 +21,22 @@ public class SpeedscopeResult public string Schema { get; set; } = "https://www.speedscope.app/file-format-schema.json"; [JsonPropertyName("profiles")] - public List Profiles { get; set; } + public List? Profiles { get; set; } [JsonPropertyName("shared")] - public SharedFrames Shared { get; set; } + public SharedFrames? Shared { get; set; } } public class SharedFrames { [JsonPropertyName("frames")] - public List Frames { get; set; } + public List? Frames { get; set; } } public class SharedFrame { [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonPropertyName("col")] public int? Column { get; set; } @@ -45,7 +45,7 @@ public class SharedFrame public int? Line { get; set; } [JsonPropertyName("file")] - public string File { get; set; } + public string? File { get; set; } } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -91,7 +91,7 @@ public class Profile public ProfileType Type { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonPropertyName("unit")] public UnitType Unit { get; set; } @@ -103,6 +103,6 @@ public class Profile public double EndValue { get; set; } [JsonPropertyName("events")] - public List Events { get; set; } + public List? Events { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs index e7429f0cb40..1c6dc0dfd69 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs @@ -23,7 +23,7 @@ internal class EgressOperation : IEgressOperation private readonly IArtifactOperation _operation; - public EgressOperation(IArtifactOperation operation, string endpointName, IProcessInfo processInfo, KeyValueLogScope scope, string tags, CollectionRuleMetadata collectionRuleMetadata = null) + public EgressOperation(IArtifactOperation operation, string endpointName, IProcessInfo processInfo, KeyValueLogScope scope, string? tags, CollectionRuleMetadata? collectionRuleMetadata = null) { _egress = (service, token) => service.EgressAsync( endpointName, diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs index e741782d252..323ac8c4c70 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs @@ -23,16 +23,19 @@ public bool IsStoppable } } +#nullable disable public ExecutionResult ExecutionResult { get; set; } +#nullable restore + public Models.OperationState State { get; set; } - public EgressRequest EgressRequest { get; set; } + public required EgressRequest EgressRequest { get; set; } public DateTime CreatedDateTime { get; } = DateTime.UtcNow; public Guid OperationId { get; set; } - public ISet Tags { get; set; } + public required ISet Tags { get; set; } public TaskCompletionSource TaskCompletionSource { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); } @@ -55,9 +58,9 @@ public async Task> ExecuteOperation(IEgressOperati EgressEntry entry = await AddOperationInternal(egressOperation, RequestLimitTracker.Unlimited); - await entry?.TaskCompletionSource.Task; + await entry.TaskCompletionSource.Task; - return entry?.ExecutionResult; + return entry.ExecutionResult; } public async Task AddOperation(IEgressOperation egressOperation, string limitKey) @@ -105,7 +108,7 @@ public void StopOperation(Guid operationId, Action onStopException) { lock (_requests) { - if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + if (!_requests.TryGetValue(operationId, out EgressEntry? entry)) { throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); } @@ -125,7 +128,7 @@ public void StopOperation(Guid operationId, Action onStopException) CancellationToken token = entry.EgressRequest.CancellationTokenSource.Token; _ = Task.Run(() => entry.EgressRequest.EgressOperation.StopAsync(token), token) - .ContinueWith(task => onStopException(task.Exception), + .ContinueWith(task => onStopException(task.Exception!), token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); @@ -136,7 +139,7 @@ public void MarkOperationAsRunning(Guid operationId) { lock (_requests) { - if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + if (!_requests.TryGetValue(operationId, out EgressEntry? entry)) { throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); } @@ -154,7 +157,7 @@ public void CancelOperation(Guid operationId) { lock (_requests) { - if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + if (!_requests.TryGetValue(operationId, out EgressEntry? entry)) { throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); } @@ -178,7 +181,7 @@ public void CompleteOperation(Guid operationId, ExecutionResult re { lock (_requests) { - if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + if (!_requests.TryGetValue(operationId, out EgressEntry? entry)) { throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); } @@ -206,7 +209,7 @@ public void CompleteOperation(Guid operationId, ExecutionResult re } } - public IEnumerable GetOperations(ProcessKey? processKey, string tags) + public IEnumerable GetOperations(ProcessKey? processKey, string? tags) { lock (_requests) { @@ -278,7 +281,7 @@ public Models.OperationStatus GetOperationStatus(Guid operationId) { lock (_requests) { - if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + if (!_requests.TryGetValue(operationId, out EgressEntry? entry)) { throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); } @@ -307,11 +310,13 @@ public Models.OperationStatus GetOperationStatus(Guid operationId) } else if (entry.State == Models.OperationState.Failed) { +#nullable disable status.Error = new Models.OperationError { Code = entry.ExecutionResult.ProblemDetails.Status?.ToString(CultureInfo.InvariantCulture), Message = entry.ExecutionResult.ProblemDetails.Detail }; +#nullable restore } return status; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/HttpResponseEgressOperation.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/HttpResponseEgressOperation.cs index 5bf592a4592..a3425ffbdea 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/HttpResponseEgressOperation.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/HttpResponseEgressOperation.cs @@ -17,7 +17,7 @@ internal sealed class HttpResponseEgressOperation : IEgressOperation private readonly TaskCompletionSource _responseFinishedCompletionSource = new(TaskCreationOptions.RunContinuationsAsynchronously); public EgressProcessInfo ProcessInfo { get; private set; } - public string EgressProviderName { get { return null; } } + public string? EgressProviderName { get { return null; } } public bool IsStoppable { get { return _operation?.IsStoppable ?? false; } } public ISet Tags { get; private set; } @@ -25,7 +25,7 @@ internal sealed class HttpResponseEgressOperation : IEgressOperation private readonly IArtifactOperation _operation; - public HttpResponseEgressOperation(HttpContext context, IProcessInfo processInfo, string tags, IArtifactOperation operation) + public HttpResponseEgressOperation(HttpContext context, IProcessInfo processInfo, string? tags, IArtifactOperation operation) { _httpContext = context; _httpContext.Response.OnCompleted(() => diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs index ea56e467166..366c363bfd6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs @@ -14,7 +14,7 @@ internal interface IEgressOperation : IStartable public ISet Tags { get; } - public string EgressProviderName { get; } + public string? EgressProviderName { get; } public EgressProcessInfo ProcessInfo { get; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperationStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperationStore.cs index 42920c5371f..be4740bb544 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperationStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperationStore.cs @@ -21,7 +21,7 @@ internal interface IEgressOperationStore void CompleteOperation(Guid operationId, ExecutionResult result); - IEnumerable GetOperations(ProcessKey? processKey, string tags); + IEnumerable GetOperations(ProcessKey? processKey, string? tags); Models.OperationStatus GetOperationStatus(Guid operationId); } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs index 892fec52c1c..7cb0ad242c2 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs @@ -16,10 +16,10 @@ internal sealed class OutputStreamResult : ActionResult { private readonly Func _action; private readonly string _contentType; - private readonly string _fileDownloadName; + private readonly string? _fileDownloadName; private readonly KeyValueLogScope _scope; - public OutputStreamResult(Func action, string contentType, string fileDownloadName, KeyValueLogScope scope) + public OutputStreamResult(Func action, string contentType, string? fileDownloadName, KeyValueLogScope scope) { _contentType = contentType; _fileDownloadName = fileDownloadName; @@ -27,7 +27,7 @@ public OutputStreamResult(Func action, string c _scope = scope; } - public OutputStreamResult(IArtifactOperation operation, string fileDownloadName, KeyValueLogScope scope) + public OutputStreamResult(IArtifactOperation operation, string? fileDownloadName, KeyValueLogScope scope) : this(operation.ExecuteAsync, operation.ContentType, fileDownloadName, scope) { } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/CapturedParametersTextFormatter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/CapturedParametersTextFormatter.cs index df757475897..f9198ed5009 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/CapturedParametersTextFormatter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/CapturedParametersTextFormatter.cs @@ -51,6 +51,6 @@ protected override async ValueTask DisposeInternalAsync() await _writer.DisposeAsync(); } - private static string GetValueOrUnknown(string value) => string.IsNullOrEmpty(value) ? "" : value; + private static string GetValueOrUnknown(string? value) => string.IsNullOrEmpty(value) ? "" : value; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/ICapturedParameters.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/ICapturedParameters.cs index dbb491518ba..f6b5e50966f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/ICapturedParameters.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ParameterCapturing/ICapturedParameters.cs @@ -9,7 +9,7 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi.ParameterCapturing { internal interface ICapturedParameters { - string ActivityId { get; } + string? ActivityId { get; } ActivityIdFormat ActivityIdFormat { get; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessInfoImpl.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessInfoImpl.cs index 898c173b056..50d9a1bdd9e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessInfoImpl.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessInfoImpl.cs @@ -29,8 +29,8 @@ internal sealed class ProcessInfoImpl : IProcessInfo public ProcessInfoImpl( IEndpointInfo endpointInfo, - string commandLine, - string processName) + string? commandLine, + string? processName) { EndpointInfo = endpointInfo; @@ -60,7 +60,7 @@ public static async Task FromEndpointInfoAsync(IEndpointInfo endpo DiagnosticsClient client = new(endpointInfo.Endpoint); - string commandLine = endpointInfo.CommandLine; + string? commandLine = endpointInfo.CommandLine; if (string.IsNullOrEmpty(commandLine)) { // The EventProcessInfoPipeline will frequently block during disposal of its @@ -70,10 +70,10 @@ public static async Task FromEndpointInfoAsync(IEndpointInfo endpo // not cancellable and hangs the entire operation for at least 30 seconds. To // mitigate, start the pipeline, get the command line, and they start the disposal // on a separate Task that is not awaited. - EventProcessInfoPipeline pipeline = null; + EventProcessInfoPipeline? pipeline = null; try { - TaskCompletionSource commandLineSource = + TaskCompletionSource commandLineSource = new(TaskCreationOptions.RunContinuationsAsynchronously); using IDisposable registration = extendedInfoCancellationToken.Register( @@ -106,7 +106,7 @@ public static async Task FromEndpointInfoAsync(IEndpointInfo endpo } } - string processName = GetProcessName(commandLine, endpointInfo.OperatingSystem); + string? processName = GetProcessName(commandLine, endpointInfo.OperatingSystem); return new ProcessInfoImpl( endpointInfo, @@ -114,9 +114,9 @@ public static async Task FromEndpointInfoAsync(IEndpointInfo endpo processName); } - internal static string GetProcessName(string commandLine, string operatingSystem) + internal static string? GetProcessName(string? commandLine, string? operatingSystem) { - string processName = null; + string? processName = null; if (!string.IsNullOrEmpty(commandLine)) { // Get the process name from the command line diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs index 91456ca38d3..46a595d4c4b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs @@ -31,7 +31,7 @@ public ProcessKey(string processName) RuntimeInstanceCookie = null; } - public ProcessKey(int? processId = null, Guid? runtimeInstanceCookie = null, string processName = null) + public ProcessKey(int? processId = null, Guid? runtimeInstanceCookie = null, string? processName = null) { ProcessId = processId; ProcessName = processName; @@ -40,14 +40,14 @@ public ProcessKey(int? processId = null, Guid? runtimeInstanceCookie = null, str public int? ProcessId { get; } - public string ProcessName { get; } + public string? ProcessName { get; } public Guid? RuntimeInstanceCookie { get; } } internal class ProcessKeyTypeConverter : TypeConverter { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { if (null == sourceType) { @@ -56,7 +56,7 @@ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceT return sourceType == typeof(string) || sourceType == typeof(ProcessKey); } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { if (value is string valueString) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/CallStackData.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/CallStackData.cs index 47e4f73b5ae..9e393dc7d62 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/CallStackData.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/CallStackData.cs @@ -34,6 +34,6 @@ internal sealed class CallStack public uint ThreadId { get; set; } - public string ThreadName { get; set; } + public string ThreadName { get; set; } = string.Empty; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs index 50508001b1e..cc891648e96 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/EventStacksPipeline.cs @@ -91,10 +91,10 @@ private void Callback(TraceEvent action) Offset = offsets[i] }; - if (_result.NameCache.FunctionData.TryGetValue(stackFrame.FunctionId, out FunctionData functionData)) + if (_result.NameCache.FunctionData.TryGetValue(stackFrame.FunctionId, out FunctionData? functionData)) { stackFrame.MethodToken = functionData.MethodToken; - if (_result.NameCache.ModuleData.TryGetValue(functionData.ModuleId, out ModuleData moduleData)) + if (_result.NameCache.ModuleData.TryGetValue(functionData.ModuleId, out ModuleData? moduleData)) { stackFrame.ModuleVersionId = moduleData.ModuleVersionId; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/SpeedScopeStacksFormatter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/SpeedScopeStacksFormatter.cs index 39b6ffc1cfa..d33d356e200 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/SpeedScopeStacksFormatter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/SpeedScopeStacksFormatter.cs @@ -76,7 +76,7 @@ public override async Task FormatStack(CallStackResult stackResult, Cancellation profile.Events.Add(NativeProfileEvent); } - else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData functionData)) + else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData? functionData)) { if (!functionToSharedFrameMap.TryGetValue(frame.FunctionId, out int mapping)) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/StacksFormatter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/StacksFormatter.cs index b4734c2aa6f..77f7e59e1e5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/StacksFormatter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/StacksFormatter.cs @@ -26,7 +26,7 @@ public StacksFormatter(Stream outputStream) public abstract Task FormatStack(CallStackResult stackResult, CancellationToken token); - protected static string FormatThreadName(uint threadId, string threadName) + protected static string FormatThreadName(uint threadId, string? threadName) { const string Separator = " "; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/TextStacksFormatter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/TextStacksFormatter.cs index cde16dda134..cbd79cf6fe1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/TextStacksFormatter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Stacks/TextStacksFormatter.cs @@ -48,7 +48,7 @@ private static void BuildFrame(StringBuilder builder, NameCache cache, CallStack { builder.Append(NativeFrame); } - else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData functionData)) + else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData? functionData)) { builder.Append(NameFormatter.GetModuleName(cache, functionData.ModuleId)); builder.Append(ModuleSeparator); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs index 99b600f0315..dd4acc6dfb6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs @@ -39,6 +39,14 @@ public void Dispose() public sealed class StreamingLogger : ILogger { + private sealed class EmptyScope : IDisposable + { + public void Dispose() + { + throw new NotImplementedException(); + } + } + private readonly ScopeState _scopes = new ScopeState(); private readonly Stream _outputStream; private readonly string _categoryName; @@ -68,18 +76,18 @@ public StreamingLogger(string category, Stream outputStream, LogFormat format, L _logLevel = logLevel; } - public IDisposable BeginScope(TState state) + IDisposable ILogger.BeginScope(TState state) { if (state is LogObject logObject) { return _scopes.Push(logObject); } - return null; + return new EmptyScope(); } public bool IsEnabled(LogLevel logLevel) => (_logLevel == null) ? true : logLevel <= _logLevel.Value; - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { if (_logFormat == LogFormat.NewlineDelimitedJson) { @@ -95,7 +103,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except } } - private void LogJson(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter, LogFormat jsonFormat = LogFormat.NewlineDelimitedJson) + private void LogJson(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter, LogFormat jsonFormat = LogFormat.NewlineDelimitedJson) { Stream outputStream = _outputStream; @@ -161,7 +169,7 @@ private void LogJson(LogLevel logLevel, EventId eventId, TState state, E outputStream.Flush(); } - private void LogText(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + private void LogText(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { Stream outputStream = _outputStream; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/TaskCompletionSourceExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/TaskCompletionSourceExtensions.cs index c698bb0e80f..321789485ef 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/TaskCompletionSourceExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/TaskCompletionSourceExtensions.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable disable + using System.Threading; using System.Threading.Tasks; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/StackUtilities.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/StackUtilities.cs index c20962c5fad..042a7975f1d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/StackUtilities.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/StackUtilities.cs @@ -60,12 +60,12 @@ internal static Models.CallStackFrame CreateFrameModel(CallStackFrame frame, Nam frameModel.ModuleName = StacksFormatter.NativeFrame; frameModel.TypeName = StacksFormatter.NativeFrame; } - else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData functionData)) + else if (cache.FunctionData.TryGetValue(frame.FunctionId, out FunctionData? functionData)) { frameModel.MethodToken = functionData.MethodToken; frameModel.ModuleName = NameFormatter.GetModuleName(cache, functionData.ModuleId); - if (cache.ModuleData.TryGetValue(functionData.ModuleId, out ModuleData moduleData)) + if (cache.ModuleData.TryGetValue(functionData.ModuleId, out ModuleData? moduleData)) { frameModel.ModuleVersionId = moduleData.ModuleVersionId; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceUtilities.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceUtilities.cs index f43ee1d3467..e139e25fb37 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceUtilities.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/TraceUtilities.cs @@ -58,7 +58,7 @@ public static MonitoringSourceConfiguration GetTraceConfiguration(Models.EventPi foreach (Models.EventPipeProvider providerModel in configurationProviders) { - if (!IntegerOrHexStringAttribute.TryParse(providerModel.Keywords, out long keywords, out string parseError)) + if (!IntegerOrHexStringAttribute.TryParse(providerModel.Keywords, out long keywords, out string? parseError)) { throw new InvalidOperationException(parseError); } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/Utilities.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/Utilities.cs index 7d04ecbb8b3..002f8da5c07 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/Utilities.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Utilities/Utilities.cs @@ -40,12 +40,12 @@ public static KeyValueLogScope CreateArtifactScope(string artifactType, IEndpoin return scope; } - public static ProcessKey? GetProcessKey(int? pid, Guid? uid, string name) + public static ProcessKey? GetProcessKey(int? pid, Guid? uid, string? name) { return (!pid.HasValue && !uid.HasValue && string.IsNullOrEmpty(name)) ? null : new ProcessKey(pid, uid, name); } - public static ISet SplitTags(string tags) + public static ISet SplitTags(string? tags) { if (string.IsNullOrEmpty(tags)) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/CounterValidator.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/CounterValidator.cs index bae063dd3c3..74d747c3c02 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/CounterValidator.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/CounterValidator.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Diagnostics.Monitoring.WebApi.Models; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Microsoft.Diagnostics.Monitoring.WebApi.Validation @@ -10,11 +11,11 @@ internal static class CounterValidator { public static bool ValidateProvider(GlobalCounterOptions counterOptions, EventPipeProvider provider, - out string errorMessage) + [NotNullWhen(false)] out string? errorMessage) { errorMessage = null; - if (provider.Arguments?.TryGetValue("EventCounterIntervalSec", out string intervalValue) == true) + if (provider.Arguments?.TryGetValue("EventCounterIntervalSec", out string? intervalValue) == true) { if (float.TryParse(intervalValue, out float intervalSeconds) && intervalSeconds != counterOptions.GetProviderSpecificInterval(provider.Name)) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs index 3930c0e1b70..a5d416f3a0d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs @@ -3,26 +3,27 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Microsoft.Diagnostics.Monitoring.WebApi.Validation { public class IntegerOrHexStringAttribute : ValidationAttribute { - protected override ValidationResult IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (!(value is string stringValue)) { return new ValidationResult(Strings.ErrorMessage_ValueNotString); } - else if (!TryParse(stringValue, out _, out string error)) + else if (!TryParse(stringValue, out _, out string? error)) { return new ValidationResult(error); } return ValidationResult.Success; } - public static bool TryParse(string value, out long result, out string error) + public static bool TryParse(string? value, out long result, [NotNullWhen(false)] out string? error) { result = 0; error = null; From 6a74a1270f56b2fd598a0eb250d9b4309ae6e0f5 Mon Sep 17 00:00:00 2001 From: Joe Schmitt Date: Mon, 1 Jul 2024 10:01:20 -0700 Subject: [PATCH 2/5] Standardize syntax --- .../Controllers/DiagController.cs | 2 +- .../Controllers/MetricsController.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index fa207571b08..60bea0b1635 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -37,7 +37,7 @@ public partial class DiagController : DiagnosticsControllerBase #nullable disable private readonly IOptions _diagnosticPortOptions; -#nullable enable +#nullable restore private readonly IOptions _callStacksOptions; private readonly IOptions _parameterCapturingOptions; private readonly IOptionsMonitor _counterOptions; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs index 70f3b0e747f..e4f8538b921 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs @@ -21,9 +21,9 @@ public class MetricsController : ControllerBase private const string ArtifactType_Metrics = "metrics"; private readonly ILogger _logger; - #nullable disable +#nullable disable private readonly MetricsStoreService _metricsStore; - #nullable enable +#nullable restore private readonly MetricsOptions _metricsOptions; public MetricsController(ILogger logger, From 2c977a54661f06416299f9d9136526c48f8c7565 Mon Sep 17 00:00:00 2001 From: Joe Schmitt Date: Mon, 1 Jul 2024 10:14:19 -0700 Subject: [PATCH 3/5] Remove test code --- src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs index dd4acc6dfb6..04aade1d0a4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs @@ -43,7 +43,6 @@ private sealed class EmptyScope : IDisposable { public void Dispose() { - throw new NotImplementedException(); } } From a65e1fea354e6af031233ff7998b8c0bc05f8da0 Mon Sep 17 00:00:00 2001 From: Joe Schmitt Date: Mon, 1 Jul 2024 10:17:05 -0700 Subject: [PATCH 4/5] Standardize required attributes --- .../Operation/EgressOperationStore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs index 323ac8c4c70..04e02491457 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs @@ -27,13 +27,13 @@ public bool IsStoppable public ExecutionResult ExecutionResult { get; set; } #nullable restore - public Models.OperationState State { get; set; } + public required Models.OperationState State { get; set; } public required EgressRequest EgressRequest { get; set; } public DateTime CreatedDateTime { get; } = DateTime.UtcNow; - public Guid OperationId { get; set; } + public required Guid OperationId { get; set; } public required ISet Tags { get; set; } From 897dedd387810bbb2bcfea94d0ec8f3b48848535 Mon Sep 17 00:00:00 2001 From: Joe Schmitt Date: Mon, 1 Jul 2024 10:33:45 -0700 Subject: [PATCH 5/5] PR feedback --- .../DiagnosticServices.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs index c3ae701723b..bfe40240e56 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs @@ -28,7 +28,7 @@ public DiagnosticServices(IEndpointInfoSource endpointInfoSource, public async Task> GetProcessesAsync(DiagProcessFilter? processFilterConfig, CancellationToken token) { - IEnumerable? processes = null; + IEnumerable processes = []; try {