Skip to content

Commit b84a4ed

Browse files
authored
chore: add logging to mutagen controller (#79)
Adds some logging to the mutagen controller.
1 parent 7ca3af3 commit b84a4ed

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

App/Services/MutagenController.cs

+27-6
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
using Coder.Desktop.Vpn.Utilities;
1818
using Grpc.Core;
1919
using Microsoft.Extensions.Options;
20+
using Microsoft.Extensions.Logging;
21+
using Serilog;
2022
using DaemonTerminateRequest = Coder.Desktop.MutagenSdk.Proto.Service.Daemon.TerminateRequest;
2123
using MutagenProtocol = Coder.Desktop.MutagenSdk.Proto.Url.Protocol;
2224
using SynchronizationTerminateRequest = Coder.Desktop.MutagenSdk.Proto.Service.Synchronization.TerminateRequest;
25+
using Microsoft.Extensions.Hosting;
2326

2427
namespace Coder.Desktop.App.Services;
2528

@@ -113,6 +116,8 @@ public sealed class MutagenController : ISyncSessionController
113116
// Protects all private non-readonly class members.
114117
private readonly RaiiSemaphoreSlim _lock = new(1, 1);
115118

119+
private readonly ILogger<MutagenController> _logger;
120+
116121
private readonly CancellationTokenSource _stateUpdateCts = new();
117122
private Task? _stateUpdateTask;
118123

@@ -142,15 +147,19 @@ public sealed class MutagenController : ISyncSessionController
142147

143148
private string MutagenDaemonLog => Path.Combine(_mutagenDataDirectory, "daemon.log");
144149

145-
public MutagenController(IOptions<MutagenControllerConfig> config)
150+
public MutagenController(IOptions<MutagenControllerConfig> config, ILogger<MutagenController> logger)
146151
{
147152
_mutagenExecutablePath = config.Value.MutagenExecutablePath;
153+
_logger = logger;
148154
}
149155

150156
public MutagenController(string executablePath, string dataDirectory)
151157
{
152158
_mutagenExecutablePath = executablePath;
153159
_mutagenDataDirectory = dataDirectory;
160+
var builder = Host.CreateApplicationBuilder();
161+
builder.Services.AddSerilog();
162+
_logger = (ILogger<MutagenController>)builder.Build().Services.GetService(typeof(ILogger<MutagenController>))!;
154163
}
155164

156165
public event EventHandler<SyncSessionControllerStateModel>? StateChanged;
@@ -447,9 +456,9 @@ private async Task<MutagenClient> EnsureDaemon(CancellationToken ct)
447456
{
448457
await StopDaemon(cts.Token);
449458
}
450-
catch
459+
catch (Exception stopEx)
451460
{
452-
// ignored
461+
_logger.LogError(stopEx, "failed to stop daemon");
453462
}
454463

455464
ReplaceState(new SyncSessionControllerStateModel
@@ -501,6 +510,8 @@ private async Task<MutagenClient> StartDaemon(CancellationToken ct)
501510
}
502511
catch (Exception e) when (e is not OperationCanceledException)
503512
{
513+
_logger.LogWarning(e, "failed to start daemon process, attempt {attempt} of {maxAttempts}", attempts,
514+
maxAttempts);
504515
if (attempts == maxAttempts)
505516
throw;
506517
// back off a little and try again.
@@ -556,8 +567,11 @@ private void StartDaemonProcess()
556567
// https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.environment?view=net-8.0
557568
_daemonProcess.StartInfo.UseShellExecute = false;
558569
_daemonProcess.StartInfo.RedirectStandardError = true;
559-
// TODO: log exited process
560-
// _daemonProcess.Exited += ...
570+
_daemonProcess.EnableRaisingEvents = true;
571+
_daemonProcess.Exited += (object? sender, EventArgs e) =>
572+
{
573+
_logger.LogInformation("mutagen daemon exited with code {exitCode}", _daemonProcess?.ExitCode);
574+
};
561575
if (!_daemonProcess.Start())
562576
throw new InvalidOperationException("Failed to start mutagen daemon process, Start returned false");
563577

@@ -572,6 +586,7 @@ private void StartDaemonProcess()
572586
/// </summary>
573587
private async Task StopDaemon(CancellationToken ct)
574588
{
589+
_logger.LogDebug("stopping mutagen daemon");
575590
var process = _daemonProcess;
576591
var client = _mutagenClient;
577592
var writer = _logWriter;
@@ -584,28 +599,34 @@ private async Task StopDaemon(CancellationToken ct)
584599
if (client == null)
585600
{
586601
if (process == null) return;
602+
_logger.LogDebug("no client; killing daemon process");
587603
process.Kill(true);
588604
}
589605
else
590606
{
591607
try
592608
{
609+
_logger.LogDebug("sending DaemonTerminateRequest");
593610
await client.Daemon.TerminateAsync(new DaemonTerminateRequest(), cancellationToken: ct);
594611
}
595-
catch
612+
catch (Exception e)
596613
{
614+
_logger.LogError(e, "failed to gracefully terminate agent");
597615
if (process == null) return;
616+
_logger.LogDebug("killing daemon process after failed graceful termination");
598617
process.Kill(true);
599618
}
600619
}
601620

602621
if (process == null) return;
603622
var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
604623
cts.CancelAfter(TimeSpan.FromSeconds(5));
624+
_logger.LogDebug("waiting for process to exit");
605625
await process.WaitForExitAsync(cts.Token);
606626
}
607627
finally
608628
{
629+
_logger.LogDebug("cleaning up daemon process objects");
609630
client?.Dispose();
610631
process?.Dispose();
611632
writer?.Dispose();

0 commit comments

Comments
 (0)