// 스마트공장 활용 로그 전송 유틸리티 // https://log.smart-factory.kr 에 사용자 접속 로그를 전송 import axios from "axios"; import { logger } from "./logger"; import { query } from "../database/db"; const SMART_FACTORY_LOG_URL = "https://log.smart-factory.kr/apisvc/sendLogDataJSON.do"; /** * 스마트공장 활용 로그 전송 + DB 저장 * 로그인 성공 시 비동기로 호출하여 응답을 블로킹하지 않음 */ export async function sendSmartFactoryLog(params: { userId: string; userName?: string; remoteAddr: string; useType?: string; companyCode?: string; }): Promise { const now = new Date(); const logDt = formatDateTime(now); const useType = params.useType || "접속"; // 회사별 키 우선 조회, 없으면 공통 키 폴백 const apiKey = (params.companyCode && process.env[`SMART_FACTORY_API_KEY_${params.companyCode}`]) || process.env.SMART_FACTORY_API_KEY; if (!apiKey) { logger.warn( "SMART_FACTORY_API_KEY 환경변수가 설정되지 않아 스마트공장 로그 전송을 건너뜁니다." ); // SKIPPED 상태로 DB 기록 await saveLog({ companyCode: params.companyCode || "", userId: params.userId, userName: params.userName, useType, connectIp: params.remoteAddr, sendStatus: "SKIPPED", responseStatus: null, errorMessage: "API 키 미설정", logDt: now, }); return; } try { const logData = { crtfcKey: apiKey, logDt, useSe: useType, sysUser: params.userId, conectIp: params.remoteAddr, dataUsgqty: "", }; const encodedLogData = encodeURIComponent(JSON.stringify(logData)); const response = await axios.get(SMART_FACTORY_LOG_URL, { params: { logData: encodedLogData }, timeout: 5000, }); logger.info("스마트공장 로그 전송 완료", { userId: params.userId, status: response.status, }); // SUCCESS 상태로 DB 기록 await saveLog({ companyCode: params.companyCode || "", userId: params.userId, userName: params.userName, useType, connectIp: params.remoteAddr, sendStatus: "SUCCESS", responseStatus: response.status, errorMessage: null, logDt: now, }); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); // 스마트공장 로그 전송 실패해도 로그인에 영향 없도록 에러만 기록 logger.error("스마트공장 로그 전송 실패", { userId: params.userId, error: errorMsg, }); // FAIL 상태로 DB 기록 await saveLog({ companyCode: params.companyCode || "", userId: params.userId, userName: params.userName, useType, connectIp: params.remoteAddr, sendStatus: "FAIL", responseStatus: null, errorMessage: errorMsg, logDt: now, }); } } /** DB에 로그 저장 */ async function saveLog(params: { companyCode: string; userId: string; userName?: string; useType: string; connectIp: string; sendStatus: string; responseStatus: number | null; errorMessage: string | null; logDt: Date; }): Promise { try { await query( `INSERT INTO smart_factory_log (company_code, user_id, user_name, use_type, connect_ip, send_status, response_status, error_message, log_dt) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, [ params.companyCode, params.userId, params.userName || null, params.useType, params.connectIp, params.sendStatus, params.responseStatus, params.errorMessage, params.logDt, ] ); } catch (dbError) { // DB 저장 실패해도 로그인 프로세스에 영향 없도록 logger.error("스마트공장 로그 DB 저장 실패", { userId: params.userId, error: dbError instanceof Error ? dbError.message : dbError, }); } } /** yyyy-MM-dd HH:mm:ss.SSS 형식 */ function formatDateTime(date: Date): string { const y = date.getFullYear(); const M = String(date.getMonth() + 1).padStart(2, "0"); const d = String(date.getDate()).padStart(2, "0"); const H = String(date.getHours()).padStart(2, "0"); const m = String(date.getMinutes()).padStart(2, "0"); const s = String(date.getSeconds()).padStart(2, "0"); const ms = String(date.getMilliseconds()).padStart(3, "0"); return `${y}-${M}-${d} ${H}:${m}:${s}.${ms}`; }