구조화 로거 — Cloud Logging 자동 파싱
소스: apps/web/lib/logging/logger.ts
왜 JSON 구조화인가
Cloud Run 은 stdout/stderr 의 JSON 라인 을 자동으로 파싱해 Cloud Logging 의 jsonPayload 필드로 정리. severity 필드가 있으면 로그 레벨로 인식되어 Grafana·Logs Explorer 에서 severity=ERROR 쿼리·Alerting 가능. 평문 console.error("...") 는 textPayload 로만 남아 필터가 어렵다.
→ Day 0 부터 JSON 구조화 적용. SDK 불필요.
API
import { logInfo, logWarn, logError } from "@/lib/logging/logger";
logInfo("event.name", { ...context });
logWarn("event.name", { ...context });
logError("event.name", { ...context });
출력 포맷 (예):
{
"severity": "ERROR",
"event": "ai.refund.failed",
"timestamp": "2026-04-20T09:15:33.241Z",
"context": {
"reason": "upstream_5xx",
"tenantId": "abc123",
"weight": 3
}
}
규약
event 이름
- 짧고 검색 가능한 키 (예:
"ai.refund","portal-token.stale","embedding.stale") - dot 또는 hyphen 으로 구분. 공백·CamelCase 금지
- 같은 계열은 공통 prefix 로 묶기 (
ai.*,portal-token.*)
context 필드
- PII 포함 금지 — 사용자 입력·본문·이메일·전화 등 원문 직접 금지. ID·카운트·태그만
- Firestore 경로·리소스 ID 는 OK (로그 필터 용)
- 자유 형식
Record<string, unknown>— 필드명 통일은 이벤트별 문서화 - 중첩 객체·배열 직렬화 OK (JSON.stringify 기준)
Severity 선택
| 레벨 | 언제 | 예시 |
|---|---|---|
INFO | 필수가 아닌 관찰 | "user.session.created" · "dashboard.cache.hit" |
WARNING | 비치명적 이상, 재시도 가능 | "embedding.stale" · "ai.retryable-5xx" |
ERROR | 사용자 영향 있는 실패 | "ai.refund.failed" · "plan.enforce.violation" |
마이그레이션 (점진적)
현행
} catch (err) {
console.error("[ai-client] 전략 보고서 생성 실패:", err);
}
개선 (신규 코드부터 적용)
import { logError } from "@/lib/logging/logger";
} catch (err) {
logError("ai.strategy-report.failed", {
tenantId,
caseId,
errorName: err instanceof Error ? err.name : "Unknown",
errorMessage: err instanceof Error ? err.message : String(err),
});
}
기존 console.error 전수 교체는 별도 PR 로 분리. Phase 0 동안은 신규 코드에만 강제.
Anti-Pattern
- ❌
console.error("foo", err)— 평문, Cloud Logging 파싱 실패 - ❌
logError("foo", { body: req.body })— PII 위험 (원문 포함) - ❌
logError("AI failed", { ... })— 공백·대문자 이벤트명."ai.failed"로 - ❌ 에러 객체 자체를
context.err = err로 넣기 — JSON 직렬화가 Error 인스턴스를 빈{}로 만듦.err.message/err.name을 풀어 전달
관련
- 멀티테넌트 격리 (guarded-query)
apps/web/lib/ai/execute-ai-action.ts(기존 로깅 대상)