오류를 찾으려다 요청 본문과 고객 메모까지 기록하면 진단 기록이 또 다른 자료 보관소가 된다. 로그를 자세히 남긴다는 말부터 다시 정할 필요가 있었다.

이번 예제는 실제 로그를 읽거나 수집하지 않는다. 새 합성 error_record 함수에서 기록할 수 있는 필드를 제한하고 허용하지 않은 입력이 통과하지 않는지 확인했다.

예외 문장을 그대로 받지 않기로 했다

함수는 code, operation과 trace_id만 받는다. message나 request_body 같은 자유 입력 통로를 두지 않았다. 예외 문장을 다 받은 뒤 특정 패턴을 지우는 방식보다 처음부터 기록할 내용을 좁힌 것이다. 새 형식이 필요한 경우는 함수의 계약과 검토를 바꿔야 하며 임의의 추가 메타데이터로 우회하지 않는다.

이 선택만으로 프로그램 전체가 안전해지지는 않는다. 다른 처리기가 예외 전문을 별도로 출력하거나 인프라가 요청을 저장할 수 있다. 이번 검사는 한 구조화 기록 함수의 출력 경계다. 실제 서비스를 연결할 때는 서버 로그, 중간 계층과 외부 수집 설정도 확인해야 한다. 작은 함수의 허용 목록을 전체 로그 보안 감사로 보고하지 않는다.

오류 코드와 작업 이름을 고정했다

코드는 INVALID_INPUT, VERSION_CONFLICT, ACCESS_DENIED와 UNEXPECTED다. 작업 이름은 read, save와 preview로 제한한다. 실제 사용자의 입력 문장을 작업 이름으로 넘기면 거절한다. 오류의 종류와 어느 경계에서 생겼는지를 알되 거래 내용 자체는 담지 않는 방향으로 구성했다.

이 네 종류가 모든 서비스에 충분하다는 뜻은 아니다. 필요한 구분을 더할 때는 운영자가 어떤 판단을 해야 하는지 먼저 생각하면 좋다. 오류 이름을 많이 만드는 것만으로 원인을 설명할 수는 없다. 이번 예제는 재현 가능한 분류와 제한된 출력의 관계를 검사하며 실제 장애의 원인을 자동 판별하지 않는다.

추적 ID도 자유로운 메모칸이 아니다

trace_id는 ASCII 식별자 형식과 40자 한도로 검사한다. 이메일처럼 보이는 문장이나 경로를 넣는 자유 메모칸으로 사용하지 않는다. 실제 시스템에서는 서버가 만든 불투명한 추적 값을 써야 한다. 이번 모듈은 형식을 확인하지만 추적 ID의 생성이나 여러 서비스 간 전달은 구현하지 않았다.

형식만 맞는 문자열에 회사 정보를 의도적으로 넣으면 그 의미를 알아서 지울 수는 없다. 그러므로 호출자의 규칙과 검토도 필요하다. 합성 테스트는 잘못된 문자의 거절과 허용 필드만 남는 결과를 확인한다. 이 함수가 모든 개인정보를 의미적으로 탐지해 지우는 도구라고 설명하지 않는다.

기록의 재시도 표시를 실행 명령으로 쓰지 않는다

출력에는 retry가 있으며 UNEXPECTED일 때만 참이다. 이것은 실제 재시도를 수행하지 않는 합성 분류다. 저장 작업의 결과를 모르는 상황에 무조건 다시 전송하면 중복 변경을 만들 수 있으므로 실제 재시도 정책은 요청 식별과 결과 재확인 계약을 먼저 봐야 한다.

특히 충돌과 권한 거절을 일반 장애처럼 반복하면 원래 해결할 조건이 보이지 않는다. 이번 예제는 오류를 숨기거나 모두 같은 빈 결과로 바꾸지 않는다. 실제 사용자 문구, 운영자 경고와 처리 경로는 연결할 서비스에서 정한다. 한 기록의 retry 값이 업무의 재실행 권한까지 뜻하지 않는다는 점을 명시했다.

진단 가능성과 보관 범위를 함께 정한다

테스트는 정확히 네 출력 키만 남는지와 message 인자를 추가하면 받지 않는지를 검사한다. 회귀 검사에서는 검토 뒤 버전 충돌을 고정 코드로 기록해도 새 초안을 지우지 않는 흐름을 함께 확인했다. 실제 회사의 예외 문장이나 요청 본문을 시험 자료로 사용하지 않았다.

현장에 적용하려면 기록 보관 기간, 열람 권한, 삭제 절차와 실제 오류 연결도 정해야 한다. 이번 모듈은 저장과 전송을 하지 않아 그런 운영 정책은 포함하지 않는다. 나는 비밀을 많이 모아야 좋은 진단이 된다는 전제 대신, 문제를 구별하는 최소 사실과 원래 자료를 분리하는 방법을 공개하고 싶었다.