로그 수정
This commit is contained in:
parent
ccca89fef6
commit
281d9bb583
@ -10,6 +10,8 @@ import Header from '@/components/header/Header'
|
|||||||
import QModal from '@/components/common/modal/QModal'
|
import QModal from '@/components/common/modal/QModal'
|
||||||
import PopupManager from '@/components/common/popupManager/PopupManager'
|
import PopupManager from '@/components/common/popupManager/PopupManager'
|
||||||
import ErrorBoundary from '@/components/common/ErrorBoundary'
|
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 './globals.css'
|
||||||
import '../styles/style.scss'
|
import '../styles/style.scss'
|
||||||
@ -73,6 +75,8 @@ export default async function RootLayout({ children }) {
|
|||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
|
<PageTracker />
|
||||||
|
<ModalTracker />
|
||||||
{headerPathname === '/login' || headerPathname === '/join' ? (
|
{headerPathname === '/login' || headerPathname === '/join' ? (
|
||||||
<QcastProvider>{children}</QcastProvider>
|
<QcastProvider>{children}</QcastProvider>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -1,30 +1,88 @@
|
|||||||
// utils/logger.js
|
// utils/logger.js
|
||||||
const isLoggingEnabled = process.env.NEXT_PUBLIC_ENABLE_LOGGING;
|
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 = {
|
export const logger = {
|
||||||
log: (...args) => {
|
log: (...args) => {
|
||||||
if (isLoggingEnabled) {
|
if (isLoggingEnabled) {
|
||||||
console.log(...args);
|
emit('log', args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: (...args) => {
|
error: (...args) => {
|
||||||
// 에러는 항상 로깅하거나, 또는 환경에 따라 다르게 처리
|
// 에러는 항상 로깅하거나, 또는 환경에 따라 다르게 처리
|
||||||
console.error(...args);
|
emit('error', args);
|
||||||
// 운영 환경에서는 서버로 에러를 보내는 코드를 추가할 수도 있음
|
// 운영 환경에서는 서버로 에러를 보내는 코드를 추가할 수도 있음
|
||||||
},
|
},
|
||||||
warn: (...args) => {
|
warn: (...args) => {
|
||||||
if (isLoggingEnabled) {
|
if (isLoggingEnabled) {
|
||||||
console.warn(...args);
|
emit('warn', args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
info: (...args) => {
|
info: (...args) => {
|
||||||
if (isLoggingEnabled) {
|
if (isLoggingEnabled) {
|
||||||
console.info(...args);
|
emit('info', args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
debug: (...args) => {
|
debug: (...args) => {
|
||||||
if (isLoggingEnabled) {
|
if (isLoggingEnabled) {
|
||||||
console.debug(...args);
|
emit('debug', args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user