diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index 1029d5623..98fda634e 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -177,13 +177,13 @@ task TestServer -If { !$script:IsUnix } { exec { & $script:dotnetExe xunit -configuration $Configuration -framework net452 -verbose -nobuild } } -task TestProtocol -If { !$script:IsUnix} { +task TestProtocol -If { !$script:IsUnix } { Set-Location .\test\PowerShellEditorServices.Test.Protocol\ exec { & $script:dotnetExe build -c $Configuration -f net452 } exec { & $script:dotnetExe xunit -configuration $Configuration -framework net452 -verbose -nobuild } } -task TestHost -If { !$script:IsUnix} { +task TestHost -If { !$script:IsUnix } { Set-Location .\test\PowerShellEditorServices.Test.Host\ exec { & $script:dotnetExe build -c $Configuration -f net452 } exec { & $script:dotnetExe xunit -configuration $Configuration -framework net452 -verbose -nobuild } @@ -204,10 +204,14 @@ task LayoutModule -After Build { New-Item -Force $PSScriptRoot\module\PowerShellEditorServices\bin\Desktop -Type Directory | Out-Null New-Item -Force $PSScriptRoot\module\PowerShellEditorServices\bin\Core -Type Directory | Out-Null + Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices\bin\$Configuration\netstandard1.6\publish\Serilog*.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Core\ + Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\netstandard1.6\* -Filter Microsoft.PowerShell.EditorServices*.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Core\ Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\netstandard1.6\UnixConsoleEcho.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Core\ Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\netstandard1.6\libdisablekeyecho.* -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Core\ if (!$script:IsUnix) { + Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices\bin\$Configuration\net451\Serilog*.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Desktop + Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\net451\* -Filter Microsoft.PowerShell.EditorServices*.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Desktop\ Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\net451\Newtonsoft.Json.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Desktop\ Copy-Item -Force -Path $PSScriptRoot\src\PowerShellEditorServices.Host\bin\$Configuration\net451\UnixConsoleEcho.dll -Destination $PSScriptRoot\module\PowerShellEditorServices\bin\Desktop\ diff --git a/Third Party Notices.txt b/Third Party Notices.txt index fcbd12a6e..822694f5f 100644 --- a/Third Party Notices.txt +++ b/Third Party Notices.txt @@ -5,7 +5,7 @@ This file is based on or incorporates material from the projects listed below (T UnixConsoleEcho Copyright (c) 2017 Patrick Meinecke - Provided for Informational Purposes Only +Provided for Informational Purposes Only MIT License @@ -14,3 +14,75 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +Serilog + +Copyright 2013-2015 Serilog Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +--- + +Serilog.Sinks.Async + +Copyright 2013-2015 Serilog Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +--- + +Serilog.Sinks.File + +Copyright 2013-2015 Serilog Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +--- + +Serilog.Sinks.Console + +Copyright 2013-2015 Serilog Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs index 6907f4a17..4392523ac 100644 --- a/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs +++ b/src/PowerShellEditorServices.Host/CodeLens/CodeLensFeature.cs @@ -160,4 +160,4 @@ private class CodeLensData public string ProviderId {get; set; } } } -} \ No newline at end of file +} diff --git a/src/PowerShellEditorServices.Host/EditorServicesHost.cs b/src/PowerShellEditorServices.Host/EditorServicesHost.cs index fa17d4e16..5afc5f723 100644 --- a/src/PowerShellEditorServices.Host/EditorServicesHost.cs +++ b/src/PowerShellEditorServices.Host/EditorServicesHost.cs @@ -140,7 +140,10 @@ public EditorServicesHost( /// The minimum level of log messages to be written. public void StartLogging(string logFilePath, LogLevel logLevel) { - this.logger = new FileLogger(logFilePath, logLevel); + this.logger = Logging.CreateLogger() + .LogLevel(logLevel) + .AddLogFile(logFilePath) + .Build(); #if CoreCLR FileVersionInfo fileVersionInfo = diff --git a/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj b/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj index ed3d06dec..f91090721 100644 --- a/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj +++ b/src/PowerShellEditorServices.Host/PowerShellEditorServices.Host.csproj @@ -4,7 +4,7 @@ PowerShell Editor Services Host Process Provides a process for hosting the PowerShell Editor Services library exposed by a JSON message protocol. - net451;netstandard1.6 + netstandard1.6;net451 Microsoft.PowerShell.EditorServices.Host diff --git a/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketClientChannel.cs b/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketClientChannel.cs index f331d6879..85d34654c 100644 --- a/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketClientChannel.cs +++ b/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketClientChannel.cs @@ -61,4 +61,4 @@ public static async Task Connect( return clientChannel; } } -} \ No newline at end of file +} diff --git a/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketServerChannel.cs b/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketServerChannel.cs index b41deb75b..152cd3bfd 100755 --- a/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketServerChannel.cs +++ b/src/PowerShellEditorServices.Protocol/MessageProtocol/Channel/TcpSocketServerChannel.cs @@ -55,4 +55,4 @@ protected override void Shutdown() } } } -} \ No newline at end of file +} diff --git a/src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj b/src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj index 5e4e156b3..d64976fbc 100644 --- a/src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj +++ b/src/PowerShellEditorServices.Protocol/PowerShellEditorServices.Protocol.csproj @@ -4,7 +4,7 @@ PowerShell Editor Services Host Protocol Library Provides message types and client/server APIs for the PowerShell Editor Services JSON protocol. - net451;netstandard1.6 + netstandard1.6;net451; Microsoft.PowerShell.EditorServices.Protocol diff --git a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs index c3dbadc18..fd3436784 100644 --- a/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs +++ b/src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs @@ -55,7 +55,7 @@ public DebugAdapter( } /// - /// Gets a boolean that indicates whether the current debug adapter is + /// Gets a boolean that indicates whether the current debug adapter is /// using a temporary integrated console. /// public bool IsUsingTempIntegratedConsole { get; private set; } @@ -506,7 +506,7 @@ protected async Task HandleSetBreakpointsRequest( } } catch (Exception e) when ( - e is FileNotFoundException || + e is FileNotFoundException || e is DirectoryNotFoundException || e is IOException || e is NotSupportedException || @@ -653,7 +653,7 @@ protected async Task HandleSetExceptionBreakpointsRequest( RequestContext requestContext) { // TODO: When support for exception breakpoints (unhandled and/or first chance) - // are added to the PowerShell engine, wire up the VSCode exception + // are added to the PowerShell engine, wire up the VSCode exception // breakpoints here using the pattern below to prevent bug regressions. //if (!this.noDebug) //{ diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 6c4895406..57fb6b557 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -54,7 +54,7 @@ public IEditorOperations EditorOperations /// An object that manages all of the message handlers /// The message sender /// A TaskCompletionSource that will be completed to stop the running process - /// The logger + /// The logger. public LanguageServer( EditorSession editorSession, IMessageHandlers messageHandlers, diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs index 1a2aed48a..05b3e6e06 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerSettings.cs @@ -95,7 +95,7 @@ public void Update( logger.Write(LogLevel.Verbose, $"Using Script Analyzer settings path - '{settingsPath ?? ""}'."); } catch (Exception ex) when ( - ex is NotSupportedException || + ex is NotSupportedException || ex is PathTooLongException || ex is SecurityException) { diff --git a/src/PowerShellEditorServices.VSCode/PowerShellEditorServices.VSCode.csproj b/src/PowerShellEditorServices.VSCode/PowerShellEditorServices.VSCode.csproj index cebb1c6a2..930922fb1 100644 --- a/src/PowerShellEditorServices.VSCode/PowerShellEditorServices.VSCode.csproj +++ b/src/PowerShellEditorServices.VSCode/PowerShellEditorServices.VSCode.csproj @@ -4,7 +4,7 @@ PowerShell Editor Services, Visual Studio Code Extensions Provides added functionality to PowerShell Editor Services for the Visual Studio Code editor. - net451;netstandard1.6 + netstandard1.6;net451 Microsoft.PowerShell.EditorServices.VSCode diff --git a/src/PowerShellEditorServices/Components/FeatureComponentBase.cs b/src/PowerShellEditorServices/Components/FeatureComponentBase.cs index adf351603..b2eac7539 100644 --- a/src/PowerShellEditorServices/Components/FeatureComponentBase.cs +++ b/src/PowerShellEditorServices/Components/FeatureComponentBase.cs @@ -34,9 +34,9 @@ public abstract class FeatureComponentBase /// /// Creates an instance of the FeatureComponentBase class with - /// the specified ILoggger. + /// the specified ILogger. /// - /// The ILogger to use for this instance. + /// The ILogger implementation to use for this instance. public FeatureComponentBase(ILogger logger) { this.Providers = new FeatureProviderCollection(); diff --git a/src/PowerShellEditorServices/Console/ChoicePromptHandler.cs b/src/PowerShellEditorServices/Console/ChoicePromptHandler.cs index e279c5570..3511d4483 100644 --- a/src/PowerShellEditorServices/Console/ChoicePromptHandler.cs +++ b/src/PowerShellEditorServices/Console/ChoicePromptHandler.cs @@ -49,7 +49,7 @@ public abstract class ChoicePromptHandler : PromptHandler #endregion /// - /// + /// /// /// An ILogger implementation used for writing log messages. public ChoicePromptHandler(ILogger logger) : base(logger) diff --git a/src/PowerShellEditorServices/Console/InputPromptHandler.cs b/src/PowerShellEditorServices/Console/InputPromptHandler.cs index 5acade505..454477b01 100644 --- a/src/PowerShellEditorServices/Console/InputPromptHandler.cs +++ b/src/PowerShellEditorServices/Console/InputPromptHandler.cs @@ -33,7 +33,7 @@ public abstract class InputPromptHandler : PromptHandler #endregion /// - /// + /// /// /// An ILogger implementation used for writing log messages. public InputPromptHandler(ILogger logger) : base(logger) diff --git a/src/PowerShellEditorServices/Console/PromptHandler.cs b/src/PowerShellEditorServices/Console/PromptHandler.cs index e32928fae..a40bd6e76 100644 --- a/src/PowerShellEditorServices/Console/PromptHandler.cs +++ b/src/PowerShellEditorServices/Console/PromptHandler.cs @@ -14,12 +14,12 @@ namespace Microsoft.PowerShell.EditorServices.Console public abstract class PromptHandler { /// - /// Gets the ILogger used for this instance. + /// Gets the ILogger implementation used for this instance. /// protected ILogger Logger { get; private set; } /// - /// + /// /// /// An ILogger implementation used for writing log messages. public PromptHandler(ILogger logger) diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj index 889b12f11..1fbf922e9 100644 --- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj +++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj @@ -3,7 +3,7 @@ PowerShell Editor Services Provides common PowerShell editor capabilities as a .NET library. - net451;netstandard1.6 + netstandard1.6;net451 Microsoft.PowerShell.EditorServices $(PackageTargetFallback);dnxcore50;portable-net45+win8 @@ -61,6 +61,10 @@ + + + + diff --git a/src/PowerShellEditorServices/Session/Capabilities/DscBreakpointCapability.cs b/src/PowerShellEditorServices/Session/Capabilities/DscBreakpointCapability.cs index bf6a6a9c0..8a28f5893 100644 --- a/src/PowerShellEditorServices/Session/Capabilities/DscBreakpointCapability.cs +++ b/src/PowerShellEditorServices/Session/Capabilities/DscBreakpointCapability.cs @@ -162,4 +162,4 @@ public static DscBreakpointCapability CheckForCapability( return capability; } } -} \ No newline at end of file +} diff --git a/src/PowerShellEditorServices/Utility/FileLogger.cs b/src/PowerShellEditorServices/Utility/FileLogger.cs deleted file mode 100644 index 5c7f318b7..000000000 --- a/src/PowerShellEditorServices/Utility/FileLogger.cs +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; - -namespace Microsoft.PowerShell.EditorServices.Utility -{ - /// - /// Provides an implementation of ILogger for writing messages to - /// a log file on disk. - /// - public class FileLogger : ILogger, IDisposable - { - private TextWriter textWriter; - private LogLevel minimumLogLevel = LogLevel.Verbose; - - /// - /// Creates an ILogger implementation that writes to the specified file. - /// - /// - /// Specifies the path at which log messages will be written. - /// - /// - /// Specifies the minimum log message level to write to the log file. - /// - public FileLogger(string logFilePath, LogLevel minimumLogLevel) - { - this.minimumLogLevel = minimumLogLevel; - - // Ensure that we have a usable log file path - if (!Path.IsPathRooted(logFilePath)) - { - logFilePath = - Path.Combine( -#if CoreCLR - AppContext.BaseDirectory, -#else - AppDomain.CurrentDomain.BaseDirectory, -#endif - logFilePath); - } - - if (!this.TryOpenLogFile(logFilePath)) - { - // If the log file couldn't be opened at this location, - // try opening it in a more reliable path - this.TryOpenLogFile( - Path.Combine( -#if CoreCLR - Environment.GetEnvironmentVariable("TEMP"), -#else - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), -#endif - Path.GetFileName(logFilePath))); - } - } - - /// - /// Writes a message to the log file. - /// - /// The level at which the message will be written. - /// The message text to be written. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - public void Write( - LogLevel logLevel, - string logMessage, - string callerName = null, - string callerSourceFile = null, - int callerLineNumber = 0) - { - if (this.textWriter != null && - logLevel >= this.minimumLogLevel) - { - // Print the timestamp and log level - this.textWriter.WriteLine( - "{0} [{1}] - Method \"{2}\" at line {3} of {4}\r\n", - DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - logLevel.ToString().ToUpper(), - callerName, - callerLineNumber, - callerSourceFile); - - // Print out indented message lines - foreach (var messageLine in logMessage.Split('\n')) - { - this.textWriter.WriteLine(" " + messageLine.TrimEnd()); - } - - // Finish with a newline and flush the writer - this.textWriter.WriteLine(); - this.textWriter.Flush(); - } - } - - /// - /// Writes an error message and exception to the log file. - /// - /// The error message text to be written. - /// The exception to be written.. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - public void WriteException( - string errorMessage, - Exception errorException, - [CallerMemberName] string callerName = null, - [CallerFilePath] string callerSourceFile = null, - [CallerLineNumber] int callerLineNumber = 0) - { - this.Write( - LogLevel.Error, - $"{errorMessage}\r\n\r\n{errorException.ToString()}", - callerName, - callerSourceFile, - callerLineNumber); - } - - /// - /// Flushes any remaining log write and closes the log file. - /// - public void Dispose() - { - if (this.textWriter != null) - { - this.textWriter.Flush(); - this.textWriter.Dispose(); - this.textWriter = null; - } - } - - private bool TryOpenLogFile(string logFilePath) - { - try - { - // Make sure the log directory exists - Directory.CreateDirectory( - Path.GetDirectoryName( - logFilePath)); - - // Open the log file for writing with UTF8 encoding - this.textWriter = - new StreamWriter( - new FileStream( - logFilePath, - FileMode.Create), - Encoding.UTF8); - - return true; - } - catch (Exception e) - { - if (e is UnauthorizedAccessException || - e is IOException) - { - // This exception is thrown when we can't open the file - // at the path in logFilePath. Return false to indicate - // that the log file couldn't be created. - return false; - } - - // Unexpected exception, rethrow it - throw; - } - } - } -} \ No newline at end of file diff --git a/src/PowerShellEditorServices/Utility/ILogger.cs b/src/PowerShellEditorServices/Utility/ILogger.cs deleted file mode 100644 index 388cef621..000000000 --- a/src/PowerShellEditorServices/Utility/ILogger.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; - -namespace Microsoft.PowerShell.EditorServices.Utility -{ - /// - /// Defines the level indicators for log messages. - /// - public enum LogLevel - { - /// - /// Indicates a diagnostic log message. - /// - Diagnostic, - - /// - /// Indicates a verbose log message. - /// - Verbose, - - /// - /// Indicates a normal, non-verbose log message. - /// - Normal, - - /// - /// Indicates a warning message. - /// - Warning, - - /// - /// Indicates an error message. - /// - Error - } - - /// - /// Defines an interface for writing messages to a logging implementation. - /// - public interface ILogger : IDisposable - { - /// - /// Writes a message to the log file. - /// - /// The level at which the message will be written. - /// The message text to be written. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - void Write( - LogLevel logLevel, - string logMessage, - [CallerMemberName] string callerName = null, - [CallerFilePath] string callerSourceFile = null, - [CallerLineNumber] int callerLineNumber = 0); - - /// - /// Writes an error message and exception to the log file. - /// - /// The error message text to be written. - /// The exception to be written.. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - void WriteException( - string errorMessage, - Exception errorException, - [CallerMemberName] string callerName = null, - [CallerFilePath] string callerSourceFile = null, - [CallerLineNumber] int callerLineNumber = 0); - } -} \ No newline at end of file diff --git a/src/PowerShellEditorServices/Utility/Logging.cs b/src/PowerShellEditorServices/Utility/Logging.cs new file mode 100644 index 000000000..dd7f0a1be --- /dev/null +++ b/src/PowerShellEditorServices/Utility/Logging.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using Serilog; +using Serilog.Events; +using Serilog.Sinks.File; +using Serilog.Sinks.Async; +using System.Runtime.CompilerServices; + +namespace Microsoft.PowerShell.EditorServices.Utility +{ + /// + /// Defines the level indicators for log messages. + /// + public enum LogLevel + { + /// + /// Indicates a diagnostic log message. + /// + Diagnostic, + + /// + /// Indicates a verbose log message. + /// + Verbose, + + /// + /// Indicates a normal, non-verbose log message. + /// + Normal, + + /// + /// Indicates a warning message. + /// + Warning, + + /// + /// Indicates an error message. + /// + Error + } + + /// + /// Provides logging for EditorServices + /// + public interface ILogger : IDisposable + { + /// + /// Write a message with the given severity to the logs. + /// + /// The severity level of the log message. + /// The log message itself. + /// The name of the calling method. + /// The name of the source file of the caller. + /// The line number where the log is being called. + void Write( + LogLevel logLevel, + string logMessage, + [CallerMemberName] string callerName = null, + [CallerFilePath] string callerSourceFile = null, + [CallerLineNumber] int callerLineNumber = 0); + + /// + /// Log an exception in the logs. + /// + /// The error message of the exception to be logged. + /// The exception itself that has been thrown. + /// The name of the method in which the ILogger is being called. + /// The name of the source file in which the ILogger is being called. + /// The line number in the file where the ILogger is being called. + void WriteException( + string errorMessage, + Exception exception, + [CallerMemberName] string callerName = null, + [CallerFilePath] string callerSourceFile = null, + [CallerLineNumber] int callerLineNumber = 0); + } + + + /// + /// Manages logging and logger constructor for EditorServices. + /// + public static class Logging + { + /// + /// Builder class for configuring and creating logger instances. + /// + public class Builder + { + /// + /// The level at which to log. + /// + private LogLevel _logLevel; + + /// + /// Paths at which to create log files. + /// + private Dictionary _filePaths; + + /// + /// Whether or not to send logging to the console. + /// + private bool _useConsole; + + /// + /// The log level to use when logging to the console. + /// + private LogLevel? _consoleLogLevel; + + /// + /// Constructs An ILogger implementation builder instance with default configurations: + /// No log files, not logging to console, log level normal. + /// + public Builder() + { + _logLevel = Utility.LogLevel.Normal; + _filePaths = new Dictionary(); + _useConsole = false; + } + + /// + /// The severity level of the messages to log. Not setting this makes the log level default to "Normal". + /// + /// The severity level of the messages to log. + /// the ILogger builder for reuse. + public Builder LogLevel(LogLevel logLevel) + { + _logLevel = logLevel; + return this; + } + + /// + /// Add a path to output a log file to. + /// + /// The path ofethe file to log to. + /// + /// The minimum log level for this file, null defaults to the configured global level. + /// Note that setting a more verbose level than the global configuration won't work -- + /// messages are filtered by the global configuration before they hit file-specific filters. + /// + /// the ILogger builder for reuse. + public Builder AddLogFile(string filePath, LogLevel? logLevel = null) + { + _filePaths.Add(filePath, logLevel); + return this; + } + + /// + /// Configure the ILogger to send log messages to the console. + /// + /// The minimum log level for console logging. + /// the ILogger builder for reuse. + public Builder AddConsoleLogging(LogLevel? logLevel = null) + { + _useConsole = true; + _consoleLogLevel = logLevel; + return this; + } + + /// + /// Take the log configuration and use it to create An ILogger implementation. + /// + /// The constructed logger. + public ILogger Build() + { + var configuration = new LoggerConfiguration() + .MinimumLevel.Is(ConvertLogLevel(_logLevel)); + + if (_useConsole) + { + configuration = configuration.WriteTo.Console( + restrictedToMinimumLevel: ConvertLogLevel(_consoleLogLevel ?? _logLevel), + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Message}{NewLine}"); + } + + foreach (KeyValuePair logFile in _filePaths) + { + configuration = configuration.WriteTo.Async(a => a.File(logFile.Key, + restrictedToMinimumLevel: ConvertLogLevel(logFile.Value ?? _logLevel), + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Message}{NewLine}") + ); + } + + return new PsesLogger(configuration.CreateLogger()); + } + } + + /// + /// A do-nothing logger that simply discards messages. + /// + public static ILogger NullLogger + { + get + { + return s_nullLogger ?? (s_nullLogger = CreateLogger().Build()); + } + } + + private static ILogger s_nullLogger; + + /// + /// Contruct An ILogger implementation with the applied configuration. + /// + /// The constructed logger. + public static Builder CreateLogger() + { + return new Builder(); + } + + /// + /// Convert an EditorServices log level to a Serilog log level. + /// + /// The EditorServices log level. + /// The Serilog LogEventLevel corresponding to the EditorServices log level. + private static LogEventLevel ConvertLogLevel(LogLevel logLevel) + { + switch (logLevel) + { + case LogLevel.Diagnostic: + return LogEventLevel.Verbose; + + case LogLevel.Verbose: + return LogEventLevel.Debug; + + case LogLevel.Normal: + return LogEventLevel.Information; + + case LogLevel.Warning: + return LogEventLevel.Warning; + + case LogLevel.Error: + return LogEventLevel.Error; + } + + throw new ArgumentException($"Unknown LogLevel: '{logLevel}')", nameof(logLevel)); + } + } +} diff --git a/src/PowerShellEditorServices/Utility/NullLogger.cs b/src/PowerShellEditorServices/Utility/NullLogger.cs deleted file mode 100644 index d94528e5d..000000000 --- a/src/PowerShellEditorServices/Utility/NullLogger.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; - -namespace Microsoft.PowerShell.EditorServices.Utility -{ - /// - /// Provides an implementation of ILogger that throws away all log messages, - /// typically used when logging isn't needed. - /// - public class NullLogger : ILogger, IDisposable - { - /// - /// Writes a message to the log file. - /// - /// The level at which the message will be written. - /// The message text to be written. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - public void Write( - LogLevel logLevel, - string logMessage, - string callerName = null, - string callerSourceFile = null, - int callerLineNumber = 0) - { - } - - /// - /// Writes an error message and exception to the log file. - /// - /// The error message text to be written. - /// The exception to be written.. - /// The name of the calling method. - /// The source file path where the calling method exists. - /// The line number of the calling method. - public void WriteException( - string errorMessage, - Exception errorException, - [CallerMemberName] string callerName = null, - [CallerFilePath] string callerSourceFile = null, - [CallerLineNumber] int callerLineNumber = 0) - { - } - - /// - /// Flushes any remaining log write and closes the log file. - /// - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/src/PowerShellEditorServices/Utility/PsesLogger.cs b/src/PowerShellEditorServices/Utility/PsesLogger.cs new file mode 100644 index 000000000..85777a813 --- /dev/null +++ b/src/PowerShellEditorServices/Utility/PsesLogger.cs @@ -0,0 +1,145 @@ +using System; +using System.Runtime.CompilerServices; +using System.Text; +using Serilog.Core; + +namespace Microsoft.PowerShell.EditorServices.Utility +{ + /// + /// An ILogger implementation object for EditorServices, acts as an adapter to Serilog. + /// + public class PsesLogger : ILogger + { + /// + /// The name of the ERROR log level. + /// + private static readonly string ErrorLevelName = LogLevel.Error.ToString().ToUpper(); + + /// + /// The internal Serilog logger to log to. + /// + private readonly Logger _logger; + + /// + /// Construct a new logger around a Serilog ILogger. + /// + /// The Serilog logger to use internally. + internal PsesLogger(Logger logger) + { + _logger = logger; + } + + /// + /// Write a message with the given severity to the logs. + /// + /// The severity level of the log message. + /// The log message itself. + /// The name of the calling method. + /// The name of the source file of the caller. + /// The line number where the log is being called. + public void Write( + LogLevel logLevel, + string logMessage, + [CallerMemberName] string callerName = null, + [CallerFilePath] string callerSourceFile = null, + [CallerLineNumber] int callerLineNumber = 0) + { + string indentedLogMsg = IndentMsg(logMessage); + string logLevelName = logLevel.ToString().ToUpper(); + + switch (logLevel) + { + case LogLevel.Diagnostic: + _logger.Verbose("[{LogLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}:{IndentedLogMsg:l}", + logLevelName, callerSourceFile, callerName, callerLineNumber, indentedLogMsg); + return; + case LogLevel.Verbose: + _logger.Debug("[{LogLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}:{IndentedLogMsg:l}", + logLevelName, callerSourceFile, callerName, callerLineNumber, indentedLogMsg); + return; + case LogLevel.Normal: + _logger.Information("[{LogLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}:{IndentedLogMsg:l}", + logLevelName, callerSourceFile, callerName, callerLineNumber, indentedLogMsg); + return; + case LogLevel.Warning: + _logger.Warning("[{LogLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}:{IndentedLogMsg:l}", + logLevelName, callerSourceFile, callerName, callerLineNumber, indentedLogMsg); + return; + case LogLevel.Error: + _logger.Error("[{LogLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}:{IndentedLogMsg:l}", + logLevelName, callerSourceFile, callerName, callerLineNumber, indentedLogMsg); + return; + } + } + + /// + /// Log an exception in the logs. + /// + /// The error message of the exception to be logged. + /// The exception itself that has been thrown. + /// The name of the method in which the ILogger is being called. + /// The name of the source file in which the ILogger is being called. + /// The line number in the file where the ILogger is being called. + public void WriteException( + string errorMessage, + Exception exception, + [CallerMemberName] string callerName = null, + [CallerFilePath] string callerSourceFile = null, + [CallerLineNumber] int callerLineNumber = 0) + { + string indentedException = IndentMsg(exception.ToString()); + + _logger.Error("[{ErrorLevelName:l}] {CallerSourceFile:l}: In method '{CallerName:l}', line {CallerLineNumber}: {ErrorMessage:l}{IndentedException:l}", + ErrorLevelName, callerSourceFile, callerName, callerLineNumber, errorMessage, indentedException); + } + + /// + /// Utility function to indent a log message by one level. + /// + /// The log message to indent. + /// The indented log message string. + private static string IndentMsg(string logMessage) + { + return new StringBuilder(logMessage) + .Replace(Environment.NewLine, s_indentedPrefix) + .Insert(0, s_indentedPrefix) + .AppendLine() + .ToString(); + } + + /// + /// A newline followed by a single indentation prefix. + /// + private static readonly string s_indentedPrefix = Environment.NewLine + " "; + + #region IDisposable Support + private bool _disposedValue = false; // To detect redundant calls + + /// + /// Internal disposer. + /// + /// Whether or not the object is being disposed. + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + _logger.Dispose(); + } + + _disposedValue = true; + } + } + + /// + /// Dispose of this object, using the Dispose pattern. + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + } + #endregion + } +} diff --git a/src/PowerShellEditorServices/Utility/ThreadSynchronizationContext.cs b/src/PowerShellEditorServices/Utility/ThreadSynchronizationContext.cs index 77db1d113..14f91e9b5 100644 --- a/src/PowerShellEditorServices/Utility/ThreadSynchronizationContext.cs +++ b/src/PowerShellEditorServices/Utility/ThreadSynchronizationContext.cs @@ -27,7 +27,7 @@ public class ThreadSynchronizationContext : SynchronizationContext #region Constructors /// - /// + /// /// /// An ILogger implementation used for writing log messages. public ThreadSynchronizationContext(ILogger logger) diff --git a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs index 16b7ef62d..ff90e093a 100644 --- a/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs +++ b/test/PowerShellEditorServices.Test.Host/DebugAdapterTests.cs @@ -35,10 +35,10 @@ public async Task InitializeAsync() this.GetType().Name, Guid.NewGuid().ToString().Substring(0, 8)); - this.logger = - new FileLogger( - testLogPath + "-client.log", - LogLevel.Verbose); + this.logger = Logging.CreateLogger() + .LogLevel(LogLevel.Verbose) + .AddLogFile(testLogPath + "-client.log") + .Build(); testLogPath += "-server.log"; System.Console.WriteLine(" Output log at path: {0}", testLogPath); diff --git a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs index b4d9fbd6b..9ea27e983 100644 --- a/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs +++ b/test/PowerShellEditorServices.Test.Host/LanguageServerTests.cs @@ -38,10 +38,10 @@ public async Task InitializeAsync() this.GetType().Name, Guid.NewGuid().ToString().Substring(0, 8)); - this.logger = - new FileLogger( - testLogPath + "-client.log", - LogLevel.Verbose); + this.logger = Logging.CreateLogger() + .LogLevel(LogLevel.Verbose) + .AddLogFile(testLogPath + "-client.log") + .Build(); testLogPath += "-server.log"; System.Console.WriteLine(" Output log at path: {0}", testLogPath); diff --git a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj index 7aec43019..b25a612c4 100644 --- a/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj +++ b/test/PowerShellEditorServices.Test.Host/PowerShellEditorServices.Test.Host.csproj @@ -2,7 +2,7 @@ - net452;netcoreapp2.0 + netcoreapp2.0;net452 Microsoft.PowerShell.EditorServices.Test.Host diff --git a/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs b/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs index 856a2518b..6ec39b431 100644 --- a/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs +++ b/test/PowerShellEditorServices.Test.Host/ServerTestsBase.cs @@ -14,9 +14,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -#if CoreCLR -using System.Reflection; -#endif namespace Microsoft.PowerShell.EditorServices.Test.Host { diff --git a/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs b/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs index 42ab1ea41..5212a7a1c 100644 --- a/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs +++ b/test/PowerShellEditorServices.Test.Protocol/Message/MessageReaderWriterTests.cs @@ -25,7 +25,7 @@ public class MessageReaderWriterTests public MessageReaderWriterTests() { - this.logger = new NullLogger(); + this.logger = Logging.NullLogger; this.messageSerializer = new V8MessageSerializer(); } diff --git a/test/PowerShellEditorServices.Test.Protocol/PowerShellEditorServices.Test.Protocol.csproj b/test/PowerShellEditorServices.Test.Protocol/PowerShellEditorServices.Test.Protocol.csproj index 9f10745c8..499964c67 100644 --- a/test/PowerShellEditorServices.Test.Protocol/PowerShellEditorServices.Test.Protocol.csproj +++ b/test/PowerShellEditorServices.Test.Protocol/PowerShellEditorServices.Test.Protocol.csproj @@ -2,7 +2,7 @@ - net452;netcoreapp2.0 + netcoreapp2.0;net452 Microsoft.PowerShell.EditorServices.Test.Protocol diff --git a/test/PowerShellEditorServices.Test.Shared/PowerShellEditorServices.Test.Shared.csproj b/test/PowerShellEditorServices.Test.Shared/PowerShellEditorServices.Test.Shared.csproj index 6d946ad28..cee19e4f2 100644 --- a/test/PowerShellEditorServices.Test.Shared/PowerShellEditorServices.Test.Shared.csproj +++ b/test/PowerShellEditorServices.Test.Shared/PowerShellEditorServices.Test.Shared.csproj @@ -3,7 +3,7 @@ 0.9.0-beta - net452;netstandard1.6 + netstandard1.6;net452 Microsoft.PowerShell.EditorServices.Test.Shared diff --git a/test/PowerShellEditorServices.Test/Console/ChoicePromptHandlerTests.cs b/test/PowerShellEditorServices.Test/Console/ChoicePromptHandlerTests.cs index 5034d5f94..2fba1ea5e 100644 --- a/test/PowerShellEditorServices.Test/Console/ChoicePromptHandlerTests.cs +++ b/test/PowerShellEditorServices.Test/Console/ChoicePromptHandlerTests.cs @@ -96,7 +96,7 @@ internal class TestChoicePromptHandler : ChoicePromptHandler public int TimesPrompted { get; private set; } - public TestChoicePromptHandler() : base(new NullLogger()) + public TestChoicePromptHandler() : base(Logging.NullLogger) { } diff --git a/test/PowerShellEditorServices.Test/Console/InputPromptHandlerTests.cs b/test/PowerShellEditorServices.Test/Console/InputPromptHandlerTests.cs index 1e2e1ad14..04bed7314 100644 --- a/test/PowerShellEditorServices.Test/Console/InputPromptHandlerTests.cs +++ b/test/PowerShellEditorServices.Test/Console/InputPromptHandlerTests.cs @@ -132,7 +132,7 @@ internal class TestInputPromptHandler : InputPromptHandler public Exception LastError { get; private set; } - public TestInputPromptHandler() : base(new NullLogger()) + public TestInputPromptHandler() : base(Logging.NullLogger) { } diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs index 7c3978722..65d8308b8 100644 --- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs @@ -31,7 +31,7 @@ public class DebugServiceTests : IDisposable public DebugServiceTests() { - var logger = new NullLogger(); + var logger = Logging.NullLogger; this.powerShellContext = PowerShellContextFactory.Create(logger); this.powerShellContext.SessionStateChanged += powerShellContext_SessionStateChanged; diff --git a/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs b/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs index 1476af82d..e56656a91 100644 --- a/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Extensions/ExtensionServiceTests.cs @@ -36,7 +36,7 @@ private enum EventType public async Task InitializeAsync() { - var logger = new NullLogger(); + var logger = Logging.NullLogger; this.powerShellContext = PowerShellContextFactory.Create(logger); await this.powerShellContext.ImportCommandsModule(@"..\..\..\..\..\module\PowerShellEditorServices\Commands"); diff --git a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs index 1b4c05e17..1e19a544a 100644 --- a/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs +++ b/test/PowerShellEditorServices.Test/Language/LanguageServiceTests.cs @@ -28,7 +28,7 @@ public class LanguageServiceTests : IDisposable public LanguageServiceTests() { - var logger = new NullLogger(); + var logger = Logging.NullLogger; this.powerShellContext = PowerShellContextFactory.Create(logger); this.workspace = new Workspace(this.powerShellContext.LocalPowerShellVersion.Version, logger); this.languageService = new LanguageService(this.powerShellContext, logger); @@ -164,7 +164,7 @@ public async Task LanguageServiceFindsFunctionDefinitionInWorkspace() var definitionResult = await this.GetDefinition( FindsFunctionDefinitionInWorkspace.SourceDetails, - new Workspace(this.powerShellContext.LocalPowerShellVersion.Version, new NullLogger()) + new Workspace(this.powerShellContext.LocalPowerShellVersion.Version, Logging.NullLogger) { WorkspacePath = Path.Combine(baseSharedScriptPath, @"References") }); diff --git a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs index 8afea7c46..806a935b3 100644 --- a/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs +++ b/test/PowerShellEditorServices.Test/PowerShellContextFactory.cs @@ -41,7 +41,7 @@ public TestPSHostUserInterface( : base( powerShellContext, new SimplePSHostRawUserInterface(logger), - new NullLogger()) + Logging.NullLogger) { } diff --git a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj index 199cd3b52..7e16604a0 100644 --- a/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj +++ b/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj @@ -2,7 +2,7 @@ - net452;netcoreapp2.0 + netcoreapp2.0;net452 Microsoft.PowerShell.EditorServices.Test diff --git a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs index 73ae260ab..ef07ae730 100644 --- a/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs +++ b/test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs @@ -42,7 +42,7 @@ public class PowerShellContextTests : IDisposable public PowerShellContextTests() { - this.powerShellContext = PowerShellContextFactory.Create(new NullLogger()); + this.powerShellContext = PowerShellContextFactory.Create(Logging.NullLogger); this.powerShellContext.SessionStateChanged += OnSessionStateChanged; this.stateChangeQueue = new AsyncQueue(); } diff --git a/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs index 41679285f..272cc891b 100644 --- a/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs +++ b/test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs @@ -22,7 +22,7 @@ public void CanResolveWorkspaceRelativePath() string testPathOutside = @"c:\Test\PeerPath\FilePath.ps1"; string testPathAnotherDrive = @"z:\TryAndFindMe\FilePath.ps1"; - Workspace workspace = new Workspace(PowerShellVersion, new NullLogger()); + Workspace workspace = new Workspace(PowerShellVersion, Logging.NullLogger); // Test without a workspace path Assert.Equal(testPathOutside, workspace.GetRelativePath(testPathOutside)); diff --git a/test/PowerShellEditorServices.Test/Utility/LoggerTests.cs b/test/PowerShellEditorServices.Test/Utility/LoggerTests.cs index 5ab202675..cdb2e2237 100644 --- a/test/PowerShellEditorServices.Test/Utility/LoggerTests.cs +++ b/test/PowerShellEditorServices.Test/Utility/LoggerTests.cs @@ -71,21 +71,28 @@ public void CanExcludeMessagesBelowErrorLevel() private void AssertWritesMessageAtLevel(LogLevel logLevel) { // Write a message at the desired level - var logger = new FileLogger(logFilePath, LogLevel.Verbose); + ILogger logger = Logging.CreateLogger() + .LogLevel(LogLevel.Verbose) + .AddLogFile(logFilePath) + .Build(); logger.Write(logLevel, testMessage); - // Dispose of the logger + // Dispose of the ILogger logger.Dispose(); // Read the contents and verify that it's there string logContents = this.ReadLogContents(); + File.Delete(logFilePath); Assert.Contains(this.GetLogLevelName(logLevel), logContents); Assert.Contains(testMessage, logContents); } private void AssertExcludesMessageBelowLevel(LogLevel minimumLogLevel) { - var logger = new FileLogger(logFilePath, minimumLogLevel); + ILogger logger = Logging.CreateLogger() + .LogLevel(minimumLogLevel) + .AddLogFile(logFilePath) + .Build(); // Get all possible log levels LogLevel[] allLogLevels = @@ -99,11 +106,12 @@ private void AssertExcludesMessageBelowLevel(LogLevel minimumLogLevel) logger.Write((LogLevel)logLevel, testMessage); } - // Dispose of the logger + // Dispose of the ILogger logger.Dispose(); // Make sure all excluded log levels aren't in the contents string logContents = this.ReadLogContents(); + File.Delete(logFilePath); for (int i = 0; i < (int)minimumLogLevel; i++) { LogLevel logLevel = allLogLevels[i];