diff --git a/.env.example b/.env.example index 9445fac..511dbe2 100644 --- a/.env.example +++ b/.env.example @@ -7,4 +7,15 @@ KC_SERVICE_ACCOUNT_SECRET= APP_HOST=0.0.0.0 APP_PORT=3000 +MINIO_HOST=192.168.1.20 +MINIO_PORT=9000 +MINIO_ACCESS_KEY= +MINIO_SECRET_KEY= +MINIO_BUCKET=jws-dev + +ELASTICSEARCH_PROTOCOL=http +ELASTICSEARCH_HOST=192.168.1.20 +ELASTICSEARCH_PORT=9200 +ELASTICSEARCH_INDEX=jws-log-index + DATABASE_URL=postgresql://postgres:1234@192.168.1.20:5432/dev_1?schema=public diff --git a/src/app.ts b/src/app.ts index 2d500f5..d9c0a8f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,6 +5,7 @@ import swaggerUi from "swagger-ui-express"; import swaggerDocument from "./swagger.json"; import error from "./middlewares/error"; import { RegisterRoutes } from "./routes"; +import logMiddleware from "./middlewares/log"; const APP_HOST = process.env.APP_HOST || "0.0.0.0"; const APP_PORT = +(process.env.APP_PORT || 3000); @@ -15,6 +16,9 @@ const APP_PORT = +(process.env.APP_PORT || 3000); app.use(cors()); app.use(json()); app.use(urlencoded({ extended: true })); + + app.use(logMiddleware); + app.use("/", express.static("static")); app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); diff --git a/src/interfaces/http-error.ts b/src/interfaces/http-error.ts index 787b79c..e9f34fd 100644 --- a/src/interfaces/http-error.ts +++ b/src/interfaces/http-error.ts @@ -1,6 +1,13 @@ import HttpStatus from "./http-status"; -type DevMessage = "missing_or_invalid_parameter" | "data_exists" | "unknown_url" | "data_not_found"; +type DevMessage = + | "missing_or_invalid_parameter" + | "data_exists" + | "data_in_used" + | "no_permission" + | "unknown_url" + | "data_not_found" + | "unauthorized"; class HttpError extends Error { /** diff --git a/src/middlewares/log.ts b/src/middlewares/log.ts new file mode 100644 index 0000000..9db083d --- /dev/null +++ b/src/middlewares/log.ts @@ -0,0 +1,77 @@ +import { NextFunction, Request, Response } from "express"; +import elasticsearch from "../services/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 = { + debug: 4, + info: 3, + warning: 2, + error: 1, + none: 0, +}; + +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", () => { + 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: "JWS-SOS", + startTimeStamp: timestamp, + endTimeStamp: new Date().toString(), + processTime: performance.now() - start, + host: req.hostname, + sessionId: req.headers["x-session-id"], + rtId: req.headers["x-rtid"], + tId: req.headers["x-tid"], + method: req.method, + endpoint: req.url, + responseCode: res.statusCode, + responseDescription: + data.devMessage !== undefined + ? data.devMessage + : { 200: "success", 201: "created_success", 204: "no_content", 304: "success" }[ + res.statusCode + ], + // input: (level < 1 && req.body) || undefined, + // output: (level < 1 && data) || undefined, + ...req.app.locals.logData, + }; + + console.log(obj); + + elasticsearch.index({ + index: ELASTICSEARCH_INDEX, + document: obj, + }); + }); + + return next(); +} + +export default logMiddleware; diff --git a/src/services/elasticsearch.ts b/src/services/elasticsearch.ts new file mode 100644 index 0000000..529bc4f --- /dev/null +++ b/src/services/elasticsearch.ts @@ -0,0 +1,7 @@ +import { Client } from "@elastic/elasticsearch"; + +const elasticsearch = new Client({ + node: `${process.env.ELASTICSEARCH_PROTOCOL}://${process.env.ELASTICSEARCH_HOST}:${process.env.ELASTICSEARCH_PORT}`, +}); + +export default elasticsearch;