feat(logging): tag UI task actions with TaskId + debug trace lines

This commit is contained in:
mika kuns
2026-06-04 19:22:08 +02:00
parent 075b6d13af
commit 50c10b6e75
3 changed files with 34 additions and 32 deletions

View File

@@ -106,7 +106,9 @@ sealed class Program
// Services // Services
sc.AddSingleton<GitService>(); sc.AddSingleton<GitService>();
sc.AddSingleton(sp => new WorkerClient(sp.GetRequiredService<AppSettings>().SignalRUrl)); sc.AddSingleton(sp => new WorkerClient(
sp.GetRequiredService<AppSettings>().SignalRUrl,
sp.GetRequiredService<ILogger<WorkerClient>>()));
sc.AddSingleton<IWorkerClient>(sp => sp.GetRequiredService<WorkerClient>()); sc.AddSingleton<IWorkerClient>(sp => sp.GetRequiredService<WorkerClient>());
// Release check + installer update // Release check + installer update

View File

@@ -11,7 +11,9 @@
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.1" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.11" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Serilog" Version="4.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -6,6 +6,8 @@ using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog.Context;
namespace ClaudeDo.Ui.Services; namespace ClaudeDo.Ui.Services;
@@ -30,6 +32,7 @@ sealed class IndefiniteRetryPolicy : IRetryPolicy
public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerClient public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerClient
{ {
private readonly HubConnection _hub; private readonly HubConnection _hub;
private readonly ILogger<WorkerClient> _logger;
private CancellationTokenSource? _startCts; private CancellationTokenSource? _startCts;
private Task _retryLoopTask = Task.CompletedTask; private Task _retryLoopTask = Task.CompletedTask;
private readonly object _startLock = new(); private readonly object _startLock = new();
@@ -65,8 +68,9 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
public string? LastMergeAllTarget { get; private set; } public string? LastMergeAllTarget { get; private set; }
public WorkerClient(string signalRUrl) public WorkerClient(string signalRUrl, ILogger<WorkerClient> logger)
{ {
_logger = logger;
_hub = new HubConnectionBuilder() _hub = new HubConnectionBuilder()
.WithUrl(signalRUrl) .WithUrl(signalRUrl)
.WithAutomaticReconnect(new IndefiniteRetryPolicy()) .WithAutomaticReconnect(new IndefiniteRetryPolicy())
@@ -240,20 +244,24 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
catch { return default; } catch { return default; }
} }
public async Task RunNowAsync(string taskId) /// <summary>Invoke a task-targeted hub method under a TaskId log scope, emitting a debug trace line.</summary>
private async Task InvokeForTaskAsync(string taskId, string method, params object?[] args)
{ {
await _hub.InvokeAsync("RunNow", taskId); using (LogContext.PushProperty("TaskId", taskId))
{
_logger.LogDebug("UI invoking {Method} for task {TaskId}", method, taskId);
await _hub.InvokeCoreAsync(method, args);
}
} }
public async Task ContinueTaskAsync(string taskId, string followUpPrompt) public Task RunNowAsync(string taskId)
{ => InvokeForTaskAsync(taskId, "RunNow", taskId);
await _hub.InvokeAsync("ContinueTask", taskId, followUpPrompt);
}
public async Task ResetTaskAsync(string taskId) public Task ContinueTaskAsync(string taskId, string followUpPrompt)
{ => InvokeForTaskAsync(taskId, "ContinueTask", taskId, followUpPrompt);
await _hub.InvokeAsync("ResetTask", taskId);
} public Task ResetTaskAsync(string taskId)
=> InvokeForTaskAsync(taskId, "ResetTask", taskId);
public async Task<MergeResultDto> MergeTaskAsync(string taskId, string targetBranch, bool removeWorktree, string commitMessage) public async Task<MergeResultDto> MergeTaskAsync(string taskId, string targetBranch, bool removeWorktree, string commitMessage)
{ {
@@ -264,10 +272,8 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
public Task<MergeTargetsDto?> GetMergeTargetsAsync(string taskId) public Task<MergeTargetsDto?> GetMergeTargetsAsync(string taskId)
=> TryInvokeAsync<MergeTargetsDto>("GetMergeTargets", taskId); => TryInvokeAsync<MergeTargetsDto>("GetMergeTargets", taskId);
public async Task CancelTaskAsync(string taskId) public Task CancelTaskAsync(string taskId)
{ => InvokeForTaskAsync(taskId, "CancelTask", taskId);
await _hub.InvokeAsync("CancelTask", taskId);
}
public async Task WakeQueueAsync() public async Task WakeQueueAsync()
{ {
@@ -386,25 +392,17 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
await _hub.InvokeAsync("SetTaskStatus", taskId, status.ToString()); await _hub.InvokeAsync("SetTaskStatus", taskId, status.ToString());
} }
public async Task ApproveReviewAsync(string taskId) public Task ApproveReviewAsync(string taskId)
{ => InvokeForTaskAsync(taskId, "ApproveReview", taskId);
await _hub.InvokeAsync("ApproveReview", taskId);
}
public async Task RejectReviewToQueueAsync(string taskId, string feedback) public Task RejectReviewToQueueAsync(string taskId, string feedback)
{ => InvokeForTaskAsync(taskId, "RejectReviewToQueue", taskId, feedback);
await _hub.InvokeAsync("RejectReviewToQueue", taskId, feedback);
}
public async Task RejectReviewToIdleAsync(string taskId) public Task RejectReviewToIdleAsync(string taskId)
{ => InvokeForTaskAsync(taskId, "RejectReviewToIdle", taskId);
await _hub.InvokeAsync("RejectReviewToIdle", taskId);
}
public async Task CancelReviewAsync(string taskId) public Task CancelReviewAsync(string taskId)
{ => InvokeForTaskAsync(taskId, "CancelReview", taskId);
await _hub.InvokeAsync("CancelReview", taskId);
}
public Task<WorktreeCleanupDto?> CleanupFinishedWorktreesAsync(string? listId = null) public Task<WorktreeCleanupDto?> CleanupFinishedWorktreesAsync(string? listId = null)
=> TryInvokeAsync<WorktreeCleanupDto>("CleanupFinishedWorktrees", listId); => TryInvokeAsync<WorktreeCleanupDto>("CleanupFinishedWorktrees", listId);