|
|
|
|
|
using System;
|
|
|
using System.IO;
|
|
|
using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Runtime.CompilerServices;
|
|
|
using System.Reflection;
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
using JM.LinqFaster;
|
|
|
|
|
|
/* Tiny log library inspired by Python's logging and Glögi.
|
|
|
*/
|
|
|
|
|
|
namespace isometricparkfna
|
|
|
{
|
|
|
public enum LogLevel
|
|
|
{
|
|
|
Critical,
|
|
|
Error,
|
|
|
Warning,
|
|
|
Success,
|
|
|
Info,
|
|
|
Debug,
|
|
|
Trace,
|
|
|
Spy
|
|
|
}
|
|
|
|
|
|
public struct LogEntry
|
|
|
{
|
|
|
public DateTime timestamp;
|
|
|
public string message;
|
|
|
public LogLevel level;
|
|
|
public ITuple data;
|
|
|
}
|
|
|
|
|
|
public class Logging
|
|
|
{
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
public static LogLevel minimumConsoleLevel = LogLevel.Debug;
|
|
|
#else
|
|
|
public static LogLevel minimumConsoleLevel = LogLevel.Success;
|
|
|
#endif
|
|
|
|
|
|
public static List<LogEntry> entries = new List<LogEntry>();
|
|
|
public static string logFileName = string.Format("log_{0:yyyyMMdd_HHmm}.txt", DateTime.Now);
|
|
|
|
|
|
public static StreamWriter logFile = File.CreateText(logFileName);
|
|
|
private static Dictionary<LogLevel, (ConsoleColor, ConsoleColor)> mappings = new Dictionary<LogLevel, (ConsoleColor, ConsoleColor)>
|
|
|
{
|
|
|
{LogLevel.Critical, (ConsoleColor.White, ConsoleColor.Red)},
|
|
|
{LogLevel.Error, (ConsoleColor.Black, ConsoleColor.Red)},
|
|
|
{LogLevel.Warning, (ConsoleColor.Black, ConsoleColor.Yellow)},
|
|
|
{LogLevel.Success, (ConsoleColor.White, ConsoleColor.Green)},
|
|
|
{LogLevel.Info, (ConsoleColor.White, ConsoleColor.Blue)},
|
|
|
{LogLevel.Debug, (ConsoleColor.Blue, ConsoleColor.Black)},
|
|
|
{LogLevel.Trace, (ConsoleColor.Magenta, ConsoleColor.Black)},
|
|
|
{LogLevel.Spy, (ConsoleColor.Black, ConsoleColor.White)},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
private static void Log_(LogLevel level, string message,
|
|
|
int lineNumber, string caller, string path, ConsoleColor message_foreground = ConsoleColor.White)
|
|
|
{
|
|
|
var timestamp = DateTime.Now;
|
|
|
|
|
|
if ((level <= minimumConsoleLevel)
|
|
|
|| level == LogLevel.Spy)
|
|
|
{
|
|
|
var start_foreground = Console.ForegroundColor;
|
|
|
var start_background = Console.BackgroundColor;
|
|
|
|
|
|
var (new_foreground, new_background) = Logging.mappings[level];
|
|
|
|
|
|
Console.ForegroundColor = new_foreground;
|
|
|
Console.BackgroundColor = new_background;
|
|
|
//29/Apr/2021 22:43:30
|
|
|
Console.Out.Write(string.Format("[{0}] {1}", timestamp.ToString("s"), level.ToString()));
|
|
|
|
|
|
Console.BackgroundColor = start_background;
|
|
|
Console.ForegroundColor = message_foreground;
|
|
|
|
|
|
Console.Out.Write(" " + message);
|
|
|
|
|
|
Console.ForegroundColor = start_foreground;
|
|
|
|
|
|
Console.Out.WriteLine(string.Format(" [{1}:{2}]", message, path, lineNumber));
|
|
|
}
|
|
|
|
|
|
logFile.WriteLine(string.Format("[{0}] {1} {2} [{3}:{4}]", timestamp.ToString("s"), level.ToString(), message, path, lineNumber));
|
|
|
|
|
|
|
|
|
Logging.entries.Add(new LogEntry { timestamp = timestamp,
|
|
|
level = level,
|
|
|
message = message
|
|
|
});
|
|
|
}
|
|
|
|
|
|
private static void Log_<T>(LogLevel level, string message, T data,
|
|
|
int lineNumber, string caller, string path)
|
|
|
where T : ITuple
|
|
|
{
|
|
|
// Logging.entries.Add(data);
|
|
|
// var d = data.GetType().GetProperties().ToDictionary(Info => Info.Name, Info => Info.GetValue(data));
|
|
|
// var data_strings = data.GetType().GetProperties().Select(Info => Info.Name + "=" + Info.GetValue(data).ToString());
|
|
|
// var data_string = string.Join(", ", data_strings);
|
|
|
// var str = String.Format("{0} {1}", message, data_string);
|
|
|
Logging.Log_(level, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
private static void Log_(LogLevel level, string message,
|
|
|
int lineNumber, string caller, string path, params object[] objects)
|
|
|
{
|
|
|
String.Format(message, objects);
|
|
|
Logging.Log_(level, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Log(LogLevel level, string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(level, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
public static void Log<T>(LogLevel level, string message, T data,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
//Constrain to Tuples and tuple-likes:
|
|
|
where T : ITuple, IStructuralEquatable, IStructuralComparable
|
|
|
{
|
|
|
Logging.Log_(level, message, data, lineNumber, caller, path);
|
|
|
}*/
|
|
|
|
|
|
public static void Log<T>(LogLevel level, string message, T data,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
//Constrain to Tuples and tuple-likes:
|
|
|
where T : class
|
|
|
{
|
|
|
|
|
|
var properties = new List<string>();
|
|
|
|
|
|
foreach (var property in typeof(T).GetProperties())
|
|
|
{
|
|
|
properties.Add(property.ToString() + "=" + property.GetValue(data));
|
|
|
}
|
|
|
|
|
|
var message_data = message + " {" + String.Join(", ", properties) + "}";
|
|
|
|
|
|
Logging.Log_(level, message_data, lineNumber, caller, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
public static void Log(LogLevel level, string message,
|
|
|
object[] format,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(level, message, lineNumber, caller, path, format);
|
|
|
}
|
|
|
|
|
|
public static void Critical(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Critical, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Error(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Error, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Warning(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Warning, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
|
|
|
public static void Success(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Success, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Info(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Info, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Debug(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Debug, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Trace(string message,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "")
|
|
|
{
|
|
|
|
|
|
Logging.Log_(LogLevel.Trace, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Spy(object value,
|
|
|
string name,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = ""
|
|
|
|
|
|
)
|
|
|
{
|
|
|
string message = string.Format("{0} ({1}) = {2}",
|
|
|
value.GetType().ToString(), name, value.ToString());
|
|
|
Logging.Log_(LogLevel.Spy, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
public static void Spy<T>(T value,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = ""
|
|
|
) where T : class
|
|
|
{
|
|
|
// var properties = typeof(T).GetProperties();
|
|
|
// string message = string.Format("{0} = {1}",
|
|
|
// value.ToString(), .ToString() );
|
|
|
// var message = String.Join(", ", (object[])properties);
|
|
|
//
|
|
|
|
|
|
var properties = new List<string>();
|
|
|
|
|
|
foreach (var property in typeof(T).GetProperties())
|
|
|
{
|
|
|
properties.Add(property.ToString() + "=" + property.GetValue(value));
|
|
|
}
|
|
|
|
|
|
var message = "{" + String.Join(", ", properties) + "}";
|
|
|
|
|
|
Logging.Log_(LogLevel.Spy, message, lineNumber, caller, path);
|
|
|
}
|
|
|
|
|
|
|
|
|
public static void Spy<T>(T? value,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = ""
|
|
|
// , T _ = default
|
|
|
) where T : struct
|
|
|
{
|
|
|
|
|
|
if (value == null)
|
|
|
{
|
|
|
Logging.Log_(LogLevel.Spy, "Value is null!", lineNumber, caller, path, ConsoleColor.Red);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var properties = new List<string>();
|
|
|
|
|
|
foreach (var field in typeof(T).GetFields())
|
|
|
{
|
|
|
try {
|
|
|
properties.Add(field.ToString() + "="
|
|
|
+ field.GetValue(value).ToString());
|
|
|
}
|
|
|
catch (NullReferenceException)
|
|
|
{
|
|
|
properties.Add(field.ToString() + "= <null>" );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var message = "{" + String.Join(", ", properties) + "}";
|
|
|
|
|
|
Logging.Log_(LogLevel.Spy, message, lineNumber, caller, path);
|
|
|
}
|
|
|
public static void Spy<T>(T value,
|
|
|
[CallerLineNumber] int lineNumber = 0,
|
|
|
[CallerMemberName] string caller = null,
|
|
|
[CallerFilePath] string path = "",
|
|
|
T _ = default) where T : struct
|
|
|
{
|
|
|
//C/o Jannes on StackOverflow for the extra parameter with a default trick
|
|
|
//https://stackoverflow.com/questions/2974519/generic-constraints-where-t-struct-and-where-t-class#comment111131939_36775837
|
|
|
|
|
|
var properties = new List<string>();
|
|
|
|
|
|
foreach (var field in typeof(T).GetFields())
|
|
|
{
|
|
|
try {
|
|
|
properties.Add(field.ToString() + "="
|
|
|
+ field.GetValue(value).ToString());
|
|
|
}
|
|
|
catch (NullReferenceException)
|
|
|
{
|
|
|
properties.Add(field.ToString() + "= <null>" );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var message = "{" + String.Join(", ", properties) + "}";
|
|
|
|
|
|
Logging.Log_(LogLevel.Spy, message, lineNumber, caller, path);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|