브라우저 콘솔에서 사용자 식별자 가림, 세션 로그는 원본 유지

마지막 업데이트 2026-10-12

42c849f7 charles-na · 2026-10-12 Fix 13 files +297 −119

PR #1160 (PPI-1361). F12 콘솔에 아동 userId, 그리고 userId가 들어 있는 roomId·게스트 peerId가 그대로 찍히던 문제를 막습니다. logger.js가 콘솔로 보내는 사본에서만 식별자를 [HIDDEN]으로 바꾸고, S3 세션 로그 싱크에는 원본을 넘깁니다. 리뷰할 때는 logger.js에서 출력이 갈라지는 지점과, 메시지 템플릿에 식별자를 넣던 59곳을 data 필드로 옮긴 부분을 먼저 보면 됩니다.

무엇이, 왜 바뀌었나

지금까지 logger.js는 토큰·쿠키 같은 인증정보만 가리고 식별자는 일부러 남겼습니다(logger-privacy.test.js가 이 동작을 테스트로 고정). 장애 분석에는 식별자가 꼭 필요하지만, 브라우저 콘솔은 누구나 열 수 있습니다. 그래서 출력 채널을 둘로 나눴습니다.

흐름 — 로그 한 줄이 두 갈래로 나뉨

1

호출처: logger.info(msg, { roomId, peerId, ... })

use-monitor-session.ts 외 11파일

2

sanitizeLogValue: 인증정보 REDACTED (기존 그대로)

packages/shared/src/utils/logger.ts

3a

콘솔(F12, LogRocket 캡처): hideIdentifiersForConsole 사본 → [HIDDEN]

apps/web/logger.js:91

3b

세션 로그 싱크 → S3: 원본 serialized

apps/web/logger.js:117

코드로 보는 핵심 지점

1. 콘솔용 사본에서만 가림

apps/web/logger.js const CONSOLE_HIDDEN_KEY_PATTERN = /(userId|childId|roomId|peerId)$|^(phone|displayName|participantName)$/i; function shouldHideForConsole(key, value) { return CONSOLE_HIDDEN_KEY_PATTERN.test(key) && (typeof value === "string" || typeof value === "number"); } const args = serialized !== undefined ? [serialized] : []; const args = serialized !== undefined ? [hideIdentifiersForConsole(serialized)] : []; ... logSink({ ts, level, ctx, msg: safeMessage, data: serialized }); // 원본

2. 메시지 보간 → data 필드

apps/web/entities/monitor-session/model/use-monitor-session.ts console.log(`[Monitor][${roomId}] Processing peer-joined`, { logger.info("[Monitor] Processing peer-joined", { roomId, joinedPeerId,

3. 보호자 전화번호 로그

apps/web/app/monitor-dashboard/[group]/[roomId]/page.tsx console.log("[handleSendAlimtalk] 요청 파라미터:", { logger.info("[handleSendAlimtalk] 요청 파라미터", { channelId: template.channelId, templateCode: template.templateCode, phone,

레이어별 변경 요약

레이어파일핵심 변경
loggerapps/web/logger.js콘솔 출력 사본만 식별자 마스킹, 싱크는 원본
테스트apps/web/logger-privacy.test.js콘솔에는 없고 싱크에는 있음을 확인하는 케이스 추가(중첩·boolean 포함)
모니터 세션entities/monitor-session/model/use-monitor-session.ts30곳을 logger + data로 전환, transcript 응답 전체 덤프 로그 제거
mediasouphooks/mediasoup/use-mediasoup-consumer.ts, use-mediasoup-producer.tspeerId·roomId 보간 23곳을 data 필드로
모니터 기능page.tsx, session-card, use-advance-step, use-session-registration, auto-response/transition, log-intervention, use-audio-streamsconsole.* → logger (logger가 없던 5개 파일은 createLogger 추가)

리뷰 관전 포인트

동작 확인

LogRocket이 콘솔을 캡처하므로 LogRocket 콘솔에서도 식별자가 [HIDDEN]으로 보입니다. 세션은 identifyUser로 찾을 수 있지만, 식별자로 대조해야 할 때는 S3 세션 로그를 봐야 합니다.

개인정보

보호자 전화번호가 이제 S3 세션 로그에 저장됩니다. 콘솔에서는 가려지지만, S3에도 남길 필요가 없다면 해당 로그에서 phone 필드를 빼야 합니다.

수집량

기존에 console.log였던 모니터·consumer 로그가 logger.info가 되면서 세션 로그 수집에 새로 들어갑니다(기본 minLevel=debug). 특히 Monitor existingProducers는 바뀔 때마다 찍힙니다.

한계

key 이름 기반입니다. peerIds 같은 복수형 배열 키나 다른 이름의 메시지 보간은 가리지 못하고, logger를 거치지 않는 라이브러리 console 출력도 대상이 아닙니다.

검증

node --test logger-privacy.test.js 4/4 통과, tsc 신규 에러 없음. vitest 실패 26건은 develop에서도 똑같이 나서 이 PR과 무관하고, 같은 이유로 Stryker 뮤테이션 테스트는 시작 단계에서 막혔습니다. 실제 브라우저와 S3 반영은 확인하지 않았습니다.

관련 문서

관련 문서: 세션 로그 시스템 코드 레벨 동작 흐름 — 원본이 남는 S3 세션 로그 싱크의 구조

관련 문서: ICE 연결 실패 진단 로그 공통 계측 — logger 출력이 LogRocket 콘솔과 S3 수업 로그로 함께 가는 선례