import { Body, Controller, Get, Post, Query, Route, Security } from "tsoa"; import { Client as ElasticsearchClient } from "@elastic/elasticsearch"; import { match } from "assert"; 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") @Security("keycloak") export class LogController extends Controller { @Post() async Post( @Body() body: { size: number; search?: string; multiSearch?: string[]; searchAfter?: number; date?: Date; startDate?: Date; endDate?: Date; }, @Query() systemName?: string, @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 (body.date && !body.startDate && !body.endDate) { startDateString = `${body.date.getFullYear()}-${`${body.date.getMonth() + 1}`.padStart(2, "0")}-${`${body.date.getDate()}`.padStart(2, "0")}T${startTimeString}`; endDateString = `${body.date.getFullYear()}-${`${body.date.getMonth() + 1}`.padStart(2, "0")}-${`${body.date.getDate()}`.padStart(2, "0")}T${endTimeString}`; } if (body.startDate) startDateString = body.startDate.toISOString(); if (body.endDate) endDateString = body.endDate.toISOString(); const queryData = await elasticsearch.search({ index: ELASTICSEARCH_INDEX, query: { bool: { must: [ ...(systemName ? [{ match: { systemName } }] : []), ...(body.search ? [ { bool: { should: [ "method", "logType", "endpoint", "host", "responseCode", "output", ].map((v) => ({ wildcard: { [v]: "*" + body.search + "*" }, })), }, }, ] : []), ...(startDateString || endDateString ? [ { range: { startTimeStamp: { time_zone: timezone, gte: startDateString, lte: endDateString, }, }, }, ] : []), ...(body.multiSearch ? [ { bool: { should: body.multiSearch.map((v) => ({ match_phrase: { userId: v, }, })), }, }, ] : []), ], }, }, search_after: body.searchAfter ? [body.searchAfter] : undefined, sort: [{ startTimeStamp: sort }], size: body.size, }); return queryData.hits.hits; } }