From 03182fef6f6a3188efce6ef4d3bea41a8c721ed0 Mon Sep 17 00:00:00 2001 From: Drew Gillies Date: Mon, 24 Jun 2024 11:26:57 +1000 Subject: [PATCH] WIP --- .../NuGetGallery.Core.csproj | 3 + .../Diagnostics/ElmahHandleErrorAttribute.cs | 64 +++++++++++++++++++ .../SendErrorsToTelemetryAttribute.cs | 7 +- src/NuGetGallery/App_Start/AppActivator.cs | 1 + 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/NuGetGallery.Services/Diagnostics/ElmahHandleErrorAttribute.cs diff --git a/src/NuGetGallery.Core/NuGetGallery.Core.csproj b/src/NuGetGallery.Core/NuGetGallery.Core.csproj index 221a3609d7..4b8b74c4b4 100644 --- a/src/NuGetGallery.Core/NuGetGallery.Core.csproj +++ b/src/NuGetGallery.Core/NuGetGallery.Core.csproj @@ -65,6 +65,9 @@ $(ServerCommonPackageVersion) + + 1.2.2 + 5.8.4 diff --git a/src/NuGetGallery.Services/Diagnostics/ElmahHandleErrorAttribute.cs b/src/NuGetGallery.Services/Diagnostics/ElmahHandleErrorAttribute.cs new file mode 100644 index 0000000000..ee50f25e41 --- /dev/null +++ b/src/NuGetGallery.Services/Diagnostics/ElmahHandleErrorAttribute.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Web; +using System.Web.Mvc; +using Elmah; + +namespace NuGetGallery.Diagnostics +{ + /// + /// Source: http://stackoverflow.com/a/779961/52749 + /// + public class ElmahHandleErrorAttribute : HandleErrorAttribute + { + public override void OnException(ExceptionContext context) + { + base.OnException(context); + if (!context.ExceptionHandled // if unhandled, will be logged anyhow + || TryRaiseErrorSignal(context) // prefer signaling, if possible + || IsFiltered(context)) // filtered? + return; + + LogException(context); + } + + private static bool TryRaiseErrorSignal(ExceptionContext context) + { + var httpContext = GetHttpContextImpl(context.HttpContext); + if (httpContext == null) + return false; + var signal = ErrorSignal.FromContext(httpContext); + if (signal == null) + return false; + signal.Raise(context.Exception, httpContext); + return true; + } + + private static bool IsFiltered(ExceptionContext context) + { + var config = context.HttpContext.GetSection("elmah/errorFilter") + as ErrorFilterConfiguration; + + if (config == null) + return false; + + var testContext = new ErrorFilterModule.AssertionHelperContext( + context.Exception, + GetHttpContextImpl(context.HttpContext)); + return config.Assertion.Test(testContext); + } + + private static void LogException(ExceptionContext context) + { + var httpContext = GetHttpContextImpl(context.HttpContext); + var error = new Error(context.Exception, httpContext); + ErrorLog.GetDefault(httpContext).Log(error); + } + + private static HttpContext GetHttpContextImpl(HttpContextBase context) + { + return context.ApplicationInstance.Context; + } + } +} \ No newline at end of file diff --git a/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs b/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs index 5003847ea9..069f10e286 100644 --- a/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs +++ b/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs @@ -8,10 +8,13 @@ namespace NuGetGallery.Diagnostics { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] - public sealed class SendErrorsToTelemetryAttribute : Attribute + public sealed class SendErrorsToTelemetryAttribute : + ElmahHandleErrorAttribute { - public void OnException(ExceptionContext context) + public override void OnException(ExceptionContext context) { + base.OnException(context); + if (context != null) { try diff --git a/src/NuGetGallery/App_Start/AppActivator.cs b/src/NuGetGallery/App_Start/AppActivator.cs index 1e6d8cfa2d..e35e692ca1 100644 --- a/src/NuGetGallery/App_Start/AppActivator.cs +++ b/src/NuGetGallery/App_Start/AppActivator.cs @@ -252,6 +252,7 @@ private static void AppPostStart(IAppConfiguration configuration) Routes.RegisterRoutes(RouteTable.Routes, configuration.FeedOnlyMode, configuration.AdminPanelEnabled); AreaRegistration.RegisterAllAreas(); + GlobalFilters.Filters.Add(new SendErrorsToTelemetryAttribute { View = "~/Views/Errors/InternalError.cshtml" }); GlobalFilters.Filters.Add(new ReadOnlyModeErrorFilter()); GlobalFilters.Filters.Add(new AntiForgeryErrorFilter()); GlobalFilters.Filters.Add(new UserDeletedErrorFilter());