forked from VilledeMontreal/authentication-nodejs-lib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
requestLogger.ts
80 lines (77 loc) · 2.85 KB
/
requestLogger.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
/*!
* Copyright (c) 2020 Ville de Montreal. All rights reserved.
* Licensed under the MIT license.
* See LICENSE file in the project root for full license information.
*/
import * as superagent from 'superagent';
import {
Stopwatch,
ILogger,
extractMessageFromError,
} from '@villedemontreal/auth-core';
/**
* plugin that will log a message before and after the execution of request,
* and provide additional information such as status code, elapsed time, error...
* @param logger the logger
* @example
* const req = superagent
* .get('http://localhost:4004/secured/profile')
* .use(requestLogger(new ConsoleLogger()));
* @example
* const correlator = new HttpRequestCorrelator();
* const req = superagent
* .get('http://localhost:4004/secured/profile')
* .use(requestLogger(new ConsoleLogger(() => correlator.getId())))
* .use(requestCorrelator(correlator));
* @example
* const agent = superagent
* .agent()
* .use(requestLogger(new ConsoleLogger()));
* const req = agent.get('http://localhost:4004/secured/profile');
* @example
* const req = superagent
* .get('http://localhost:4004/secured/profile')
* .use(requestLogger(session.logger))
* .use(authenticator(session, authenticatorConfig));
*/
export function requestLogger(logger: ILogger) {
return (request: superagent.SuperAgentRequest): superagent.Request => {
const watch = Stopwatch.startNew();
let responseLogged = false;
// Note that we don't listen to the native http events
// because we loose the correlation context that is maintained
// only with the Superagent request EventEmitter.
request.on('request', ({ req }) => {
// we restart the watch just in case the request would be retried.
watch.restart();
const { url, method } = request;
logger.debug({ method, url }, `Start of ${method} ${url}`);
});
request.on('response', (res: any) => {
const { url, method } = request;
const elapsedTimeInMS = watch.elapsedTimeInMS();
const { statusCode } = res;
logger.debug(
{ method, url, elapsedTimeInMS, statusCode },
`End of ${method} ${url} => ${statusCode} in ${elapsedTimeInMS} ms`,
);
responseLogged = true;
});
request.on('error', (error: any) => {
if (!responseLogged) {
const { url, method } = request;
const elapsedTimeInMS = watch.elapsedTimeInMS();
const errorMessage = extractMessageFromError(error);
// note that we clone and trim the error object to avoid
// displaying too much information in the logs.
const clonedError = { ...error, message: error.message };
delete clonedError.response;
logger.error(
{ method, url, elapsedTimeInMS, error: clonedError },
`${method} ${url} failed in ${elapsedTimeInMS} ms: ${errorMessage}`,
);
}
});
return request;
};
}