From f399bed01e7758889ba0fbf7eca16162a71f3e59 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Tue, 2 Feb 2021 16:14:13 -0800 Subject: [PATCH] Refactor and add additional logging. (#1941) --- .../ActionContextExtensions.cs | 6 +- .../Controllers/DiagController.cs | 22 ++- .../Controllers/DiagControllerExtensions.cs | 6 +- .../EgressStreamResult.cs | 2 +- .../LoggingExtensions.cs | 67 +++++++ .../OutputStreamResult.cs | 2 +- .../AzureBlob/AzureBlobEgressProvider.cs | 40 ++--- .../Egress/AzureBlobEgressFactory.cs | 2 +- .../Configuration/EgressConfigureOptions.cs | 14 +- .../dotnet-monitor/Egress/EgressFactory.cs | 2 +- .../dotnet-monitor/Egress/EgressProvider.cs | 2 +- .../Egress/EgressProviderTypes.cs | 13 ++ .../Egress/EgressProviderValidation.cs | 2 +- .../FileSystem/FileSystemEgressProvider.cs | 28 +-- .../dotnet-monitor/Egress/LoggerExtensions.cs | 51 ------ src/Tools/dotnet-monitor/LoggingExtensions.cs | 164 ++++++++++++++++++ .../appsettings.Development.json | 0 .../dotnet-monitor}/appsettings.json | 2 + .../dotnet-monitor/dotnet-monitor.csproj | 14 ++ 19 files changed, 311 insertions(+), 128 deletions(-) create mode 100644 src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs create mode 100644 src/Tools/dotnet-monitor/Egress/EgressProviderTypes.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/LoggerExtensions.cs create mode 100644 src/Tools/dotnet-monitor/LoggingExtensions.cs rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Tools/dotnet-monitor}/appsettings.Development.json (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Tools/dotnet-monitor}/appsettings.json (84%) diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs index 6e751f922..043d19cb5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs @@ -16,8 +16,6 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer { internal static class ActionContextExtensions { - private const string ExceptionLogMessage = "Request failed."; - public static Task ProblemAsync(this ActionContext context, Exception ex) { if (context.HttpContext.Features.Get().HasStarted) @@ -81,13 +79,13 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer private static bool LogError(ILogger logger, Exception ex) { - logger.LogError(ex, ExceptionLogMessage); + logger.RequestFailed(ex); return true; } private static bool LogInformation(ILogger logger, Exception ex) { - logger.LogInformation(ex.Message); + logger.RequestCanceled(); return true; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs index 0862e7674..c01778107 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs @@ -56,6 +56,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers { processesIdentifiers.Add(ProcessIdentifierModel.FromProcessInfo(p)); } + _logger.WrittenToHttpStream(); return new ActionResult>(processesIdentifiers); }, _logger); } @@ -64,9 +65,15 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers public Task> GetProcess( ProcessFilter processFilter) { - return InvokeForProcess( - processInfo => ProcessModel.FromProcessInfo(processInfo), - processFilter); + return InvokeForProcess(processInfo => + { + ProcessModel processModel = ProcessModel.FromProcessInfo(processInfo); + + _logger.WrittenToHttpStream(); + + return processModel; + }, + processFilter); } [HttpGet("processes/{processFilter}/env")] @@ -79,7 +86,11 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers try { - return client.GetProcessEnvironment(); + Dictionary environment = client.GetProcessEnvironment(); + + _logger.WrittenToHttpStream(); + + return environment; } catch (ServerErrorException) { @@ -105,6 +116,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers { Stream dumpStream = await _diagnosticServices.GetDump(processInfo, type, HttpContext.RequestAborted); + _logger.WrittenToHttpStream(); //Compression is done automatically by the response //Chunking is done because the result has no content-length return File(dumpStream, ContentTypes.ApplicationOctectStream, dumpFileName); @@ -475,7 +487,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers processInfoScope.AddEndpointInfo(processInfo.EndpointInfo); using var _ = _logger.BeginScope(processInfoScope); - _logger.LogDebug("Resolved target process."); + _logger.ResolvedTargetProcess(); return await func(processInfo); }, _logger); diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs index 450bbe32f..3dc273c21 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs @@ -17,8 +17,6 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers { internal static class DiagControllerExtensions { - private const string ExceptionLogMessage = "Request failed."; - public static ActionResult NotAcceptable(this ControllerBase controller) { return new StatusCodeResult((int)HttpStatusCode.NotAcceptable); @@ -94,13 +92,13 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers private static bool LogError(ILogger logger, Exception ex) { - logger.LogError(ex, ExceptionLogMessage); + logger.RequestFailed(ex); return true; } private static bool LogInformation(ILogger logger, Exception ex) { - logger.LogInformation(ex.Message); + logger.RequestCanceled(); return true; } } diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs index 9239a6494..e3d143b2f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs @@ -45,7 +45,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer EgressResult egressResult = await _egress(egressService, token); - logger.LogInformation("Egressed to {0}", egressResult.Value); + logger.EgressedArtifact(egressResult.Value); // The remaining code is creating a JSON object with a single property and scalar value // that indiates where the stream data was egressed. Because the name of the artifact is diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs new file mode 100644 index 000000000..3acb09ebf --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Logging; +using System; + +namespace Microsoft.Diagnostics.Monitoring.RestServer +{ + internal static class LoggingExtensions + { + private static readonly Action _requestFailed = + LoggerMessage.Define( + eventId: new EventId(1, "RequestFailed"), + logLevel: LogLevel.Error, + formatString: "Request failed."); + + private static readonly Action _requestCanceled = + LoggerMessage.Define( + eventId: new EventId(2, "RequestCanceled"), + logLevel: LogLevel.Information, + formatString: "Request canceled."); + + private static readonly Action _resolvedTargetProcess = + LoggerMessage.Define( + eventId: new EventId(3, "ResolvedTargetProcess"), + logLevel: LogLevel.Debug, + formatString: "Resolved target process."); + + private static readonly Action _egressedArtifact = + LoggerMessage.Define( + eventId: new EventId(4, "EgressedArtifact"), + logLevel: LogLevel.Information, + formatString: "Egressed artifact to {location}"); + + private static readonly Action _writtenToHttpStream = + LoggerMessage.Define( + eventId: new EventId(5, "WrittenToHttpStream"), + logLevel: LogLevel.Information, + formatString: "Written to HTTP stream."); + + public static void RequestFailed(this ILogger logger, Exception ex) + { + _requestFailed(logger, ex); + } + + public static void RequestCanceled(this ILogger logger) + { + _requestCanceled(logger, null); + } + + public static void ResolvedTargetProcess(this ILogger logger) + { + _resolvedTargetProcess(logger, null); + } + + public static void EgressedArtifact(this ILogger logger, string location) + { + _egressedArtifact(logger, location, null); + } + + public static void WrittenToHttpStream(this ILogger logger) + { + _writtenToHttpStream(logger, null); + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs index 09b205e27..7765bd52c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs @@ -55,7 +55,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer await _action(context.HttpContext.Response.Body, token); - logger.LogInformation("Written to HTTP stream."); + logger.WrittenToHttpStream(); }, logger); } } diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs index aa24d95ec..f6865a3bb 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs @@ -43,17 +43,14 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage BlobClient blobClient = containerClient.GetBlobClient(GetBlobName(name)); - Logger?.LogDebug("Start invoking stream action."); + Logger?.EgressProviderInvokeStreamAction(EgressProviderTypes.AzureBlobStorage); using var stream = await action(token); - Logger?.LogDebug("End invoking stream action."); // Write blob content, headers, and metadata - Logger?.LogDebug("Start uploading to storage with headers and metadata."); await blobClient.UploadAsync(stream, CreateHttpHeaders(streamOptions), streamOptions.Metadata, cancellationToken: token); - Logger?.LogDebug("End uploading to storage with headers and metadata."); string blobUriString = GetBlobUri(blobClient); - Logger?.LogDebug("Uploaded stream to {0}", blobUriString); + Logger?.EgressProviderSavedStream(EgressProviderTypes.AzureBlobStorage, blobUriString); return blobUriString; } catch (AggregateException ex) when (ex.InnerException is RequestFailedException innerException) @@ -81,27 +78,22 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage BlockBlobClient blobClient = containerClient.GetBlockBlobClient(GetBlobName(name)); // Write blob content - Logger?.LogDebug("Start uploading to storage."); using (Stream blobStream = await blobClient.OpenWriteAsync(overwrite: true, cancellationToken: token)) { + Logger?.EgressProviderInvokeStreamAction(EgressProviderTypes.AzureBlobStorage); await action(blobStream, token); await blobStream.FlushAsync(token); } - Logger?.LogDebug("End uploading to storage."); // Write blob headers - Logger?.LogDebug("Start writing headers."); await blobClient.SetHttpHeadersAsync(CreateHttpHeaders(streamOptions), cancellationToken: token); - Logger?.LogDebug("End writing headers."); // Write blob metadata - Logger?.LogDebug("Start writing metadata."); await blobClient.SetMetadataAsync(streamOptions.Metadata, cancellationToken: token); - Logger?.LogDebug("End writing metadata."); string blobUriString = GetBlobUri(blobClient); - Logger?.LogDebug("Uploaded stream to {0}", blobUriString); + Logger?.EgressProviderSavedStream(EgressProviderTypes.AzureBlobStorage, blobUriString); return blobUriString; } catch (AggregateException ex) when (ex.InnerException is RequestFailedException innerException) @@ -116,15 +108,15 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage private void LogAndValidateOptions(AzureBlobEgressStreamOptions streamOptions, string fileName) { - Logger?.LogProviderOption(nameof(Options.AccountKey), Options.AccountKey, redact: true); - Logger?.LogProviderOption(nameof(Options.AccountUri), GetAccountUri(out _)); - Logger?.LogProviderOption(nameof(Options.BlobPrefix), Options.BlobPrefix); - Logger?.LogProviderOption(nameof(Options.ContainerName), Options.ContainerName); - Logger?.LogProviderOption(nameof(Options.SharedAccessSignature), Options.SharedAccessSignature, redact: true); - Logger?.LogStreamOption(nameof(streamOptions.ContentEncoding), streamOptions.ContentEncoding); - Logger?.LogStreamOption(nameof(streamOptions.ContentType), streamOptions.ContentType); - Logger?.LogStreamOption(nameof(streamOptions.Metadata), "[" + string.Join(", ", streamOptions.Metadata.Keys) + "]"); - Logger?.LogDebug($"File name: {fileName}"); + Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.AccountKey), Options.AccountKey, redact: true); + Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.AccountUri), GetAccountUri(out _)); + Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.BlobPrefix), Options.BlobPrefix); + Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.ContainerName), Options.ContainerName); + Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.SharedAccessSignature), Options.SharedAccessSignature, redact: true); + Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.ContentEncoding), streamOptions.ContentEncoding); + Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.ContentType), streamOptions.ContentType); + Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.Metadata), "[" + string.Join(", ", streamOptions.Metadata.Keys) + "]"); + Logger?.EgressProviderFileName(EgressProviderTypes.AzureBlobStorage, fileName); ValidateOptions(); } @@ -146,8 +138,6 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage BlobServiceClient serviceClient; if (!string.IsNullOrWhiteSpace(Options.SharedAccessSignature)) { - Logger?.LogDebug("Using shared access signature."); - var serviceUriBuilder = new UriBuilder(Options.AccountUri) { Query = Options.SharedAccessSignature @@ -157,8 +147,6 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage } else if (!string.IsNullOrEmpty(Options.AccountKey)) { - Logger?.LogDebug("Using account key."); - // Remove Query in case SAS token was specified Uri accountUri = GetAccountUri(out string accountName); @@ -173,10 +161,8 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage throw CreateException("SharedAccessSignature or AccountKey must be specified."); } - Logger?.LogDebug("Start creating blob container if not exists."); BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(Options.ContainerName); await containerClient.CreateIfNotExistsAsync(cancellationToken: token); - Logger?.LogDebug("End creating blob container if not exists."); return containerClient; } diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs b/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs index 2d7dc45d8..a86d1f8bf 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs @@ -74,7 +74,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress { if (!egressProperties.TryGetValue(propertyName, out value)) { - Logger.LogWarning("Provider '{0}': Unable to find '{1}' key in egress properties.", providerName, propertyName); + Logger.EgressProviderUnableToFindPropertyKey(providerName, propertyName); return false; } return true; diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs index 379b557a9..948971f4b 100644 --- a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs @@ -48,8 +48,8 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration _logger = loggerFactory.CreateLogger(); // Register egress providers - _factories.Add("AzureBlobStorage", new AzureBlobEgressFactory(loggerFactory)); - _factories.Add("FileSystem", new FileSystemEgressFactory(loggerFactory)); + _factories.Add(EgressProviderTypes.AzureBlobStorage, new AzureBlobEgressFactory(loggerFactory)); + _factories.Add(EgressProviderTypes.FileSystem, new FileSystemEgressFactory(loggerFactory)); } public void Configure(EgressOptions options) @@ -59,7 +59,6 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration IConfigurationSection propertiesSection = egressSection.GetSection(nameof(EgressOptions.Properties)); propertiesSection.Bind(options.Properties); - _logger.LogDebug("Start loading egress providers."); IConfigurationSection providersSection = egressSection.GetSection(nameof(EgressOptions.Providers)); foreach (var providerSection in providersSection.GetChildren()) { @@ -75,7 +74,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration EgressProviderValidation validation = new EgressProviderValidation(providerName, _logger); if (!validation.TryValidate(commonOptions)) { - _logger.LogWarning("Provider '{0}': Skipped: Invalid options.", providerName); + _logger.EgressProviderInvalidOptions(providerName); } string providerType = commonOptions.Type; @@ -85,21 +84,20 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration if (!_factories.TryGetValue(providerType, out EgressFactory factory)) { - _logger.LogWarning("Provider '{0}': Skipped: Type '{1}' is not supported.", providerName, providerType); + _logger.EgressProviderInvalidType(providerName, providerType); continue; } if (!factory.TryCreate(providerName, providerSection, options.Properties, out ConfiguredEgressProvider provider)) { - _logger.LogWarning("Provider '{0}': Skipped: Invalid options.", providerName); + _logger.EgressProviderInvalidOptions(providerName); continue; } options.Providers.Add(providerName, provider); - _logger.LogDebug("Added egress provider '{0}'.", providerName); + _logger.EgressProviderAdded(providerName); } - _logger.LogDebug("End loading egress providers."); } /// diff --git a/src/Tools/dotnet-monitor/Egress/EgressFactory.cs b/src/Tools/dotnet-monitor/Egress/EgressFactory.cs index 7fe152d5d..00a2a0f87 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressFactory.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressFactory.cs @@ -35,7 +35,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress protected bool TryValidateOptions(object value, string providerName) { - Logger.LogDebug("Provider '{0}': Validating options.", providerName); + Logger.EgressProviderValidatingOptions(providerName); EgressProviderValidation validation = new EgressProviderValidation(providerName, Logger); return validation.TryValidate(value); } diff --git a/src/Tools/dotnet-monitor/Egress/EgressProvider.cs b/src/Tools/dotnet-monitor/Egress/EgressProvider.cs index bddced850..cb4f2438b 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressProvider.cs @@ -70,7 +70,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress int copyBufferSize = Options.CopyBufferSize.GetValueOrDefault(0x100000); - Logger?.LogDebug("Copying action stream to egress stream with buffer size {0}", copyBufferSize); + Logger?.EgressCopyActionStreamToEgressStream(copyBufferSize); await sourceStream.CopyToAsync( targetStream, diff --git a/src/Tools/dotnet-monitor/Egress/EgressProviderTypes.cs b/src/Tools/dotnet-monitor/Egress/EgressProviderTypes.cs new file mode 100644 index 000000000..2c4d895d8 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/EgressProviderTypes.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress +{ + internal static class EgressProviderTypes + { + public const string AzureBlobStorage = nameof(AzureBlobStorage); + + public const string FileSystem = nameof(FileSystem); + } +} diff --git a/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs b/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs index 14a8aaf10..87dd35616 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs @@ -43,7 +43,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress { if (ValidationResult.Success != result) { - _logger.LogWarning("Provider '{0}': {1}", _providerName, result.ErrorMessage); + _logger.EgressProviderOptionsValidationWarning(_providerName, result.ErrorMessage); } } } diff --git a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs index 9d41a20b9..8209b2bdf 100644 --- a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs @@ -30,30 +30,23 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem { LogAndValidateOptions(name); - Logger?.LogDebug("Check if target directory exists."); if (!Directory.Exists(Options.DirectoryPath)) { - Logger?.LogDebug("Start creating target directory."); WrapException(() => Directory.CreateDirectory(Options.DirectoryPath)); - Logger?.LogDebug("End creating target directory."); } string targetPath = Path.Combine(Options.DirectoryPath, name); if (!string.IsNullOrEmpty(Options.IntermediateDirectoryPath)) { - Logger?.LogDebug("Check if intermediate directory exists."); if (!Directory.Exists(Options.IntermediateDirectoryPath)) { - Logger?.LogDebug("Start creating intermediate directory."); WrapException(() => Directory.CreateDirectory(Options.IntermediateDirectoryPath)); - Logger?.LogDebug("End creating intermediate directory."); } string intermediateFilePath = null; try { - Logger?.LogDebug("Generating intermediate file."); int remainingAttempts = 10; bool intermediatePathExists; do @@ -71,21 +64,16 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem await WriteFileAsync(action, intermediateFilePath, token); - Logger?.LogDebug("Start moving intermediate file to destination."); WrapException(() => File.Move(intermediateFilePath, targetPath)); - Logger?.LogDebug("End moving intermediate file to destination."); } finally { // Attempt to delete the intermediate file if it exists. try { - Logger?.LogDebug("Check if intermediate file exists."); if (File.Exists(intermediateFilePath)) { - Logger?.LogDebug("Start removing intermediate file."); File.Delete(intermediateFilePath); - Logger?.LogDebug("End removing intermediate file."); } } catch (Exception) @@ -98,34 +86,28 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem await WriteFileAsync(action, targetPath, token); } - Logger?.LogDebug("Saved stream to '{0}.", targetPath); + Logger?.EgressProviderSavedStream(EgressProviderTypes.FileSystem, targetPath); return targetPath; } private void LogAndValidateOptions(string fileName) { - Logger?.LogProviderOption(nameof(Options.DirectoryPath), Options.DirectoryPath); - Logger?.LogProviderOption(nameof(Options.IntermediateDirectoryPath), Options.IntermediateDirectoryPath); - Logger?.LogDebug($"File name: {fileName}"); + Logger?.EgressProviderOptionValue(EgressProviderTypes.FileSystem, nameof(Options.DirectoryPath), Options.DirectoryPath); + Logger?.EgressProviderOptionValue(EgressProviderTypes.FileSystem, nameof(Options.IntermediateDirectoryPath), Options.IntermediateDirectoryPath); + Logger?.EgressProviderFileName(EgressProviderTypes.FileSystem, fileName); ValidateOptions(); } private async Task WriteFileAsync(Func action, string filePath, CancellationToken token) { - Logger?.LogDebug("Opening file stream."); - using Stream fileStream = WrapException( () => new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)); - Logger?.LogDebug("Start writing to file."); - - Logger?.LogDebug("Start invoking stream action."); + Logger?.EgressProviderInvokeStreamAction(EgressProviderTypes.FileSystem); await action(fileStream, token); - Logger?.LogDebug("End invoking stream action."); await fileStream.FlushAsync(token); - Logger?.LogDebug("End writing to file."); } private static void WrapException(Action action) diff --git a/src/Tools/dotnet-monitor/Egress/LoggerExtensions.cs b/src/Tools/dotnet-monitor/Egress/LoggerExtensions.cs deleted file mode 100644 index 3e4729c67..000000000 --- a/src/Tools/dotnet-monitor/Egress/LoggerExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Logging; -using System; -using System.Globalization; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - internal static class LoggerExtensions - { - private const string ProviderOptionLogFormat = "Provider option: {0} = {1}"; - private const string StreamOptionLogFormat = "Stream option: {0} = {1}"; - - public static void LogProviderOption(this ILogger logger, string name, bool value) - { - logger.LogProviderOption(name, value.ToString(CultureInfo.InvariantCulture)); - } - - public static void LogProviderOption(this ILogger logger, string name, Uri value) - { - logger.LogProviderOption(name, value.ToString()); - } - - public static void LogProviderOption(this ILogger logger, string name, string value, bool redact = false) - { - if (redact) - { - value = Redact(value); - } - - logger?.LogDebug(ProviderOptionLogFormat, name, value); - } - - public static void LogStreamOption(this ILogger logger, string name, string value, bool redact = false) - { - if (redact) - { - value = Redact(value); - } - - logger?.LogDebug(StreamOptionLogFormat, name, value); - } - - private static string Redact(string value) - { - return string.IsNullOrEmpty(value) ? value : ""; - } - } -} diff --git a/src/Tools/dotnet-monitor/LoggingExtensions.cs b/src/Tools/dotnet-monitor/LoggingExtensions.cs new file mode 100644 index 000000000..006ba41b2 --- /dev/null +++ b/src/Tools/dotnet-monitor/LoggingExtensions.cs @@ -0,0 +1,164 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Logging; +using System; + +namespace Microsoft.Diagnostics.Tools.Monitor +{ + internal static class LoggingExtensions + { + private static readonly Action _egressProviderAdded = + LoggerMessage.Define( + eventId: new EventId(1, "EgressProviderAdded"), + logLevel: LogLevel.Debug, + formatString: "Provider '{providerName}': Added."); + + private static readonly Action _egressProviderInvalidOptions = + LoggerMessage.Define( + eventId: new EventId(2, "EgressProviderInvalidOptions"), + logLevel: LogLevel.Error, + formatString: "Provider '{providerName}': Invalid options."); + + private static readonly Action _egressProviderInvalidType = + LoggerMessage.Define( + eventId: new EventId(3, "EgressProviderInvalidType"), + logLevel: LogLevel.Error, + formatString: "Provider '{providerName}': Type '{providerType}' is not supported."); + + private static readonly Action _egressProviderValidatingOptions = + LoggerMessage.Define( + eventId: new EventId(4, "EgressProviderValidatingOptions"), + logLevel: LogLevel.Debug, + formatString: "Provider '{providerName}': Validating options."); + + private static readonly Action _egressCopyActionStreamToEgressStream = + LoggerMessage.Define( + eventId: new EventId(5, "EgressCopyActionStreamToEgressStream"), + logLevel: LogLevel.Debug, + formatString: "Copying action stream to egress stream with buffer size {bufferSize}"); + + private static readonly Action _egressProviderOptionsValidationWarning = + LoggerMessage.Define( + eventId: new EventId(6, "EgressProviderOptionsValidationWarning"), + logLevel: LogLevel.Warning, + formatString: "Provider '{providerName}': {validationWarning}"); + + private static readonly Action _egressProviderOptionValue = + LoggerMessage.Define( + eventId: new EventId(7, "EgressProviderOptionValue"), + logLevel: LogLevel.Debug, + formatString: "Provider {providerType}: Provider option {optionName} = {optionValue}"); + + private static readonly Action _egressStreamOptionValue = + LoggerMessage.Define( + eventId: new EventId(8, "EgressStreamOptionValue"), + logLevel: LogLevel.Debug, + formatString: "Provider {providerType}: Stream option {optionName} = {optionValue}"); + + private static readonly Action _egressProviderFileName = + LoggerMessage.Define( + eventId: new EventId(9, "EgressProviderFileName"), + logLevel: LogLevel.Debug, + formatString: "Provider {providerType}: File name = {fileName}"); + + private static readonly Action _egressProviderUnableToFindPropertyKey = + LoggerMessage.Define( + eventId: new EventId(10, "EgressProvideUnableToFindPropertyKey"), + logLevel: LogLevel.Warning, + formatString: "Provider {providerType}: Unable to find '{keyName}' key in egress properties"); + + private static readonly Action _egressProviderInvokeStreamAction = + LoggerMessage.Define( + eventId: new EventId(11, "EgressProviderInvokeStreamAction"), + logLevel: LogLevel.Debug, + formatString: "Provider {providerType}: Invoking stream action."); + + private static readonly Action _egressProviderSavedStream = + LoggerMessage.Define( + eventId: new EventId(12, "EgressProviderSavedStream"), + logLevel: LogLevel.Debug, + formatString: "Provider {providerType}: Saved stream to {path}"); + + public static void EgressProviderAdded(this ILogger logger, string providerName) + { + _egressProviderAdded(logger, providerName, null); + } + + public static void EgressProviderInvalidOptions(this ILogger logger, string providerName) + { + _egressProviderInvalidOptions(logger, providerName, null); + } + + public static void EgressProviderInvalidType(this ILogger logger, string providerName, string providerType) + { + _egressProviderInvalidType(logger, providerName, providerType, null); + } + + public static void EgressProviderValidatingOptions(this ILogger logger, string providerName) + { + _egressProviderValidatingOptions(logger, providerName, null); + } + + public static void EgressCopyActionStreamToEgressStream(this ILogger logger, int bufferSize) + { + _egressCopyActionStreamToEgressStream(logger, bufferSize, null); + } + + public static void EgressProviderOptionsValidationWarning(this ILogger logger, string providerName, string validationWarning) + { + _egressProviderOptionsValidationWarning(logger, providerName, validationWarning, null); + } + + public static void EgressProviderOptionValue(this ILogger logger, string providerName, string optionName, Uri optionValue) + { + logger.EgressProviderOptionValue(providerName, optionName, optionValue?.ToString()); + } + + public static void EgressProviderOptionValue(this ILogger logger, string providerName, string optionName, string optionValue, bool redact = false) + { + if (redact) + { + optionValue = Redact(optionValue); + } + + _egressProviderOptionValue(logger, providerName, optionName, optionValue, null); + } + + public static void EgressStreamOptionValue(this ILogger logger, string providerName, string optionName, string optionValue, bool redact = false) + { + if (redact) + { + optionValue = Redact(optionValue); + } + + _egressStreamOptionValue(logger, providerName, optionName, optionValue, null); + } + + public static void EgressProviderFileName(this ILogger logger, string providerName, string fileName) + { + _egressProviderFileName(logger, providerName, fileName, null); + } + + public static void EgressProviderUnableToFindPropertyKey(this ILogger logger, string providerName, string keyName) + { + _egressProviderUnableToFindPropertyKey(logger, providerName, keyName, null); + } + + public static void EgressProviderInvokeStreamAction(this ILogger logger, string providerName) + { + _egressProviderInvokeStreamAction(logger, providerName, null); + } + + public static void EgressProviderSavedStream(this ILogger logger, string providerName, string path) + { + _egressProviderSavedStream(logger, providerName, path, null); + } + + private static string Redact(string value) + { + return string.IsNullOrEmpty(value) ? value : ""; + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.Development.json b/src/Tools/dotnet-monitor/appsettings.Development.json similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.Development.json rename to src/Tools/dotnet-monitor/appsettings.Development.json diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json b/src/Tools/dotnet-monitor/appsettings.json similarity index 84% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json rename to src/Tools/dotnet-monitor/appsettings.json index bb0389bc5..aeb12963a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json +++ b/src/Tools/dotnet-monitor/appsettings.json @@ -3,6 +3,7 @@ "LogLevel": { "Default": "Information", "Microsoft": "Warning", + "Microsoft.Diagnostics": "Information", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { @@ -16,6 +17,7 @@ "LogLevel": { "Default": "Information", "Microsoft": "Warning", + "Microsoft.Diagnostics": "Information", "Microsoft.Hosting.Lifetime": "Information" } } diff --git a/src/Tools/dotnet-monitor/dotnet-monitor.csproj b/src/Tools/dotnet-monitor/dotnet-monitor.csproj index f323d2ac3..f6a715f4c 100644 --- a/src/Tools/dotnet-monitor/dotnet-monitor.csproj +++ b/src/Tools/dotnet-monitor/dotnet-monitor.csproj @@ -20,6 +20,11 @@ 3 + + + + + @@ -31,6 +36,15 @@ + + + PreserveNewest + + + PreserveNewest + + + -- 2.34.1