diff options
Diffstat (limited to 'lib/integration-log/service.ts')
| -rw-r--r-- | lib/integration-log/service.ts | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/lib/integration-log/service.ts b/lib/integration-log/service.ts new file mode 100644 index 00000000..e42fcfde --- /dev/null +++ b/lib/integration-log/service.ts @@ -0,0 +1,317 @@ +"use server"; + +import db from "@/db/db"; +import { integrationLogTable } from "@/db/schema/integration-log"; +import { integrations } from "@/db/schema/integration"; +import { eq } from "drizzle-orm"; +import { GetIntegrationLogsSchema } from "./validations"; +import { filterColumns } from "@/lib/filter-columns"; +import { asc, desc, ilike, and, or, count } from "drizzle-orm"; +import { NewIntegrationLog } from "@/db/schema/integration-log"; + +/* ----------------------------------------------------- + 1) 통합 로그 목록 조회 +----------------------------------------------------- */ +export async function getIntegrationLogs(input: GetIntegrationLogsSchema) { + try { + const offset = (input.page - 1) * input.perPage; + + // 1. where 절 + let advancedWhere; + try { + advancedWhere = filterColumns({ + table: integrationLogTable, + filters: input.filters, + joinOperator: input.joinOperator, + }); + } catch (whereErr) { + console.error("Error building advanced where:", whereErr); + advancedWhere = undefined; + } + + let globalWhere; + if (input.search) { + try { + const s = `%${input.search}%`; + globalWhere = or( + ilike(integrationLogTable.status, s), + ilike(integrationLogTable.errorMessage, s), + ilike(integrationLogTable.requestUrl, s), + ilike(integrationLogTable.requestMethod, s) + ); + } catch (searchErr) { + console.error("Error building search where:", searchErr); + globalWhere = undefined; + } + } + + // 2. where 결합 + let finalWhere; + const whereArr = [advancedWhere, globalWhere].filter(Boolean); + if (whereArr.length === 2) { + finalWhere = and(...whereArr); + } else if (whereArr.length === 1) { + finalWhere = whereArr[0]; + } else { + finalWhere = undefined; + } + + // 3. order by + let orderBy = [desc(integrationLogTable.executionTime)]; + try { + if (input.sort.length > 0) { + const sortItems = input.sort + .map((item) => { + if (!item || !item.id || typeof item.id !== "string") return null; + + // 기본 정렬 컬럼들만 허용 + switch (item.id) { + case "id": + return item.desc ? desc(integrationLogTable.id) : asc(integrationLogTable.id); + case "integrationId": + return item.desc ? desc(integrationLogTable.integrationId) : asc(integrationLogTable.integrationId); + case "executionTime": + return item.desc ? desc(integrationLogTable.executionTime) : asc(integrationLogTable.executionTime); + case "status": + return item.desc ? desc(integrationLogTable.status) : asc(integrationLogTable.status); + case "responseTime": + return item.desc ? desc(integrationLogTable.responseTime) : asc(integrationLogTable.responseTime); + case "errorMessage": + return item.desc ? desc(integrationLogTable.errorMessage) : asc(integrationLogTable.errorMessage); + case "httpStatusCode": + return item.desc ? desc(integrationLogTable.httpStatusCode) : asc(integrationLogTable.httpStatusCode); + case "retryCount": + return item.desc ? desc(integrationLogTable.retryCount) : asc(integrationLogTable.retryCount); + case "requestMethod": + return item.desc ? desc(integrationLogTable.requestMethod) : asc(integrationLogTable.requestMethod); + case "requestUrl": + return item.desc ? desc(integrationLogTable.requestUrl) : asc(integrationLogTable.requestUrl); + case "ipAddress": + return item.desc ? desc(integrationLogTable.ipAddress) : asc(integrationLogTable.ipAddress); + case "userAgent": + return item.desc ? desc(integrationLogTable.userAgent) : asc(integrationLogTable.userAgent); + case "sessionId": + return item.desc ? desc(integrationLogTable.sessionId) : asc(integrationLogTable.sessionId); + case "correlationId": + return item.desc ? desc(integrationLogTable.correlationId) : asc(integrationLogTable.correlationId); + case "createdAt": + return item.desc ? desc(integrationLogTable.createdAt) : asc(integrationLogTable.createdAt); + default: + return null; + } + }) + .filter((v): v is Exclude<typeof v, null> => v !== null); + + if (sortItems.length > 0) { + orderBy = sortItems; + } + } + } catch (orderErr) { + console.error("Error building order by:", orderErr); + } + + // 4. 쿼리 실행 + let data = []; + let total = 0; + + try { + const queryBuilder = db.select({ + id: integrationLogTable.id, + integrationId: integrationLogTable.integrationId, + executionTime: integrationLogTable.executionTime, + status: integrationLogTable.status, + responseTime: integrationLogTable.responseTime, + errorMessage: integrationLogTable.errorMessage, + httpStatusCode: integrationLogTable.httpStatusCode, + retryCount: integrationLogTable.retryCount, + requestMethod: integrationLogTable.requestMethod, + requestUrl: integrationLogTable.requestUrl, + ipAddress: integrationLogTable.ipAddress, + userAgent: integrationLogTable.userAgent, + sessionId: integrationLogTable.sessionId, + correlationId: integrationLogTable.correlationId, + createdAt: integrationLogTable.createdAt, + // 통합 정보 + code: integrations.code, + name: integrations.name, + type: integrations.type, + sourceSystem: integrations.sourceSystem, + targetSystem: integrations.targetSystem, + integrationStatus: integrations.status, + }) + .from(integrationLogTable) + .leftJoin(integrations, eq(integrationLogTable.integrationId, integrations.id)); + + if (finalWhere !== undefined) { + queryBuilder.where(finalWhere); + } + + if (orderBy && orderBy.length > 0) { + queryBuilder.orderBy(...orderBy); + } + if (typeof offset === "number" && !isNaN(offset)) { + queryBuilder.offset(offset); + } + if (typeof input.perPage === "number" && !isNaN(input.perPage)) { + queryBuilder.limit(input.perPage); + } + + data = await queryBuilder; + + const countBuilder = db + .select({ count: count() }) + .from(integrationLogTable); + + if (finalWhere !== undefined) { + countBuilder.where(finalWhere); + } + + const countResult = await countBuilder; + total = countResult[0]?.count || 0; + } catch (queryErr) { + console.error("Query execution failed:", queryErr); + throw queryErr; + } + + const pageCount = Math.ceil(total / input.perPage); + + return { data, pageCount }; + } catch (err) { + console.error("Error in getIntegrationLogs:", err); + if (err instanceof Error) { + console.error("Error message:", err.message); + console.error("Error stack:", err.stack); + } + return { data: [], pageCount: 0 }; + } +} + +/* ----------------------------------------------------- + 2) 통합 로그 상세 조회 +----------------------------------------------------- */ +export async function getIntegrationLogById(id: number) { + try { + const [result] = await db.select({ + id: integrationLogTable.id, + integrationId: integrationLogTable.integrationId, + executionTime: integrationLogTable.executionTime, + status: integrationLogTable.status, + responseTime: integrationLogTable.responseTime, + errorMessage: integrationLogTable.errorMessage, + httpStatusCode: integrationLogTable.httpStatusCode, + retryCount: integrationLogTable.retryCount, + requestMethod: integrationLogTable.requestMethod, + requestUrl: integrationLogTable.requestUrl, + ipAddress: integrationLogTable.ipAddress, + userAgent: integrationLogTable.userAgent, + sessionId: integrationLogTable.sessionId, + correlationId: integrationLogTable.correlationId, + createdAt: integrationLogTable.createdAt, + // 통합 정보 + code: integrations.code, + name: integrations.name, + type: integrations.type, + sourceSystem: integrations.sourceSystem, + targetSystem: integrations.targetSystem, + integrationStatus: integrations.status, + }) + .from(integrationLogTable) + .leftJoin(integrations, eq(integrationLogTable.integrationId, integrations.id)) + .where(eq(integrationLogTable.id, id)); + + return result; + } catch (err) { + console.error("Error getting integration log by id:", err); + return null; + } +} + +/* ----------------------------------------------------- + 3) 통합별 로그 조회 +----------------------------------------------------- */ +export async function getIntegrationLogsByIntegrationId(integrationId: number, limit: number = 50) { + try { + const data = await db.select({ + id: integrationLogTable.id, + integrationId: integrationLogTable.integrationId, + executionTime: integrationLogTable.executionTime, + status: integrationLogTable.status, + responseTime: integrationLogTable.responseTime, + errorMessage: integrationLogTable.errorMessage, + httpStatusCode: integrationLogTable.httpStatusCode, + retryCount: integrationLogTable.retryCount, + requestMethod: integrationLogTable.requestMethod, + requestUrl: integrationLogTable.requestUrl, + ipAddress: integrationLogTable.ipAddress, + userAgent: integrationLogTable.userAgent, + sessionId: integrationLogTable.sessionId, + correlationId: integrationLogTable.correlationId, + createdAt: integrationLogTable.createdAt, + }) + .from(integrationLogTable) + .where(eq(integrationLogTable.integrationId, integrationId)) + .orderBy(desc(integrationLogTable.executionTime)) + .limit(limit); + + return data; + } catch (err) { + console.error("Error getting integration logs by integration id:", err); + return []; + } +} + +/* ----------------------------------------------------- + 로그 저장 함수 추가 +----------------------------------------------------- */ +export async function createIntegrationLog(logData: NewIntegrationLog) { + try { + const [created] = await db.insert(integrationLogTable).values(logData).returning(); + return { data: created }; + } catch (err) { + console.error("Error creating integration log:", err); + return { error: "로그 저장 중 오류가 발생했습니다." }; + } +} + +/* ----------------------------------------------------- + Server Action: 외부에서 호출 가능한 로그 저장 함수 +----------------------------------------------------- */ + +export async function logIntegrationExecution(logData: { + integrationId: number; + status: 'success' | 'failed' | 'timeout' | 'pending'; + responseTime?: number; + errorMessage?: string; + httpStatusCode?: number; + requestMethod?: string; + requestUrl?: string; + ipAddress?: string; + userAgent?: string; + sessionId?: string; + correlationId?: string; + retryCount?: number; +}) { + try { + const logEntry: NewIntegrationLog = { + integrationId: logData.integrationId, + executionTime: new Date(), + status: logData.status, + responseTime: logData.responseTime || 0, + errorMessage: logData.errorMessage || null, + httpStatusCode: logData.httpStatusCode || null, + retryCount: logData.retryCount || 0, + requestMethod: logData.requestMethod || null, + requestUrl: logData.requestUrl || null, + ipAddress: logData.ipAddress || null, + userAgent: logData.userAgent || null, + sessionId: logData.sessionId || null, + correlationId: logData.correlationId || null, + }; + + const result = await createIntegrationLog(logEntry); + return result; + } catch (error) { + console.error("Error in logIntegrationExecution:", error); + return { error: "로그 저장에 실패했습니다." }; + } +}
\ No newline at end of file |
