From 08f562db122705634c53fc0912068a5d26e913a6 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Tue, 13 Jan 2026 13:08:19 +0100 Subject: [PATCH] Added stacktrace handling --- .../Tools/Rust/LogEventRequest.cs | 3 +- .../Tools/Services/RustService.Log.cs | 7 ++- .../Tools/TerminalLogger.cs | 23 +++++--- runtime/src/log.rs | 57 ++++++++++++++++--- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/app/MindWork AI Studio/Tools/Rust/LogEventRequest.cs b/app/MindWork AI Studio/Tools/Rust/LogEventRequest.cs index 18e95aed..c3f8fe89 100644 --- a/app/MindWork AI Studio/Tools/Rust/LogEventRequest.cs +++ b/app/MindWork AI Studio/Tools/Rust/LogEventRequest.cs @@ -5,5 +5,6 @@ public readonly record struct LogEventRequest( string Level, string Category, string Message, - string? Exception + string? Exception, + string? StackTrace ); diff --git a/app/MindWork AI Studio/Tools/Services/RustService.Log.cs b/app/MindWork AI Studio/Tools/Services/RustService.Log.cs index 595a9708..b8542ddd 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.Log.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.Log.cs @@ -20,13 +20,14 @@ public sealed partial class RustService /// The log level. /// The category of the log event. /// The log message. - /// Optional exception details. - public void LogEvent(string timestamp, string level, string category, string message, string? exception = null) + /// Optional exception message. + /// Optional exception stack trace. + public void LogEvent(string timestamp, string level, string category, string message, string? exception = null, string? stackTrace = null) { try { // Fire-and-forget the log event to avoid blocking: - var request = new LogEventRequest(timestamp, level, category, message, exception); + var request = new LogEventRequest(timestamp, level, category, message, exception, stackTrace); _ = this.http.PostAsJsonAsync("/log/event", request, this.jsonRustSerializerOptions); } catch diff --git a/app/MindWork AI Studio/Tools/TerminalLogger.cs b/app/MindWork AI Studio/Tools/TerminalLogger.cs index 65075d4a..ed05222a 100644 --- a/app/MindWork AI Studio/Tools/TerminalLogger.cs +++ b/app/MindWork AI Studio/Tools/TerminalLogger.cs @@ -33,17 +33,26 @@ public sealed class TerminalLogger() : ConsoleFormatter(FORMATTER_NAME) var timestamp = DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff"); var logLevel = logEntry.LogLevel.ToString(); var category = logEntry.Category; - var exception = logEntry.Exception?.ToString(); + var exceptionMessage = logEntry.Exception?.Message; + var stackTrace = logEntry.Exception?.StackTrace; var colorCode = GetColorForLogLevel(logEntry.LogLevel); - textWriter.Write($"{colorCode}[{timestamp}] {logLevel} [{category}]{ANSI_RESET} {message}"); - if (exception is not null) - textWriter.Write($" Exception: {exception}"); - - textWriter.WriteLine(); + textWriter.Write($"[{colorCode}{timestamp}{ANSI_RESET}] {colorCode}{logLevel}{ANSI_RESET} [{category}] {colorCode}{message}{ANSI_RESET}"); + if (logEntry.Exception is not null) + { + textWriter.Write($" {colorCode}Exception: {exceptionMessage}{ANSI_RESET}"); + if (stackTrace is not null) + { + textWriter.WriteLine(); + foreach (var line in stackTrace.Split('\n')) + textWriter.WriteLine($" {line.TrimEnd()}"); + } + } + else + textWriter.WriteLine(); // Send log event to Rust via API (fire-and-forget): - RUST_SERVICE?.LogEvent(timestamp, logLevel, category, message, exception); + RUST_SERVICE?.LogEvent(timestamp, logLevel, category, message, exceptionMessage, stackTrace); } private static string GetColorForLogLevel(LogLevel logLevel) => logLevel switch diff --git a/runtime/src/log.rs b/runtime/src/log.rs index d9d403f3..46bdbad9 100644 --- a/runtime/src/log.rs +++ b/runtime/src/log.rs @@ -240,16 +240,58 @@ pub fn log_event(_token: APIToken, event: Json) -> Json debug!(Source = ".NET Server", Comp = category; "{message}"), - "Information" => info!(Source = ".NET Server", Comp = category; "{message}"), - "Warning" => warn!(Source = ".NET Server", Comp = category; "{message}"), - "Error" | "Critical" => { + "Trace" | "Debug" => { + debug!(Source = ".NET Server", Comp = category; "{message}"); if let Some(ref ex) = event.exception { - error!(Source = ".NET Server", Comp = category; "{message} Exception: {ex}") - } else { - error!(Source = ".NET Server", Comp = category; "{message}") + debug!(Source = ".NET Server", Comp = category; " Exception: {ex}"); + } + + if let Some(ref stack_trace) = event.stack_trace { + for line in stack_trace.lines() { + debug!(Source = ".NET Server", Comp = category; " {line}"); + } } }, + + "Information" => { + info!(Source = ".NET Server", Comp = category; "{message}"); + if let Some(ref ex) = event.exception { + info!(Source = ".NET Server", Comp = category; " Exception: {ex}"); + } + + if let Some(ref stack_trace) = event.stack_trace { + for line in stack_trace.lines() { + info!(Source = ".NET Server", Comp = category; " {line}"); + } + } + }, + + "Warning" => { + warn!(Source = ".NET Server", Comp = category; "{message}"); + if let Some(ref ex) = event.exception { + warn!(Source = ".NET Server", Comp = category; " Exception: {ex}"); + } + + if let Some(ref stack_trace) = event.stack_trace { + for line in stack_trace.lines() { + warn!(Source = ".NET Server", Comp = category; " {line}"); + } + } + }, + + "Error" | "Critical" => { + error!(Source = ".NET Server", Comp = category; "{message}"); + if let Some(ref ex) = event.exception { + error!(Source = ".NET Server", Comp = category; " Exception: {ex}"); + } + + if let Some(ref stack_trace) = event.stack_trace { + for line in stack_trace.lines() { + error!(Source = ".NET Server", Comp = category; " {line}"); + } + } + }, + _ => error!(Source = ".NET Server", Comp = category; "{message} (unknown log level '{}')", event.level), } @@ -272,6 +314,7 @@ pub struct LogEvent { category: String, message: String, exception: Option, + stack_trace: Option, } /// The response to a log event request.