11using  System ; 
22using  System . Diagnostics ; 
33using  System . IO ; 
4+ using  System . Linq ; 
45using  System . Threading ; 
56using  System . Threading . Tasks ; 
67using  Coder . Desktop . App . Models ; 
1617using  Microsoft . Win32 ; 
1718using  Microsoft . Windows . AppLifecycle ; 
1819using  Windows . ApplicationModel . Activation ; 
20+ using  Microsoft . Extensions . Logging ; 
21+ using  Serilog ; 
1922
2023namespace  Coder . Desktop . App ; 
2124
@@ -24,22 +27,51 @@ public partial class App : Application
2427    private  readonly  IServiceProvider  _services ; 
2528
2629    private  bool  _handleWindowClosed  =  true ; 
30+     private  const  string  MutagenControllerConfigSection  =  "MutagenController" ; 
31+ 
32+     private  const  string  logTemplate  = 
33+         "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}" ; 
2734
2835#if ! DEBUG 
29-     private  const  string  MutagenControllerConfigSection  =  "AppMutagenController" ; 
36+     private  const  string  ConfigSubKey  =  @"SOFTWARE\Coder Desktop\App" ; 
37+     private  const  string  logFilename  =  "app.log" ; 
3038#else
31-     private  const  string  MutagenControllerConfigSection  =  "DebugAppMutagenController" ; 
39+     private  const  string  ConfigSubKey  =  @"SOFTWARE\Coder Desktop\DebugApp" ; 
40+     private  const  string  logFilename  =  "debug-app.log" ; 
3241#endif
3342
43+     private  readonly  ILogger < App >  _logger ; 
44+ 
3445    public  App ( ) 
3546    { 
3647        var  builder  =  Host . CreateApplicationBuilder ( ) ; 
3748
3849        ( builder . Configuration  as  IConfigurationBuilder ) . Add ( 
39-             new  RegistryConfigurationSource ( Registry . LocalMachine ,  @"SOFTWARE\Coder Desktop" ) ) ; 
50+             new  RegistryConfigurationSource ( Registry . LocalMachine ,  ConfigSubKey ) ) ; 
4051
4152        var  services  =  builder . Services ; 
4253
54+         // Logging 
55+         builder . Services . AddSerilog ( ( _ ,  loggerConfig )  => 
56+         { 
57+             loggerConfig . ReadFrom . Configuration ( builder . Configuration ) ; 
58+             var  sinkConfig  =  builder . Configuration . GetSection ( "Serilog" ) . GetSection ( "WriteTo" ) ; 
59+             if  ( ! sinkConfig . GetChildren ( ) . Any ( ) ) 
60+             { 
61+                 // no log sink defined in the registry, so we'll add one here. 
62+                 // We can't generally define these in the registry because we don't 
63+                 // know, a priori, what user will execute Coder Desktop, and therefore 
64+                 // what directories are writable by them. But, it's nice to be able to 
65+                 // directly customize Serilog via the registry if you know what you are 
66+                 // doing. 
67+                 var  logPath  =  Path . Combine ( 
68+                     Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , 
69+                     "CoderDesktop" , 
70+                     logFilename ) ; 
71+                 loggerConfig . WriteTo . File ( logPath ,  outputTemplate :  logTemplate ,  rollingInterval :  RollingInterval . Day ) ; 
72+             } 
73+         } ) ; 
74+ 
4375        services . AddSingleton < ICredentialManager ,  CredentialManager > ( ) ; 
4476        services . AddSingleton < IRpcController ,  RpcController > ( ) ; 
4577
@@ -69,6 +101,7 @@ public App()
69101        services . AddTransient < TrayWindow > ( ) ; 
70102
71103        _services  =  services . BuildServiceProvider ( ) ; 
104+         _logger  =  ( ILogger < App > ) ( _services . GetService ( typeof ( ILogger < App > ) ) ! ) ; 
72105
73106        InitializeComponent ( ) ; 
74107    } 
@@ -87,6 +120,7 @@ public async Task ExitApplication()
87120
88121    protected  override  void  OnLaunched ( Microsoft . UI . Xaml . LaunchActivatedEventArgs  args ) 
89122    { 
123+         _logger . LogInformation ( "new instance launched" ) ; 
90124        // Start connecting to the manager in the background. 
91125        var  rpcController  =  _services . GetRequiredService < IRpcController > ( ) ; 
92126        if  ( rpcController . GetState ( ) . RpcLifecycle  ==  RpcLifecycle . Disconnected ) 
@@ -110,13 +144,15 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
110144        _  =  credentialManager . LoadCredentials ( credentialManagerCts . Token ) . ContinueWith ( t => 
111145        { 
112146            // TODO: log 
113- #if DEBUG 
114147            if  ( t . Exception  !=  null ) 
115148            { 
149+                 _logger . LogError ( t . Exception ,  "failed to load credentials" ) ; 
150+ #if DEBUG 
116151                Debug . WriteLine ( t . Exception ) ; 
117152                Debugger . Break ( ) ; 
118-             } 
119153#endif
154+             } 
155+ 
120156            credentialManagerCts . Dispose ( ) ; 
121157        } ,  CancellationToken . None ) ; 
122158
@@ -126,9 +162,13 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
126162        _  =  syncSessionController . RefreshState ( syncSessionCts . Token ) . ContinueWith ( t => 
127163        { 
128164            // TODO: log 
165+             if  ( t . IsCanceled  ||  t . Exception  !=  null ) 
166+             { 
167+                 _logger . LogError ( t . Exception ,  "failed to refresh sync state (canceled = {canceled})" ,  t . IsCanceled ) ; 
129168#if DEBUG 
130-             if   ( t . IsCanceled   ||   t . Exception   !=   null )  Debugger . Break ( ) ; 
169+                  Debugger . Break ( ) ; 
131170#endif
171+             } 
132172            syncSessionCts . Dispose ( ) ; 
133173        } ,  CancellationToken . None ) ; 
134174
@@ -148,17 +188,24 @@ public void OnActivated(object? sender, AppActivationArguments args)
148188        { 
149189            case  ExtendedActivationKind . Protocol : 
150190                var  protoArgs  =  args . Data  as  IProtocolActivatedEventArgs ; 
191+                 if  ( protoArgs  ==  null ) 
192+                 { 
193+                     _logger . LogWarning ( "URI activation with null data" ) ; 
194+                     return ; 
195+                 } 
196+ 
151197                HandleURIActivation ( protoArgs . Uri ) ; 
152198                break ; 
153199
154200            default : 
155-                 // TODO: log 
201+                 _logger . LogWarning ( "activation for {kind}, which is unhandled" ,   args . Kind ) ; 
156202                break ; 
157203        } 
158204    } 
159205
160206    public  void  HandleURIActivation ( Uri  uri ) 
161207    { 
162-         // TODO: handle 
208+         // don't log the query string as that's where we include some sensitive information like passwords 
209+         _logger . LogInformation ( "handling URI activation for {path}" ,  uri . AbsolutePath ) ; 
163210    } 
164211} 
0 commit comments