Merge pull request #698 from WoLfulus/fix/response-event

Fix & improvements in the response hook
This commit is contained in:
Rijk van Zanten
2020-10-19 16:26:10 -04:00
committed by GitHub
5 changed files with 84 additions and 45 deletions

16
api/package-lock.json generated
View File

@@ -6475,6 +6475,11 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
}
}
},
@@ -7505,6 +7510,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -10396,9 +10406,9 @@
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"querystring": {
"version": "0.2.0",

View File

@@ -115,6 +115,7 @@
"otplib": "^12.0.1",
"pino": "^6.4.1",
"pino-colada": "^2.1.0",
"qs": "^6.9.4",
"rate-limiter-flexible": "^2.1.10",
"resolve-cwd": "^3.0.0",
"sharp": "^0.25.4",

View File

@@ -14,7 +14,6 @@ import rateLimiter from './middleware/rate-limiter';
import cache from './middleware/cache';
import extractToken from './middleware/extract-token';
import authenticate from './middleware/authenticate';
import responseHook from './middleware/response-hook';
import activityRouter from './controllers/activity';
import assetsRouter from './controllers/assets';
import authRouter from './controllers/auth';
@@ -55,7 +54,6 @@ app.disable('x-powered-by');
app.set('trust proxy', true);
app.use(expressLogger({ logger }));
app.use(responseHook);
app.use((req, res, next) => {
bodyParser.json()(req, res, (err) => {

View File

@@ -1,38 +0,0 @@
import { RequestHandler } from 'express';
import asyncHandler from 'express-async-handler';
import emitter from '../emitter';
import logger from '../logger';
const responseHook: RequestHandler = asyncHandler((req, res, next) => {
res.on('close', afterResponse);
const startTime = process.hrtime();
return next();
function afterResponse() {
res.removeListener('close', afterResponse);
const info = {
request: {
method: req.method,
uri: req.path,
url: req.protocol + '://' + req.get('host') + req.originalUrl,
size: req.socket.bytesRead,
query: req.query,
headers: req.headers,
},
response: {
status: res.statusCode,
size: (res as any)['_contentLength'] || res.getHeader('content-length'),
headers: res.getHeaders(),
},
ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
duration: (process.hrtime(startTime)[1] / 1000000).toFixed(),
};
emitter.emitAsync('response', info).catch((err) => logger.warn(err));
}
});
export default responseHook;

View File

@@ -1,12 +1,80 @@
import logger from './logger';
import * as http from 'http';
import * as https from 'https';
import qs from 'qs';
import { URL } from 'url';
import { createTerminus, TerminusOptions } from '@godaddy/terminus';
import http from 'http';
import { Request } from 'express';
import logger from './logger';
import emitter from './emitter';
import database from './database';
import app from './app';
import { once } from 'lodash';
const server = http.createServer(app);
server.on('request', function (req: http.IncomingMessage & Request, res: http.ServerResponse) {
const startTime = process.hrtime();
const complete = once(function (finished: boolean) {
const elapsedTime = process.hrtime(startTime);
const elapsedNanoseconds = elapsedTime[0] * 1e9 + elapsedTime[1];
const elapsedMilliseconds = elapsedNanoseconds / 1e6;
const previousIn = (req.connection as any)._metrics?.in || 0;
const previousOut = (req.connection as any)._metrics?.out || 0;
const metrics = {
in: req.connection.bytesRead - previousIn,
out: req.connection.bytesWritten - previousOut,
};
(req.connection as any)._metrics = {
in: req.connection.bytesRead,
out: req.connection.bytesWritten,
};
// Compatibility when supporting serving with certificates
const protocol = server instanceof https.Server ? 'https' : 'http';
const url = new URL(
(req.originalUrl || req.url) as string,
`${protocol}://${req.headers.host}`
);
const query = url.search.startsWith('?') ? url.search.substr(1) : url.search;
const info = {
finished,
request: {
aborted: req.aborted,
completed: req.complete,
method: req.method,
url: url.href,
path: url.pathname,
protocol,
host: req.headers.host,
size: metrics.in,
query: qs.parse(query),
headers: req.headers,
},
response: {
status: res.statusCode,
size: metrics.out,
headers: res.getHeaders(),
},
ip:
req.headers['x-forwarded-for'] ||
req.connection?.remoteAddress ||
req.socket?.remoteAddress,
duration: elapsedMilliseconds.toFixed(),
};
emitter.emitAsync('response', info).catch((err) => logger.warn(err));
});
res.once('finish', complete.bind(null, true));
res.once('close', complete.bind(null, false));
});
const terminusOptions: TerminusOptions = {
timeout: 1000,
signals: ['SIGINT', 'SIGTERM', 'SIGHUP'],