- add logging lib

pull/26/head
Simon G 6 years ago
parent 5543360a50
commit a0199c4933
  1. 33
      GBase.Logging/ConsoleLogger.cs
  2. 82
      GBase.Logging/FileLogger.cs
  3. 7
      GBase.Logging/GBase.Logging.csproj
  4. 38
      GBase.Logging/Interfaces/ILog.cs
  5. 17
      GBase.Logging/Interfaces/ILogComponent.cs
  6. 34
      GBase.Logging/Interfaces/ILogMessage.cs
  7. 21
      GBase.Logging/Interfaces/ILogger.cs
  8. 201
      GBase.Logging/Log.cs
  9. 39
      GBase.Logging/LogComponentAttribute.cs
  10. 37
      GBase.Logging/LogLevels.cs
  11. 44
      GBase.Logging/LogMessage.cs

@ -0,0 +1,33 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
using GBase.Logging.Interfaces;
namespace GBase.Logging
{
/// <summary>
/// An <see cref="ILogger"/> that writes log messages to the <see cref="Console"/>
/// </summary>
public class ConsoleLogger : ILogger
{
/// <summary>
/// Write the given <see cref="string"/> to the <see cref="Console"/>
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
public async Task Write(ILogMessage message)
{
await Task.Run(() => Console.Write(message.ToString()));
}
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="ConsoleLogger"/>
/// </summary>
public async ValueTask DisposeAsync()
{
await Task.Run(Console.Clear);
}
}
}

@ -0,0 +1,82 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using GBase.Logging.Interfaces;
namespace GBase.Logging
{
/// <summary>
/// An <see cref="ILogger"/> that writes log messages to a set file
/// </summary>
public class FileLogger : ILogger
{
private readonly StreamWriter _fileWriter;
private readonly Timer _timer;
private readonly SemaphoreSlim _lockObject = new SemaphoreSlim(1);
/// <summary>
/// Constructor for <see cref="FileLogger"/>
/// </summary>
/// <param name="filePath">The directory of the LogFile</param>
/// <param name="fileName">The path of the LogFile</param>
public FileLogger(string filePath, string fileName)
{
Directory.CreateDirectory(filePath);
_fileWriter = new StreamWriter(Path.Combine(filePath, fileName), true);
_timer = new Timer(TimerCallback, null, 0, 1000);
}
/// <summary>
/// Write the given <see cref="string"/> to the file
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
public async Task Write(ILogMessage message)
{
await _lockObject.WaitAsync();
try
{
await _fileWriter.WriteAsync(message.ToString());
}
finally
{
_lockObject.Release();
}
}
private async void TimerCallback(object state)
{
await Flush();
}
private async Task Flush()
{
await _lockObject.WaitAsync();
try
{
await _fileWriter.FlushAsync();
}
finally
{
_lockObject.Release();
}
}
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="FileLogger"/>
/// </summary>
public async ValueTask DisposeAsync()
{
_timer.Dispose();
await Flush();
_fileWriter.Dispose();
_lockObject.Dispose();
}
}
}

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
</Project>

@ -0,0 +1,38 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Logging.Interfaces
{
/// <summary>
/// The main logging interface
/// </summary>
public interface ILog : IAsyncDisposable
{
/// <summary>
/// Initialize the <see cref="ILog"/>
/// </summary>
/// <returns>True if successful, false if not</returns>
bool InitializeLog();
/// <summary>
/// Set the <see cref="LogLevels"/> of the current <see cref="ILog"/> instance
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
void SetLogLevel(LogLevels logLevel);
/// <summary>
/// Add an <see cref="ILogger"/> to the <see cref="ILog"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
void AddLogger(ILogger logger);
/// <summary>
/// Remove an <see cref="ILogger"/> from the <see cref="ILog"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
void RemoveLogger(ILogger logger);
}
}

@ -0,0 +1,17 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Logging.Interfaces
{
/// <summary>
/// The <see cref="ILogComponent"/>
/// </summary>
public interface ILogComponent
{
/// <summary>
/// The <see cref="Component"/>
/// </summary>
string Component { get; }
}
}

@ -0,0 +1,34 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Logging.Interfaces
{
/// <summary>
/// An interface that is used to handle log messages
/// </summary>
public interface ILogMessage
{
/// <summary>
/// The <see cref="LogLevels"/> of the <see cref="ILogMessage"/>
/// </summary>
LogLevels LogLevel { get; set; }
/// <summary>
/// The <see cref="Timestamp"/> of the <see cref="ILogMessage"/>
/// </summary>
DateTime Timestamp { get; set; }
/// <summary>
/// The <see cref="ILogComponent"/> of the <see cref="ILogMessage"/>
/// </summary>
ILogComponent Component { get; set; }
/// <summary>
/// The <see cref="Message"/> of the <see cref="ILogMessage"/>
/// </summary>
string Message { get; set; }
}
}

@ -0,0 +1,21 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
namespace GBase.Logging.Interfaces
{
/// <summary>
/// Base class for loggers
/// </summary>
public interface ILogger : IAsyncDisposable
{
/// <summary>
/// Write the given <see cref="ILogMessage"/>
/// </summary>
/// <param name="message">The <see cref="ILogMessage"/></param>
Task Write(ILogMessage message);
}
}

@ -0,0 +1,201 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using GBase.Logging.Interfaces;
namespace GBase.Logging
{
/// <summary>
/// The main logging class
/// </summary>
public class Log : ILog
{
/// <summary>
/// Constructor for <see cref="Log"/>
/// </summary>
public Log()
{
Loggers = new List<ILogger>();
}
/// <summary>
/// <see cref="List{T}"/> of <see cref="ILogger"/>s that are subscribed to this <see cref="Log"/>
/// </summary>
protected static List<ILogger> Loggers { get; private set; }
/// <summary>
/// The <see cref="LogLevels"/> of this logging instance
/// </summary>
protected static LogLevels LogLevel { get; private set; } //TODO: Move LogLevel to ILogger? Allows to set logLevel separately for each ILogger
/// <summary>
/// Initialize the <see cref="ILog"/>
/// </summary>
/// <returns>True if successful, false if not</returns>
public bool InitializeLog()
{
return true;
}
/// <summary>
/// Set the <see cref="LogLevels"/> of the current <see cref="Log"/> instance
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
public void SetLogLevel(LogLevels logLevel)
{
LogLevel = logLevel;
LogLevelChanged?.Invoke(this, LogLevel);
}
/// <summary>
/// Add an <see cref="ILogger"/> to the <see cref="Log"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
public void AddLogger(ILogger logger)
{
Loggers.Add(logger);
}
/// <summary>
/// Remove an <see cref="ILogger"/> from the <see cref="Log"/>
/// </summary>
/// <param name="logger">The <see cref="ILogger"/></param>
public void RemoveLogger(ILogger logger)
{
Loggers.Remove(logger);
}
/// <summary>
/// Write a given <see cref="Exception"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="ex">The <see cref="Exception"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(Exception ex)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
}
/// <summary>
/// Write a given <see cref="Exception"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="component">The <see cref="ILogComponent"/></param>
/// <param name="ex">The <see cref="Exception"/></param>
public static async Task Write(ILogComponent component, Exception ex)
{
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
}
/// <summary>
/// Write a given <see cref="AggregateException"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="ex">The <see cref="AggregateException"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(AggregateException ex)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Error, ex.Message);
await Write(component, LogLevels.Error, "");
await Write(component, LogLevels.Error, ex.StackTrace);
await Write(component, LogLevels.Error, "");
foreach (var innerException in ex.InnerExceptions)
{
await Write(component, innerException);
await Write(component, LogLevels.Error, "");
}
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="LogLevels.Default"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="line"></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(string line)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, LogLevels.Default, line);
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="ILogComponent"/> of the calling <see cref="Assembly"/> and the <see cref="LogLevels"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
/// <param name="line">The given <see cref="string"/></param>
/// <typeparam name="T">The <see cref="Type"/> of the caller</typeparam>
public static async Task Write<T>(LogLevels logLevel, string line)
{
ILogComponent component = GetDefaultComponentFromType<T>();
await Write(component, logLevel, line);
}
/// <summary>
/// Write a given <see cref="string"/> with the <see cref="ILogComponent"/> and the <see cref="LogLevels"/> to the set <see cref="ILogger"/>s
/// </summary>
/// <param name="component">The <see cref="ILogComponent"/></param>
/// <param name="logLevel">The <see cref="LogLevels"/></param>
/// <param name="line">The given <see cref="string"/></param>
public static async Task Write(ILogComponent component, LogLevels logLevel, string line)
{
if (logLevel > LogLevel) //logLevel of the message can't be higher than the set LogLevel
return;
ILogMessage message = new LogMessage()
{
LogLevel = logLevel,
Timestamp = DateTime.Now,
Component = component,
Message = line
};
foreach (var logger in Loggers)
{
await logger.Write(message);
}
}
/// <summary>
/// Get the default <see cref="ILogComponent"/> for the given <see cref="Assembly"/>
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <returns></returns>
protected static ILogComponent GetDefaultComponentFromType<T>()
{
Assembly assembly = Assembly.GetAssembly(typeof(T));
LogComponentAttribute attribute = assembly.GetCustomAttribute<LogComponentAttribute>();
return attribute ?? new LogComponentAttribute("UNKNOWN");
}
/// <summary>
/// <see cref="DisposeAsync"/> the <see cref="Log"/>
/// </summary>
public async ValueTask DisposeAsync()
{
foreach (var logger in Loggers)
{
await logger.DisposeAsync();
}
Loggers.Clear();
LogLevel = LogLevels.None;
}
/// <summary>
/// Event that is fired when <see cref="SetLogLevel"/> is called
/// <para><see cref="EventArgs"/> is the newly set <see cref="LogLevels"/></para>
/// </summary>
public static event EventHandler<LogLevels> LogLevelChanged;
}
}

@ -0,0 +1,39 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.Logging.Interfaces;
namespace GBase.Logging
{
/// <summary>
/// The <see cref="ILogComponent"/> attribute
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class LogComponentAttribute : Attribute, ILogComponent
{
/// <summary>
/// <see cref="LogComponentAttribute"/> constructor
/// </summary>
/// <param name="component">The <see cref="Component"/></param>
public LogComponentAttribute(string component)
{
Component = component;
}
/// <summary>
/// The <see cref="Component"/>
/// </summary>
public string Component { get; private set; }
/// <summary>
/// Returns the <see cref="Component"/> of this <see cref="ILogComponent"/>
/// </summary>
/// <returns>The <see cref="Component"/></returns>
public override string ToString()
{
return Component;
}
}
}

@ -0,0 +1,37 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Logging
{
/// <summary>
/// The available <see cref="LogLevels"/>
/// </summary>
public enum LogLevels
{
/// <summary>
/// No logging
/// </summary>
None,
/// <summary>
/// Error logging
/// </summary>
Error,
/// <summary>
/// Default logging
/// </summary>
Default,
/// <summary>
/// Advanced logging
/// </summary>
Advanced,
/// <summary>
/// Debug logging
/// </summary>
Debug
}
}

@ -0,0 +1,44 @@
// Author: Simon Gockner
// Created: 2020-02-08
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.Logging.Interfaces;
namespace GBase.Logging
{
/// <summary>
/// Implementation of <see cref="ILogMessage"/>
/// </summary>
public class LogMessage : ILogMessage
{
/// <summary>
/// The <see cref="LogLevels"/> of the <see cref="LogMessage"/>
/// </summary>
public LogLevels LogLevel { get; set; }
/// <summary>
/// The <see cref="Timestamp"/> of the <see cref="LogMessage"/>
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// The <see cref="ILogComponent"/> of the <see cref="LogMessage"/>
/// </summary>
public ILogComponent Component { get; set; }
/// <summary>
/// The <see cref="Message"/> of the <see cref="LogMessage"/>
/// </summary>
public string Message { get; set; }
/// <summary>
/// Builds the <see cref="LogMessage"/> out of all parts and returns it as a <see cref="string"/>
/// </summary>
/// <returns>The <see cref="LogMessage"/> as a <see cref="string"/></returns>
public override string ToString()
{
return $"{Timestamp:u}: [{Component}] {Message}\n";
}
}
}
Loading…
Cancel
Save