Refactor and add additional logging. (#1941)
authorJustin Anderson <jander-msft@users.noreply.github.com>
Wed, 3 Feb 2021 00:14:13 +0000 (16:14 -0800)
committerGitHub <noreply@github.com>
Wed, 3 Feb 2021 00:14:13 +0000 (16:14 -0800)
21 files changed:
src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs
src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs
src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs
src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs
src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs
src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.Development.json [deleted file]
src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json [deleted file]
src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs
src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs
src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs
src/Tools/dotnet-monitor/Egress/EgressFactory.cs
src/Tools/dotnet-monitor/Egress/EgressProvider.cs
src/Tools/dotnet-monitor/Egress/EgressProviderTypes.cs [new file with mode: 0644]
src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs
src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs
src/Tools/dotnet-monitor/Egress/LoggerExtensions.cs [deleted file]
src/Tools/dotnet-monitor/LoggingExtensions.cs [new file with mode: 0644]
src/Tools/dotnet-monitor/appsettings.Development.json [new file with mode: 0644]
src/Tools/dotnet-monitor/appsettings.json [new file with mode: 0644]
src/Tools/dotnet-monitor/dotnet-monitor.csproj

index 6e751f92207ba435328bace0b194636ce82f50a0..043d19cb55c0a9383c2d0de7cb5f2e51d6f07244 100644 (file)
@@ -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<IHttpResponseFeature>().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;
         }
     }
index 0862e7674e92a653b455e49427f91b3d244ef373..c017781076e32a4d8e63397101ccf942abffd23a 100644 (file)
@@ -56,6 +56,7 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers
                 {
                     processesIdentifiers.Add(ProcessIdentifierModel.FromProcessInfo(p));
                 }
+                _logger.WrittenToHttpStream();
                 return new ActionResult<IEnumerable<ProcessIdentifierModel>>(processesIdentifiers);
             }, _logger);
         }
@@ -64,9 +65,15 @@ namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers
         public Task<ActionResult<ProcessModel>> GetProcess(
             ProcessFilter processFilter)
         {
-            return InvokeForProcess<ProcessModel>(
-                processInfo => ProcessModel.FromProcessInfo(processInfo),
-                processFilter);
+            return InvokeForProcess<ProcessModel>(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<string, string> 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);
index 450bbe32fa6567134737fd5a4cd8d52a0851d75e..3dc273c21fe3d3ac52c87908c990cf1263bdf508 100644 (file)
@@ -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;
         }
     }
index 9239a64947f534b23e5f11b596aae3ebf235a6bd..e3d143b2f7c3f895a4fdd10fcacb7aa6d32c2ec0 100644 (file)
@@ -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 (file)
index 0000000..3acb09e
--- /dev/null
@@ -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<ILogger, Exception> _requestFailed =
+            LoggerMessage.Define(
+                eventId: new EventId(1, "RequestFailed"),
+                logLevel: LogLevel.Error,
+                formatString: "Request failed.");
+
+        private static readonly Action<ILogger, Exception> _requestCanceled =
+            LoggerMessage.Define(
+                eventId: new EventId(2, "RequestCanceled"),
+                logLevel: LogLevel.Information,
+                formatString: "Request canceled.");
+
+        private static readonly Action<ILogger, Exception> _resolvedTargetProcess =
+            LoggerMessage.Define(
+                eventId: new EventId(3, "ResolvedTargetProcess"),
+                logLevel: LogLevel.Debug,
+                formatString: "Resolved target process.");
+
+        private static readonly Action<ILogger, string, Exception> _egressedArtifact =
+            LoggerMessage.Define<string>(
+                eventId: new EventId(4, "EgressedArtifact"),
+                logLevel: LogLevel.Information,
+                formatString: "Egressed artifact to {location}");
+
+        private static readonly Action<ILogger, Exception> _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);
+        }
+    }
+}
index 09b205e278ffaea09c33ca54f6be99507921cad5..7765bd52c53ecdcefc44b4c3326adedc3615ca8e 100644 (file)
@@ -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/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.Development.json b/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.Development.json
deleted file mode 100644 (file)
index e203e94..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Debug",
-      "System": "Information",
-      "Microsoft": "Information"
-    }
-  }
-}
diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json b/src/Microsoft.Diagnostics.Monitoring.RestServer/appsettings.json
deleted file mode 100644 (file)
index bb0389b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft": "Warning",
-      "Microsoft.Hosting.Lifetime": "Information"
-    },
-    "Console": {
-      "FormatterName": "simple",
-      "FormatterOptions": {
-        "IncludeScopes": true,
-        "TimestampFormat": "HH:mm:ss "
-      }
-    },
-    "EventLog": {
-      "LogLevel": {
-        "Default": "Information",
-        "Microsoft": "Warning",
-        "Microsoft.Hosting.Lifetime": "Information"
-      }
-    }
-  },
-  "AllowedHosts": "*"
-}
index aa24d95ec8ff7c844f166fafb78333da926fc605..f6865a3bb5f51f2da968a1fdbccce8de757dc601 100644 (file)
@@ -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;
         }
index 2d7dc45d840241738587bf634eadb2f97c567dba..a86d1f8bfb035fc25967cebdd9dcb551207991d3 100644 (file)
@@ -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;
index 379b557a901dcf6c2fe06734273458bb04a7d5a5..948971f4b6e998ea09e594e976b4665d7327e0ee 100644 (file)
@@ -48,8 +48,8 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration
             _logger = loggerFactory.CreateLogger<EgressConfigureOptions>();
 
             // 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.");
         }
 
         /// <summary>
index 7fe152d5d662c4588984d18e649331465270fa54..00a2a0f87c1a32df4466c69991c3963d81f00147 100644 (file)
@@ -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);
         }
index bddced8503a2d98659b3e38e123527ad7dc6e49a..cb4f2438b0b759a627332a52ed2b66903dc305ad 100644 (file)
@@ -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 (file)
index 0000000..2c4d895
--- /dev/null
@@ -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);
+    }
+}
index 14a8aaf106ee8f2468d109aa263a699e1e19f1ab..87dd35616b6baff018fcf05d88ab9f175b70fde1 100644 (file)
@@ -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);
                         }
                     }
                 }
index 9d41a20b98ad5d9a6facf5dd97fa42ec6a707101..8209b2bdf1e92a4c58780bdd5aecc25cf0d3d2ba 100644 (file)
@@ -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<Stream, CancellationToken, Task> 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 (file)
index 3e4729c..0000000
+++ /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 : "<REDACTED>";
-        }
-    }
-}
diff --git a/src/Tools/dotnet-monitor/LoggingExtensions.cs b/src/Tools/dotnet-monitor/LoggingExtensions.cs
new file mode 100644 (file)
index 0000000..006ba41
--- /dev/null
@@ -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<ILogger, string, Exception> _egressProviderAdded =
+            LoggerMessage.Define<string>(
+                eventId: new EventId(1, "EgressProviderAdded"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider '{providerName}': Added.");
+
+        private static readonly Action<ILogger, string, Exception> _egressProviderInvalidOptions =
+            LoggerMessage.Define<string>(
+                eventId: new EventId(2, "EgressProviderInvalidOptions"),
+                logLevel: LogLevel.Error,
+                formatString: "Provider '{providerName}': Invalid options.");
+
+        private static readonly Action<ILogger, string, string, Exception> _egressProviderInvalidType =
+            LoggerMessage.Define<string, string>(
+                eventId: new EventId(3, "EgressProviderInvalidType"),
+                logLevel: LogLevel.Error,
+                formatString: "Provider '{providerName}': Type '{providerType}' is not supported.");
+
+        private static readonly Action<ILogger, string, Exception> _egressProviderValidatingOptions =
+            LoggerMessage.Define<string>(
+                eventId: new EventId(4, "EgressProviderValidatingOptions"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider '{providerName}': Validating options.");
+
+        private static readonly Action<ILogger, int, Exception> _egressCopyActionStreamToEgressStream =
+            LoggerMessage.Define<int>(
+                eventId: new EventId(5, "EgressCopyActionStreamToEgressStream"),
+                logLevel: LogLevel.Debug,
+                formatString: "Copying action stream to egress stream with buffer size {bufferSize}");
+
+        private static readonly Action<ILogger, string, string, Exception> _egressProviderOptionsValidationWarning =
+            LoggerMessage.Define<string, string>(
+                eventId: new EventId(6, "EgressProviderOptionsValidationWarning"),
+                logLevel: LogLevel.Warning,
+                formatString: "Provider '{providerName}': {validationWarning}");
+
+        private static readonly Action<ILogger, string, string, string, Exception> _egressProviderOptionValue =
+            LoggerMessage.Define<string, string, string>(
+                eventId: new EventId(7, "EgressProviderOptionValue"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider {providerType}: Provider option {optionName} = {optionValue}");
+
+        private static readonly Action<ILogger, string, string, string, Exception> _egressStreamOptionValue =
+            LoggerMessage.Define<string, string, string>(
+                eventId: new EventId(8, "EgressStreamOptionValue"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider {providerType}: Stream option {optionName} = {optionValue}");
+
+        private static readonly Action<ILogger, string, string, Exception> _egressProviderFileName =
+            LoggerMessage.Define<string, string>(
+                eventId: new EventId(9, "EgressProviderFileName"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider {providerType}: File name = {fileName}");
+
+        private static readonly Action<ILogger, string, string, Exception> _egressProviderUnableToFindPropertyKey =
+            LoggerMessage.Define<string, string>(
+                eventId: new EventId(10, "EgressProvideUnableToFindPropertyKey"),
+                logLevel: LogLevel.Warning,
+                formatString: "Provider {providerType}: Unable to find '{keyName}' key in egress properties");
+
+        private static readonly Action<ILogger, string, Exception> _egressProviderInvokeStreamAction =
+            LoggerMessage.Define<string>(
+                eventId: new EventId(11, "EgressProviderInvokeStreamAction"),
+                logLevel: LogLevel.Debug,
+                formatString: "Provider {providerType}: Invoking stream action.");
+
+        private static readonly Action<ILogger, string, string, Exception> _egressProviderSavedStream =
+            LoggerMessage.Define<string, string>(
+                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 : "<REDACTED>";
+        }
+    }
+}
diff --git a/src/Tools/dotnet-monitor/appsettings.Development.json b/src/Tools/dotnet-monitor/appsettings.Development.json
new file mode 100644 (file)
index 0000000..e203e94
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Debug",
+      "System": "Information",
+      "Microsoft": "Information"
+    }
+  }
+}
diff --git a/src/Tools/dotnet-monitor/appsettings.json b/src/Tools/dotnet-monitor/appsettings.json
new file mode 100644 (file)
index 0000000..aeb1296
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Diagnostics": "Information",
+      "Microsoft.Hosting.Lifetime": "Information"
+    },
+    "Console": {
+      "FormatterName": "simple",
+      "FormatterOptions": {
+        "IncludeScopes": true,
+        "TimestampFormat": "HH:mm:ss "
+      }
+    },
+    "EventLog": {
+      "LogLevel": {
+        "Default": "Information",
+        "Microsoft": "Warning",
+        "Microsoft.Diagnostics": "Information",
+        "Microsoft.Hosting.Lifetime": "Information"
+      }
+    }
+  },
+  "AllowedHosts": "*"
+}
index f323d2ac36132ac0af0a59aee372bf307cd32b2c..f6a715f4c8cefb121c1b1acc91d7057fd581e472 100644 (file)
     <PreReleaseVersionIteration>3</PreReleaseVersionIteration>
   </PropertyGroup>
 
+  <ItemGroup>
+    <None Remove="appsettings.Development.json" />
+    <None Remove="appsettings.json" />
+  </ItemGroup>
+
   <ItemGroup>
     <PackageReference Include="Azure.Storage.Blobs" Version="$(AzureStorageBlobsVersion)" />
     <PackageReference Include="Microsoft.Extensions.Configuration.KeyPerFile" Version="$(MicrosoftExtensionsConfigurationKeyPerFileVersion)" />
     <Compile Include="..\Common\CommandExtensions.cs" Link="CommandExtensions.cs" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Content Include="appsettings.Development.json">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="appsettings.json">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
   <ItemGroup>
     <ProjectReference Include="..\..\Microsoft.Diagnostics.Monitoring.RestServer\Microsoft.Diagnostics.Monitoring.RestServer.csproj" />
     <ProjectReference Include="..\..\Microsoft.Diagnostics.Monitoring\Microsoft.Diagnostics.Monitoring.csproj" />