-
Notifications
You must be signed in to change notification settings - Fork 0
/
GlobalExceptionFilter.cs
127 lines (108 loc) · 4.2 KB
/
GlobalExceptionFilter.cs
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
115
116
117
118
119
120
121
122
123
124
125
126
127
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Sparrow.Core;
using Sparrow.API.Exceptions;
using Sparrow.API.Results.Models;
using System.Net;
using System.Text;
namespace Sparrow.API.Results.ExceptionHandling;
public class GlobalExceptionFilter : IExceptionFilter
{
protected readonly ILogger _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
SeverityAwareLog(context.Exception);
HandleAndWrapException(context);
}
protected virtual void HandleAndWrapException(ExceptionContext context)
{
context.HttpContext.Response.StatusCode = GetStatusCode(context);
bool unathorized = context.HttpContext.Response.StatusCode == (int)HttpStatusCode.Unauthorized;
context.Result = new ObjectResult(
new SparrowApiResponse(CreateErrorInfo(context.Exception), unathorized));
context.Exception = null; // Handled!
context.ExceptionHandled = true;
}
private ErrorInfo CreateErrorInfo(Exception exception)
{
var detailBuilder = new StringBuilder();
CreateDetailsFromException(exception, detailBuilder);
// Exlucde TechnicalMessage if it's Production env
return new ErrorInfo("InternalServerError", detailBuilder.ToString());
}
private void CreateDetailsFromException(Exception exception, StringBuilder detailBuilder)
{
//Exception Message
detailBuilder.AppendLine(exception.GetType().Name + ": " + exception.Message);
//Exception StackTrace
if (!string.IsNullOrEmpty(exception.StackTrace))
{
detailBuilder.AppendLine("STACK TRACE: " + exception.StackTrace);
}
//Inner exception
if (exception.InnerException != null)
{
CreateDetailsFromException(exception.InnerException, detailBuilder);
}
}
protected virtual int GetStatusCode(ExceptionContext context)
{
//Implement custom exceptions
//if (context.Exception is EntityNotFoundException)
//{
// return (int)HttpStatusCode.NotFound;
//}
// کد خطا، نبود؟
return (int)HttpStatusCode.InternalServerError;
}
protected virtual void SeverityAwareLog(Exception exception)
{
var logSeverity = LogSeverity.Error;
string expMessage = exception.Message;
string expTechMessage = "";
if (exception is SparrowException exp)
{
logSeverity = exp.Severity;
expTechMessage = exp.TechnicalMessage;
}
// TODO: Move it to NLog configuration file log parameters
string message = string.Format(
"Processed an unhandled exception of type {0}:\r\nMessage: {1}\r\nTechnicalMessage: {2}",
exception.GetType().Name, EscapeForStringFormat(expMessage), EscapeForStringFormat(expTechMessage));
EventId eventId = exception is SparrowException mtrException ? new EventId(mtrException.ErrorCode ?? 0) : default;
switch (logSeverity)
{
case LogSeverity.Debug:
_logger.LogDebug(eventId, exception, message);
break;
case LogSeverity.Info:
_logger.LogInformation(eventId, exception, message);
break;
case LogSeverity.Warn:
_logger.LogWarning(eventId, exception, message);
break;
case LogSeverity.Error:
_logger.LogError(exception, message, exception);
break;
case LogSeverity.Critical:
_logger.LogCritical(eventId, exception, message);
break;
default:
_logger.LogWarning(
"Invalid parameter passed to SeverityAwareLog method, Please check the code and correct the issue");
_logger.LogError(eventId, exception, message);
break;
}
}
protected virtual string EscapeForStringFormat(string input)
{
StringBuilder sb = new(input);
sb.Replace("{", "{{");
sb.Replace("}", "}}");
return sb.ToString();
}
}