diff --git a/GBase.Logging/ConsoleLogger.cs b/GBase.Logging/ConsoleLogger.cs
new file mode 100644
index 0000000..f285376
--- /dev/null
+++ b/GBase.Logging/ConsoleLogger.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
+{
+ ///
+ /// An that writes log messages to the
+ ///
+ public class ConsoleLogger : ILogger
+ {
+ ///
+ /// Write the given to the
+ ///
+ /// The
+ public async Task Write(ILogMessage message)
+ {
+ await Task.Run(() => Console.Write(message.ToString()));
+ }
+
+ ///
+ /// the
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ await Task.Run(Console.Clear);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/FileLogger.cs b/GBase.Logging/FileLogger.cs
new file mode 100644
index 0000000..f7b1ab7
--- /dev/null
+++ b/GBase.Logging/FileLogger.cs
@@ -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
+{
+ ///
+ /// An that writes log messages to a set file
+ ///
+ public class FileLogger : ILogger
+ {
+ private readonly StreamWriter _fileWriter;
+ private readonly Timer _timer;
+
+ private readonly SemaphoreSlim _lockObject = new SemaphoreSlim(1);
+
+ ///
+ /// Constructor for
+ ///
+ /// The directory of the LogFile
+ /// The path of the LogFile
+ public FileLogger(string filePath, string fileName)
+ {
+ Directory.CreateDirectory(filePath);
+ _fileWriter = new StreamWriter(Path.Combine(filePath, fileName), true);
+ _timer = new Timer(TimerCallback, null, 0, 1000);
+ }
+
+ ///
+ /// Write the given to the file
+ ///
+ /// The
+ 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();
+ }
+ }
+
+ ///
+ /// the
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ _timer.Dispose();
+
+ await Flush();
+ _fileWriter.Dispose();
+
+ _lockObject.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/GBase.Logging.csproj b/GBase.Logging/GBase.Logging.csproj
new file mode 100644
index 0000000..d4c395e
--- /dev/null
+++ b/GBase.Logging/GBase.Logging.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netstandard2.1
+
+
+
diff --git a/GBase.Logging/Interfaces/ILog.cs b/GBase.Logging/Interfaces/ILog.cs
new file mode 100644
index 0000000..e7d6f11
--- /dev/null
+++ b/GBase.Logging/Interfaces/ILog.cs
@@ -0,0 +1,38 @@
+// Author: Simon Gockner
+// Created: 2020-02-08
+// Copyright(c) 2020 SimonG. All Rights Reserved.
+
+using System;
+
+namespace GBase.Logging.Interfaces
+{
+ ///
+ /// The main logging interface
+ ///
+ public interface ILog : IAsyncDisposable
+ {
+ ///
+ /// Initialize the
+ ///
+ /// True if successful, false if not
+ bool InitializeLog();
+
+ ///
+ /// Set the of the current instance
+ ///
+ /// The
+ void SetLogLevel(LogLevels logLevel);
+
+ ///
+ /// Add an to the
+ ///
+ /// The
+ void AddLogger(ILogger logger);
+
+ ///
+ /// Remove an from the
+ ///
+ /// The
+ void RemoveLogger(ILogger logger);
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/Interfaces/ILogComponent.cs b/GBase.Logging/Interfaces/ILogComponent.cs
new file mode 100644
index 0000000..3bc9f1d
--- /dev/null
+++ b/GBase.Logging/Interfaces/ILogComponent.cs
@@ -0,0 +1,17 @@
+// Author: Simon Gockner
+// Created: 2020-02-08
+// Copyright(c) 2020 SimonG. All Rights Reserved.
+
+namespace GBase.Logging.Interfaces
+{
+ ///
+ /// The
+ ///
+ public interface ILogComponent
+ {
+ ///
+ /// The
+ ///
+ string Component { get; }
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/Interfaces/ILogMessage.cs b/GBase.Logging/Interfaces/ILogMessage.cs
new file mode 100644
index 0000000..c8b1502
--- /dev/null
+++ b/GBase.Logging/Interfaces/ILogMessage.cs
@@ -0,0 +1,34 @@
+// Author: Simon Gockner
+// Created: 2020-02-08
+// Copyright(c) 2020 SimonG. All Rights Reserved.
+
+using System;
+
+namespace GBase.Logging.Interfaces
+{
+ ///
+ /// An interface that is used to handle log messages
+ ///
+ public interface ILogMessage
+ {
+ ///
+ /// The of the
+ ///
+ LogLevels LogLevel { get; set; }
+
+ ///
+ /// The of the
+ ///
+ DateTime Timestamp { get; set; }
+
+ ///
+ /// The of the
+ ///
+ ILogComponent Component { get; set; }
+
+ ///
+ /// The of the
+ ///
+ string Message { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/Interfaces/ILogger.cs b/GBase.Logging/Interfaces/ILogger.cs
new file mode 100644
index 0000000..8377ef8
--- /dev/null
+++ b/GBase.Logging/Interfaces/ILogger.cs
@@ -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
+{
+ ///
+ /// Base class for loggers
+ ///
+ public interface ILogger : IAsyncDisposable
+ {
+ ///
+ /// Write the given
+ ///
+ /// The
+ Task Write(ILogMessage message);
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/Log.cs b/GBase.Logging/Log.cs
new file mode 100644
index 0000000..fe4ce4f
--- /dev/null
+++ b/GBase.Logging/Log.cs
@@ -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
+{
+ ///
+ /// The main logging class
+ ///
+ public class Log : ILog
+ {
+ ///
+ /// Constructor for
+ ///
+ public Log()
+ {
+ Loggers = new List();
+ }
+
+ ///
+ /// of s that are subscribed to this
+ ///
+ protected static List Loggers { get; private set; }
+
+ ///
+ /// The of this logging instance
+ ///
+ protected static LogLevels LogLevel { get; private set; } //TODO: Move LogLevel to ILogger? Allows to set logLevel separately for each ILogger
+
+ ///
+ /// Initialize the
+ ///
+ /// True if successful, false if not
+ public bool InitializeLog()
+ {
+ return true;
+ }
+
+ ///
+ /// Set the of the current instance
+ ///
+ /// The
+ public void SetLogLevel(LogLevels logLevel)
+ {
+ LogLevel = logLevel;
+ LogLevelChanged?.Invoke(this, LogLevel);
+ }
+
+ ///
+ /// Add an to the
+ ///
+ /// The
+ public void AddLogger(ILogger logger)
+ {
+ Loggers.Add(logger);
+ }
+
+ ///
+ /// Remove an from the
+ ///
+ /// The
+ public void RemoveLogger(ILogger logger)
+ {
+ Loggers.Remove(logger);
+ }
+
+ ///
+ /// Write a given to the set s
+ ///
+ /// The
+ /// The of the caller
+ public static async Task Write(Exception ex)
+ {
+ ILogComponent component = GetDefaultComponentFromType();
+
+ await Write(component, LogLevels.Error, ex.Message);
+ await Write(component, LogLevels.Error, "");
+ await Write(component, LogLevels.Error, ex.StackTrace);
+ }
+
+ ///
+ /// Write a given to the set s
+ ///
+ /// The
+ /// The
+ 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);
+ }
+
+ ///
+ /// Write a given to the set s
+ ///
+ /// The
+ /// The of the caller
+ public static async Task Write(AggregateException ex)
+ {
+ ILogComponent component = GetDefaultComponentFromType();
+
+ 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, "");
+ }
+ }
+
+ ///
+ /// Write a given with the to the set s
+ ///
+ ///
+ /// The of the caller
+ public static async Task Write(string line)
+ {
+ ILogComponent component = GetDefaultComponentFromType();
+ await Write(component, LogLevels.Default, line);
+ }
+
+ ///
+ /// Write a given with the of the calling and the to the set s
+ ///
+ /// The
+ /// The given
+ /// The of the caller
+ public static async Task Write(LogLevels logLevel, string line)
+ {
+ ILogComponent component = GetDefaultComponentFromType();
+ await Write(component, logLevel, line);
+ }
+
+ ///
+ /// Write a given with the and the to the set s
+ ///
+ /// The
+ /// The
+ /// The given
+ 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);
+ }
+ }
+
+ ///
+ /// Get the default for the given
+ ///
+ /// The
+ ///
+ protected static ILogComponent GetDefaultComponentFromType()
+ {
+ Assembly assembly = Assembly.GetAssembly(typeof(T));
+ LogComponentAttribute attribute = assembly.GetCustomAttribute();
+ return attribute ?? new LogComponentAttribute("UNKNOWN");
+ }
+
+ ///
+ /// the
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ foreach (var logger in Loggers)
+ {
+ await logger.DisposeAsync();
+ }
+
+ Loggers.Clear();
+ LogLevel = LogLevels.None;
+ }
+
+
+ ///
+ /// Event that is fired when is called
+ /// is the newly set
+ ///
+ public static event EventHandler LogLevelChanged;
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/LogComponentAttribute.cs b/GBase.Logging/LogComponentAttribute.cs
new file mode 100644
index 0000000..9941fec
--- /dev/null
+++ b/GBase.Logging/LogComponentAttribute.cs
@@ -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
+{
+ ///
+ /// The attribute
+ ///
+ [AttributeUsage(AttributeTargets.Assembly)]
+ public class LogComponentAttribute : Attribute, ILogComponent
+ {
+ ///
+ /// constructor
+ ///
+ /// The
+ public LogComponentAttribute(string component)
+ {
+ Component = component;
+ }
+
+ ///
+ /// The
+ ///
+ public string Component { get; private set; }
+
+ ///
+ /// Returns the of this
+ ///
+ /// The
+ public override string ToString()
+ {
+ return Component;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/LogLevels.cs b/GBase.Logging/LogLevels.cs
new file mode 100644
index 0000000..9fa567d
--- /dev/null
+++ b/GBase.Logging/LogLevels.cs
@@ -0,0 +1,37 @@
+// Author: Simon Gockner
+// Created: 2020-02-08
+// Copyright(c) 2020 SimonG. All Rights Reserved.
+
+namespace GBase.Logging
+{
+ ///
+ /// The available
+ ///
+ public enum LogLevels
+ {
+ ///
+ /// No logging
+ ///
+ None,
+
+ ///
+ /// Error logging
+ ///
+ Error,
+
+ ///
+ /// Default logging
+ ///
+ Default,
+
+ ///
+ /// Advanced logging
+ ///
+ Advanced,
+
+ ///
+ /// Debug logging
+ ///
+ Debug
+ }
+}
\ No newline at end of file
diff --git a/GBase.Logging/LogMessage.cs b/GBase.Logging/LogMessage.cs
new file mode 100644
index 0000000..d0592cd
--- /dev/null
+++ b/GBase.Logging/LogMessage.cs
@@ -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
+{
+ ///
+ /// Implementation of
+ ///
+ public class LogMessage : ILogMessage
+ {
+ ///
+ /// The of the
+ ///
+ public LogLevels LogLevel { get; set; }
+
+ ///
+ /// The of the
+ ///
+ public DateTime Timestamp { get; set; }
+
+ ///
+ /// The of the
+ ///
+ public ILogComponent Component { get; set; }
+
+ ///
+ /// The of the
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// Builds the out of all parts and returns it as a
+ ///
+ /// The as a
+ public override string ToString()
+ {
+ return $"{Timestamp:u}: [{Component}] {Message}\n";
+ }
+ }
+}
\ No newline at end of file