#region usings
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL4;
using SM.OGL;
#endregion
namespace SM.Base
{
///
/// Specifies the target.
///
[Flags]
public enum LogTarget
{
///
/// No target, will not draw.
///
None = 0,
///
/// Takes the .
///
Default = 1,
///
/// Writes the log to the console.
///
Console = 2,
///
/// Writes the log to the debugger at .
///
Debugger = 4,
///
/// Writes the log to the specific file.
///
File = 8,
///
/// Writes the log to every target.
///
All = Console | Debugger | File
}
///
/// Preset log types.
///
public enum LogType
{
///
/// Informations. Console Color: Green
///
Info,
///
/// Warnings. Console Color: Yellow
///
Warning,
///
/// Error. Console Color: Red
///
Error
}
///
/// Contains the system for logging.
///
public class Log
{
private static StreamWriter _logStream;
private static bool _init;
///
/// Presets for the log targets.
///
public static Dictionary Preset = new Dictionary
{
{LogTarget.Console, "[%type%] %msg%"},
{LogTarget.Debugger, "[%type%] %msg%"},
{LogTarget.File, "<%date%, %time%> [%type%] %msg%"}
};
private static readonly Dictionary Colors = new Dictionary
{
{LogType.Info, ConsoleColor.Green},
{LogType.Warning, ConsoleColor.Yellow},
{LogType.Error, ConsoleColor.Red}
};
///
/// Specified the default target.
///
public static LogTarget DefaultTarget = LogTarget.All;
///
/// Sets the log file. At wish compresses the old file to a zip file.
///
/// The path to the log file.
/// Path for the compression, if desired.
public static void SetLogFile(string path = "sm.log", string compressionFolder = "")
{
_logStream?.Close();
if (!_init) Init();
if (File.Exists(path))
{
if (compressionFolder != "")
{
if (!Directory.Exists(compressionFolder)) Directory.CreateDirectory(compressionFolder);
var creation = File.GetLastWriteTime(path);
try
{
using var archive =
ZipFile.Open(
$"{compressionFolder}{Path.DirectorySeparatorChar}{Path.GetFileName(path)}_{creation.Year.ToString() + creation.Month + creation.Day}_{creation.Hour.ToString() + creation.Minute + creation.Second + creation.Millisecond}.zip",
ZipArchiveMode.Create);
archive.CreateEntryFromFile(path, Path.GetFileName(path));
}
catch
{
// ignore
}
}
File.Delete(path);
}
_logStream = new StreamWriter(path) {AutoFlush = true};
Write(LogType.Info, $"Activated new log file. ['{path}']");
}
internal static void Init()
{
if (_init) return;
AppDomain.CurrentDomain.UnhandledException += ExceptionHandler;
AppDomain.CurrentDomain.DomainUnload += (sender, args) =>
{
_logStream.WriteLine("Unload application");
_logStream.Close();
};
GLCustomActions.AtKHRDebug = GLDebugAction;
GLCustomActions.AtError = err => Write(LogType.Error, err);
GLCustomActions.AtWarning = warning => Write(LogType.Warning, warning);
GLCustomActions.AtInfo = info => Write(LogType.Info, info);
_init = true;
}
private static void GLDebugAction(DebugSource source, DebugType type, DebugSeverity severity, string msg)
{
if (type.HasFlag(DebugType.DebugTypeError)) throw new Exception("[GLError] " + msg);
Write(type != DebugType.DontCare ? type.ToString().Substring(9) : "DontCare", ConsoleColor.Gray, msg);
}
[DebuggerStepThrough]
private static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
Write(e.IsTerminating ? "Terminating Error" : LogType.Error.ToString(),
e.IsTerminating ? ConsoleColor.DarkRed : ConsoleColor.Red, e.ExceptionObject);
if (e.IsTerminating)
{
MessageBox.Show($"Critical error occured.\n\n{e.ExceptionObject}",
$"Terminating Error: {e.ExceptionObject.GetType().Name}");
_logStream?.Close();
}
}
///
/// Writes multiple lines of the same type to the log.
///
public static void Write(LogType type, params T[] values)
{
Write(type.ToString(), Colors[type], values);
}
///
/// Writes multiple lines of the same type to the log.
///
public static void Write(string type, ConsoleColor color, params T[] values)
{
for (var i = 0; i < values.Length; i++) Write(type, color, values[i], DefaultTarget);
}
///
/// Writes one line to the log.
///
public static void Write(LogType type, T value, LogTarget target = LogTarget.Default)
{
Write(type.ToString(), Colors[type], value, target);
}
///
/// Writes one line to the log.
///
public static void Write(string type, ConsoleColor color, T value, LogTarget target = LogTarget.Default)
{
if (target == LogTarget.Default)
target = DefaultTarget;
if (target.HasFlag(LogTarget.Console))
ColorfulWriteLine(color, ProcessPreset(LogTarget.Console, type, value.ToString()));
if (target.HasFlag(LogTarget.Debugger))
Debug.WriteLine(ProcessPreset(LogTarget.Debugger, type, value.ToString()));
if (target.HasFlag(LogTarget.File))
_logStream?.WriteLine(ProcessPreset(LogTarget.File, type, value.ToString()));
}
///
/// Writes a text with a different color.
///
///
///
public static void ColorfulWriteLine(ConsoleColor color, string value)
{
var before = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(value);
Console.ForegroundColor = before;
}
private static string ProcessPreset(LogTarget target, string type, string msg)
{
var preset = Preset[target];
var now = DateTime.Now;
return preset.Replace("%date%", now.ToShortDateString())
.Replace("%time%", now.ToShortTimeString())
.Replace("%type%", type)
.Replace("%msg%", msg);
}
}
}