Strip Swan library Part 1

This commit is contained in:
2019-12-09 17:25:54 +01:00
parent d0b26111dd
commit f1c7a29b38
73 changed files with 11356 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
using System;
using Swan.Lite.Logging;
namespace Swan.Logging {
/// <summary>
/// Represents a Console implementation of <c>ILogger</c>.
/// </summary>
/// <seealso cref="ILogger" />
public class ConsoleLogger : TextLogger, ILogger {
/// <summary>
/// Initializes a new instance of the <see cref="ConsoleLogger"/> class.
/// </summary>
protected ConsoleLogger() {
// Empty
}
/// <summary>
/// Gets the current instance of ConsoleLogger.
/// </summary>
/// <value>
/// The instance.
/// </value>
public static ConsoleLogger Instance { get; } = new ConsoleLogger();
/// <summary>
/// Gets or sets the debug logging prefix.
/// </summary>
/// <value>
/// The debug prefix.
/// </value>
public static String DebugPrefix { get; set; } = "DBG";
/// <summary>
/// Gets or sets the trace logging prefix.
/// </summary>
/// <value>
/// The trace prefix.
/// </value>
public static String TracePrefix { get; set; } = "TRC";
/// <summary>
/// Gets or sets the warning logging prefix.
/// </summary>
/// <value>
/// The warn prefix.
/// </value>
public static String WarnPrefix { get; set; } = "WRN";
/// <summary>
/// Gets or sets the fatal logging prefix.
/// </summary>
/// <value>
/// The fatal prefix.
/// </value>
public static String FatalPrefix { get; set; } = "FAT";
/// <summary>
/// Gets or sets the error logging prefix.
/// </summary>
/// <value>
/// The error prefix.
/// </value>
public static String ErrorPrefix { get; set; } = "ERR";
/// <summary>
/// Gets or sets the information logging prefix.
/// </summary>
/// <value>
/// The information prefix.
/// </value>
public static String InfoPrefix { get; set; } = "INF";
/// <summary>
/// Gets or sets the color of the information output logging.
/// </summary>
/// <value>
/// The color of the information.
/// </value>
public static ConsoleColor InfoColor { get; set; } = ConsoleColor.Cyan;
/// <summary>
/// Gets or sets the color of the debug output logging.
/// </summary>
/// <value>
/// The color of the debug.
/// </value>
public static ConsoleColor DebugColor { get; set; } = ConsoleColor.Gray;
/// <summary>
/// Gets or sets the color of the trace output logging.
/// </summary>
/// <value>
/// The color of the trace.
/// </value>
public static ConsoleColor TraceColor { get; set; } = ConsoleColor.DarkGray;
/// <summary>
/// Gets or sets the color of the warning logging.
/// </summary>
/// <value>
/// The color of the warn.
/// </value>
public static ConsoleColor WarnColor { get; set; } = ConsoleColor.Yellow;
/// <summary>
/// Gets or sets the color of the error logging.
/// </summary>
/// <value>
/// The color of the error.
/// </value>
public static ConsoleColor ErrorColor { get; set; } = ConsoleColor.DarkRed;
/// <summary>
/// Gets or sets the color of the error logging.
/// </summary>
/// <value>
/// The color of the error.
/// </value>
public static ConsoleColor FatalColor { get; set; } = ConsoleColor.Red;
/// <inheritdoc />
public LogLevel LogLevel { get; set; } = DebugLogger.IsDebuggerAttached ? LogLevel.Trace : LogLevel.Info;
/// <inheritdoc />
public void Log(LogMessageReceivedEventArgs logEvent) {
// Select the writer based on the message type
TerminalWriters writer = logEvent.MessageType == LogLevel.Error ? TerminalWriters.StandardError : TerminalWriters.StandardOutput;
(String outputMessage, ConsoleColor color) = this.GetOutputAndColor(logEvent);
Terminal.Write(outputMessage, color, writer);
}
/// <inheritdoc />
public void Dispose() {
// Do nothing
}
}
}
+49
View File
@@ -0,0 +1,49 @@
using System;
using Swan.Lite.Logging;
namespace Swan.Logging {
/// <summary>
/// Represents a logger target. This target will write to the
/// Debug console using System.Diagnostics.Debug.
/// </summary>
/// <seealso cref="ILogger" />
public class DebugLogger : TextLogger, ILogger {
/// <summary>
/// Initializes a new instance of the <see cref="DebugLogger"/> class.
/// </summary>
protected DebugLogger() {
// Empty
}
/// <summary>
/// Gets the current instance of DebugLogger.
/// </summary>
/// <value>
/// The instance.
/// </value>
public static DebugLogger Instance { get; } = new DebugLogger();
/// <summary>
/// Gets a value indicating whether a debugger is attached.
/// </summary>
/// <value>
/// <c>true</c> if this instance is debugger attached; otherwise, <c>false</c>.
/// </value>
public static Boolean IsDebuggerAttached => System.Diagnostics.Debugger.IsAttached;
/// <inheritdoc/>
public LogLevel LogLevel { get; set; } = IsDebuggerAttached ? LogLevel.Trace : LogLevel.None;
/// <inheritdoc/>
public void Log(LogMessageReceivedEventArgs logEvent) {
(String outputMessage, ConsoleColor _) = this.GetOutputAndColor(logEvent);
System.Diagnostics.Debug.Write(outputMessage);
}
/// <inheritdoc/>
public void Dispose() {
// do nothing
}
}
}
+24
View File
@@ -0,0 +1,24 @@
using System;
namespace Swan.Logging {
/// <summary>
/// Interface for a logger implementation.
/// </summary>
public interface ILogger : IDisposable {
/// <summary>
/// Gets the log level.
/// </summary>
/// <value>
/// The log level.
/// </value>
LogLevel LogLevel {
get;
}
/// <summary>
/// Logs the specified log event.
/// </summary>
/// <param name="logEvent">The <see cref="LogMessageReceivedEventArgs"/> instance containing the event data.</param>
void Log(LogMessageReceivedEventArgs logEvent);
}
}
+41
View File
@@ -0,0 +1,41 @@
namespace Swan {
/// <summary>
/// Defines the log levels.
/// </summary>
public enum LogLevel {
/// <summary>
/// The none message type
/// </summary>
None,
/// <summary>
/// The trace message type
/// </summary>
Trace,
/// <summary>
/// The debug message type
/// </summary>
Debug,
/// <summary>
/// The information message type
/// </summary>
Info,
/// <summary>
/// The warning message type
/// </summary>
Warning,
/// <summary>
/// The error message type
/// </summary>
Error,
/// <summary>
/// The fatal message type
/// </summary>
Fatal,
}
}
@@ -0,0 +1,147 @@
#nullable enable
using System;
namespace Swan {
/// <summary>
/// Event arguments representing the message that is logged
/// on to the terminal. Use the properties to forward the data to
/// your logger of choice.
/// </summary>
/// <seealso cref="System.EventArgs" />
public class LogMessageReceivedEventArgs : EventArgs {
/// <summary>
/// Initializes a new instance of the <see cref="LogMessageReceivedEventArgs" /> class.
/// </summary>
/// <param name="sequence">The sequence.</param>
/// <param name="messageType">Type of the message.</param>
/// <param name="utcDate">The UTC date.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public LogMessageReceivedEventArgs(
UInt64 sequence,
LogLevel messageType,
DateTime utcDate,
String source,
String message,
Object? extendedData,
String callerMemberName,
String callerFilePath,
Int32 callerLineNumber) {
this.Sequence = sequence;
this.MessageType = messageType;
this.UtcDate = utcDate;
this.Source = source;
this.Message = message;
this.CallerMemberName = callerMemberName;
this.CallerFilePath = callerFilePath;
this.CallerLineNumber = callerLineNumber;
this.ExtendedData = extendedData;
}
/// <summary>
/// Gets logging message sequence.
/// </summary>
/// <value>
/// The sequence.
/// </value>
public UInt64 Sequence {
get;
}
/// <summary>
/// Gets the type of the message.
/// It can be a combination as the enumeration is a set of bitwise flags.
/// </summary>
/// <value>
/// The type of the message.
/// </value>
public LogLevel MessageType {
get;
}
/// <summary>
/// Gets the UTC date at which the event at which the message was logged.
/// </summary>
/// <value>
/// The UTC date.
/// </value>
public DateTime UtcDate {
get;
}
/// <summary>
/// Gets the name of the source where the logging message
/// came from. This can come empty if the logger did not set it.
/// </summary>
/// <value>
/// The source.
/// </value>
public String Source {
get;
}
/// <summary>
/// Gets the body of the message.
/// </summary>
/// <value>
/// The message.
/// </value>
public String Message {
get;
}
/// <summary>
/// Gets the name of the caller member.
/// </summary>
/// <value>
/// The name of the caller member.
/// </value>
public String CallerMemberName {
get;
}
/// <summary>
/// Gets the caller file path.
/// </summary>
/// <value>
/// The caller file path.
/// </value>
public String CallerFilePath {
get;
}
/// <summary>
/// Gets the caller line number.
/// </summary>
/// <value>
/// The caller line number.
/// </value>
public Int32 CallerLineNumber {
get;
}
/// <summary>
/// Gets an object representing extended data.
/// It could be an exception or anything else.
/// </summary>
/// <value>
/// The extended data.
/// </value>
public Object? ExtendedData {
get;
}
/// <summary>
/// Gets the Extended Data properties cast as an Exception (if possible)
/// Otherwise, it return null.
/// </summary>
/// <value>
/// The exception.
/// </value>
public Exception? Exception => this.ExtendedData as Exception;
}
}
+423
View File
@@ -0,0 +1,423 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace Swan.Logging {
/// <summary>
/// Entry-point for logging. Use this static class to register/unregister
/// loggers instances. By default, the <c>ConsoleLogger</c> is registered.
/// </summary>
public static class Logger {
private static readonly Object SyncLock = new Object();
private static readonly List<ILogger> Loggers = new List<ILogger>();
private static UInt64 _loggingSequence;
static Logger() {
if(Terminal.IsConsolePresent) {
Loggers.Add(ConsoleLogger.Instance);
}
if(DebugLogger.IsDebuggerAttached) {
Loggers.Add(DebugLogger.Instance);
}
}
#region Standard Public API
/// <summary>
/// Registers the logger.
/// </summary>
/// <typeparam name="T">The type of logger to register.</typeparam>
/// <exception cref="InvalidOperationException">There is already a logger with that class registered.</exception>
public static void RegisterLogger<T>() where T : ILogger {
lock(SyncLock) {
ILogger loggerInstance = Loggers.FirstOrDefault(x => x.GetType() == typeof(T));
if(loggerInstance != null) {
throw new InvalidOperationException("There is already a logger with that class registered.");
}
Loggers.Add(Activator.CreateInstance<T>());
}
}
/// <summary>
/// Registers the logger.
/// </summary>
/// <param name="logger">The logger.</param>
public static void RegisterLogger(ILogger logger) {
lock(SyncLock) {
Loggers.Add(logger);
}
}
/// <summary>
/// Unregisters the logger.
/// </summary>
/// <param name="logger">The logger.</param>
/// <exception cref="ArgumentOutOfRangeException">logger.</exception>
public static void UnregisterLogger(ILogger logger) => RemoveLogger(x => x == logger);
/// <summary>
/// Unregisters the logger.
/// </summary>
/// <typeparam name="T">The type of logger to unregister.</typeparam>
public static void UnregisterLogger<T>() => RemoveLogger(x => x.GetType() == typeof(T));
/// <summary>
/// Remove all the loggers.
/// </summary>
public static void NoLogging() {
lock(SyncLock) {
Loggers.Clear();
}
}
#region Debug
/// <summary>
/// Logs a debug message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Debug(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Debug, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a debug message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Debug(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Debug, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a debug message to the console.
/// </summary>
/// <param name="extendedData">The exception.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Debug(this Exception extendedData, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Debug, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#region Trace
/// <summary>
/// Logs a trace message to the console.
/// </summary>
/// <param name="message">The text.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Trace(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Trace, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a trace message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Trace(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Trace, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a trace message to the console.
/// </summary>
/// <param name="extendedData">The extended data.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Trace(this Exception extendedData, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Trace, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#region Warn
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="message">The text.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Warn(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Warning, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Warn(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Warning, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="extendedData">The extended data.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Warn(this Exception extendedData, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Warning, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#region Fatal
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="message">The text.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Fatal(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Fatal, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Fatal(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Fatal, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a warning message to the console.
/// </summary>
/// <param name="extendedData">The extended data.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Fatal(this Exception extendedData, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Fatal, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#region Info
/// <summary>
/// Logs an info message to the console.
/// </summary>
/// <param name="message">The text.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Info(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Info, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an info message to the console.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Info(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Info, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an info message to the console.
/// </summary>
/// <param name="extendedData">The extended data.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Info(this Exception extendedData, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Info, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#region Error
/// <summary>
/// Logs an error message to the console's standard error.
/// </summary>
/// <param name="message">The text.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Error(this String message, String source = null, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Error, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an error message to the console's standard error.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Error(this String message, Type source, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Error, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an error message to the console's standard error.
/// </summary>
/// <param name="ex">The exception.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Error(this Exception ex, String source, String message, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Error, message, source, ex, callerMemberName, callerFilePath, callerLineNumber);
#endregion
#endregion
#region Extended Public API
/// <summary>
/// Logs the specified message.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="messageType">Type of the message.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Log(this String message, String source, LogLevel messageType, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(messageType, message, source, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs the specified message.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The source.</param>
/// <param name="messageType">Type of the message.</param>
/// <param name="extendedData">The extended data.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Log(this String message, Type source, LogLevel messageType, Object extendedData = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(messageType, message, source?.FullName, extendedData, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an error message to the console's standard error.
/// </summary>
/// <param name="ex">The ex.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Log(this Exception ex, String source = null, String message = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Error, message ?? ex.Message, source ?? ex.Source, ex, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs an error message to the console's standard error.
/// </summary>
/// <param name="ex">The ex.</param>
/// <param name="source">The source.</param>
/// <param name="message">The message.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Log(this Exception ex, Type source = null, String message = null, [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) => LogMessage(LogLevel.Error, message ?? ex.Message, source?.FullName ?? ex.Source, ex, callerMemberName, callerFilePath, callerLineNumber);
/// <summary>
/// Logs a trace message showing all possible non-null properties of the given object
/// This method is expensive as it uses Stringify internally.
/// </summary>
/// <param name="obj">The object.</param>
/// <param name="source">The source.</param>
/// <param name="text">The title.</param>
/// <param name="callerMemberName">Name of the caller member. This is automatically populated.</param>
/// <param name="callerFilePath">The caller file path. This is automatically populated.</param>
/// <param name="callerLineNumber">The caller line number. This is automatically populated.</param>
public static void Dump(this Object obj, String source, String text = "Object Dump", [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) {
if(obj == null) {
return;
}
String message = $"{text} ({obj.GetType()}): {Environment.NewLine}{obj.Stringify().Indent(5)}";
LogMessage(LogLevel.Trace, message, source, obj, callerMemberName, callerFilePath, callerLineNumber);
}
/// <summary>
/// Logs a trace message showing all possible non-null properties of the given object
/// This method is expensive as it uses Stringify internally.
/// </summary>
/// <param name="obj">The object.</param>
/// <param name="source">The source.</param>
/// <param name="text">The text.</param>
/// <param name="callerMemberName">Name of the caller member.</param>
/// <param name="callerFilePath">The caller file path.</param>
/// <param name="callerLineNumber">The caller line number.</param>
public static void Dump(this Object obj, Type source, String text = "Object Dump", [CallerMemberName] String callerMemberName = "", [CallerFilePath] String callerFilePath = "", [CallerLineNumber] Int32 callerLineNumber = 0) {
if(obj == null) {
return;
}
String message = $"{text} ({obj.GetType()}): {Environment.NewLine}{obj.Stringify().Indent(5)}";
LogMessage(LogLevel.Trace, message, source?.FullName, obj, callerMemberName, callerFilePath, callerLineNumber);
}
#endregion
private static void RemoveLogger(Func<ILogger, Boolean> criteria) {
lock(SyncLock) {
ILogger loggerInstance = Loggers.FirstOrDefault(criteria);
if(loggerInstance == null) {
throw new InvalidOperationException("The logger is not registered.");
}
loggerInstance.Dispose();
_ = Loggers.Remove(loggerInstance);
}
}
private static void LogMessage(LogLevel logLevel, String message, String sourceName, Object extendedData, String callerMemberName, String callerFilePath, Int32 callerLineNumber) {
UInt64 sequence = _loggingSequence;
DateTime date = DateTime.UtcNow;
_loggingSequence++;
String loggerMessage = String.IsNullOrWhiteSpace(message) ? String.Empty : message.RemoveControlCharsExcept('\n');
LogMessageReceivedEventArgs eventArgs = new LogMessageReceivedEventArgs(sequence, logLevel, date, sourceName, loggerMessage, extendedData, callerMemberName, callerFilePath, callerLineNumber);
foreach(ILogger logger in Loggers) {
_ = Task.Run(() => {
if(logger.LogLevel <= logLevel) {
logger.Log(eventArgs);
}
});
}
}
}
}
+63
View File
@@ -0,0 +1,63 @@
using Swan.Logging;
using System;
namespace Swan.Lite.Logging {
/// <summary>
/// Use this class for text-based logger.
/// </summary>
public abstract class TextLogger {
/// <summary>
/// Gets or sets the logging time format.
/// set to null or empty to prevent output.
/// </summary>
/// <value>
/// The logging time format.
/// </value>
public static String LoggingTimeFormat { get; set; } = "HH:mm:ss.fff";
/// <summary>
/// Gets the color of the output of the message (the output message has a new line char in the end).
/// </summary>
/// <param name="logEvent">The <see cref="LogMessageReceivedEventArgs" /> instance containing the event data.</param>
/// <returns>
/// The output message formatted and the color of the console to be used.
/// </returns>
protected (String outputMessage, ConsoleColor color) GetOutputAndColor(LogMessageReceivedEventArgs logEvent) {
(String prefix, ConsoleColor color) = GetConsoleColorAndPrefix(logEvent.MessageType);
String loggerMessage = String.IsNullOrWhiteSpace(logEvent.Message) ? String.Empty : logEvent.Message.RemoveControlCharsExcept('\n');
String outputMessage = CreateOutputMessage(logEvent.Source, loggerMessage, prefix, logEvent.UtcDate);
// Further format the output in the case there is an exception being logged
if(logEvent.MessageType == LogLevel.Error && logEvent.Exception != null) {
try {
outputMessage += $"{logEvent.Exception.Stringify().Indent()}{Environment.NewLine}";
} catch {
// Ignore
}
}
return (outputMessage, color);
}
private static (String Prefix, ConsoleColor color) GetConsoleColorAndPrefix(LogLevel messageType) => messageType switch
{
LogLevel.Debug => (ConsoleLogger.DebugPrefix, ConsoleLogger.DebugColor),
LogLevel.Error => (ConsoleLogger.ErrorPrefix, ConsoleLogger.ErrorColor),
LogLevel.Info => (ConsoleLogger.InfoPrefix, ConsoleLogger.InfoColor),
LogLevel.Trace => (ConsoleLogger.TracePrefix, ConsoleLogger.TraceColor),
LogLevel.Warning => (ConsoleLogger.WarnPrefix, ConsoleLogger.WarnColor),
LogLevel.Fatal => (ConsoleLogger.FatalPrefix, ConsoleLogger.FatalColor),
_ => (new String(' ', ConsoleLogger.InfoPrefix.Length), Terminal.Settings.DefaultColor),
};
private static String CreateOutputMessage(String sourceName, String loggerMessage, String prefix, DateTime date) {
String friendlySourceName = String.IsNullOrWhiteSpace(sourceName) ? String.Empty : sourceName.SliceLength(sourceName.LastIndexOf('.') + 1, sourceName.Length);
String outputMessage = String.IsNullOrWhiteSpace(sourceName) ? loggerMessage : $"[{friendlySourceName}] {loggerMessage}";
return String.IsNullOrWhiteSpace(LoggingTimeFormat) ? $" {prefix} >> {outputMessage}{Environment.NewLine}" : $" {date.ToLocalTime().ToString(LoggingTimeFormat)} {prefix} >> {outputMessage}{Environment.NewLine}";
}
}
}