summaryrefslogtreecommitdiff
path: root/lib/integration-log/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/integration-log/service.ts')
-rw-r--r--lib/integration-log/service.ts317
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