콘텐츠로 이동

로그 정책 (Logging Policy)

문서 역할

  • 역할: 규범
  • 문서 종류: policy
  • 충돌 시 우선 문서: 로그 레벨·형식·운영 INFO 허용 범위는 이 문서, 개인정보 분류·마스킹은 데이터 거버넌스 정책
  • 기준 성격: as-is

목적

개발 로그와 운영 로그를 명확히 분리하여 디버깅 효율성을 높이고, 운영 환경에서 불필요한 로그로 인한 성능 저하 및 보안 이슈를 방지한다.


기본 원칙

0. API 실패 로그

  • API 실패 응답 계약과 상관관계 필드는 API 에러 계약 정책을 단일 SoT(단일 기준)로 따른다.
  • API 실패 로그는 error_source, error_code를 함께 남긴다.
  • request_idErrorData.request_id와 같은 값을 남기고, error_source, error_code와 같은 로그 이벤트에서 확인할 수 있어야 한다.
  • 로그 정책은 출력 레벨, 민감정보 제외, 저장/전송 방식만 다룬다.

1. 환경 분리

Backend (coupler-api)

// 개발 로그
if (process.env.NODE_ENV === "development") {
  console.log("[ModuleName] debug summary:", debugSummary);
}

// 운영 로그 (에러, 경고만)
console.error("[ModuleName] error:", safeError);
console.warn("[ModuleName] warning:", safeWarning);

Frontend (coupler-mobile-app, coupler-admin-web)

// 개발 로그
if (__DEV__) {
  console.log("[ComponentName] debug summary:", debugSummary);
}

// 운영 로그 (에러만, 모니터링 시스템으로 전송)
console.error("[ComponentName] error:", safeError);

2. 로그 레벨 구분

레벨 용도 개발 환경 운영 환경
DEBUG 상세 디버깅 정보
INFO 일반 정보성 로그 ⚠️ 최소화
WARN 경고 (복구 가능한 이슈)
ERROR 에러 (복구 불가능한 이슈)

로그 형식 규칙

로그 메시지 포맷

[ModuleName] key: value

가독성 원칙

  • 태그는 대괄호 [ModuleName]로 시작
  • 키-값 쌍은 콜론(:) 구분
  • 여러 값은 쉼표로 구분하지 말고 별도 로그로 분리
  • 객체/배열은 자동 포맷팅 활용 (JSON.stringify 지양)

좋은 예

// ✅ 명확하고 읽기 쉬운 형식
console.log("[uploadImages] type:", uploadType);
console.log("[uploadImages] files count:", req.files.length);
console.log("[SignupScreen] selected images count:", images.length);
console.error("[auth.js] signup failed:", safeErrorMessage);

// ✅ 여러 값은 별도 로그로 분리
if (__DEV__) {
  console.log("[Step3] next count:", nextList.length);
  console.log("[Step3] filtered count:", filtered.length);
  console.log("[Step3] can proceed:", canProceed);
}

나쁜 예

// ❌ 태그 없음
console.log("type", uploadType);

// ❌ 불명확한 메시지
console.log("디버그:", debugSummary);

// ❌ 여러 값을 한 줄에 섞음 (가독성 저하)
console.log(
  "[Step3] nextList:",
  nextList.length,
  "filtered count:",
  filtered.length,
  "can proceed:",
  canProceed,
);

// ❌ JSON.stringify 남용 (자동 포맷팅이 더 읽기 쉬움)
console.log("[Step3] summary:", JSON.stringify(debugSummary));

Convention

모듈명 표기

  • Backend 함수: [functionName] (예: [uploadImages], [signup])
  • Frontend 컴포넌트: [ComponentName] (예: [SignupScreen], [Step3])
  • 유틸리티/라이브러리: [ModuleName] (예: [review-image], [APIUtils])

일관성 유지

  • 같은 모듈 내에서는 동일한 태그 사용
  • 키 이름은 변수명과 일치시키기
  • 순서: 입력 파라미터 → 중간 결과 → 최종 결과

개발 로그 예시

Backend 예시

exports.uploadImages = async (req, res) => {
  if (process.env.NODE_ENV === "development") {
    console.log("[uploadImages] files count:", req.files.length);
  }

  // 비즈니스 로직...
};

Frontend (Mobile/Web)

const handleSubmit = () => {
  if (__DEV__) {
    console.log("[SignupScreen] submit started");
  }

  // API 호출...
};

운영 로그 예시

에러만 기록 (항상 표시)

try {
  await someOperation();
} catch (error) {
  console.error("[ModuleName] operation failed:", {
    request_id: requestId,
    error_source: "MODULE_NAME",
    error_code: "MODULE_OPERATION_FAILED",
    message: safeErrorMessage,
    stack: sanitizedStack,
    context: safeContext,
  });
}

금지 사항

❌ 개인정보/민감정보 로깅 금지

개발·운영 환경 모두 개인정보 분류와 마스킹은 데이터 거버넌스 정책을 따른다. 개발 환경은 원문 식별자와 개인정보 로깅의 예외가 아니다.

// ❌ 절대 금지
console.log("User password:", user.pwd);
console.log("Card number:", payment.card_number);
console.log("User email:", user.email);
console.log("User ID:", user.id);

// ✅ 허용
console.log("User ID:", maskedUserId);
console.log("User email:", maskedEmail);
console.log("Payment status:", payment.status);

❌ 과도한 반복 로그 금지

// ❌ 금지 (루프 내부)
for (let i = 0; i < 1000; i++) {
  console.log("Processing item:", i);
}

// ✅ 허용
if (__DEV__) {
  console.log("Processing items, count:", items.length);
}
// 처리 후 요약 로그
console.log("Processed items:", successCount, "success,", failCount, "failed");

❌ 무분별한 객체 로깅 금지

// ❌ 금지 (너무 큰 객체)
console.log("Entire state:", GlobalState);

// ✅ 허용 (필요한 부분만)
if (__DEV__) {
  console.log("User profile images count:", GlobalState.me.profile.profile_image_paths.length);
}

로그 색인 (Log Indexing)

주요 모듈별 로그 태그

Backend 로그 태그

[auth.js]       - 인증 관련
[member.js]     - 회원 관리
[upload.js]     - 파일 업로드
[review-image]  - 이미지 심사
[APIUtils]      - API 유틸리티

Frontend 로그 태그

[SignupScreen]          - 회원가입
[ProfilePreviewScreen]  - 프로필 미리보기
[MatchingTab]           - 매칭 탭
[APIUtils]              - API 호출
[GlobalState]           - 전역 상태

검색 팁

특정 모듈 로그만 필터링:

# Backend
NODE_ENV=development node app.js | grep '\[uploadImages\]'

# Frontend (Metro bundler)
# Cmd/Ctrl + F: [SignupScreen]

운영 환경 로그 관리

Backend

  • 에러 로그: console.error로 기록, 필요 시 모니터링 시스템 연동
  • 접근 로그: Express 미들웨어 사용
  • 비즈니스 로그: 최소화, 필요 시 DB에 별도 저장

Frontend

  • 에러 로그: console.error로 기록, 필요 시 모니터링 시스템 연동
  • console.log: 번들에서 자동 제거 (Babel plugin 또는 Terser 설정)

체크리스트

로그 추가 시 다음을 확인:

  • [ ] 개발 환경 조건 (__DEV__ 또는 NODE_ENV === 'development') 사용했는가?
  • [ ] 로그 메시지에 모듈/컴포넌트명 포함했는가?
  • [ ] 개인정보/민감정보가 포함되지 않았는가?
  • [ ] 운영 환경에 필요한 로그인가? (에러/경고만 허용)
  • [ ] API 실패 로그라면 request_id, error_source, error_code가 함께 남는가?
  • [ ] 반복 로그가 아닌가? (루프 외부로 이동 또는 요약)

예외 상황

다음 경우에만 운영 환경에서 INFO 로그 허용:

  1. 중요 비즈니스 이벤트: 회원가입 완료, 결제 완료 등
  2. 서버 시작/종료: 서버 부팅, graceful shutdown
  3. 스케줄러 실행: Cron 작업 시작/종료 (성공/실패 결과만)
// 허용되는 운영 INFO 로그 예시
console.log("[app.js] Server started on port:", PORT);
console.log("[cron.js] Daily cleanup completed:", { deleted: count });
console.log("[auth.js] User signup completed:", { timestamp });