feat(claude-do): UI-Prozess loggt auf Platte (ui-.log) + fehlgeschlagene Hub-

## Problem
Beim DeleteTask-Bug (Fix 352aaa52) gab es null Spuren: Der UI-Prozess (ClaudeDo.App) hat gar kein File-Logging (weder Serilog noch `Microsoft.Extensions.Logging` sind in App/Ui referenziert), und im Worker loggt SignalR fehlgeschlagene Hub-Invocations nur auf Debug (`Microsoft.AspNetCore` steht in `src/ClaudeDo.Worker/Program.cs` Z. 60 auf Warning). Die Ursache ließ sich nur finden, ind

ClaudeDo-Task: d2ae3831-733f-4d40-93d7-70c93da11590
This commit is contained in:
Mika Kuns
2026-09-28 13:27:21 +02:00
parent 352aaa525b
commit 57dd676672
8 changed files with 93 additions and 2 deletions
@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
namespace ClaudeDo.Worker.Hub;
/// <summary>
/// Logs a Warning for any exception thrown out of a hub method body, so a failed UI action
/// leaves a trace in <c>worker-.log</c> instead of only a generic error at the caller.
/// Does NOT see an argument-binding failure (e.g. a stray CancellationToken parameter) — SignalR
/// rejects those while parsing the invocation message, before a hub method is ever dispatched.
/// </summary>
public sealed class HubExceptionLoggingFilter(ILogger<HubExceptionLoggingFilter> logger) : IHubFilter
{
public async ValueTask<object?> InvokeMethodAsync(
HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next)
{
try
{
return await next(invocationContext);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Hub method {Method} failed", invocationContext.HubMethodName);
throw;
}
}
}
+11 -1
View File
@@ -28,6 +28,7 @@ using ClaudeDo.Worker.Usage.Interfaces;
using ClaudeDo.Worker.Usage.TokenTracker;
using ClaudeDo.Worker.Usage.TokenTracker.Interfaces;
using ClaudeDo.Worker.Worktrees;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Serilog;
@@ -58,6 +59,11 @@ builder.Host.UseSerilog((ctx, lc) => lc
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
// SignalR logs an argument-binding failure (e.g. a stray CancellationToken parameter, see
// fix 352aaa52) at Debug on this specific source context — HubExceptionLoggingFilter can't
// see it either, since SignalR rejects the invocation while parsing the message, before any
// hub method (and its filter pipeline) is dispatched.
.MinimumLevel.Override("Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher", Serilog.Events.LogEventLevel.Debug)
.WriteTo.File(
System.IO.Path.Combine(logRoot, "worker-.log"),
rollingInterval: RollingInterval.Day,
@@ -90,7 +96,11 @@ builder.Services.AddHostedService<UntrackedWorktreeRecovery>();
// Default MaximumParallelInvocationsPerClient=1 serializes every hub call on one connection —
// a slow one (e.g. GetTicketProjects hitting an unreachable ticket system) blocks unrelated
// calls like UpdateList/UpdateListConfig behind it for the same 10s.
builder.Services.AddSignalR(options => options.MaximumParallelInvocationsPerClient = 10)
builder.Services.AddSignalR(options =>
{
options.MaximumParallelInvocationsPerClient = 10;
options.AddFilter<HubExceptionLoggingFilter>();
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());