73 lines
2.9 KiB
TypeScript
73 lines
2.9 KiB
TypeScript
import type { RenderResponse } from 'nitropack'
|
|
import type { H3Event } from 'h3'
|
|
import { defineNitroPlugin } from 'nitropack/runtime'
|
|
import { getTrueClientIp } from '#layers/utils/apiUtil'
|
|
|
|
function generateRequestId(): string {
|
|
return Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
}
|
|
|
|
function getIpAddress(event: H3Event): string {
|
|
return getTrueClientIp(event.node.req as any) || 'unknown'
|
|
}
|
|
|
|
export default defineNitroPlugin(nitroApp => {
|
|
// 정적 파일 체크 함수 추가
|
|
const isStaticFile = (path: string): boolean => {
|
|
return /\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$/i.test(path)
|
|
}
|
|
|
|
// 헬스체크 경로 체크 함수 추가
|
|
const isHealthCheck = (path: string): boolean => {
|
|
return path === '/health' || path === '/api/healthz'
|
|
}
|
|
|
|
nitroApp.hooks.hook('request', event => {
|
|
// 정적 파일 요청은 로깅 제외
|
|
if (isStaticFile(event.path) || isHealthCheck(event.path)) {
|
|
return
|
|
}
|
|
// 상세 로깅을 위한 정보 수집
|
|
const startTime = Date.now()
|
|
const userAgent = event.node.req.headers['user-agent'] || ''
|
|
const method = event.method || ''
|
|
const headers = JSON.stringify(event.node.req.headers, null, 2)
|
|
const requestId = generateRequestId()
|
|
const domain = event.node.req.headers.host || 'unknown'
|
|
|
|
// if (process.env.NODE_ENV !== 'development') {
|
|
console.log(
|
|
`Request Info {"requestId":"${requestId}", "type":"request","method":"${method}","domain":"${domain}","url":"${event.path}","userIp":"${getIpAddress(event)}","userAgent":"${userAgent}", "headers" : "${headers}" }`
|
|
)
|
|
|
|
// 요청 완료 후 응답 상태 코드 로깅
|
|
event.node.res.on('finish', () => {
|
|
console.log(
|
|
`Response Info {"requestId":"${requestId}","type":"response","method":"${method}","domain":"${domain}","url":"${event.path}","statusCode":${event.node.res.statusCode},"responseTime":"${Date.now() - startTime}ms","userIp":"${getIpAddress(event)}","userAgent":"${userAgent}","statusMessage":"${event.node.res.statusMessage}","responseHeader": ${JSON.stringify(event.node.res.getHeaders(), null, 2)}}`
|
|
)
|
|
console.log(
|
|
'==========================================================================================================================================================================================================================================================='
|
|
)
|
|
})
|
|
// }
|
|
})
|
|
|
|
nitroApp.hooks.hook('error', error => {
|
|
console.error('[Nitro Error]', {
|
|
message: error.message,
|
|
stack: error.stack,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
})
|
|
|
|
// 응답 헤더에서 'x-powered-by' 제거
|
|
nitroApp.hooks.hook(
|
|
'render:response',
|
|
(response: Partial<RenderResponse>) => {
|
|
if (response?.headers) {
|
|
delete response.headers['x-powered-by']
|
|
}
|
|
}
|
|
)
|
|
})
|