Skip to content

Commit b803aa1

Browse files
authored
feat: add logging to App (#78)
Adds logging to the Coder Desktop application.
1 parent e5d9dc1 commit b803aa1

File tree

10 files changed

+788
-606
lines changed

10 files changed

+788
-606
lines changed

App/App.csproj

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@
6161
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
6262
</PackageReference>
6363
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.2.0" />
64-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1" />
65-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
66-
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.1" />
64+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
65+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.4" />
66+
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.4" />
6767
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.250108002" />
68+
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
69+
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
70+
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
6871
<PackageReference Include="WinUIEx" Version="2.5.1" />
6972
</ItemGroup>
7073

App/App.xaml.cs

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
using Microsoft.Win32;
1717
using Microsoft.Windows.AppLifecycle;
1818
using Windows.ApplicationModel.Activation;
19+
using Microsoft.Extensions.Logging;
20+
using Serilog;
21+
using System.Collections.Generic;
1922

2023
namespace Coder.Desktop.App;
2124

@@ -24,22 +27,39 @@ public partial class App : Application
2427
private readonly IServiceProvider _services;
2528

2629
private bool _handleWindowClosed = true;
30+
private const string MutagenControllerConfigSection = "MutagenController";
2731

2832
#if !DEBUG
29-
private const string MutagenControllerConfigSection = "AppMutagenController";
33+
private const string ConfigSubKey = @"SOFTWARE\Coder Desktop\App";
34+
private const string logFilename = "app.log";
3035
#else
31-
private const string MutagenControllerConfigSection = "DebugAppMutagenController";
36+
private const string ConfigSubKey = @"SOFTWARE\Coder Desktop\DebugApp";
37+
private const string logFilename = "debug-app.log";
3238
#endif
3339

40+
private readonly ILogger<App> _logger;
41+
3442
public App()
3543
{
3644
var builder = Host.CreateApplicationBuilder();
45+
var configBuilder = builder.Configuration as IConfigurationBuilder;
3746

38-
(builder.Configuration as IConfigurationBuilder).Add(
39-
new RegistryConfigurationSource(Registry.LocalMachine, @"SOFTWARE\Coder Desktop"));
47+
// Add config in increasing order of precedence: first builtin defaults, then HKLM, finally HKCU
48+
// so that the user's settings in the registry take precedence.
49+
AddDefaultConfig(configBuilder);
50+
configBuilder.Add(
51+
new RegistryConfigurationSource(Registry.LocalMachine, ConfigSubKey));
52+
configBuilder.Add(
53+
new RegistryConfigurationSource(Registry.CurrentUser, ConfigSubKey));
4054

4155
var services = builder.Services;
4256

57+
// Logging
58+
builder.Services.AddSerilog((_, loggerConfig) =>
59+
{
60+
loggerConfig.ReadFrom.Configuration(builder.Configuration);
61+
});
62+
4363
services.AddSingleton<ICredentialManager, CredentialManager>();
4464
services.AddSingleton<IRpcController, RpcController>();
4565

@@ -69,12 +89,14 @@ public App()
6989
services.AddTransient<TrayWindow>();
7090

7191
_services = services.BuildServiceProvider();
92+
_logger = (ILogger<App>)(_services.GetService(typeof(ILogger<App>))!);
7293

7394
InitializeComponent();
7495
}
7596

7697
public async Task ExitApplication()
7798
{
99+
_logger.LogDebug("exiting app");
78100
_handleWindowClosed = false;
79101
Exit();
80102
var syncController = _services.GetRequiredService<ISyncSessionController>();
@@ -87,36 +109,39 @@ public async Task ExitApplication()
87109

88110
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
89111
{
112+
_logger.LogInformation("new instance launched");
90113
// Start connecting to the manager in the background.
91114
var rpcController = _services.GetRequiredService<IRpcController>();
92115
if (rpcController.GetState().RpcLifecycle == RpcLifecycle.Disconnected)
93116
// Passing in a CT with no cancellation is desired here, because
94117
// the named pipe open will block until the pipe comes up.
95-
// TODO: log
96-
_ = rpcController.Reconnect(CancellationToken.None).ContinueWith(t =>
118+
_logger.LogDebug("reconnecting with VPN service");
119+
_ = rpcController.Reconnect(CancellationToken.None).ContinueWith(t =>
120+
{
121+
if (t.Exception != null)
97122
{
123+
_logger.LogError(t.Exception, "failed to connect to VPN service");
98124
#if DEBUG
99-
if (t.Exception != null)
100-
{
101-
Debug.WriteLine(t.Exception);
102-
Debugger.Break();
103-
}
125+
Debug.WriteLine(t.Exception);
126+
Debugger.Break();
104127
#endif
105-
});
128+
}
129+
});
106130

107131
// Load the credentials in the background.
108132
var credentialManagerCts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
109133
var credentialManager = _services.GetRequiredService<ICredentialManager>();
110134
_ = credentialManager.LoadCredentials(credentialManagerCts.Token).ContinueWith(t =>
111135
{
112-
// TODO: log
113-
#if DEBUG
114136
if (t.Exception != null)
115137
{
138+
_logger.LogError(t.Exception, "failed to load credentials");
139+
#if DEBUG
116140
Debug.WriteLine(t.Exception);
117141
Debugger.Break();
118-
}
119142
#endif
143+
}
144+
120145
credentialManagerCts.Dispose();
121146
}, CancellationToken.None);
122147

@@ -125,10 +150,14 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
125150
var syncSessionController = _services.GetRequiredService<ISyncSessionController>();
126151
_ = syncSessionController.RefreshState(syncSessionCts.Token).ContinueWith(t =>
127152
{
128-
// TODO: log
153+
if (t.IsCanceled || t.Exception != null)
154+
{
155+
_logger.LogError(t.Exception, "failed to refresh sync state (canceled = {canceled})", t.IsCanceled);
129156
#if DEBUG
130-
if (t.IsCanceled || t.Exception != null) Debugger.Break();
157+
Debugger.Break();
131158
#endif
159+
}
160+
132161
syncSessionCts.Dispose();
133162
}, CancellationToken.None);
134163

@@ -148,17 +177,44 @@ public void OnActivated(object? sender, AppActivationArguments args)
148177
{
149178
case ExtendedActivationKind.Protocol:
150179
var protoArgs = args.Data as IProtocolActivatedEventArgs;
180+
if (protoArgs == null)
181+
{
182+
_logger.LogWarning("URI activation with null data");
183+
return;
184+
}
185+
151186
HandleURIActivation(protoArgs.Uri);
152187
break;
153188

154189
default:
155-
// TODO: log
190+
_logger.LogWarning("activation for {kind}, which is unhandled", args.Kind);
156191
break;
157192
}
158193
}
159194

160195
public void HandleURIActivation(Uri uri)
161196
{
162-
// TODO: handle
197+
// don't log the query string as that's where we include some sensitive information like passwords
198+
_logger.LogInformation("handling URI activation for {path}", uri.AbsolutePath);
199+
}
200+
201+
private static void AddDefaultConfig(IConfigurationBuilder builder)
202+
{
203+
var logPath = Path.Combine(
204+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
205+
"CoderDesktop",
206+
logFilename);
207+
builder.AddInMemoryCollection(new Dictionary<string, string?>
208+
{
209+
[MutagenControllerConfigSection + ":MutagenExecutablePath"] = @"C:\mutagen.exe",
210+
["Serilog:Using:0"] = "Serilog.Sinks.File",
211+
["Serilog:MinimumLevel"] = "Information",
212+
["Serilog:Enrich:0"] = "FromLogContext",
213+
["Serilog:WriteTo:0:Name"] = "File",
214+
["Serilog:WriteTo:0:Args:path"] = logPath,
215+
["Serilog:WriteTo:0:Args:outputTemplate"] =
216+
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}",
217+
["Serilog:WriteTo:0:Args:rollingInterval"] = "Day",
218+
});
163219
}
164220
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy