@naturalcycles/backend-lib 5.17.2 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { CommonLogger, Primitive, StringMap } from '@naturalcycles/js-lib';
|
|
2
|
-
import type { Breadcrumb,
|
|
2
|
+
import type { Breadcrumb, SeverityLevel } from '@sentry/node';
|
|
3
3
|
import type * as SentryLib from '@sentry/node';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export interface SentrySharedServiceCfg {
|
|
5
|
+
sentry: typeof SentryLib;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Recommended sentry configuration:
|
|
9
|
+
*
|
|
10
|
+
* {
|
|
11
|
+
* maxValueLength: 2000, // default is 250 characters
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
7
15
|
export declare class SentrySharedService {
|
|
8
|
-
private sentryServiceCfg;
|
|
9
16
|
constructor(sentryServiceCfg: SentrySharedServiceCfg);
|
|
10
|
-
|
|
11
|
-
sentry(): typeof SentryLib;
|
|
12
|
-
/**
|
|
13
|
-
* Currently not recommended, because it makes `void` requests throw user-facing errors.
|
|
14
|
-
*
|
|
15
|
-
* UPD: to be tested. Without it - request is not enriched and the error is less useful.
|
|
16
|
-
*/
|
|
17
|
-
getRequestHandler(): BackendRequestHandler;
|
|
18
|
-
/**
|
|
19
|
-
* Currently not recommended, as it's replaced by our custom sentryErrorHandler.
|
|
20
|
-
*
|
|
21
|
-
* @deprecated
|
|
22
|
-
*/
|
|
23
|
-
getErrorHandler(): BackendErrorRequestHandler;
|
|
17
|
+
sentry: typeof SentryLib;
|
|
24
18
|
/**
|
|
25
19
|
* For GDPR reasons we never send more information than just User ID.
|
|
26
20
|
*/
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SentrySharedService = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
4
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
5
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
7
6
|
const index_1 = require("../index");
|
|
@@ -17,54 +16,27 @@ const INSPECT_OPT = {
|
|
|
17
16
|
colors: false,
|
|
18
17
|
includeErrorData: true,
|
|
19
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Recommended sentry configuration:
|
|
21
|
+
*
|
|
22
|
+
* {
|
|
23
|
+
* maxValueLength: 2000, // default is 250 characters
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
20
27
|
class SentrySharedService {
|
|
21
28
|
constructor(sentryServiceCfg) {
|
|
22
|
-
this.
|
|
23
|
-
}
|
|
24
|
-
init() {
|
|
25
|
-
this.sentry();
|
|
26
|
-
}
|
|
27
|
-
sentry() {
|
|
28
|
-
// Lazy-loading `@sentry/node`
|
|
29
|
-
// Reasons:
|
|
30
|
-
// 1. Can be useful is this module is imported but never actually used
|
|
31
|
-
// 2. Works around memory leak when used with Jest
|
|
32
|
-
const sentry = require('@sentry/node');
|
|
33
|
-
if (this.sentryServiceCfg.dsn) {
|
|
34
|
-
// Sentry enabled
|
|
35
|
-
console.log('SentryService init...');
|
|
36
|
-
}
|
|
37
|
-
sentry.init({
|
|
38
|
-
maxValueLength: 2000, // default is 250 characters
|
|
39
|
-
...this.sentryServiceCfg,
|
|
40
|
-
});
|
|
41
|
-
return sentry;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Currently not recommended, because it makes `void` requests throw user-facing errors.
|
|
45
|
-
*
|
|
46
|
-
* UPD: to be tested. Without it - request is not enriched and the error is less useful.
|
|
47
|
-
*/
|
|
48
|
-
getRequestHandler() {
|
|
49
|
-
return this.sentry().Handlers.requestHandler();
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Currently not recommended, as it's replaced by our custom sentryErrorHandler.
|
|
53
|
-
*
|
|
54
|
-
* @deprecated
|
|
55
|
-
*/
|
|
56
|
-
getErrorHandler() {
|
|
57
|
-
return this.sentry().Handlers.errorHandler();
|
|
29
|
+
this.sentry = sentryServiceCfg.sentry;
|
|
58
30
|
}
|
|
59
31
|
/**
|
|
60
32
|
* For GDPR reasons we never send more information than just User ID.
|
|
61
33
|
*/
|
|
62
34
|
setUserId(id) {
|
|
63
35
|
if (id === null) {
|
|
64
|
-
this.sentry
|
|
36
|
+
this.sentry.setUser(null);
|
|
65
37
|
return;
|
|
66
38
|
}
|
|
67
|
-
this.sentry
|
|
39
|
+
this.sentry.setUser({
|
|
68
40
|
id,
|
|
69
41
|
});
|
|
70
42
|
}
|
|
@@ -78,7 +50,7 @@ class SentrySharedService {
|
|
|
78
50
|
* https://docs.sentry.io/platforms/node/enriching-events/scopes/
|
|
79
51
|
*/
|
|
80
52
|
setTags(tags) {
|
|
81
|
-
this.sentry
|
|
53
|
+
this.sentry.setTags(tags);
|
|
82
54
|
}
|
|
83
55
|
/**
|
|
84
56
|
* Does console.log(err)
|
|
@@ -104,20 +76,20 @@ class SentrySharedService {
|
|
|
104
76
|
// This is to avoid Sentry cutting err.message to 253 characters
|
|
105
77
|
// It will log additional "breadcrumb object" before the error
|
|
106
78
|
// It's a Breadcrumb, not a console.log, because console.log are NOT automatically attached as Breadcrumbs in cron-job environments (outside of Express)
|
|
107
|
-
this.sentry
|
|
79
|
+
this.sentry.addBreadcrumb({
|
|
108
80
|
message: (0, nodejs_lib_1._inspect)(err, INSPECT_OPT),
|
|
109
81
|
});
|
|
110
|
-
return this.sentry
|
|
82
|
+
return this.sentry.captureException(err);
|
|
111
83
|
}
|
|
112
84
|
/**
|
|
113
85
|
* Returns "eventId"
|
|
114
86
|
*/
|
|
115
87
|
captureMessage(msg, level) {
|
|
116
88
|
(0, index_1.getRequestLogger)()[sentrySeverityMap[level] || 'log']('captureMessage:', msg);
|
|
117
|
-
return this.sentry
|
|
89
|
+
return this.sentry.captureMessage(msg, level);
|
|
118
90
|
}
|
|
119
91
|
addBreadcrumb(breadcrumb) {
|
|
120
|
-
this.sentry
|
|
92
|
+
this.sentry.addBreadcrumb(breadcrumb);
|
|
121
93
|
}
|
|
122
94
|
/**
|
|
123
95
|
* Currently it will only use `logger.error` ("error" level) and ignore `log` and `warn`.
|
|
@@ -132,15 +104,12 @@ class SentrySharedService {
|
|
|
132
104
|
warn: () => { }, // noop
|
|
133
105
|
error: (...args) => {
|
|
134
106
|
const message = args.map(arg => (0, nodejs_lib_1._inspect)(arg, INSPECT_OPT)).join(' ');
|
|
135
|
-
this.sentry
|
|
107
|
+
this.sentry.addBreadcrumb({
|
|
136
108
|
message,
|
|
137
109
|
});
|
|
138
|
-
this.sentry
|
|
110
|
+
this.sentry.captureException((0, js_lib_1._anyToError)(args.length === 1 ? args[0] : args));
|
|
139
111
|
},
|
|
140
112
|
};
|
|
141
113
|
}
|
|
142
114
|
}
|
|
143
115
|
exports.SentrySharedService = SentrySharedService;
|
|
144
|
-
tslib_1.__decorate([
|
|
145
|
-
(0, js_lib_1._Memo)()
|
|
146
|
-
], SentrySharedService.prototype, "sentry", null);
|
|
@@ -24,12 +24,6 @@ function createDefaultApp(cfg) {
|
|
|
24
24
|
if (!isTest) {
|
|
25
25
|
app.use((0, asyncLocalStorageMiddleware_1.asyncLocalStorageMiddleware)());
|
|
26
26
|
}
|
|
27
|
-
// The request handler must be the first middleware on the app
|
|
28
|
-
if (sentryService) {
|
|
29
|
-
// On error - this handler will set res.headers,
|
|
30
|
-
// which will trigger genericErrorHandler "headers already sent"
|
|
31
|
-
app.use(sentryService.getRequestHandler());
|
|
32
|
-
}
|
|
33
27
|
app.use((0, __1.methodOverrideMiddleware)());
|
|
34
28
|
app.use((0, requestTimeoutMiddleware_1.requestTimeoutMiddleware)());
|
|
35
29
|
// app.use(serverStatsMiddleware()) // disabled by default
|
|
@@ -81,6 +75,9 @@ function createDefaultApp(cfg) {
|
|
|
81
75
|
useHandlers(app, cfg.postHandlers);
|
|
82
76
|
// Generic 404 handler
|
|
83
77
|
app.use((0, notFoundMiddleware_1.notFoundMiddleware)());
|
|
78
|
+
// todo: test if it's needed!
|
|
79
|
+
// Add this after all routes, but before any and other error-handling middlewares are defined
|
|
80
|
+
// Sentry.setupExpressErrorHandler(app);
|
|
84
81
|
// Generic error handler
|
|
85
82
|
// It handles errors, returns proper status, does sentry.captureException(),
|
|
86
83
|
// assigns err.data.errorId from sentry
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/backend-lib",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky",
|
|
6
6
|
"build": "dev-lib build",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"deploy-health-check-debug2": "yarn tsn ./src/bin/deploy-health-check.ts --url https://api-master2.naturalcycles.com --thresholdUnhealthy 5"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"@sentry/node": "^
|
|
21
|
+
"@sentry/node": "^8"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@naturalcycles/db-lib": "^9",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@naturalcycles/bench-lib": "^3",
|
|
45
45
|
"@naturalcycles/dev-lib": "^15",
|
|
46
|
-
"@sentry/node": "^
|
|
46
|
+
"@sentry/node": "^8",
|
|
47
47
|
"@types/ejs": "^3",
|
|
48
48
|
"@types/node": "^22",
|
|
49
49
|
"@types/yargs": "^16",
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
_anyToError,
|
|
3
3
|
_isErrorObject,
|
|
4
|
-
_Memo,
|
|
5
4
|
CommonLogger,
|
|
6
5
|
CommonLogLevel,
|
|
7
6
|
Primitive,
|
|
8
7
|
StringMap,
|
|
9
8
|
} from '@naturalcycles/js-lib'
|
|
10
9
|
import { _inspect, InspectAnyOptions } from '@naturalcycles/nodejs-lib'
|
|
11
|
-
import type { Breadcrumb,
|
|
10
|
+
import type { Breadcrumb, SeverityLevel } from '@sentry/node'
|
|
12
11
|
import type * as SentryLib from '@sentry/node'
|
|
13
|
-
import {
|
|
12
|
+
import { getRequestLogger } from '../index'
|
|
14
13
|
|
|
15
|
-
export interface SentrySharedServiceCfg
|
|
14
|
+
export interface SentrySharedServiceCfg {
|
|
15
|
+
sentry: typeof SentryLib
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
const sentrySeverityMap: Record<SeverityLevel, CommonLogLevel> = {
|
|
18
19
|
debug: 'log',
|
|
@@ -28,62 +29,31 @@ const INSPECT_OPT: InspectAnyOptions = {
|
|
|
28
29
|
includeErrorData: true,
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Recommended sentry configuration:
|
|
34
|
+
*
|
|
35
|
+
* {
|
|
36
|
+
* maxValueLength: 2000, // default is 250 characters
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
31
40
|
export class SentrySharedService {
|
|
32
|
-
constructor(
|
|
33
|
-
|
|
34
|
-
init(): void {
|
|
35
|
-
this.sentry()
|
|
41
|
+
constructor(sentryServiceCfg: SentrySharedServiceCfg) {
|
|
42
|
+
this.sentry = sentryServiceCfg.sentry
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
sentry(): typeof SentryLib {
|
|
40
|
-
// Lazy-loading `@sentry/node`
|
|
41
|
-
// Reasons:
|
|
42
|
-
// 1. Can be useful is this module is imported but never actually used
|
|
43
|
-
// 2. Works around memory leak when used with Jest
|
|
44
|
-
const sentry = require('@sentry/node') as typeof SentryLib
|
|
45
|
-
|
|
46
|
-
if (this.sentryServiceCfg.dsn) {
|
|
47
|
-
// Sentry enabled
|
|
48
|
-
console.log('SentryService init...')
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
sentry.init({
|
|
52
|
-
maxValueLength: 2000, // default is 250 characters
|
|
53
|
-
...this.sentryServiceCfg,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return sentry
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Currently not recommended, because it makes `void` requests throw user-facing errors.
|
|
61
|
-
*
|
|
62
|
-
* UPD: to be tested. Without it - request is not enriched and the error is less useful.
|
|
63
|
-
*/
|
|
64
|
-
getRequestHandler(): BackendRequestHandler {
|
|
65
|
-
return this.sentry().Handlers.requestHandler()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Currently not recommended, as it's replaced by our custom sentryErrorHandler.
|
|
70
|
-
*
|
|
71
|
-
* @deprecated
|
|
72
|
-
*/
|
|
73
|
-
getErrorHandler(): BackendErrorRequestHandler {
|
|
74
|
-
return this.sentry().Handlers.errorHandler()
|
|
75
|
-
}
|
|
45
|
+
sentry: typeof SentryLib
|
|
76
46
|
|
|
77
47
|
/**
|
|
78
48
|
* For GDPR reasons we never send more information than just User ID.
|
|
79
49
|
*/
|
|
80
50
|
setUserId(id: string | null): void {
|
|
81
51
|
if (id === null) {
|
|
82
|
-
this.sentry
|
|
52
|
+
this.sentry.setUser(null)
|
|
83
53
|
return
|
|
84
54
|
}
|
|
85
55
|
|
|
86
|
-
this.sentry
|
|
56
|
+
this.sentry.setUser({
|
|
87
57
|
id,
|
|
88
58
|
})
|
|
89
59
|
}
|
|
@@ -98,7 +68,7 @@ export class SentrySharedService {
|
|
|
98
68
|
* https://docs.sentry.io/platforms/node/enriching-events/scopes/
|
|
99
69
|
*/
|
|
100
70
|
setTags(tags: StringMap<Primitive>): void {
|
|
101
|
-
this.sentry
|
|
71
|
+
this.sentry.setTags(tags)
|
|
102
72
|
}
|
|
103
73
|
|
|
104
74
|
/**
|
|
@@ -131,11 +101,11 @@ export class SentrySharedService {
|
|
|
131
101
|
// This is to avoid Sentry cutting err.message to 253 characters
|
|
132
102
|
// It will log additional "breadcrumb object" before the error
|
|
133
103
|
// It's a Breadcrumb, not a console.log, because console.log are NOT automatically attached as Breadcrumbs in cron-job environments (outside of Express)
|
|
134
|
-
this.sentry
|
|
104
|
+
this.sentry.addBreadcrumb({
|
|
135
105
|
message: _inspect(err, INSPECT_OPT),
|
|
136
106
|
})
|
|
137
107
|
|
|
138
|
-
return this.sentry
|
|
108
|
+
return this.sentry.captureException(err)
|
|
139
109
|
}
|
|
140
110
|
|
|
141
111
|
/**
|
|
@@ -143,11 +113,11 @@ export class SentrySharedService {
|
|
|
143
113
|
*/
|
|
144
114
|
captureMessage(msg: string, level?: SeverityLevel): string {
|
|
145
115
|
getRequestLogger()[sentrySeverityMap[level!] || 'log']('captureMessage:', msg)
|
|
146
|
-
return this.sentry
|
|
116
|
+
return this.sentry.captureMessage(msg, level)
|
|
147
117
|
}
|
|
148
118
|
|
|
149
119
|
addBreadcrumb(breadcrumb: Breadcrumb): void {
|
|
150
|
-
this.sentry
|
|
120
|
+
this.sentry.addBreadcrumb(breadcrumb)
|
|
151
121
|
}
|
|
152
122
|
|
|
153
123
|
/**
|
|
@@ -164,11 +134,11 @@ export class SentrySharedService {
|
|
|
164
134
|
error: (...args) => {
|
|
165
135
|
const message = args.map(arg => _inspect(arg, INSPECT_OPT)).join(' ')
|
|
166
136
|
|
|
167
|
-
this.sentry
|
|
137
|
+
this.sentry.addBreadcrumb({
|
|
168
138
|
message,
|
|
169
139
|
})
|
|
170
140
|
|
|
171
|
-
this.sentry
|
|
141
|
+
this.sentry.captureException(_anyToError(args.length === 1 ? args[0] : args))
|
|
172
142
|
},
|
|
173
143
|
}
|
|
174
144
|
}
|
|
@@ -34,13 +34,6 @@ export function createDefaultApp(cfg: DefaultAppCfg): BackendApplication {
|
|
|
34
34
|
app.use(asyncLocalStorageMiddleware())
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// The request handler must be the first middleware on the app
|
|
38
|
-
if (sentryService) {
|
|
39
|
-
// On error - this handler will set res.headers,
|
|
40
|
-
// which will trigger genericErrorHandler "headers already sent"
|
|
41
|
-
app.use(sentryService.getRequestHandler())
|
|
42
|
-
}
|
|
43
|
-
|
|
44
37
|
app.use(methodOverrideMiddleware())
|
|
45
38
|
app.use(requestTimeoutMiddleware())
|
|
46
39
|
// app.use(serverStatsMiddleware()) // disabled by default
|
|
@@ -117,6 +110,10 @@ export function createDefaultApp(cfg: DefaultAppCfg): BackendApplication {
|
|
|
117
110
|
// Generic 404 handler
|
|
118
111
|
app.use(notFoundMiddleware())
|
|
119
112
|
|
|
113
|
+
// todo: test if it's needed!
|
|
114
|
+
// Add this after all routes, but before any and other error-handling middlewares are defined
|
|
115
|
+
// Sentry.setupExpressErrorHandler(app);
|
|
116
|
+
|
|
120
117
|
// Generic error handler
|
|
121
118
|
// It handles errors, returns proper status, does sentry.captureException(),
|
|
122
119
|
// assigns err.data.errorId from sentry
|