@unito/integration-sdk 2.1.3 → 2.2.1
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.
- package/dist/src/index.cjs +38 -33
- package/dist/src/integration.js +3 -1
- package/dist/src/middlewares/finish.js +33 -32
- package/dist/src/middlewares/health.d.ts +3 -0
- package/dist/src/middlewares/health.js +4 -0
- package/dist/test/middlewares/finish.test.js +23 -1
- package/dist/test/middlewares/health.test.d.ts +1 -0
- package/dist/test/middlewares/health.test.js +23 -0
- package/package.json +1 -1
- package/src/integration.ts +3 -1
- package/src/middlewares/finish.ts +30 -30
- package/src/middlewares/health.ts +7 -0
- package/test/middlewares/finish.test.ts +27 -1
- package/test/middlewares/health.test.ts +31 -0
package/dist/src/index.cjs
CHANGED
|
@@ -849,38 +849,38 @@ function extractFilters(req, res, next) {
|
|
|
849
849
|
}
|
|
850
850
|
|
|
851
851
|
function onFinish(req, res, next) {
|
|
852
|
-
|
|
853
|
-
res.
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
}
|
|
852
|
+
res.on('finish', function () {
|
|
853
|
+
const logger = res.locals.logger ?? new Logger();
|
|
854
|
+
const error = res.locals.error;
|
|
855
|
+
const durationInNs = Number(process.hrtime.bigint() - res.locals.requestStartTime);
|
|
856
|
+
const durationInMs = (durationInNs / 1_000_000) | 0;
|
|
857
|
+
const message = `${req.method} ${req.originalUrl} ${res.statusCode} - ${durationInMs} ms`;
|
|
858
|
+
const metadata = {
|
|
859
|
+
duration: durationInNs,
|
|
860
|
+
// Use reserved and standard attributes of Datadog
|
|
861
|
+
// https://app.datadoghq.com/logs/pipelines/standard-attributes
|
|
862
|
+
http: { method: req.method, status_code: res.statusCode, url_details: { path: req.originalUrl } },
|
|
863
|
+
...(error
|
|
864
|
+
? {
|
|
865
|
+
error: {
|
|
866
|
+
kind: error.message,
|
|
867
|
+
stack: (error.originalError?.details?.stack ?? error.details?.stack),
|
|
868
|
+
message: error.originalError?.message ?? error.message,
|
|
869
|
+
},
|
|
870
|
+
}
|
|
871
|
+
: {}),
|
|
872
|
+
};
|
|
873
|
+
if ([404, 429].includes(res.statusCode)) {
|
|
874
|
+
logger.warn(message, metadata);
|
|
875
|
+
}
|
|
876
|
+
else if (res.statusCode >= 400) {
|
|
877
|
+
logger.error(message, metadata);
|
|
878
|
+
}
|
|
879
|
+
else if (req.originalUrl !== '/health') {
|
|
880
|
+
// Don't log successful health check requests
|
|
881
|
+
logger.info(message, metadata);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
884
|
next();
|
|
885
885
|
}
|
|
886
886
|
|
|
@@ -975,6 +975,10 @@ function extractOperationDeadline(req, res, next) {
|
|
|
975
975
|
next();
|
|
976
976
|
}
|
|
977
977
|
|
|
978
|
+
function onHealthCheck(_req, res) {
|
|
979
|
+
res.status(200).json({});
|
|
980
|
+
}
|
|
981
|
+
|
|
978
982
|
function printErrorMessage(message) {
|
|
979
983
|
console.error();
|
|
980
984
|
console.error(`\x1b[31m Oops! Something went wrong! \x1b[0m`);
|
|
@@ -1002,7 +1006,7 @@ class Integration {
|
|
|
1002
1006
|
* @param options The {@link Options} to configure the Integration instance. Can be used to override the default port.
|
|
1003
1007
|
*/
|
|
1004
1008
|
constructor(options = {}) {
|
|
1005
|
-
this.port = options.port || 9200;
|
|
1009
|
+
this.port = options.port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 9200);
|
|
1006
1010
|
this.handlers = [];
|
|
1007
1011
|
}
|
|
1008
1012
|
/**
|
|
@@ -1090,6 +1094,7 @@ class Integration {
|
|
|
1090
1094
|
});
|
|
1091
1095
|
// Instantiate application middlewares. These can throw, so they have an implicit dependency on the internal
|
|
1092
1096
|
// middlewares such as the logger, the correlationId, and the error handling.
|
|
1097
|
+
app.get('/health', onHealthCheck);
|
|
1093
1098
|
app.use(extractCredentials);
|
|
1094
1099
|
app.use(extractSecrets);
|
|
1095
1100
|
app.use(extractFilters);
|
package/dist/src/integration.js
CHANGED
|
@@ -14,6 +14,7 @@ import searchMiddleware from './middlewares/search.js';
|
|
|
14
14
|
import selectsMiddleware from './middlewares/selects.js';
|
|
15
15
|
import relationsMiddleware from './middlewares/relations.js';
|
|
16
16
|
import signalMiddleware from './middlewares/signal.js';
|
|
17
|
+
import healthMiddleware from './middlewares/health.js';
|
|
17
18
|
function printErrorMessage(message) {
|
|
18
19
|
console.error();
|
|
19
20
|
console.error(`\x1b[31m Oops! Something went wrong! \x1b[0m`);
|
|
@@ -41,7 +42,7 @@ export default class Integration {
|
|
|
41
42
|
* @param options The {@link Options} to configure the Integration instance. Can be used to override the default port.
|
|
42
43
|
*/
|
|
43
44
|
constructor(options = {}) {
|
|
44
|
-
this.port = options.port || 9200;
|
|
45
|
+
this.port = options.port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 9200);
|
|
45
46
|
this.handlers = [];
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
@@ -129,6 +130,7 @@ export default class Integration {
|
|
|
129
130
|
});
|
|
130
131
|
// Instantiate application middlewares. These can throw, so they have an implicit dependency on the internal
|
|
131
132
|
// middlewares such as the logger, the correlationId, and the error handling.
|
|
133
|
+
app.get('/health', healthMiddleware);
|
|
132
134
|
app.use(credentialsMiddleware);
|
|
133
135
|
app.use(secretsMiddleware);
|
|
134
136
|
app.use(filtersMiddleware);
|
|
@@ -1,36 +1,37 @@
|
|
|
1
|
+
import { default as Logger } from '../resources/logger.js';
|
|
1
2
|
function onFinish(req, res, next) {
|
|
2
|
-
|
|
3
|
-
res.
|
|
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
|
-
}
|
|
3
|
+
res.on('finish', function () {
|
|
4
|
+
const logger = res.locals.logger ?? new Logger();
|
|
5
|
+
const error = res.locals.error;
|
|
6
|
+
const durationInNs = Number(process.hrtime.bigint() - res.locals.requestStartTime);
|
|
7
|
+
const durationInMs = (durationInNs / 1_000_000) | 0;
|
|
8
|
+
const message = `${req.method} ${req.originalUrl} ${res.statusCode} - ${durationInMs} ms`;
|
|
9
|
+
const metadata = {
|
|
10
|
+
duration: durationInNs,
|
|
11
|
+
// Use reserved and standard attributes of Datadog
|
|
12
|
+
// https://app.datadoghq.com/logs/pipelines/standard-attributes
|
|
13
|
+
http: { method: req.method, status_code: res.statusCode, url_details: { path: req.originalUrl } },
|
|
14
|
+
...(error
|
|
15
|
+
? {
|
|
16
|
+
error: {
|
|
17
|
+
kind: error.message,
|
|
18
|
+
stack: (error.originalError?.details?.stack ?? error.details?.stack),
|
|
19
|
+
message: error.originalError?.message ?? error.message,
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
: {}),
|
|
23
|
+
};
|
|
24
|
+
if ([404, 429].includes(res.statusCode)) {
|
|
25
|
+
logger.warn(message, metadata);
|
|
26
|
+
}
|
|
27
|
+
else if (res.statusCode >= 400) {
|
|
28
|
+
logger.error(message, metadata);
|
|
29
|
+
}
|
|
30
|
+
else if (req.originalUrl !== '/health') {
|
|
31
|
+
// Don't log successful health check requests
|
|
32
|
+
logger.info(message, metadata);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
34
35
|
next();
|
|
35
36
|
}
|
|
36
37
|
export default onFinish;
|
|
@@ -46,7 +46,7 @@ describe('finish middleware', () => {
|
|
|
46
46
|
eventHandler();
|
|
47
47
|
assert.equal(expected, 'works!');
|
|
48
48
|
});
|
|
49
|
-
it('health', () => {
|
|
49
|
+
it('health success', () => {
|
|
50
50
|
let expected = '';
|
|
51
51
|
let eventHandler = () => { };
|
|
52
52
|
const request = { originalUrl: '/health' };
|
|
@@ -68,4 +68,26 @@ describe('finish middleware', () => {
|
|
|
68
68
|
eventHandler();
|
|
69
69
|
assert.equal(expected, '');
|
|
70
70
|
});
|
|
71
|
+
it('health failure', () => {
|
|
72
|
+
let expected = '';
|
|
73
|
+
let eventHandler = () => { };
|
|
74
|
+
const request = { originalUrl: '/health' };
|
|
75
|
+
const response = {
|
|
76
|
+
on: (_event, func) => {
|
|
77
|
+
eventHandler = func;
|
|
78
|
+
},
|
|
79
|
+
locals: {
|
|
80
|
+
requestStartTime: 0n,
|
|
81
|
+
logger: {
|
|
82
|
+
error: (_message) => {
|
|
83
|
+
expected = 'works!';
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
statusCode: 500,
|
|
88
|
+
};
|
|
89
|
+
onFinish(request, response, () => { });
|
|
90
|
+
eventHandler();
|
|
91
|
+
assert.equal(expected, 'works!');
|
|
92
|
+
});
|
|
71
93
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import onHealth from '../../src/middlewares/health.js';
|
|
4
|
+
describe('health middleware', () => {
|
|
5
|
+
it('on GET /health returns 200', () => {
|
|
6
|
+
const request = { originalUrl: '/' };
|
|
7
|
+
let actualStatus;
|
|
8
|
+
let actualBody;
|
|
9
|
+
const response = {
|
|
10
|
+
status: (status) => {
|
|
11
|
+
actualStatus = status;
|
|
12
|
+
return {
|
|
13
|
+
json: (body) => {
|
|
14
|
+
actualBody = body;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
onHealth(request, response);
|
|
20
|
+
assert.deepEqual(actualStatus, 200);
|
|
21
|
+
assert.deepEqual(actualBody, {});
|
|
22
|
+
});
|
|
23
|
+
});
|
package/package.json
CHANGED
package/src/integration.ts
CHANGED
|
@@ -16,6 +16,7 @@ import searchMiddleware from './middlewares/search.js';
|
|
|
16
16
|
import selectsMiddleware from './middlewares/selects.js';
|
|
17
17
|
import relationsMiddleware from './middlewares/relations.js';
|
|
18
18
|
import signalMiddleware from './middlewares/signal.js';
|
|
19
|
+
import healthMiddleware from './middlewares/health.js';
|
|
19
20
|
|
|
20
21
|
function printErrorMessage(message: string) {
|
|
21
22
|
console.error();
|
|
@@ -52,7 +53,7 @@ export default class Integration {
|
|
|
52
53
|
* @param options The {@link Options} to configure the Integration instance. Can be used to override the default port.
|
|
53
54
|
*/
|
|
54
55
|
constructor(options: Options = {}) {
|
|
55
|
-
this.port = options.port || 9200;
|
|
56
|
+
this.port = options.port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 9200);
|
|
56
57
|
this.handlers = [];
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -147,6 +148,7 @@ export default class Integration {
|
|
|
147
148
|
|
|
148
149
|
// Instantiate application middlewares. These can throw, so they have an implicit dependency on the internal
|
|
149
150
|
// middlewares such as the logger, the correlationId, and the error handling.
|
|
151
|
+
app.get('/health', healthMiddleware);
|
|
150
152
|
app.use(credentialsMiddleware);
|
|
151
153
|
app.use(secretsMiddleware);
|
|
152
154
|
app.use(filtersMiddleware);
|
|
@@ -14,39 +14,39 @@ declare global {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function onFinish(req: Request, res: Response, next: NextFunction) {
|
|
17
|
-
|
|
18
|
-
res.
|
|
19
|
-
|
|
17
|
+
res.on('finish', function () {
|
|
18
|
+
const logger = res.locals.logger ?? new Logger();
|
|
19
|
+
const error = res.locals.error;
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const durationInNs = Number(process.hrtime.bigint() - res.locals.requestStartTime);
|
|
22
|
+
const durationInMs = (durationInNs / 1_000_000) | 0;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
const message = `${req.method} ${req.originalUrl} ${res.statusCode} - ${durationInMs} ms`;
|
|
25
|
+
const metadata: Metadata = {
|
|
26
|
+
duration: durationInNs,
|
|
27
|
+
// Use reserved and standard attributes of Datadog
|
|
28
|
+
// https://app.datadoghq.com/logs/pipelines/standard-attributes
|
|
29
|
+
http: { method: req.method, status_code: res.statusCode, url_details: { path: req.originalUrl } },
|
|
30
|
+
...(error
|
|
31
|
+
? {
|
|
32
|
+
error: {
|
|
33
|
+
kind: error.message,
|
|
34
|
+
stack: (error.originalError?.details?.stack ?? error.details?.stack) as string,
|
|
35
|
+
message: error.originalError?.message ?? error.message,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
: {}),
|
|
39
|
+
};
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
}
|
|
41
|
+
if ([404, 429].includes(res.statusCode)) {
|
|
42
|
+
logger.warn(message, metadata);
|
|
43
|
+
} else if (res.statusCode >= 400) {
|
|
44
|
+
logger.error(message, metadata);
|
|
45
|
+
} else if (req.originalUrl !== '/health') {
|
|
46
|
+
// Don't log successful health check requests
|
|
47
|
+
logger.info(message, metadata);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
50
|
|
|
51
51
|
next();
|
|
52
52
|
}
|
|
@@ -56,7 +56,7 @@ describe('finish middleware', () => {
|
|
|
56
56
|
assert.equal(expected, 'works!');
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
it('health', () => {
|
|
59
|
+
it('health success', () => {
|
|
60
60
|
let expected = '';
|
|
61
61
|
let eventHandler: () => void = () => {};
|
|
62
62
|
|
|
@@ -81,4 +81,30 @@ describe('finish middleware', () => {
|
|
|
81
81
|
|
|
82
82
|
assert.equal(expected, '');
|
|
83
83
|
});
|
|
84
|
+
|
|
85
|
+
it('health failure', () => {
|
|
86
|
+
let expected = '';
|
|
87
|
+
let eventHandler: () => void = () => {};
|
|
88
|
+
|
|
89
|
+
const request = { originalUrl: '/health' } as express.Request;
|
|
90
|
+
const response = {
|
|
91
|
+
on: (_event, func: () => void) => {
|
|
92
|
+
eventHandler = func;
|
|
93
|
+
},
|
|
94
|
+
locals: {
|
|
95
|
+
requestStartTime: 0n,
|
|
96
|
+
logger: {
|
|
97
|
+
error: (_message: string) => {
|
|
98
|
+
expected = 'works!';
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
statusCode: 500,
|
|
103
|
+
} as express.Response;
|
|
104
|
+
|
|
105
|
+
onFinish(request, response, () => {});
|
|
106
|
+
eventHandler();
|
|
107
|
+
|
|
108
|
+
assert.equal(expected, 'works!');
|
|
109
|
+
});
|
|
84
110
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { describe, it } from 'node:test';
|
|
4
|
+
|
|
5
|
+
import onHealth from '../../src/middlewares/health.js';
|
|
6
|
+
|
|
7
|
+
describe('health middleware', () => {
|
|
8
|
+
it('on GET /health returns 200', () => {
|
|
9
|
+
const request = { originalUrl: '/' } as Request;
|
|
10
|
+
|
|
11
|
+
let actualStatus;
|
|
12
|
+
let actualBody;
|
|
13
|
+
|
|
14
|
+
const response = {
|
|
15
|
+
status: (status: number) => {
|
|
16
|
+
actualStatus = status;
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
json: (body: object) => {
|
|
20
|
+
actualBody = body;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
} as Response;
|
|
25
|
+
|
|
26
|
+
onHealth(request, response);
|
|
27
|
+
|
|
28
|
+
assert.deepEqual(actualStatus, 200);
|
|
29
|
+
assert.deepEqual(actualBody, {});
|
|
30
|
+
});
|
|
31
|
+
});
|