diff --git a/src/controllers/log-controller.ts b/src/controllers/log-controller.ts index c6a17b8..7cb247a 100644 --- a/src/controllers/log-controller.ts +++ b/src/controllers/log-controller.ts @@ -24,6 +24,8 @@ export class LogController extends Controller { @Query() size: number = 30, @Query() rootId?: string, @Query() search?: string, + @Query() searchId?: string, + @Query() searchStatus?: string, @Query() searchAfter?: number, @Query() systemName?: string, @Query() date?: Date, @@ -56,15 +58,39 @@ export class LogController extends Controller { { bool: { should: [ - "method", + ...[ + "method", + "endpoint", + "host", + "responseCode", + "output", + "rootId", + ].map((v) => ({ + wildcard: { [`${v}.keyword`]: `*${search}*` }, + })), + {term: {_id: search}}, + ], + }, + }, + ] + : []), + ...(searchId + ? [ + { + term: { + _id: searchId, + }, + }, + ] + : []), + ...(searchStatus + ? [ + { + bool: { + should: [ "logType", - "endpoint", - "host", - "responseCode", - "output", - "rootId", ].map((v) => ({ - wildcard: { [v]: "*" + search + "*" }, + wildcard: { [v]: "*" + searchStatus + "*" }, })), }, }, diff --git a/src/controllers/report-controller.ts b/src/controllers/report-controller.ts new file mode 100644 index 0000000..43ce5c7 --- /dev/null +++ b/src/controllers/report-controller.ts @@ -0,0 +1,201 @@ +import { Body, Controller, Get, Post, Query, Route, Security, Tags } from "tsoa"; +import { Client as ElasticsearchClient } from "@elastic/elasticsearch"; + +function getEnvVar(name: string) { + const value = process.env[name]; + if (!value) throw new Error(`${name} is required.`); + return value; +} + +const ELASTICSEARCH_PROTOCOL = getEnvVar("ELASTICSEARCH_PROTOCOL"); +const ELASTICSEARCH_HOST = getEnvVar("ELASTICSEARCH_HOST"); +const ELASTICSEARCH_PORT = getEnvVar("ELASTICSEARCH_PORT"); +const ELASTICSEARCH_INDEX = getEnvVar("ELASTICSEARCH_INDEX"); + +const elasticsearch = new ElasticsearchClient({ + node: `${ELASTICSEARCH_PROTOCOL}://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}`, +}); + +@Route("/api/v1/log/report") +@Security("keycloak") +@Tags("Report") +export class ReportController extends Controller { + + @Get('logsList') + async reportLogsList( + @Query() rootId?: string, + @Query() search?: string, + @Query() searchId?: string, + @Query() searchStatus?: string, + @Query() systemName?: string, + @Query() date?: Date, + @Query() startDate?: Date, + @Query() endDate?: Date, + @Query() timezone = "+07:00", + @Query() sort: "asc" | "desc" = "desc", + ) { + let startDateString: string | undefined; + let endDateString: string | undefined; + let startTimeString = "00:00:00"; + let endTimeString = "23:59:59"; + + if (date && !startDate && !endDate) { + startDateString = `${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(2, "0")}-${`${date.getDate()}`.padStart(2, "0")}T${startTimeString}`; + endDateString = `${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(2, "0")}-${`${date.getDate()}`.padStart(2, "0")}T${endTimeString}`; + } + if (startDate) startDateString = startDate.toISOString(); + if (endDate) endDateString = endDate.toISOString(); + + const queryData = await elasticsearch.search({ + index: ELASTICSEARCH_INDEX, + query: { + bool: { + must: [ + ...(systemName ? [{ match: { systemName } }] : []), + ...(rootId ? [{ match: { rootId } }] : []), + ...(search + ? [ + { + bool: { + should: [ + ...[ + "method", + "endpoint", + "host", + "responseCode", + "output", + "rootId", + ].map((v) => ({ + wildcard: { [`${v}.keyword`]: `*${search}*` }, + })), + {term: {_id: search}}, + ], + }, + }, + ] + : []), + ...(searchId + ? [ + { + term: { + _id: searchId, + }, + }, + ] + : []), + ...(searchStatus + ? [ + { + bool: { + should: [ + "logType", + ].map((v) => ({ + wildcard: { [v]: "*" + searchStatus + "*" }, + })), + }, + }, + ] + : []), + ...(startDateString || endDateString + ? [ + { + range: { + startTimeStamp: { + time_zone: timezone, + gte: startDateString, + lte: endDateString, + }, + }, + }, + ] + : []), + ], + }, + }, + sort: [{ startTimeStamp: sort }], + }); + interface DocumentSource { + startTimeStamp: Date; + userName: string; + host: string; + endpoint: string; + method: string; + responseCode: string; + logType: string; + responseDescription: string; + } + const raw_data = queryData.hits.hits.map((x) => { + const source = x._source as DocumentSource; + return { + id: x._id, + startTimeStamp: source.startTimeStamp, + userName: source.userName, + host: source.host, + endpoint: source.endpoint, + method: source.method, + responseCode: source.responseCode, + logType: source.logType, + responseDescription: source.responseDescription, + }; + }); + const meta_data ={ + // systemName: systemName, + list: raw_data, + } + return ({ + template: "logs_list", + reportName: "xlsx-report", + data: meta_data, + }); + } + + @Get("detail") + async reportDetail( + @Query() id?: string, + ) { + const queryData = await elasticsearch.search({ + index: ELASTICSEARCH_INDEX, + query: { + bool: { + must: [ ...(id ? [{term: {_id: id}} ] : []) ], + }, + }, + }); + interface DocumentSource { + startTimeStamp: Date; + userName: string; + host: string; + endpoint: string; + method: string; + responseCode: string; + logType: string; + responseDescription: string; + input: string; + output: string; + sequence: string[]; + } + const lists = queryData.hits.hits.map((x) => { + const source = x._source as DocumentSource; + return { + id: x._id, + startTimeStamp: source.startTimeStamp, + userName: source.userName, + host: source.host, + endpoint: source.endpoint, + method: source.method, + responseCode: source.responseCode, + logType: source.logType, + responseDescription: source.responseDescription, + input: source.input, + output: source.output, + sequence: source.sequence + }; + }); + + return ({ + template: "logs_detail", + reportName: "xlsx-report", + data: lists, + }); + } +}