Added ASP.Net Core exception logging

This commit is contained in:
djbadders 2019-11-12 23:17:02 +00:00
parent 99c0c628dc
commit ef9f76ed9c
6 changed files with 101 additions and 81 deletions

31
Monitor/Logger.cs Normal file
View File

@ -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<LogHelper>();
// 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);
}
}
}

View File

@ -13,9 +13,4 @@
<p> <p>
<strong>Request ID:</strong> <code>@Model.RequestId</code> <strong>Request ID:</strong> <code>@Model.RequestId</code>
</p> </p>
}
@if (Model.Exception != null) {
<h2>@Model.Exception.Error.Message</h2>
<p>@Model.Exception.Error.StackTrace</p>
} }

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
@ -11,15 +7,16 @@ namespace Monitor.Pages
public class ErrorModel : PageModel public class ErrorModel : PageModel
{ {
public string RequestId { get; set; } public string RequestId { get; set; }
public IExceptionHandlerFeature Exception = null;
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public void OnGet() public void OnGet()
{ {
Exception = HttpContext.Features.Get<IExceptionHandlerFeature>(); var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
Logger.WriteException(exceptionFeature.Error, "An error occurred whilst requesting " + exceptionFeature.Path);
} }
} }
} }

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http;
using Core.Main; using Core.Main;
using Core.Helper; using Core.Helper;
using Core.Main.DataObjects.PTMagicData; using Core.Main.DataObjects.PTMagicData;
@ -16,7 +15,6 @@ namespace Monitor.Pages
public void OnGet() public void OnGet()
{ {
base.Init(); base.Init();
BindData(); BindData();
} }

View File

@ -11,10 +11,6 @@ namespace Monitor
{ {
public class Program public class Program
{ {
// Create a logger
private static LogHelper _log = ServiceHelper.BuildLoggerService().GetRequiredService<LogHelper>();
// Main entry point // Main entry point
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)] [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
public static void Main(string[] args) public static void Main(string[] args)
@ -23,10 +19,10 @@ namespace Monitor
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalUnhandledExceptionHandler); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalUnhandledExceptionHandler);
// Start // Start
WriteConsoleLogLine("##########################################################"); Logger.WriteLine("##########################################################");
WriteConsoleLogLine("#********************************************************#"); Logger.WriteLine("#********************************************************#");
WriteConsoleLogLine("INFO: Starting PT Magic Monitor..."); Logger.WriteLine("INFO: Starting PT Magic Monitor...");
WriteConsoleLogLine("INFO: Beginning startup checks..."); Logger.WriteLine("INFO: Beginning startup checks...");
string monitorBasePath = Directory.GetCurrentDirectory(); string monitorBasePath = Directory.GetCurrentDirectory();
if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json")) if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"))
@ -38,12 +34,12 @@ namespace Monitor
string appsettingsJson = monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"; string appsettingsJson = monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json";
if (!File.Exists(appsettingsJson)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else else
{ {
WriteConsoleLogLine("INFO: appsettings.json found in " + monitorBasePath); Logger.WriteLine("INFO: appsettings.json found in " + monitorBasePath);
IConfiguration config = new ConfigurationBuilder() IConfiguration config = new ConfigurationBuilder()
.SetBasePath(monitorBasePath) .SetBasePath(monitorBasePath)
@ -61,34 +57,34 @@ namespace Monitor
// Check if PT Magic directoy is correctly configured // Check if PT Magic directoy is correctly configured
if (!Directory.Exists(ptMagicBasePath)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else 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 // Check if PT Magic settings file exists
string settingsGeneralJson = ptMagicBasePath + "settings.general.json"; string settingsGeneralJson = ptMagicBasePath + "settings.general.json";
if (!File.Exists(settingsGeneralJson)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else 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 // Check if PT Magic settings file exists
string lastRuntimeSummaryJson = ptMagicBasePath + Constants.PTMagicPathData + Path.DirectorySeparatorChar + "LastRuntimeSummary.json"; string lastRuntimeSummaryJson = ptMagicBasePath + Constants.PTMagicPathData + Path.DirectorySeparatorChar + "LastRuntimeSummary.json";
if (!File.Exists(lastRuntimeSummaryJson)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else else
{ {
WriteConsoleLogLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson); Logger.WriteLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson);
PTMagicConfiguration ptMagicConfiguration = null; PTMagicConfiguration ptMagicConfiguration = null;
try try
@ -103,29 +99,29 @@ namespace Monitor
string wwwrootPath = monitorBasePath + Path.DirectorySeparatorChar + "wwwroot"; string wwwrootPath = monitorBasePath + Path.DirectorySeparatorChar + "wwwroot";
if (!Directory.Exists(wwwrootPath)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else else
{ {
WriteConsoleLogLine("INFO: wwwroot directory found at " + wwwrootPath); Logger.WriteLine("INFO: wwwroot directory found at " + wwwrootPath);
string assetsPath = wwwrootPath + Path.DirectorySeparatorChar + "assets"; string assetsPath = wwwrootPath + Path.DirectorySeparatorChar + "assets";
if (!Directory.Exists(assetsPath)) 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(); if (!Console.IsInputRedirected) Console.ReadKey();
} }
else else
{ {
WriteConsoleLogLine("INFO: assets directory found at " + assetsPath); Logger.WriteLine("INFO: assets directory found at " + assetsPath);
WriteConsoleLogLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER..."); Logger.WriteLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER...");
WriteConsoleLogLine("#********************************************************#"); Logger.WriteLine("#********************************************************#");
WriteConsoleLogLine(""); Logger.WriteLine("");
WriteConsoleLogLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!"); Logger.WriteLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!");
WriteConsoleLogLine(""); Logger.WriteLine("");
WriteConsoleLogLine("##########################################################"); Logger.WriteLine("##########################################################");
WriteConsoleLogLine(""); Logger.WriteLine("");
BuildWebHost(args, monitorBasePath, monitorBasePath + Path.DirectorySeparatorChar + "wwwroot", ptMagicConfiguration.GeneralSettings.Monitor.Port).Run(); BuildWebHost(args, monitorBasePath, monitorBasePath + Path.DirectorySeparatorChar + "wwwroot", ptMagicConfiguration.GeneralSettings.Monitor.Port).Run();
} }
@ -146,29 +142,12 @@ namespace Monitor
.UseWebRoot(webroot) .UseWebRoot(webroot)
.Build(); .Build();
// Log writer
private static void WriteConsoleLogLine(string line)
{
// Write to console and log
Console.WriteLine(line);
_log.DoLogInfo(line);
}
// Global unhandled exception handler // Global unhandled exception handler
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{ {
Exception e = (Exception)args.ExceptionObject; Exception e = (Exception)args.ExceptionObject;
Console.WriteLine("Unhandled exception occurred: " + e.ToString()); Logger.WriteException(e, "An unhandled fatal exception occurred");
if (args.IsTerminating)
{
_log.DoLogCritical("Unhandled fatal exception occurred: ", e);
}
else
{
_log.DoLogError("Unhandled fatal exception occurred: " + e.ToString());
}
} }
} }

View File

@ -1,29 +1,31 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Session; using Microsoft.AspNetCore.Diagnostics;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Core.Main; using Core.Main;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
namespace Monitor { namespace Monitor
public class Startup { {
public class Startup
{
PTMagicConfiguration systemConfiguration = null; PTMagicConfiguration systemConfiguration = null;
public Startup() { public Startup()
{
} }
// This method gets called by the runtime. Use this method to add services to the container. // 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(); 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"; monitorBasePath += Path.DirectorySeparatorChar + "Monitor";
} }
@ -34,14 +36,17 @@ namespace Monitor {
string ptMagicBasePath = config.GetValue<string>("PTMagicBasePath"); string ptMagicBasePath = config.GetValue<string>("PTMagicBasePath");
if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar)) { if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar))
{
ptMagicBasePath += Path.DirectorySeparatorChar; ptMagicBasePath += Path.DirectorySeparatorChar;
} }
try
try { {
systemConfiguration = new PTMagicConfiguration(ptMagicBasePath); systemConfiguration = new PTMagicConfiguration(ptMagicBasePath);
} catch (Exception ex) { }
catch (Exception ex)
{
throw ex; throw ex;
} }
@ -49,7 +54,8 @@ namespace Monitor {
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddDistributedMemoryCache(); services.AddDistributedMemoryCache();
services.AddSession(options => { services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(900); options.IdleTimeout = TimeSpan.FromSeconds(900);
options.Cookie.HttpOnly = true; options.Cookie.HttpOnly = true;
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString(); 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. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseStaticFiles(); {
if (env.IsDevelopment()) { // Register global exception handler
if (env.IsDevelopment())
{
app.UseBrowserLink(); app.UseBrowserLink();
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
//app.UseExceptionHandler("/Error"); }
} else { else
{
app.UseExceptionHandler("/Error"); app.UseExceptionHandler("/Error");
} }
// Configure request pipeline
app.UseStaticFiles();
app.UseSession(); app.UseSession();
app.UseMvc(); app.UseMvc();
// Open the browser
if (systemConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart) OpenBrowser("http://localhost:" + systemConfiguration.GeneralSettings.Monitor.Port.ToString()); if (systemConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart) OpenBrowser("http://localhost:" + systemConfiguration.GeneralSettings.Monitor.Port.ToString());
} }
public static void OpenBrowser(string url) { public static void OpenBrowser(string url)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); // Works ok on 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 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 Process.Start("open", url); // Not tested
} }
} }