Merge pull request '로그 수정' (#848) from dev into dev-deploy

Reviewed-on: #848
This commit is contained in:
ysCha 2026-05-14 14:40:02 +09:00
commit 33260796f7
2 changed files with 68 additions and 6 deletions

View File

@ -10,6 +10,8 @@ import Header from '@/components/header/Header'
import QModal from '@/components/common/modal/QModal'
import PopupManager from '@/components/common/popupManager/PopupManager'
import ErrorBoundary from '@/components/common/ErrorBoundary'
import PageTracker from '@/components/common/PageTracker' // [PAGE-TRACKER 2026-05-14] 라우트 변경 시 콘솔/탭타이틀에 경로 표시
import ModalTracker from '@/components/common/ModalTracker' // [MODAL-TRACKER 2026-05-14] 모달/팝업 open·close 추적
import './globals.css'
import '../styles/style.scss'
@ -73,6 +75,8 @@ export default async function RootLayout({ children }) {
<ErrorBoundary>
<html lang="en">
<body>
<PageTracker />
<ModalTracker />
{headerPathname === '/login' || headerPathname === '/join' ? (
<QcastProvider>{children}</QcastProvider>
) : (

View File

@ -1,30 +1,88 @@
// utils/logger.js
const isLoggingEnabled = process.env.NEXT_PUBLIC_ENABLE_LOGGING;
// [LOGGER-CALLER 2026-05-14] stack 에서 logger.js 이외의 첫 frame 을 추출해 prefix 로 붙임.
// 페이지/hook/컴포넌트 어디서 찍힌 로그인지 콘솔에서 즉시 식별 가능. webpack chunk 매칭 위해 파일명만 추출.
const FILE_LINE_RE = /([\w\-\.]+\.(?:jsx?|tsx?)):(\d+)/
// [LOGGER-FORMAT 2026-05-14] 통일 포맷: [HH:mm:ss.SSS] [LEVEL] [caller] <message>
// 레벨별 색상 배지로 콘솔에서 한눈에 구분.
const STYLE_TS = 'color:#888'
const STYLE_CALLER = 'color:#888;font-style:italic'
const STYLE_LEVEL = {
log: 'background:#616161;color:#fff;padding:1px 6px;border-radius:2px;font-weight:bold',
info: 'background:#1e88e5;color:#fff;padding:1px 6px;border-radius:2px;font-weight:bold',
warn: 'background:#fb8c00;color:#fff;padding:1px 6px;border-radius:2px;font-weight:bold',
error: 'background:#e53935;color:#fff;padding:1px 6px;border-radius:2px;font-weight:bold',
debug: 'background:#8e24aa;color:#fff;padding:1px 6px;border-radius:2px;font-weight:bold',
}
function formatTime() {
const d = new Date()
const hh = String(d.getHours()).padStart(2, '0')
const mm = String(d.getMinutes()).padStart(2, '0')
const ss = String(d.getSeconds()).padStart(2, '0')
const ms = String(d.getMilliseconds()).padStart(3, '0')
return `${hh}:${mm}:${ss}.${ms}`
}
function getCallerTag() {
try {
const stack = new Error().stack
if (!stack) return ''
const lines = stack.split('\n')
for (let i = 1; i < lines.length; i++) {
const m = lines[i].match(FILE_LINE_RE)
if (m && m[1] !== 'logger.js') return `${m[1]}:${m[2]}`
}
} catch (_) {}
return ''
}
function emit(level, args) {
const ts = formatTime()
const caller = getCallerTag()
const levelStyle = STYLE_LEVEL[level] || STYLE_LEVEL.log
const levelLabel = level.toUpperCase()
// prefix: '[ts] %cLEVEL%c [caller] ' → styled level + dimmed caller
// user 첫 인자가 string 이면 prefix 와 합쳐 %c 호환 유지.
const prefixText = caller
? `%c[${ts}] %c${levelLabel}%c [${caller}]`
: `%c[${ts}] %c${levelLabel}%c`
const prefixStyles = [STYLE_TS, levelStyle, STYLE_CALLER]
if (typeof args[0] === 'string') {
console[level](`${prefixText} ${args[0]}`, ...prefixStyles, ...args.slice(1))
} else {
console[level](prefixText, ...prefixStyles, ...args)
}
}
export const logger = {
log: (...args) => {
if (isLoggingEnabled) {
console.log(...args);
emit('log', args);
}
},
error: (...args) => {
// 에러는 항상 로깅하거나, 또는 환경에 따라 다르게 처리
console.error(...args);
emit('error', args);
// 운영 환경에서는 서버로 에러를 보내는 코드를 추가할 수도 있음
},
warn: (...args) => {
if (isLoggingEnabled) {
console.warn(...args);
emit('warn', args);
}
},
info: (...args) => {
if (isLoggingEnabled) {
console.info(...args);
emit('info', args);
}
},
debug: (...args) => {
if (isLoggingEnabled) {
console.debug(...args);
emit('debug', args);
}
}
};