Added stacktrace handling

This commit is contained in:
Thorsten Sommer 2026-01-13 13:08:19 +01:00
parent 2210118596
commit 08f562db12
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 72 additions and 18 deletions

View File

@ -5,5 +5,6 @@ public readonly record struct LogEventRequest(
string Level,
string Category,
string Message,
string? Exception
string? Exception,
string? StackTrace
);

View File

@ -20,13 +20,14 @@ public sealed partial class RustService
/// <param name="level">The log level.</param>
/// <param name="category">The category of the log event.</param>
/// <param name="message">The log message.</param>
/// <param name="exception">Optional exception details.</param>
public void LogEvent(string timestamp, string level, string category, string message, string? exception = null)
/// <param name="exception">Optional exception message.</param>
/// <param name="stackTrace">Optional exception stack trace.</param>
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

View File

@ -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

View File

@ -240,16 +240,58 @@ pub fn log_event(_token: APIToken, event: Json<LogEvent>) -> Json<LogEventRespon
// Log with the appropriate level
match event.level.as_str() {
"Trace" | "Debug" => 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<String>,
stack_trace: Option<String>,
}
/// The response to a log event request.