1616using  Microsoft . Win32 ; 
1717using  Microsoft . Windows . AppLifecycle ; 
1818using  Windows . ApplicationModel . Activation ; 
19+ using  Microsoft . Extensions . Logging ; 
20+ using  Serilog ; 
21+ using  System . Collections . Generic ; 
1922
2023namespace  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