Merge branch 'feat/log-middleware' into develop
This commit is contained in:
commit
04de0940ea
4 changed files with 172 additions and 5 deletions
94
package-lock.json
generated
94
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@elastic/elasticsearch": "^8.14.0",
|
||||||
"@nestjs/platform-express": "^10.3.7",
|
"@nestjs/platform-express": "^10.3.7",
|
||||||
"@tsoa/runtime": "^6.0.0",
|
"@tsoa/runtime": "^6.0.0",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
|
|
@ -51,6 +52,66 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@elastic/elasticsearch": {
|
||||||
|
"version": "8.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-8.14.0.tgz",
|
||||||
|
"integrity": "sha512-MGrgCI4y+Ozssf5Q2IkVJlqt5bUMnKIICG2qxeOfrJNrVugMCBCAQypyesmSSocAtNm8IX3LxfJ3jQlFHmKe2w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@elastic/transport": "^8.6.0",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@elastic/transport": {
|
||||||
|
"version": "8.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@elastic/transport/-/transport-8.7.0.tgz",
|
||||||
|
"integrity": "sha512-IqXT7a8DZPJtqP2qmX1I2QKmxYyN27kvSW4g6pInESE1SuGwZDp2FxHJ6W2kwmYOJwQdAt+2aWwzXO5jHo9l4A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@opentelemetry/api": "1.x",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"hpagent": "^1.0.0",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"secure-json-parse": "^2.4.0",
|
||||||
|
"tslib": "^2.4.0",
|
||||||
|
"undici": "^6.12.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@elastic/transport/node_modules/debug": {
|
||||||
|
"version": "4.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||||
|
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@elastic/transport/node_modules/debug/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@elastic/transport/node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||||
|
|
@ -253,6 +314,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
||||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
|
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@opentelemetry/api": {
|
||||||
|
"version": "1.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||||
|
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
|
|
@ -2140,6 +2210,15 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hpagent": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/http-errors": {
|
"node_modules/http-errors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||||
|
|
@ -3674,6 +3753,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
|
||||||
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/secure-json-parse": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.5.4",
|
"version": "7.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||||
|
|
@ -4858,6 +4943,15 @@
|
||||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/undici": {
|
||||||
|
"version": "6.19.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.2.tgz",
|
||||||
|
"integrity": "sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@elastic/elasticsearch": "^8.14.0",
|
||||||
"@nestjs/platform-express": "^10.3.7",
|
"@nestjs/platform-express": "^10.3.7",
|
||||||
"@tsoa/runtime": "^6.0.0",
|
"@tsoa/runtime": "^6.0.0",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,7 @@ import HttpStatus from "../interfaces/http-status";
|
||||||
if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) {
|
if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) {
|
||||||
throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL.");
|
throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL.");
|
||||||
}
|
}
|
||||||
if (
|
if (process.env.AUTH_PUBLIC_KEY && process.env.AUTH_REALM_URL && !process.env.AUTH_PREFERRED_MODE) {
|
||||||
process.env.AUTH_PUBLIC_KEY &&
|
|
||||||
process.env.AUTH_REALM_URL &&
|
|
||||||
!process.env.AUTH_PREFERRED_MODE
|
|
||||||
) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"AUTH_PREFFERRED must be specified if AUTH_PUBLIC_KEY and AUTH_REALM_URL is provided.",
|
"AUTH_PREFFERRED must be specified if AUTH_PUBLIC_KEY and AUTH_REALM_URL is provided.",
|
||||||
);
|
);
|
||||||
|
|
@ -57,6 +53,9 @@ export async function expressAuthentication(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.app.locals.logData.userId = payload.sub;
|
||||||
|
request.app.locals.logData.user = payload.preferred_username;
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
73
src/middlewares/logs.ts
Normal file
73
src/middlewares/logs.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import { Client } from "@elastic/elasticsearch";
|
||||||
|
|
||||||
|
if (!process.env.ELASTICSEARCH_INDEX) {
|
||||||
|
throw new Error("Require ELASTICSEARCH_INDEX to store log.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ELASTICSEARCH_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||||
|
|
||||||
|
const LOG_LEVEL_MAP: Record<string, number> = {
|
||||||
|
debug: 4,
|
||||||
|
info: 3,
|
||||||
|
warning: 2,
|
||||||
|
error: 1,
|
||||||
|
none: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const elasticsearch = new Client({
|
||||||
|
node: `${process.env.ELASTICSEARCH_PROTOCOL}://${process.env.ELASTICSEARCH_HOST}:${process.env.ELASTICSEARCH_PORT}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function logMiddleware(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if (!req.url.startsWith("/api/")) return next();
|
||||||
|
|
||||||
|
let data: any;
|
||||||
|
|
||||||
|
const originalJson = res.json;
|
||||||
|
|
||||||
|
res.json = function (v: any) {
|
||||||
|
data = v;
|
||||||
|
return originalJson.call(this, v);
|
||||||
|
};
|
||||||
|
|
||||||
|
const timestamp = new Date().toString();
|
||||||
|
const start = performance.now();
|
||||||
|
|
||||||
|
req.app.locals.logData = {};
|
||||||
|
|
||||||
|
res.on("finish", () => {
|
||||||
|
if (!req.url.startsWith("/api/")) return;
|
||||||
|
|
||||||
|
const level = LOG_LEVEL_MAP[process.env.LOG_LEVEL ?? "info"] || 1;
|
||||||
|
|
||||||
|
if (level === 1 && res.statusCode < 500) return;
|
||||||
|
if (level === 2 && res.statusCode < 400) return;
|
||||||
|
if (level === 3 && res.statusCode < 200) return;
|
||||||
|
|
||||||
|
const obj = {
|
||||||
|
logType: res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warning" : "info",
|
||||||
|
systemName: "BMA_EHR_DEVELOPMENT",
|
||||||
|
startTimeStamp: timestamp,
|
||||||
|
endTimeStamp: new Date().toString(),
|
||||||
|
processTime: performance.now() - start,
|
||||||
|
host: req.hostname,
|
||||||
|
method: req.method,
|
||||||
|
endpoint: req.url,
|
||||||
|
responseCode: String(res.statusCode === 304 ? 200 : res.statusCode),
|
||||||
|
responseDescription: data?.code,
|
||||||
|
input: (level === 4 && JSON.stringify(req.body, null, 2)) || undefined,
|
||||||
|
output: (level === 4 && JSON.stringify(data, null, 2)) || undefined,
|
||||||
|
...req.app.locals.logData,
|
||||||
|
};
|
||||||
|
|
||||||
|
elasticsearch.index({
|
||||||
|
index: ELASTICSEARCH_INDEX,
|
||||||
|
document: obj,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default logMiddleware;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue