Initial version.

This commit is contained in:
Oliver Hauff 2021-05-13 20:03:07 +02:00
parent 193aaa1a56
commit b72c67a53e
228 changed files with 25924 additions and 0 deletions

View file

@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace TINK.Model.Logging
{
public class EmptyDirectoryLoggingManger : ILoggingDirectoryManager
{
public void DeleteObsoleteLogs() { }
/// <summary> Gets the log file name. </summary>
public string LogFileName { get { return string.Empty; } }
/// <summary> Gets all log files in logging directory. </summary>
/// <returns>List of log files.</returns>
public IList<string> GetLogFiles() { return new List<string>(); }
/// <summary> Gets path where log files are located. </summary>
/// <returns>Path to log files.</returns>
public string LogFilePath { get { return string.Empty; } }
}
}

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
namespace TINK.Model.Logging
{
public interface ILoggingDirectoryManager
{
/// <summary> Deletes files which are out of retainment scope. </summary>
void DeleteObsoleteLogs();
/// <summary> Gets the log file name. </summary>
string LogFileName { get; }
/// <summary> Gets all log files in logging directory. </summary>
/// <returns>List of log files.</returns>
IList<string> GetLogFiles();
/// <summary> Gets path where log files are located. </summary>
/// <returns>Path to log files.</returns>
string LogFilePath { get; }
}
}

View file

@ -0,0 +1,35 @@
using Serilog;
using System;
using TINK.Model.Repository.Exception;
namespace TINK.Model.Logging
{
public static class LogEntryClassifyHelper
{
/// <summary> Classifies exception and logs information or error depending on result of classification. </summary>
/// <typeparam name="T0">Type of first message parameter.</typeparam>
/// <typeparam name="T1">Type of second message parameter.</typeparam>
/// <param name="p_oLogger">Object to use for logging.</param>
/// <param name="messageTemplate">Templated used to output message.</param>
/// <param name="propertyValue0">First message parameter.</param>
/// <param name="propertyValue1">Second message parameter.</param>
/// <param name="p_oException">Exception to classify.</param>
public static void InformationOrError<T0, T1>(this ILogger p_oLogger, string messageTemplate, T0 propertyValue0, T1 propertyValue1, Exception p_oException)
{
if (p_oException == null)
{
p_oLogger.Error(messageTemplate, propertyValue0, propertyValue1, string.Empty);
return;
}
if (p_oException.GetIsConnectFailureException())
{
// Expected exception (LAN or mobile data off/ not reachable, proxy, ...)
p_oLogger.Information(messageTemplate, propertyValue0, propertyValue1, p_oException);
return;
}
p_oLogger.Error(messageTemplate, propertyValue0, propertyValue1, p_oException);
}
}
}

View file

@ -0,0 +1,103 @@
using Serilog;
using Serilog.Configuration;
using Serilog.Formatting.Json;
using System;
using System.Collections.Generic;
using System.IO;
namespace TINK.Model.Logging
{
/// <summary> Holds new logging levels. </summary>
public enum RollingInterval
{
/// <summary> Create a new log file for each session (start of app).</summary>
Session,
}
/// <summary> Provides logging file name helper functionality.</summary>
public static class LoggerConfigurationHelper
{
/// <summary> Holds the log file name. </summary>
private static ILoggingDirectoryManager m_oDirectoryManager = new EmptyDirectoryLoggingManger();
/// <summary> Sets up logging to file.</summary>
/// <param name="p_oLoggerConfiguration">Object to set up logging with.</param>
/// <param name="p_oDevice">Object to get file informaton from.</param>
/// <param name="p_oRollingInterval">Specifies rolling type.</param>
/// <param name="p_iRetainedFilesCountLimit">Count of file being retained.</param>
/// <returns>Logger object.</returns>
public static LoggerConfiguration File(
this LoggerSinkConfiguration p_oLoggerConfiguration,
string p_strLogFileFolder,
RollingInterval p_oRollingInterval = RollingInterval.Session,
int p_iRetainedFilesCountLimit = 10)
{
if (m_oDirectoryManager is EmptyDirectoryLoggingManger)
{
// Roll file only once per app session.
try
{
m_oDirectoryManager = new LoggingDirectoryManager(
Directory.GetFiles,
Directory.Exists,
(path) => Directory.CreateDirectory(path),
System.IO.File.Delete,
p_strLogFileFolder,
Path.DirectorySeparatorChar,
p_iRetainedFilesCountLimit);
}
catch (Exception l_oException)
{
Log.Error("Log directory manager could not be instanciated successfully. {@l_oException}", l_oException);
m_oDirectoryManager = new EmptyDirectoryLoggingManger();
}
}
try
{
m_oDirectoryManager.DeleteObsoleteLogs();
}
catch (Exception l_oException)
{
Log.Error("Not all obsolte log files could be deleted successfully. {@l_oException}", l_oException);
}
if (p_oLoggerConfiguration == null)
{
return null;
}
return p_oLoggerConfiguration.File(
new JsonFormatter(),
m_oDirectoryManager.LogFileName,
/*shared: true, // Leads to exception if activated.*/
rollingInterval: Serilog.RollingInterval.Infinite,
retainedFileCountLimit: p_iRetainedFilesCountLimit);
}
/// <summary> Gets all log files in logging directory. </summary>
/// <param name="p_oLogger"></param>
/// <returns>List of log files.</returns>
public static IList<string> GetLogFiles(this ILogger p_oLogger)
{
try
{
return m_oDirectoryManager.GetLogFiles();
}
catch (Exception l_oException)
{
Log.Error("Getting list of log files failed. Empty list is returned instead. {@l_oException}", l_oException);
return new List<string>();
}
}
/// <summary> Gets path where log files are located. </summary>
/// <param name="p_oLogger"></param>
/// <returns>List of log files.</returns>
public static string GetLogFilePath(
this ILogger p_oLogger)
{
return m_oDirectoryManager.LogFilePath;
}
}
}

View file

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace TINK.Model.Logging
{
public class LoggingDirectoryManager : ILoggingDirectoryManager
{
/// <summary> Name of logging subdirectory.</summary>
private const string LOGDIRECTORYTITLE = "Log";
/// <summary> Prevents an invalid instance to be created. </summary>
private LoggingDirectoryManager() { }
public LoggingDirectoryManager(
Func<string, IList<string>> p_oFileListProvider,
Func<string, bool> p_oDirectoryExistsChecker,
Action<string> p_oDirectoryCreator,
Action<string> p_oFileEraser,
string p_oLogFilePath,
char p_strDirectorySeparatorChar,
int p_iRetainedFilesCountLimit)
{
m_oFileListProvider = p_oFileListProvider ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File list provider delegate can not be null.");
if (p_oDirectoryExistsChecker == null)
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory existance checker delegate can not be null.");
}
if (p_oDirectoryCreator == null)
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory creator delegate can not be null.");
}
m_oFileEraser = p_oFileEraser ?? throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. File eraser delegate can not be null.");
if (string.IsNullOrEmpty(p_oLogFilePath))
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Log file path can not be null or empty.");
}
if (string.IsNullOrEmpty(p_strDirectorySeparatorChar.ToString()))
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Directory separtor character can not be null or empty.");
}
if (p_iRetainedFilesCountLimit < 1)
{
throw new ArgumentException($"Can not instantiate {nameof(LoggingDirectoryManager)}- object. Count of retained log files is {p_iRetainedFilesCountLimit} but must be equal or larger one.");
}
DirectorySeparatorChar = p_strDirectorySeparatorChar.ToString();
LogFilePath = $"{p_oLogFilePath}{DirectorySeparatorChar}{LOGDIRECTORYTITLE}";
m_iRetainedFilesCountLimit = p_iRetainedFilesCountLimit;
if (string.IsNullOrEmpty(LogFileTitle))
{
LogFileTitle = $"{ DateTime.Now:yyyy_MM_dd_HH_mm_ss}.jsnl";
}
// Create directory if direcotry does not exist.
if (p_oDirectoryExistsChecker(LogFilePath) == false)
{
try
{
p_oDirectoryCreator(LogFilePath);
}
catch (Exception l_oException)
{
throw new FileOperationException($"Logging directory {LogFilePath} could not be created successfully.", l_oException);
}
}
}
/// <summary> Deletes files which are out of retainment scope. </summary>
public void DeleteObsoleteLogs()
{
var l_oExceptions = new List<Exception>();
var l_oSortedFileArray = m_oFileListProvider(LogFilePath).OrderByDescending(x => x).ToArray();
for (int l_iIndex = l_oSortedFileArray.Length - 1;
l_iIndex >= m_iRetainedFilesCountLimit - 1; /* files remaining count must be m_iRetainedFilesCountLimit - 1 because new log file will be added afterwards */
l_iIndex --)
{
try
{
m_oFileEraser(l_oSortedFileArray[l_iIndex]);
}
catch (Exception l_oExpetion)
{
// Getting list of log files found.
l_oExceptions.Add(l_oExpetion);
}
}
if (l_oExceptions.Count <= 0)
{
return;
}
throw new AggregateException("Deleting obsolete log files failed.", l_oExceptions.ToArray());
}
/// <summary> Gets all log files in logging directory. </summary>
/// <param name="p_oLogger"></param>
/// <returns>List of log files.</returns>
public IList<string> GetLogFiles()
{
try
{
return m_oFileListProvider(LogFilePath).OrderBy(x => x).ToList();
}
catch (Exception l_oExpetion)
{
// Getting list of log files found.
throw new FileOperationException("Getting list of log files failed.", l_oExpetion);
}
}
/// <summary>Holds delegate to provide file names.</summary>
private readonly Func<string, IList<string>> m_oFileListProvider;
/// <summary>Holds delegate to delete files.</summary>
private readonly Action<string> m_oFileEraser;
/// <summary>Holds delegate to provide file names.</summary>
private int m_iRetainedFilesCountLimit;
/// <summary> Holds the log file name. </summary>
private string LogFileTitle { get; }
/// <summary> Holds the log file name. </summary>
public string LogFilePath { get; }
/// <summary> Holds the directory separator character. </summary>
private string DirectorySeparatorChar { get; }
/// <summary> Holds the log file name. </summary>
public string LogFileName { get { return $"{LogFilePath}{DirectorySeparatorChar}{LogFileTitle}"; } }
}
}