From ef9f76ed9c5a567394e9e8cb72d94e6777bcb58f Mon Sep 17 00:00:00 2001 From: djbadders <34887832+djbadders@users.noreply.github.com> Date: Tue, 12 Nov 2019 23:17:02 +0000 Subject: [PATCH] Added ASP.Net Core exception logging --- Monitor/Logger.cs | 31 ++++++++++++ Monitor/Pages/Error.cshtml | 5 -- Monitor/Pages/Error.cshtml.cs | 9 ++-- Monitor/Pages/MarketAnalyzer.cshtml.cs | 2 - Monitor/Program.cs | 69 +++++++++----------------- Monitor/Startup.cs | 66 +++++++++++++++--------- 6 files changed, 101 insertions(+), 81 deletions(-) create mode 100644 Monitor/Logger.cs diff --git a/Monitor/Logger.cs b/Monitor/Logger.cs new file mode 100644 index 0000000..841563c --- /dev/null +++ b/Monitor/Logger.cs @@ -0,0 +1,31 @@ +using System; +using Core.Helper; +using Microsoft.Extensions.DependencyInjection; + +namespace Monitor +{ + public static class Logger + { + // Create a logger + private static LogHelper _log = ServiceHelper.BuildLoggerService().GetRequiredService(); + + // Log writer functions + public static void WriteLine(string line) + { + // Write to console and log + Console.WriteLine(line); + _log.DoLogInfo(line); + } + + public static void WriteException(Exception ex, string description = null) + { + string output; + + output = string.Format("An exception has occurred {0}: {1}", description != null ? description : "", ex.ToString()); + + // Write to console and log + Console.WriteLine(output); + _log.DoLogInfo(output); + } + } +} \ No newline at end of file diff --git a/Monitor/Pages/Error.cshtml b/Monitor/Pages/Error.cshtml index 6c83966..0ea6585 100644 --- a/Monitor/Pages/Error.cshtml +++ b/Monitor/Pages/Error.cshtml @@ -13,9 +13,4 @@

Request ID: @Model.RequestId

-} - -@if (Model.Exception != null) { -

@Model.Exception.Error.Message

-

@Model.Exception.Error.StackTrace

} \ No newline at end of file diff --git a/Monitor/Pages/Error.cshtml.cs b/Monitor/Pages/Error.cshtml.cs index 448cfde..f96bf8a 100644 --- a/Monitor/Pages/Error.cshtml.cs +++ b/Monitor/Pages/Error.cshtml.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc.RazorPages; @@ -11,15 +7,16 @@ namespace Monitor.Pages public class ErrorModel : PageModel { public string RequestId { get; set; } - public IExceptionHandlerFeature Exception = null; public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); public void OnGet() { - Exception = HttpContext.Features.Get(); + var exceptionFeature = HttpContext.Features.Get(); RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + + Logger.WriteException(exceptionFeature.Error, "An error occurred whilst requesting " + exceptionFeature.Path); } } } diff --git a/Monitor/Pages/MarketAnalyzer.cshtml.cs b/Monitor/Pages/MarketAnalyzer.cshtml.cs index 85ef6f7..9d27e60 100644 --- a/Monitor/Pages/MarketAnalyzer.cshtml.cs +++ b/Monitor/Pages/MarketAnalyzer.cshtml.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.AspNetCore.Http; using Core.Main; using Core.Helper; using Core.Main.DataObjects.PTMagicData; @@ -16,7 +15,6 @@ namespace Monitor.Pages public void OnGet() { base.Init(); - BindData(); } diff --git a/Monitor/Program.cs b/Monitor/Program.cs index a9a8294..3e73f7d 100644 --- a/Monitor/Program.cs +++ b/Monitor/Program.cs @@ -11,10 +11,6 @@ namespace Monitor { public class Program { - - // Create a logger - private static LogHelper _log = ServiceHelper.BuildLoggerService().GetRequiredService(); - // Main entry point [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)] public static void Main(string[] args) @@ -23,10 +19,10 @@ namespace Monitor AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalUnhandledExceptionHandler); // Start - WriteConsoleLogLine("##########################################################"); - WriteConsoleLogLine("#********************************************************#"); - WriteConsoleLogLine("INFO: Starting PT Magic Monitor..."); - WriteConsoleLogLine("INFO: Beginning startup checks..."); + Logger.WriteLine("##########################################################"); + Logger.WriteLine("#********************************************************#"); + Logger.WriteLine("INFO: Starting PT Magic Monitor..."); + Logger.WriteLine("INFO: Beginning startup checks..."); string monitorBasePath = Directory.GetCurrentDirectory(); if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json")) @@ -38,12 +34,12 @@ namespace Monitor string appsettingsJson = monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"; if (!File.Exists(appsettingsJson)) { - WriteConsoleLogLine("ERROR: appsettings.json not found: '" + appsettingsJson + "'. Please check if the file exists. If not, review the PT Magic setup steps listed on the wiki!"); + Logger.WriteLine("ERROR: appsettings.json not found: '" + appsettingsJson + "'. Please check if the file exists. If not, review the PT Magic setup steps listed on the wiki!"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: appsettings.json found in " + monitorBasePath); + Logger.WriteLine("INFO: appsettings.json found in " + monitorBasePath); IConfiguration config = new ConfigurationBuilder() .SetBasePath(monitorBasePath) @@ -61,34 +57,34 @@ namespace Monitor // Check if PT Magic directoy is correctly configured if (!Directory.Exists(ptMagicBasePath)) { - WriteConsoleLogLine("ERROR: PT Magic directory not found: '" + ptMagicBasePath + "'. Please check your setting for 'PTMagicBasePath' in 'Monitor/appsettings.json'"); + Logger.WriteLine("ERROR: PT Magic directory not found: '" + ptMagicBasePath + "'. Please check your setting for 'PTMagicBasePath' in 'Monitor/appsettings.json'"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: PT Magic directory found at " + ptMagicBasePath); + Logger.WriteLine("INFO: PT Magic directory found at " + ptMagicBasePath); // Check if PT Magic settings file exists string settingsGeneralJson = ptMagicBasePath + "settings.general.json"; if (!File.Exists(settingsGeneralJson)) { - WriteConsoleLogLine("ERROR: PT Magic settings not found: '" + settingsGeneralJson + "'. Please check if you setup PT Magic correctly!"); + Logger.WriteLine("ERROR: PT Magic settings not found: '" + settingsGeneralJson + "'. Please check if you setup PT Magic correctly!"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: settings.general.json found at " + settingsGeneralJson); + Logger.WriteLine("INFO: settings.general.json found at " + settingsGeneralJson); // Check if PT Magic settings file exists string lastRuntimeSummaryJson = ptMagicBasePath + Constants.PTMagicPathData + Path.DirectorySeparatorChar + "LastRuntimeSummary.json"; if (!File.Exists(lastRuntimeSummaryJson)) { - WriteConsoleLogLine("ERROR: PT Magic runtime summary not found: '" + lastRuntimeSummaryJson + "'. Please wait for PT Magic to complete its first run!"); + Logger.WriteLine("ERROR: PT Magic runtime summary not found: '" + lastRuntimeSummaryJson + "'. Please wait for PT Magic to complete its first run!"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson); + Logger.WriteLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson); PTMagicConfiguration ptMagicConfiguration = null; try @@ -103,29 +99,29 @@ namespace Monitor string wwwrootPath = monitorBasePath + Path.DirectorySeparatorChar + "wwwroot"; if (!Directory.Exists(wwwrootPath)) { - WriteConsoleLogLine("ERROR: wwwroot directory not found: '" + wwwrootPath + "'. Did you copy all files as instructed on the wiki?"); + Logger.WriteLine("ERROR: wwwroot directory not found: '" + wwwrootPath + "'. Did you copy all files as instructed on the wiki?"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: wwwroot directory found at " + wwwrootPath); + Logger.WriteLine("INFO: wwwroot directory found at " + wwwrootPath); string assetsPath = wwwrootPath + Path.DirectorySeparatorChar + "assets"; if (!Directory.Exists(assetsPath)) { - WriteConsoleLogLine("ERROR: assets directory not found: '" + assetsPath + "'. Did you copy all files as instructed on the wiki?"); + Logger.WriteLine("ERROR: assets directory not found: '" + assetsPath + "'. Did you copy all files as instructed on the wiki?"); if (!Console.IsInputRedirected) Console.ReadKey(); } else { - WriteConsoleLogLine("INFO: assets directory found at " + assetsPath); - WriteConsoleLogLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER..."); - WriteConsoleLogLine("#********************************************************#"); - WriteConsoleLogLine(""); - WriteConsoleLogLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!"); - WriteConsoleLogLine(""); - WriteConsoleLogLine("##########################################################"); - WriteConsoleLogLine(""); + Logger.WriteLine("INFO: assets directory found at " + assetsPath); + Logger.WriteLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER..."); + Logger.WriteLine("#********************************************************#"); + Logger.WriteLine(""); + Logger.WriteLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!"); + Logger.WriteLine(""); + Logger.WriteLine("##########################################################"); + Logger.WriteLine(""); BuildWebHost(args, monitorBasePath, monitorBasePath + Path.DirectorySeparatorChar + "wwwroot", ptMagicConfiguration.GeneralSettings.Monitor.Port).Run(); } @@ -146,29 +142,12 @@ namespace Monitor .UseWebRoot(webroot) .Build(); - // Log writer - private static void WriteConsoleLogLine(string line) - { - // Write to console and log - Console.WriteLine(line); - _log.DoLogInfo(line); - } - // Global unhandled exception handler private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) { Exception e = (Exception)args.ExceptionObject; - Console.WriteLine("Unhandled exception occurred: " + e.ToString()); - - if (args.IsTerminating) - { - _log.DoLogCritical("Unhandled fatal exception occurred: ", e); - } - else - { - _log.DoLogError("Unhandled fatal exception occurred: " + e.ToString()); - } + Logger.WriteException(e, "An unhandled fatal exception occurred"); } } diff --git a/Monitor/Startup.cs b/Monitor/Startup.cs index 9cccea2..2afd563 100644 --- a/Monitor/Startup.cs +++ b/Monitor/Startup.cs @@ -1,29 +1,31 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Session; +using Microsoft.AspNetCore.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Core.Main; using System.Runtime.InteropServices; using System.Diagnostics; -namespace Monitor { - public class Startup { +namespace Monitor +{ + public class Startup + { PTMagicConfiguration systemConfiguration = null; - public Startup() { + public Startup() + { } // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) { + public void ConfigureServices(IServiceCollection services) + { string monitorBasePath = Directory.GetCurrentDirectory(); - if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json")) { + if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json")) + { monitorBasePath += Path.DirectorySeparatorChar + "Monitor"; } @@ -34,14 +36,17 @@ namespace Monitor { string ptMagicBasePath = config.GetValue("PTMagicBasePath"); - if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar)) { + if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar)) + { ptMagicBasePath += Path.DirectorySeparatorChar; } - - try { + try + { systemConfiguration = new PTMagicConfiguration(ptMagicBasePath); - } catch (Exception ex) { + } + catch (Exception ex) + { throw ex; } @@ -49,7 +54,8 @@ namespace Monitor { services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); services.AddSingleton(); services.AddDistributedMemoryCache(); - services.AddSession(options => { + services.AddSession(options => + { options.IdleTimeout = TimeSpan.FromSeconds(900); options.Cookie.HttpOnly = true; options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString(); @@ -57,26 +63,40 @@ namespace Monitor { } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) { - app.UseStaticFiles(); - if (env.IsDevelopment()) { + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + // Register global exception handler + if (env.IsDevelopment()) + { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); - //app.UseExceptionHandler("/Error"); - } else { + } + else + { app.UseExceptionHandler("/Error"); } + + // Configure request pipeline + app.UseStaticFiles(); app.UseSession(); app.UseMvc(); + + // Open the browser if (systemConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart) OpenBrowser("http://localhost:" + systemConfiguration.GeneralSettings.Monitor.Port.ToString()); } - public static void OpenBrowser(string url) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + public static void OpenBrowser(string url) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); // Works ok on windows - } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { Process.Start("xdg-open", url); // Works ok on linux - } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { Process.Start("open", url); // Not tested } }