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..9b156894c3 100644
--- a/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs
+++ b/src/NuGetGallery.Services/Diagnostics/SendErrorsToTelemetryAttribute.cs
@@ -8,10 +8,12 @@
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());