-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathaggregate-errors.ts
125 lines (112 loc) · 4.05 KB
/
aggregate-errors.ts
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
import type { Event, EventHint, Exception, ExtendedError, StackParser } from '@sentry/types';
import { isInstanceOf } from './is';
/**
* Creates exceptions inside `event.exception.values` for errors that are nested on properties based on the `key` parameter.
*/
export function applyAggregateErrorsToEvent(
exceptionFromErrorImplementation: (stackParser: StackParser, ex: Error) => Exception,
parser: StackParser,
key: string,
limit: number,
event: Event,
hint?: EventHint,
): void {
if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
return;
}
// Generally speaking the last item in `event.exception.values` is the exception originating from the original Error
const originalException: Exception | undefined =
event.exception.values.length > 0 ? event.exception.values[event.exception.values.length - 1] : undefined;
// We only create exception grouping if there is an exception in the event.
if (originalException) {
event.exception.values = aggregateExceptionsFromError(
exceptionFromErrorImplementation,
parser,
limit,
hint.originalException as ExtendedError,
key,
event.exception.values,
originalException,
0,
);
}
}
function aggregateExceptionsFromError(
exceptionFromErrorImplementation: (stackParser: StackParser, ex: Error) => Exception,
parser: StackParser,
limit: number,
error: ExtendedError,
key: string,
prevExceptions: Exception[],
exception: Exception,
exceptionId: number,
): Exception[] {
if (prevExceptions.length >= limit + 1) {
return prevExceptions;
}
let newExceptions = [...prevExceptions];
if (isInstanceOf(error[key], Error)) {
applyExceptionGroupFieldsForParentException(exception, exceptionId);
const newException = exceptionFromErrorImplementation(parser, error[key]);
const newExceptionId = newExceptions.length;
applyExceptionGroupFieldsForChildException(newException, key, newExceptionId, exceptionId);
newExceptions = aggregateExceptionsFromError(
exceptionFromErrorImplementation,
parser,
limit,
error[key],
key,
[newException, ...newExceptions],
newException,
newExceptionId,
);
}
// This will create exception grouping for AggregateErrors
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError
if (Array.isArray(error.errors)) {
error.errors.forEach((childError, i) => {
if (isInstanceOf(childError, Error)) {
applyExceptionGroupFieldsForParentException(exception, exceptionId);
const newException = exceptionFromErrorImplementation(parser, childError);
const newExceptionId = newExceptions.length;
applyExceptionGroupFieldsForChildException(newException, `errors[${i}]`, newExceptionId, exceptionId);
newExceptions = aggregateExceptionsFromError(
exceptionFromErrorImplementation,
parser,
limit,
childError,
key,
[newException, ...newExceptions],
newException,
newExceptionId,
);
}
});
}
return newExceptions;
}
function applyExceptionGroupFieldsForParentException(exception: Exception, exceptionId: number): void {
// Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default.
exception.mechanism = exception.mechanism || { type: 'generic', handled: true };
exception.mechanism = {
...exception.mechanism,
is_exception_group: true,
exception_id: exceptionId,
};
}
function applyExceptionGroupFieldsForChildException(
exception: Exception,
source: string,
exceptionId: number,
parentId: number | undefined,
): void {
// Don't know if this default makes sense. The protocol requires us to set these values so we pick *some* default.
exception.mechanism = exception.mechanism || { type: 'generic', handled: true };
exception.mechanism = {
...exception.mechanism,
type: 'chained',
source,
exception_id: exceptionId,
parent_id: parentId,
};
}