diff --git a/Snowflake.Data.Tests/UnitTests/Logger/EasyLoggingStarterTest.cs b/Snowflake.Data.Tests/UnitTests/Logger/EasyLoggingStarterTest.cs index 8b1c6ebfe..d816455d5 100644 --- a/Snowflake.Data.Tests/UnitTests/Logger/EasyLoggingStarterTest.cs +++ b/Snowflake.Data.Tests/UnitTests/Logger/EasyLoggingStarterTest.cs @@ -24,7 +24,7 @@ public class EasyLoggingStarterTest private const string ConfigPath = "/some-path/config.json"; private const string AnotherConfigPath = "/another/path"; private static readonly string s_expectedLogPath = Path.Combine(LogPath, "dotnet"); - + private static readonly ClientConfig s_configWithErrorLevel = new ClientConfig { CommonProps = new ClientConfigCommonProps @@ -33,7 +33,7 @@ public class EasyLoggingStarterTest LogPath = LogPath } }; - + private static readonly ClientConfig s_configWithInfoLevel = new ClientConfig { CommonProps = new ClientConfigCommonProps @@ -51,12 +51,21 @@ public class EasyLoggingStarterTest } }; + private static readonly ClientConfig s_configWithStdoutAsLogPath = new ClientConfig + { + CommonProps = new ClientConfigCommonProps + { + LogLevel = "Info", + LogPath = "STDOUT" + } + }; + [ThreadStatic] private static Mock t_easyLoggingProvider; - + [ThreadStatic] private static Mock t_easyLoggerManager; - + [ThreadStatic] private static Mock t_unixOperations; @@ -68,7 +77,7 @@ public class EasyLoggingStarterTest [ThreadStatic] private static EasyLoggingStarter t_easyLoggerStarter; - + [SetUp] public void BeforeEach() { @@ -158,7 +167,7 @@ public void TestFailIfDirectoryCreationFails() { Assert.Ignore("skip test on Windows"); } - + // arrange t_easyLoggingProvider .Setup(provider => provider.ProvideConfig(ConfigPath)) @@ -169,7 +178,7 @@ public void TestFailIfDirectoryCreationFails() // act var thrown = Assert.Throws(() => t_easyLoggerStarter.Init(ConfigPath)); - + // assert Assert.That(thrown.Message, Does.Contain("Failed to create logs directory")); } @@ -187,10 +196,10 @@ public void TestThatConfiguresEasyLoggingOnlyOnceWhenInitializedWithConfigPath() t_easyLoggingProvider .Setup(provider => provider.ProvideConfig(AnotherConfigPath)) .Returns(s_configWithInfoLevel); - + // act t_easyLoggerStarter.Init(ConfigPath); - + // assert if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -202,16 +211,16 @@ public void TestThatConfiguresEasyLoggingOnlyOnceWhenInitializedWithConfigPath() FilePermissions.S_IRUSR | FilePermissions.S_IWUSR | FilePermissions.S_IXUSR), Times.Once); } t_easyLoggerManager.Verify(manager => manager.ReconfigureEasyLogging(EasyLoggingLogLevel.Error, s_expectedLogPath), Times.Once); - + // act t_easyLoggerStarter.Init(null); t_easyLoggerStarter.Init(ConfigPath); t_easyLoggerStarter.Init(AnotherConfigPath); - + // assert t_easyLoggerManager.VerifyNoOtherCalls(); } - + [Test] public void TestThatConfiguresEasyLoggingOnlyOnceForInitializationsWithoutConfigPath() { @@ -219,7 +228,7 @@ public void TestThatConfiguresEasyLoggingOnlyOnceForInitializationsWithoutConfig t_easyLoggingProvider .Setup(provider => provider.ProvideConfig(null)) .Returns(s_configWithErrorLevel); - + // act t_easyLoggerStarter.Init(null); t_easyLoggerStarter.Init(null); @@ -247,10 +256,10 @@ public void TestThatReconfiguresEasyLoggingWithConfigPathIfNotGivenForTheFirstTi t_easyLoggingProvider .Setup(provider => provider.ProvideConfig(ConfigPath)) .Returns(s_configWithInfoLevel); - + // act t_easyLoggerStarter.Init(null); - + // assert if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -265,10 +274,25 @@ public void TestThatReconfiguresEasyLoggingWithConfigPathIfNotGivenForTheFirstTi // act t_easyLoggerStarter.Init(ConfigPath); - + // assert t_easyLoggerManager.Verify(manager => manager.ReconfigureEasyLogging(EasyLoggingLogLevel.Info, s_expectedLogPath), Times.Once); t_easyLoggerManager.VerifyNoOtherCalls(); } + + [Test] + public void TestConfigureStdout() + { + // arrange + t_easyLoggingProvider + .Setup(provider => provider.ProvideConfig(null)) + .Returns(s_configWithStdoutAsLogPath); + + // act + t_easyLoggerStarter.Init(null); + + // assert + t_easyLoggerManager.Verify(manager => manager.ReconfigureEasyLogging(EasyLoggingLogLevel.Info, "STDOUT"), Times.Once); + } } } diff --git a/Snowflake.Data/Core/Session/EasyLoggingStarter.cs b/Snowflake.Data/Core/Session/EasyLoggingStarter.cs index 51a402bf1..f0ff20852 100644 --- a/Snowflake.Data/Core/Session/EasyLoggingStarter.cs +++ b/Snowflake.Data/Core/Session/EasyLoggingStarter.cs @@ -16,7 +16,7 @@ namespace Snowflake.Data.Core internal class EasyLoggingStarter { private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); - + private readonly EasyLoggingConfigProvider _easyLoggingConfigProvider; private readonly EasyLoggerManager _easyLoggerManager; @@ -28,12 +28,12 @@ internal class EasyLoggingStarter private readonly EnvironmentOperations _environmentOperations; private readonly object _lockForExclusiveInit = new object(); - + private EasyLoggingInitTrialParameters _initTrialParameters = null; public static readonly EasyLoggingStarter Instance = new EasyLoggingStarter(EasyLoggingConfigProvider.Instance, EasyLoggerManager.Instance, UnixOperations.Instance, DirectoryOperations.Instance, EnvironmentOperations.Instance); - + internal EasyLoggingStarter( EasyLoggingConfigProvider easyLoggingConfigProvider, EasyLoggerManager easyLoggerManager, @@ -91,7 +91,7 @@ internal void Reset(EasyLoggingLogLevel logLevel) _easyLoggerManager.ResetEasyLogging(logLevel); } } - + private bool AllowedToInitialize(string configFilePathFromConnectionString) { var everTriedToInitialize = _initTrialParameters != null; @@ -128,6 +128,10 @@ private string GetLogPath(string logPath) throw new Exception("No log path found for easy logging. Home directory is not configured and log path is not provided"); } } + if (EasyLoggerManager.IsStdout(logPath)) + { + return logPath; + } var pathWithDotnetSubdirectory = Path.Combine(logPathOrDefault, "dotnet"); if (!_directoryOperations.Exists(pathWithDotnetSubdirectory)) { @@ -184,7 +188,7 @@ public bool IsConfigFilePathGiven() { return _configFilePathFromConnectionString != null; } - + public bool HasDifferentConfigPath(string configFilePath) { return IsConfigFilePathGiven() diff --git a/Snowflake.Data/Logger/EasyLoggerManager.cs b/Snowflake.Data/Logger/EasyLoggerManager.cs index ca7800f0e..18ffe818b 100644 --- a/Snowflake.Data/Logger/EasyLoggerManager.cs +++ b/Snowflake.Data/Logger/EasyLoggerManager.cs @@ -21,7 +21,7 @@ internal class EasyLoggerManager private const string AppenderPrefix = "SFEasyLogging"; private readonly EasyLoggingLevelMapper _levelMapper = EasyLoggingLevelMapper.Instance; - + public virtual void ReconfigureEasyLogging(EasyLoggingLogLevel easyLoggingLogLevel, string logsPath) { var log4netLevel = _levelMapper.ToLog4NetLevel(easyLoggingLogLevel); @@ -30,7 +30,7 @@ public virtual void ReconfigureEasyLogging(EasyLoggingLogLevel easyLoggingLogLev var repository = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(); var rootLogger = (log4net.Repository.Hierarchy.Logger)repository.GetLogger("Snowflake.Data"); rootLogger.Level = log4netLevel; - var appender = string.Equals(logsPath, "STDOUT", StringComparison.OrdinalIgnoreCase) + var appender = IsStdout(logsPath) ? AddConsoleAppender(rootLogger) : AddRollingFileAppender(rootLogger, logsPath); RemoveOtherEasyLoggingAppenders(rootLogger, appender); @@ -38,6 +38,11 @@ public virtual void ReconfigureEasyLogging(EasyLoggingLogLevel easyLoggingLogLev } } + internal static bool IsStdout(string logsPath) + { + return string.Equals(logsPath, "STDOUT", StringComparison.OrdinalIgnoreCase); + } + internal void ResetEasyLogging(EasyLoggingLogLevel easyLoggingLogLevel) { var log4netLevel = _levelMapper.ToLog4NetLevel(easyLoggingLogLevel); @@ -57,7 +62,7 @@ internal static bool HasEasyLoggingAppender() var rootLogger = (log4net.Repository.Hierarchy.Logger)repository.GetLogger("Snowflake.Data"); return rootLogger.Appenders.ToArray().Any(IsEasyLoggingAppender); } - + private static void RemoveOtherEasyLoggingAppenders(log4net.Repository.Hierarchy.Logger logger, IAppender appender) { var existingAppenders = logger.Appenders.ToArray();