Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Logger class. #148

Merged
merged 9 commits into from
Jun 27, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
198 changes: 121 additions & 77 deletions QModManager/Utility/Logger.cs
Original file line number Diff line number Diff line change
@@ -1,127 +1,171 @@
namespace QModManager.Utility
{
using System;
using System.Diagnostics;
using System.IO;

internal static class Logger
/// <summary>A simple logging class. Can be used for basic logging or to know which logging level is enabled.</summary>
public static class Logger
{
internal enum Level
/// <summary>Possible logging levels.</summary>
public enum Level
{
/// <summary>Debugging log level</summary>
Debug,
/// <summary>Informational log level</summary>
Info,
/// <summary>Warning log level</summary>
Warn,
/// <summary>Error log level</summary>
Error,
/// <summary>Fatal log level</summary>
Fatal
}

private static void Log(string logLevel, params string[] text)
private const string AssemblyName = "QModManager";

#region Private functions (used by the Logger)

private static string GetCallingAssemblyName() => ReflectionHelper.CallingAssemblyByStackTrace()?.GetName().Name;

private static void Debug(string msg, bool showOnScreen = false, string callingAssembly = null, bool force = false)
{
if (text == null || text.Length < 1)
if (!force && !Config.EnableDebugLogs)
return;

string from;
Type classType = GetCallingClass();
Console.WriteLine($"[{callingAssembly ?? GetCallingAssemblyName()}:DEBUG] {msg}");

if (classType == null)
from = null;
else if (classType.Namespace.Contains("SMLHelper"))
from = "SMLHelper";
else
from = classType.Name;
if (showOnScreen)
ErrorMessage.AddDebug(msg);
}

string toWrite = "[QModManager] ";
if (!string.IsNullOrEmpty(from) && !from.Contains("<>"))
toWrite += $"[{from}] ";
else if (!string.IsNullOrEmpty(from) && from.Contains("<>"))
toWrite += $"[Anonymous] ";
if (!string.IsNullOrEmpty(logLevel))
toWrite += $"[{logLevel}] ";
private static void Info(string msg, bool showOnScreen = false, string callingAssembly = null)
{
Console.WriteLine($"[{callingAssembly ?? GetCallingAssemblyName()}:INFO] {msg}");

int length = toWrite.Length;
if (showOnScreen)
ErrorMessage.AddMessage(msg);
}

Console.WriteLine($"{toWrite}{text[0]}");
private static void Warn(string msg, bool showOnScreen = false, string callingAssembly = null)
{
Console.WriteLine($"[{callingAssembly ?? GetCallingAssemblyName()}:WARN] {msg}");

for (int i = 1; i < text.Length; i++)
Console.WriteLine($"{text[i]}");
if (showOnScreen)
ErrorMessage.AddWarning(msg);
}

internal static void Log(params string[] text)
private static void Error(string msg = null, Exception ex = null, bool showOnScreen = false, string callingAssembly = null)
{
Log("", text);
if (ex != null)
msg = (string.IsNullOrEmpty(msg) ? ex.ToString() : msg + Environment.NewLine + ex.ToString());

Console.WriteLine($"[{callingAssembly ?? GetCallingAssemblyName()}:ERROR] {msg}");

if (showOnScreen && !string.IsNullOrEmpty(msg))
ErrorMessage.AddError(msg);
}

internal static void Log(Level logLevel, params string[] text)
private static void Exception(Exception e, bool selfAssembly = false) => Error(null, e, false, selfAssembly ? AssemblyName : GetCallingAssemblyName());

private static void Fatal(string msg = null, Exception ex = null, bool showOnScreen = false, string callingAssembly = null)
{
if (ex != null)
msg = (string.IsNullOrEmpty(msg) ? ex.ToString() : msg + Environment.NewLine + ex.ToString());
Console.WriteLine($"[{callingAssembly ?? GetCallingAssemblyName()}:FATAL] {msg}");

if (showOnScreen && !string.IsNullOrEmpty(msg))
ErrorMessage.AddError(msg);
}

#endregion

#region Internal functions (used by QModManager)

internal static void Debug(string msg) => Debug(msg, false, AssemblyName, false);

internal static void DebugForce(string msg) => Debug(msg, false, AssemblyName, true);

internal static void Info(string msg) => Info(msg, false, AssemblyName);

internal static void Warn(string msg) => Warn(msg, false, AssemblyName);

internal static void Error(string msg) => Error(msg, null, false, AssemblyName);

internal static void Exception(Exception e) => Exception(e, true);

internal static void Fatal(string msg) => Fatal(msg, null, false, AssemblyName);

internal static void Log(Level logLevel, string msg)
{
if (msg == null) // Return if there is no messages
return;

switch (logLevel)
{
case Level.Debug:
Debug(text);
break;
case Level.Info:
Info(text);
Debug(msg);
break;
case Level.Warn:
Warn(text);
Warn(msg);
break;
case Level.Error:
Error(text);
Error(msg);
break;
case Level.Fatal:
Fatal(text);
Fatal(msg);
break;
default: // Defaults to informational logging
Info(msg);
break;
}
}

internal static void Debug(params string[] text)
{
if (Config.EnableDebugLogs)
Log("Debug", text);
}

internal static void DebugForce(params string[] text)
{
Log("Debug", text);
}

internal static void Info(params string[] text)
{
Log("Info", text);
}
#endregion

internal static void Warn(params string[] text)
{
Log("Warn", text);
}
#region Public functions (used by mods)

internal static void Error(params string[] text)
{
Log("Error", text);
}

internal static void Exception(Exception e)
{
Log("Exception", e.ToString());
}

internal static void Fatal(params string[] text)
{
Log("Fatal", text);
}
/// <summary>Used to know if debug logging is enabled or not.</summary>
public static bool DebugLogsEnabled => Config.EnableDebugLogs;

private static Type GetCallingClass()
/// <summary>
/// This function will log given message and/or exception. It can optionally show the message on screen.
/// You need to provide a message and/or an exception (this function will do nothing if both are set to null).
/// Warning: You can call this function from any mod but don't call it from QModManager (<see cref="GetCallingAssemblyName"/> would fail).
/// </summary>
/// <param name="logLevel">The level of the log.</param>
/// <param name="msg">Optional: The message that needs to be logged.</param>
/// <param name="ex">Optional: The exception that needs to be logged.</param>
/// <param name="showOnScreen">Optional: Whether to show the message on screen or not.</param>
public static void Log(Level logLevel, string msg = null, Exception ex = null, bool showOnScreen = false)
{
var stackTrace = new StackTrace();
StackFrame[] frames = stackTrace.GetFrames();

foreach (StackFrame stackFrame in frames)
if (ex != null)
{
Type declaringClass = stackFrame.GetMethod().DeclaringType;
if (declaringClass != typeof(Logger))
return declaringClass;
// If exception was provided, concatenate its message to the log message
if (logLevel != Level.Error && logLevel != Level.Fatal)
msg = (msg == null) ? ex.Message : msg + Environment.NewLine + ex.Message;
}
else if (msg == null) // Return if both given message and exception were null
return;

return null;
switch (logLevel)
{
case Level.Debug:
Debug(msg, showOnScreen, null, false);
break;
case Level.Warn:
Warn(msg, showOnScreen, null);
break;
case Level.Error:
Error(msg, ex, showOnScreen, null);
break;
case Level.Fatal:
Fatal(msg, ex, showOnScreen, null);
break;
default: // Defaults to informational logging
Info(msg, showOnScreen, null);
break;
}
}

#endregion
}
}