forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExceptionLogger.cs
More file actions
114 lines (96 loc) · 4.27 KB
/
Copy pathExceptionLogger.cs
File metadata and controls
114 lines (96 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 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.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Properties;
namespace System.Web.Http.ExceptionHandling
{
/// <summary>Represents an unhandled exception logger.</summary>
public abstract class ExceptionLogger : IExceptionLogger
{
internal const string LoggedByKey = "MS_LoggedBy";
/// <inheritdoc />
Task IExceptionLogger.LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
ExceptionContext exceptionContext = context.ExceptionContext;
Contract.Assert(exceptionContext != null);
if (!ShouldLog(context))
{
return TaskHelpers.Completed();
}
return LogAsync(context, cancellationToken);
}
/// <summary>When overridden in a derived class, logs the exception asynchronously.</summary>
/// <param name="context">The exception logger context.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task representing the asynchronous exception logging operation.</returns>
public virtual Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
{
Log(context);
return TaskHelpers.Completed();
}
/// <summary>When overridden in a derived class, logs the exception synchronously.</summary>
/// <param name="context">The exception logger context.</param>
public virtual void Log(ExceptionLoggerContext context)
{
}
/// <summary>Determines whether the exception should be logged.</summary>
/// <param name="context">The exception logger context.</param>
/// <returns>
/// <see langword="true"/> if the exception should be logged; otherwise, <see langword="false"/>.
/// </returns>
/// <remarks>
/// The default decision is only to log an exception instance the first time it is seen by this logger.
/// </remarks>
public virtual bool ShouldLog(ExceptionLoggerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
ExceptionContext exceptionContext = context.ExceptionContext;
Contract.Assert(exceptionContext != null);
IDictionary data = exceptionContext.Exception.Data;
if (data == null || data.IsReadOnly)
{
// If the exception doesn't have a mutable Data collection, we can't prevent duplicate logging. In this
// case, just log every time.
return true;
}
ICollection<object> loggedBy;
if (data.Contains(LoggedByKey))
{
object untypedLoggedBy = data[LoggedByKey];
loggedBy = untypedLoggedBy as ICollection<object>;
if (loggedBy == null)
{
// If exception.Data["MS_LoggedBy"] exists but is not of the right type, we can't prevent duplicate
// logging. In this case, just log every time.
return true;
}
if (loggedBy.Contains(this))
{
// If this logger has already logged this exception, don't log again.
return false;
}
}
else
{
loggedBy = new List<object>();
data.Add(LoggedByKey, loggedBy);
}
// Either loggedBy did not exist before (we just added it) or it already existed of the right type and did
// not already contain this logger. Log now, but mark not to log this exception again for this logger.
Contract.Assert(loggedBy != null);
loggedBy.Add(this);
return true;
}
}
}