static ExceptionLogger() { Instance = new ExceptionLogger(); }
public static void Main(string[] args) { IsShuttingDown = false; var loggerConfig = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.File("log/detail-.txt", //?restrictedToMinimumLevel: LogEventLevel.Warning, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7, shared: true, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3} {Message:lj}{NewLine}{Exception}" ) // .WriteTo.File("log/info-.txt", // rollingInterval: RollingInterval.Day, // shared: true, // outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3} {Message:lj}{NewLine}{Exception}", // restrictedToMinimumLevel: LogEventLevel.Information // ) ; try { CTS = new CancellationTokenSource(); var isService = args.Length == 1 && args[0].Equals("--service", StringComparison.OrdinalIgnoreCase); var justRun = args.Length == 1 && args[0].Equals("--run", StringComparison.OrdinalIgnoreCase); if (isService) { var pathToExe = Process.GetCurrentProcess().MainModule.FileName; var pathToContentRootService = Path.GetDirectoryName(pathToExe); Directory.SetCurrentDirectory(pathToContentRootService); } else if (!Debugger.IsAttached && !justRun) { TerminalUI.Init(); return; } else { loggerConfig.WriteTo.Console(); } Log.Logger = loggerConfig.CreateLogger(); var pathToContentRoot = Directory.GetCurrentDirectory(); if (Debugger.IsAttached) { // var pathToExe = Process.GetCurrentProcess().MainModule.FileName; // pathToContentRoot = Path.GetDirectoryName(pathToExe); } else { // now relying on serilog // OverrideStdout(); } AppDomain.CurrentDomain.UnhandledException += (sender, e) => { var isTerminating = e.IsTerminating; Log.Fatal("Unhandled exception", e.ExceptionObject); ExceptionLogger.LogException(e.ExceptionObject as Exception); }; AppConfigSettings appConfigSettings = null; try { var appSettingsJson = File.ReadAllText("./appsettings.json"); appConfigSettings = System.Text.Json.JsonSerializer.Deserialize <AppConfigSettings>(appSettingsJson); } catch (Exception ex) { Log.Error(ex, "Failed to read appsettings.json"); } _startDate = DateTime.Now; var _ = UptimeLogger.LogServerUptimeAsync(); Log.Information($"Application started with process id {System.Diagnostics.Process.GetCurrentProcess().Id}."); // I forget what the different msg types look like Log.Warning("This is what a warning looks like"); Log.Error("This is what an error looks like"); Log.Fatal("This is what a fatal error looks like"); Log.Information("Loading users"); UserManagement.LoadUsersFromFile(); Log.Information("Initialising exception logger"); ExceptionLogger.Instance.Init(); Log.Information("Loading settings"); SettingsInstance.LoadSettingsFromFile(); Log.Information("Initialising real-time tracker"); RealtimeTrackerThread.Instance.Init(); if (appConfigSettings?.AppSettings?.Startup?.HealthMonitor ?? false) { Log.Information("Initialising jsDAL health monitor"); jsDALHealthMonitorThread.Instance.Init(); } else { Log.Information("jsDAL health monitor not configured to run at startup"); } if (appConfigSettings?.AppSettings?.Startup?.DataCollector ?? false) { Log.Information("Initialising data collector"); DataCollectorThread.Instance.Init(); } else { Log.Information("Data collector not configured to run at startup"); } Log.Information("Initialising inline module manifest"); InlineModuleManifest.Instance.Init(); Log.Information("Configuring global culture"); var globalCulture = new System.Globalization.CultureInfo("en-US"); // set global culture to en-US - will help with things like parsing numbers from Javascript(e.g. 10.123) as double/decimal even if server uses a comma as decimal separator for example CultureInfo.DefaultThreadCurrentCulture = globalCulture; CultureInfo.DefaultThreadCurrentUICulture = globalCulture; Log.Information("Building web host"); var builder = BuildWebHost(pathToContentRoot, args); var host = builder.Build(); if (isService) { host.RunAsCustomService(); } else { host.RunAsync(); Console.WriteLine("\r\nPress CTRL+X to shutdown server"); while (true) { var keyInfo = Console.ReadKey(true); if (keyInfo.Key == ConsoleKey.X && (keyInfo.Modifiers & ConsoleModifiers.Control) == ConsoleModifiers.Control) { //host.StopAsync(); ShutdownAllBackgroundThreads(); break; } } } } catch (Exception ex) { Log.Fatal(ex, "Application terminated unexpectedly"); SessionLog.Exception(ex); ShutdownAllBackgroundThreads(); } finally { Log.CloseAndFlush(); } }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IHostApplicationLifetime applicationLifetime) { //app.UseDeveloperExceptionPage(); // force instantiation on singletons { var pmInst = app.ApplicationServices.GetService <PluginLoader>(); CommonNotificationThread.Instance = app.ApplicationServices.GetService <CommonNotificationThread>(); BackgroundThreadPluginManager.Instance = app.ApplicationServices.GetService <BackgroundThreadPluginManager>(); WorkerMonitor.Instance = app.ApplicationServices.GetService <WorkerMonitor>(); RealtimeMonitor.Instance = app.ApplicationServices.GetService <RealtimeMonitor>(); BackgroundTaskMonitor.Instance = app.ApplicationServices.GetService <BackgroundTaskMonitor>(); ConnectionStringSecurity.Instance = app.ApplicationServices.GetService <ConnectionStringSecurity>(); DotNetCoreCounterListener.Instance = app.ApplicationServices.GetService <DotNetCoreCounterListener>(); DotNetCoreCounterListener.Instance.Start(); {// More app startup stuff...but have a dependency on the singleton objects above. Can we move this somewhere else? Log.Information("Initialising project object model"); // we can only initialise the Project structure once ConnectionStringSecurity exists Settings.SettingsInstance.Instance.ProjectList.ForEach(p => p.AfterDeserializationInit()); Log.Information("Initialising plugin loader"); PluginLoader.Instance = pmInst; PluginLoader.Instance.InitAsync().GetAwaiter().GetResult(); ServerMethodManager.RebuildCacheForAllApps(); Log.Information("Starting work spawner."); WorkSpawner.Start(); } } applicationLifetime.ApplicationStopped.Register(() => { Log.Information("Application stopped"); }); applicationLifetime.ApplicationStopping.Register(() => { Log.Information("Application is shutting down"); }); // app.Use(async (httpContext, next) => // { // //if (httpContext.Request.Path.Value.Contains("api/") && httpContext.Request.Method == "OPTIONS") // if (httpContext.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase)) // { // httpContext.Response.Headers.Add("Access-Control-Max-Age", "600"); // // return; // } // await next(); // }); var webSocketOptions = new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(120), ReceiveBufferSize = 4 * 1024, }; app.UseWebSockets(webSocketOptions); app.UseCors("CorsPolicy"); // SPA (angular) route fallback app.Use(async(context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !(context.Request.Path.Value?.ToLower().StartsWith("/api/") ?? false)) { context.Request.Path = "/index.html"; context.Response.StatusCode = 200; await next(); } }); /***** * var mirrorSharpOptions = new MirrorSharpOptions() * { * SelfDebugEnabled = true, * IncludeExceptionDetails = true, * //SetOptionsFromClient = SetOptionsFromClientExtension() * // CSharp = { * // MetadataReferences = ImmutableList.Create<MetadataReference>(all), * // CompilationOptions = compilationOptions * // }, * ExceptionLogger = new MirrorSharpExceptionLogger() * }.SetupCSharp(cs => * { * //cs.MetadataReferences = cs.MetadataReferences.Clear(); * //cs.AddMetadataReferencesFromFiles(all); * cs.MetadataReferences = ImmutableList.Create<MetadataReference>(all); * cs.CompilationOptions = compilationOptions; * * }); * * * app.UseMirrorSharp(mirrorSharpOptions); */ app.UseDefaultFiles(); app.UseStaticFiles(); // TODO: This outputs full request detail into log. Perhaps consider outputting this to a different detailed log //app.UseSerilogRequestLogging(); app.UseSerilogRequestLogging(options => { options.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); // Customize the message template //HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms options.MessageTemplate = "Req/Res: {ReqLen,7} {ResLen,7} {StatusCode} {Elapsed,7:0} ms {RequestMethod,4} {RequestPath}"; //options.GetLevel = (httpContext, elapsed, ex) => Serilog.Events.LogEventLevel.Warning; // Attach additional properties to the request completion event options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => { diagnosticContext.Set("ResLen", httpContext.Response.ContentLength ?? 0); diagnosticContext.Set("ReqLen", httpContext.Request.ContentLength ?? 0); }; }); app.UseRouting(); MetadataReference[] allMetadataReferences = null; try { allMetadataReferences = CSharpCompilerHelper.GetCommonMetadataReferences(); var jsDALBasePluginPath = Path.GetFullPath("./plugins/jsdal-plugin.dll"); if (File.Exists("./plugins/jsdal-plugin.dll")) { Array.Resize(ref allMetadataReferences, allMetadataReferences.Length + 1); allMetadataReferences[allMetadataReferences.Length - 1] = Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(jsDALBasePluginPath); } else { Log.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}"); SessionLog.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}"); } } catch (Exception mex) { Log.Error(mex, "Failed to compile collection of metadata references"); } app.UseEndpoints(endpoints => { endpoints.MapHub <Hubs.HomeDashboardHub>("/main-stats"); endpoints.MapHub <Hubs.WorkerDashboardHub>("/worker-hub"); endpoints.MapHub <Hubs.Performance.RealtimeHub>("/performance-realtime-hub"); endpoints.MapHub <Hubs.HeartBeat.HeartBeatHub>("/heartbeat"); endpoints.MapHub <Hubs.BackgroundTaskHub>("/bgtasks-hub"); endpoints.MapHub <Hubs.BackgroundPluginHub>("/bgplugin-hub"); endpoints.MapHub <Hubs.ExecHub>("/exec-hub"); if (allMetadataReferences?.Length > 0) { var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, // generalDiagnosticOption: ReportDiagnostic.Suppress specificDiagnosticOptions: new Dictionary <string, ReportDiagnostic> { { "CS1701", ReportDiagnostic.Suppress }, // Binding redirects { "CS1702", ReportDiagnostic.Suppress }, { "CS1705", ReportDiagnostic.Suppress } } ); var mirrorSharpOptions = new MirrorSharpOptions() { SelfDebugEnabled = true, IncludeExceptionDetails = true //SetOptionsFromClient = SetOptionsFromClientExtension() // CSharp = { // MetadataReferences = ImmutableList.Create<MetadataReference>(all), // CompilationOptions = compilationOptions // }, // ExceptionLogger = new MirrorSharpExceptionLogger() }.SetupCSharp(cs => { //cs.MetadataReferences = cs.MetadataReferences.Clear(); //cs.AddMetadataReferencesFromFiles(all); cs.MetadataReferences = ImmutableList.Create <MetadataReference>(allMetadataReferences); cs.CompilationOptions = compilationOptions; }); endpoints.MapMirrorSharp("/mirrorsharp", mirrorSharpOptions); } else { Log.Warning("Mirrorsharp not started because of errors builiding up metadata references"); } }); app.UseAuthentication(); app.UseWebSockets(); app.UseCookiePolicy(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); // unhandled exceptions app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { try { var exceptionHandlerPathFeature = context.Features.Get <IExceptionHandlerPathFeature>(); var id = ExceptionLogger.LogException(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Path, "jsdal-server", null); context.Response.StatusCode = 500; context.Response.ContentType = "text/plain"; await context.Response.WriteAsync($"Server error. Ref: {id}"); await context.Response.WriteAsync(new string(' ', 512)); // IE padding } catch (Exception ex) { Log.Error(ex, $"Failed to log unhandled exception because of:\r\n {ex.ToString()}"); } }); }); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }