Log: Also log filename and line number of caller

This commit is contained in:
Simon Lübeß
2024-01-20 21:23:34 +01:00
parent 55eef017e7
commit 02be6d8eb7
7 changed files with 160 additions and 87 deletions
-28
View File
@@ -5,34 +5,6 @@ using internal GlitchLog;
namespace GlitchLog namespace GlitchLog
{ {
public abstract class Logger
{
protected LogLevel _logLevel;
public LogLevel Level
{
get => _logLevel;
set => _logLevel = value;
}
public abstract String Name {get; set;}
public abstract void Trace(StringView format, params Object[] args);
public abstract void Info(StringView format, params Object[] args);
public abstract void Warning(StringView format, params Object[] args);
public abstract void Error(StringView format, params Object[] args);
public abstract void Critical(StringView format, params Object[] args);
public abstract void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum);
#if !DEBUG
[SkipCall]
#endif
public abstract void AssertDebug(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum);
public abstract void Log(LogLevel level, StringView format, params Object[] args);
}
public class DebugLogger : Logger public class DebugLogger : Logger
{ {
// {l} = log level (first parameter) // {l} = log level (first parameter)
+31
View File
@@ -0,0 +1,31 @@
using System;
namespace GlitchLog;
public abstract class Logger
{
protected LogLevel _logLevel;
public LogLevel Level
{
get => _logLevel;
set => _logLevel = value;
}
public abstract String Name {get; set;}
public abstract void Trace(StringView format, params Object[] args);
public abstract void Info(StringView format, params Object[] args);
public abstract void Warning(StringView format, params Object[] args);
public abstract void Error(StringView format, params Object[] args);
public abstract void Critical(StringView format, params Object[] args);
public abstract void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum);
#if !DEBUG
[SkipCall]
#endif
public abstract void AssertDebug(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum);
public abstract void Log(LogLevel level, StringView format, params Object[] args);
}
+48 -35
View File
@@ -6,6 +6,7 @@ using GlitchyEngine.World;
using GlitchLog; using GlitchLog;
using GlitchyEngine.Scripting; using GlitchyEngine.Scripting;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using GlitchyEngine;
namespace GlitchyEditor.EditWindows; namespace GlitchyEditor.EditWindows;
@@ -38,8 +39,7 @@ enum MessageType
class MessageSource class MessageSource
{ {
public UUID? Entity = null; public UUID? Entity = null;
public StringView? ScriptName = null; public MessageOrigin MessageOrigin = null ~ delete _;
public int? Line = null;
/// If true, the message is only meant for engine developers... so only me :( /// If true, the message is only meant for engine developers... so only me :(
public bool IsEngineMessage = false; public bool IsEngineMessage = false;
@@ -258,53 +258,66 @@ class LogWindow : EditorWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
// Timestamp if (ImGui.BeginChild("Message", .Zero, .None, .None))
ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]");
if (message.Source.IsEngineMessage)
{ {
ImGui.SameLine(); // Timestamp
ImGui.TextUnformatted("Engine"); ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]");
}
// Show entity if (message.Source.IsEngineMessage)
if (message.Source?.Entity != null)
{
ImGui.SameLine();
Result<Entity> entity = Editor.Instance.CurrentScene.GetEntityByID(message.Source.Entity.Value);
if (entity case .Ok(let e))
{ {
ImGui.Text($"Entity: \"{e.Name}\" (ID: {message.Source.Entity})"); ImGui.SameLine();
ImGui.TextUnformatted("Engine");
}
if (ImGui.IsItemClicked()) // Show entity
Editor.Instance.EntityHierarchyWindow.HighlightEntity(entity); if (message.Source?.Entity != null)
{
ImGui.SameLine();
Result<Entity> entity = Editor.Instance.CurrentScene.GetEntityByID(message.Source.Entity.Value);
if (entity case .Ok(let e))
{
ImGui.Text($"Entity: \"{e.Name}\" (ID: {message.Source.Entity})");
if (ImGui.IsItemClicked())
Editor.Instance.EntityHierarchyWindow.HighlightEntity(entity);
}
else
{
ImGui.Text($"Entity: (ID: {message.Source.Entity})");
}
}
if (message.Source.Exception != null)
{
if (ImGui.CollapsingHeader(message.Message.Ptr))
{
// Show the native to managed entry point only if we show engine messages
if (_showEngineMessages)
ImGui.TextUnformatted(message.Source.Exception.StackTrace);
else
ImGui.TextUnformatted(message.Source.Exception.CleanStackTrace);
ImGui.NewLine();
}
} }
else else
{ {
ImGui.Text($"Entity: (ID: {message.Source.Entity})"); ImGui.TextUnformatted(message.Message);
} }
} }
if (message.Source.Exception != null) ImGui.EndChild();
if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(.Left))
{ {
if (ImGui.CollapsingHeader(message.Message.Ptr)) if (message.Source.MessageOrigin != null)
{ {
// Show the native to managed entry point only if we show engine messages VisualStudioUtility.OpenScript(message.Source.MessageOrigin.FileName);
if (_showEngineMessages)
ImGui.TextUnformatted(message.Source.Exception.StackTrace);
else
ImGui.TextUnformatted(message.Source.Exception.CleanStackTrace);
ImGui.NewLine();
} }
} }
else
{
ImGui.TextUnformatted(message.Message);
}
// Dont show the counter if we only have one message. // Dont show the counter if we only have one message.
if (count > 1) if (count > 1)
+4
View File
@@ -120,6 +120,10 @@ public class EditorLogger : Logger
{ {
Editor.Instance.LogWindow.LogException(timestamp, ex); Editor.Instance.LogWindow.LogException(timestamp, ex);
} }
else if (args.Count > 0 && (var messageOrigin = args[^1] as MessageOrigin))
{
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger, MessageOrigin = messageOrigin});
}
else else
{ {
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger}); Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger});
+33 -2
View File
@@ -15,6 +15,24 @@ namespace GlitchyEngine.Scripting;
using internal GlitchyEngine.Scripting; using internal GlitchyEngine.Scripting;
class MessageOrigin
{
private String _fileName;
private int _lineNumber;
public StringView FileName => _fileName;
public int LineNumber => _lineNumber;
[AllowAppend]
public this(StringView fileName, int lineNumber)
{
String file = append String(fileName);
_fileName = file;
_lineNumber = lineNumber;
}
}
static class ScriptGlue static class ScriptGlue
{ {
private static Dictionary<MonoType*, function void(Entity entityId)> s_AddComponentMethods = new .() ~ delete _; private static Dictionary<MonoType*, function void(Entity entityId)> s_AddComponentMethods = new .() ~ delete _;
@@ -185,11 +203,24 @@ static class ScriptGlue
#region Log #region Log
[RegisterCall("ScriptGlue::Log_LogMessage")] [RegisterCall("ScriptGlue::Log_LogMessage")]
static void Log_LogMessage(int32 logLevel, MonoString* message) static void Log_LogMessage(int32 logLevel, MonoString* message, MonoString* fileName, int lineNumber)
{ {
char8* utfMessage = Mono.mono_string_to_utf8(message); char8* utfMessage = Mono.mono_string_to_utf8(message);
Log.ClientLogger.Log((LogLevel)logLevel, StringView(utfMessage)); if (fileName != null)
{
char8* utfFileName = Mono.mono_string_to_utf8(fileName);
MessageOrigin messageOrigin = new MessageOrigin(StringView(utfFileName), lineNumber);
Log.ClientLogger.Log((LogLevel)logLevel, StringView(utfMessage), messageOrigin);
Mono.mono_free(utfFileName);
}
else
{
Log.ClientLogger.Log((LogLevel)logLevel, StringView(utfMessage));
}
Mono.mono_free(utfMessage); Mono.mono_free(utfMessage);
} }
+42 -20
View File
@@ -1,4 +1,6 @@
using System; using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace GlitchyEngine; namespace GlitchyEngine;
@@ -25,90 +27,110 @@ public class Log
/// Logs a trace message. /// Logs a trace message.
/// </summary> /// </summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
public static void Trace(string message) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Trace(string message, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Trace, message); ScriptGlue.Log_LogMessage(LogLevel.Trace, message, callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Logs an info message. /// Logs an info message.
/// </summary> /// </summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
public static void Info(string message) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Info(string message, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Info, message); ScriptGlue.Log_LogMessage(LogLevel.Info, message, callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Logs a warning message. /// Logs a warning message.
/// </summary> /// </summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
public static void Warning(string message) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Warning(string message, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Warning, message); ScriptGlue.Log_LogMessage(LogLevel.Warning, message, callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Logs an error message. /// Logs an error message.
/// </summary> /// </summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
public static void Error(string message) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Error(string message, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Error, message); ScriptGlue.Log_LogMessage(LogLevel.Error, message, callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Logs a critical error message. /// Logs a critical error message.
/// </summary> /// </summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
public static void Critical(string message) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Critical(string message, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Critical, message); ScriptGlue.Log_LogMessage(LogLevel.Critical, message, callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a trace message. /// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a trace message.
/// </summary> /// </summary>
/// <param name="obj">The object to serialize.</param> /// <param name="obj">The object to serialize.</param>
public static void Trace(object obj) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Trace(object obj, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Trace, obj.ToString()); ScriptGlue.Log_LogMessage(LogLevel.Trace, obj.ToString(), callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Serializes the given object (using <see cref="object.ToString"/>) and logs it as an info message. /// Serializes the given object (using <see cref="object.ToString"/>) and logs it as an info message.
/// </summary> /// </summary>
/// <param name="obj">The object to serialize.</param> /// <param name="obj">The object to serialize.</param>
public static void Info(object obj) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Info(object obj, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Info, obj.ToString()); ScriptGlue.Log_LogMessage(LogLevel.Info, obj.ToString(), callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a warning message. /// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a warning message.
/// </summary> /// </summary>
/// <param name="obj">The object to serialize.</param> /// <param name="obj">The object to serialize.</param>
public static void Warning(object obj) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Warning(object obj, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Warning, obj.ToString()); ScriptGlue.Log_LogMessage(LogLevel.Warning, obj.ToString(), callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Serializes the given object (using <see cref="object.ToString"/>) and logs it as an error message. /// Serializes the given object (using <see cref="object.ToString"/>) and logs it as an error message.
/// </summary> /// </summary>
/// <param name="obj">The object to serialize.</param> /// <param name="obj">The object to serialize.</param>
public static void Error(object obj) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Error(object obj, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Error, obj.ToString()); ScriptGlue.Log_LogMessage(LogLevel.Error, obj.ToString(), callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
/// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a critical error message. /// Serializes the given object (using <see cref="object.ToString"/>) and logs it as a critical error message.
/// </summary> /// </summary>
/// <param name="obj">The object to serialize.</param> /// <param name="obj">The object to serialize.</param>
public static void Critical(object obj) /// <param name="callerFilePath">File path of the caller.</param>
/// <param name="callerLineNumber">Line number of the caller.</param>
public static void Critical(object obj, [CallerFilePath]string callerFilePath = "", [CallerLineNumber]int callerLineNumber = 0)
{ {
ScriptGlue.Log_LogMessage(LogLevel.Critical, obj.ToString()); ScriptGlue.Log_LogMessage(LogLevel.Critical, obj.ToString(), callerFilePath, callerLineNumber);
} }
/// <summary> /// <summary>
+1 -1
View File
@@ -14,7 +14,7 @@ internal static class ScriptGlue
#region Log #region Log
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void Log_LogMessage(Log.LogLevel logLevel, string message); internal static extern void Log_LogMessage(Log.LogLevel logLevel, string message, string filePath, int line);
[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]