Skip to content

Commit

Permalink
SNOW-856231 Enable easy logging (#774)
Browse files Browse the repository at this point in the history
### Description
Enable easy logging feature.

### Checklist
- [x] Code compiles correctly
- [x] Code is formatted according to [Coding
Conventions](../CodingConventions.md)
- [x] Created tests which fail without the change (if possible)
- [x] All tests passing (`dotnet test`)
- [x] Extended the README / documentation, if necessary
- [x] Provide JIRA issue id (if possible) or GitHub issue id in PR name
  • Loading branch information
sfc-gh-knozderko authored Sep 19, 2023
1 parent ca3153c commit 6fceac1
Show file tree
Hide file tree
Showing 27 changed files with 837 additions and 104 deletions.
93 changes: 64 additions & 29 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using System;
using System.IO;
using Moq;
using NUnit.Framework;
using Snowflake.Data.Configuration;
using Snowflake.Data.Core.Tools;

namespace Snowflake.Data.Tests.UnitTests.Configuration
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using System.IO;

namespace Snowflake.Data.Tests.UnitTests.Configuration
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using System;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
Expand All @@ -6,7 +11,7 @@

namespace Snowflake.Data.Tests.UnitTests.Configuration
{
[TestFixture]
[TestFixture, NonParallelizable]
public class EasyLoggingConfigParserTest
{
private const string NotExistingFilePath = "../../../Resources/EasyLogging/not_existing_config.json";
Expand Down Expand Up @@ -45,32 +50,72 @@ public void TestThatParsesConfigFile()
Assert.AreEqual(LogPath, config.CommonProps.LogPath);
}

[Test]
public void TestThatReturnsNullIfFileDoesNotExist(
[Values(null, "", NotExistingFilePath)]
string notExistingFilePath)
[Test, TestCaseSource(nameof(ConfigFilesWithoutValues))]
public void TestThatParsesConfigFileWithNullValues(string filePath)
{
// arrange
var parser = new EasyLoggingConfigParser();

// act
var config = parser.Parse(notExistingFilePath);
var config = parser.Parse(filePath);

// assert
Assert.IsNotNull(config);
Assert.IsNotNull(config.CommonProps);
Assert.IsNull(config.CommonProps.LogLevel);
Assert.IsNull(config.CommonProps.LogPath);
}

[Test]
[TestCase(null)]
[TestCase("")]
public void TestThatReturnsNullWhenNothingToParse(string noFilePath)
{
// arrange
var parser = new EasyLoggingConfigParser();

// act
var config = parser.Parse(noFilePath);

// assert
Assert.IsNull(config);
}

[Test]
public void TestThatFailsWhenTheFileDoesNotExist()
{
// arrange
var parser = new EasyLoggingConfigParser();

// act
var thrown = Assert.Throws<Exception>(() => parser.Parse(NotExistingFilePath));

// assert
Assert.IsNotNull(thrown);
Assert.AreEqual("Finding easy logging configuration failed", thrown.Message);
}

[Test, TestCaseSource(nameof(WrongConfigFiles))]
public void TestThatReturnsNullIfMissingOrInvalidRequiredFields(string filePath)
public void TestThatFailsIfMissingOrInvalidRequiredFields(string filePath)
{
// arrange
var parser = new EasyLoggingConfigParser();

// act
var config = parser.Parse(filePath);

var thrown = Assert.Throws<Exception>(() => parser.Parse(filePath));
// assert
Assert.IsNull(config);
Assert.IsNotNull(thrown);
Assert.IsTrue(thrown.Message == "Parsing easy logging configuration failed");
}

public static IEnumerable<string> ConfigFilesWithoutValues()
{
BeforeAll();
return new[]
{
CreateConfigTempFile(EmptyCommonConfig),
CreateConfigTempFile(Config(null, null))
};
}

public static IEnumerable<string> WrongConfigFiles()
Expand All @@ -79,9 +124,6 @@ public static IEnumerable<string> WrongConfigFiles()
return new[]
{
CreateConfigTempFile(EmptyConfig),
CreateConfigTempFile(EmptyCommonConfig),
CreateConfigTempFile(Config(null, LogPath)),
CreateConfigTempFile(Config(LogLevel, null)),
CreateConfigTempFile(Config("unknown", LogPath)),
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using Moq;
using NUnit.Framework;
using Snowflake.Data.Configuration;
Expand All @@ -17,7 +21,7 @@ public void TestThatProvidesConfiguration()
var configFinder = new Mock<EasyLoggingConfigFinder>();
var configParser = new Mock<EasyLoggingConfigParser>();
var configProvider = new EasyLoggingConfigProvider(configFinder.Object, configParser.Object);
var config = new EasyLoggingConfig();
var config = new ClientConfig();
configFinder
.Setup(finder => finder.FindConfigFilePath(FilePathFromConnectionString))
.Returns(FilePathToUse);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using System;
using NUnit.Framework;
using Snowflake.Data.Configuration;
Expand Down
117 changes: 117 additions & 0 deletions Snowflake.Data.Tests/UnitTests/Logger/EasyLoggerManagerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using Snowflake.Data.Configuration;
using Snowflake.Data.Core;
using Snowflake.Data.Log;

namespace Snowflake.Data.Tests.UnitTests.Logger
{
[TestFixture, NonParallelizable]
public class EasyLoggerManagerTest
{

private const string InfoMessage = "Easy logging Info message";
private const string DebugMessage = "Easy logging Debug message";
private const string WarnMessage = "Easy logging Warn message";
private const string ErrorMessage = "Easy logging Error message";
private const string FatalMessage = "Easy logging Fatal message";
private static readonly string s_logsDirectory = Path.GetTempPath();

[ThreadStatic]
private static string t_directoryLogPath;

[OneTimeTearDown]
public static void CleanUp()
{
RemoveEasyLoggingLogFiles();
}

[SetUp]
public void BeforeEach()
{
t_directoryLogPath = RandomLogsDirectoryPath();
}

[TearDown]
public void AfterEach()
{
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Warn, t_directoryLogPath);
}

[Test]
public void TestThatChangesLogLevel()
{
// arrange
var logger = SFLoggerFactory.GetLogger<SFBlockingChunkDownloaderV3>();
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Warn, t_directoryLogPath);

// assert
Assert.IsFalse(logger.IsDebugEnabled());
Assert.IsFalse(logger.IsInfoEnabled());
Assert.IsTrue(logger.IsWarnEnabled());
Assert.IsTrue(logger.IsErrorEnabled());
Assert.IsTrue(logger.IsFatalEnabled());

// act
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Debug, t_directoryLogPath);

// assert
Assert.IsTrue(logger.IsDebugEnabled());
Assert.IsTrue(logger.IsInfoEnabled());
Assert.IsTrue(logger.IsWarnEnabled());
Assert.IsTrue(logger.IsErrorEnabled());
Assert.IsTrue(logger.IsFatalEnabled());
}

[Test]
public void TestThatLogsToProperFileWithProperLogLevelOnly()
{
// arrange
var logger = SFLoggerFactory.GetLogger<SFBlockingChunkDownloaderV3>();
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Info, t_directoryLogPath);

// act
logger.Debug(DebugMessage);
logger.Info(InfoMessage);
logger.Warn(WarnMessage);
logger.Error(ErrorMessage);
logger.Fatal(FatalMessage);

// assert
var logLines = File.ReadLines(FindLogFilePath(t_directoryLogPath));
Assert.That(logLines, Has.Exactly(0).Matches<string>(s => s.Contains(DebugMessage)));
Assert.That(logLines, Has.Exactly(1).Matches<string>(s => s.Contains(InfoMessage)));
Assert.That(logLines, Has.Exactly(1).Matches<string>(s => s.Contains(WarnMessage)));
Assert.That(logLines, Has.Exactly(1).Matches<string>(s => s.Contains(ErrorMessage)));
Assert.That(logLines, Has.Exactly(1).Matches<string>(s => s.Contains(FatalMessage)));
}

private static string RandomLogsDirectoryPath()
{
var randomName = Path.GetRandomFileName();
return Path.Combine(s_logsDirectory, $"easy_logging_logs_{randomName}", "dotnet");
}

private static string FindLogFilePath(string directoryLogPath)
{
Assert.IsTrue(Directory.Exists(directoryLogPath));
var files = Directory.GetFiles(directoryLogPath);
Assert.AreEqual(1, files.Length);
return files.First();
}

private static void RemoveEasyLoggingLogFiles()
{
Directory.GetFiles(s_logsDirectory)
.Where(filePath => filePath.StartsWith(Path.Combine(s_logsDirectory, "easy_logging_logs")))
.AsParallel()
.ForAll(filePath => File.Delete(filePath));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,32 @@
* Copyright (c) 2023 Snowflake Computing Inc. All rights reserved.
*/

using Snowflake.Data.Configuration;

namespace Snowflake.Data.Tests.UnitTests
{
using log4net.Repository.Hierarchy;
using log4net;
using NUnit.Framework;
using Snowflake.Data.Log;
using log4net.Core;
using System;

[TestFixture]

[TestFixture, NonParallelizable]
class SFLoggerTest
{
SFLogger _logger;

[OneTimeSetUp]
public void BeforeTest()
public static void BeforeTest()
{
// Log level defaults to Warn on net6.0 builds in github actions
// Set the root level to Debug
((Hierarchy)LogManager.GetRepository()).Root.Level = Level.Debug;
((Hierarchy)LogManager.GetRepository()).RaiseConfigurationChanged(EventArgs.Empty);
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Debug, "STDOUT");
}

[OneTimeTearDown]
public static void AfterAll()
{
EasyLoggerManager.Instance.ReconfigureEasyLogging(EasyLoggingLogLevel.Warn, "STDOUT");
}

[TearDown] public void AfterTest()
{
// Return to default setting
Expand Down
22 changes: 22 additions & 0 deletions Snowflake.Data.Tests/UnitTests/SFSessionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved.
*/

using Snowflake.Data.Configuration;
using Snowflake.Data.Log;

namespace Snowflake.Data.Tests.UnitTests
{
using Snowflake.Data.Core;
Expand Down Expand Up @@ -33,5 +36,24 @@ public void TestUpdateDatabaseAndSchema()
Assert.AreEqual(schemaName, sfSession.schema);
}

[Test]
[TestCase(null)]
[TestCase("/some-path/config.json")]
[TestCase("C:\\some-path\\config.json")]
public void TestThatConfiguresEasyLogging(string configPath)
{
// arrange
var easyLoggingStarter = new Moq.Mock<EasyLoggingStarter>();
var simpleConnectionString = "account=test;user=test;password=test;";
var connectionString = configPath == null
? simpleConnectionString
: $"{simpleConnectionString}client_config_file={configPath};";

// act
new SFSession(connectionString, null, easyLoggingStarter.Object);

// assert
easyLoggingStarter.Verify(starter => starter.Init(configPath));
}
}
}
Loading

0 comments on commit 6fceac1

Please sign in to comment.