로그 한 줄을 표로 옮길 때: 시각·코드·메시지와 추정 분리하기
장애 문의에 로그를 붙여 AI에게 정리해 달라고 했는데 “디스크를 늘리면 해결됩니다”라는 답이 나오면, 로그에 적힌 사실과 추정한 조치를 분리하세요. 먼저 시각·코드·메시지를 원문 그대로 표로 만들면 다른 로그와 비교하기 쉽습니다. 원인을 확정하려면 제품의 코드 문서와 추가 관찰이 필요합니다.

한 줄의 구조와 원문 보존 위치를 정합니다
이 실습의 로그는 시각, 코드, 나머지 메시지 순서입니다. 실제 서버에서 받은 로그가 아닌 가상 입력입니다. 세 줄의 정상 형식과 잘못된 시각 한 줄을 함께 준비했습니다.
L1 2026-10-04T09:15:00Z ERR-14 disk space low
L2 2026-10-04T09:16:00Z ERR-02 timeout
L3 2026-10-04T09:17:00Z OK-00 ready
L4 2026-10-04T25:18:00Z ERR-02 timeout
L1의 메시지는 disk space low이고, 원문에 “디스크 확장”이라는 조치나 확정된 근본 원인은 없습니다. L2의 timeout도 어디에서 어떤 제한 때문에 발생했는지 이 줄만으로 알 수 없습니다. 코드 ERR-14나 ERR-02의 뜻은 이 가상 제품의 공식 정의가 제공되지 않았으므로 메시지와 별도 보존합니다.
원본 로그는 변경 없이 보관하고, 공유용 사본은 조직 정책에 맞게 줄입니다. 사용자 이름, 파일 경로, 개인 정보, 접속 토큰이나 세션 값 등이 섞였는지 AI에 보내기 전에 확인하세요. 오류 부분이 사라지도록 로그 전체를 무작정 삭제하지 말고 필요한 줄·시각·코드와 허용한 문맥을 남깁니다.
복사할 로그 분리 요청문
아래 로그를 원문 기반 표로만 정리해 주세요.
각 줄의 ID와 원문을 보존하세요.
형식: 시각 / 코드 / 나머지 메시지
출력 열:
ID, 원문 시각, 확인한 시간대, 코드, 원문 메시지,
파싱 상태, 확인할 문제, 확정 원인
확정 원인은 이번 입력에 없으므로 비워 두세요.
메시지를 조치나 원인으로 바꾸지 마세요.
시간대가 없으면 KST나 UTC를 추정해서 붙이지 마세요.
잘못된 날짜·시각·형식은 보류표로 남기고 버리지 마세요.
원문 메시지는 먼저 보존하고 한국어 설명은 별도 열에 적으세요.
정상 결과의 메시지 세 칸은 disk space low, timeout, ready 그대로입니다. L4는 25시가 유효한 시각이 아니므로 보류해야 합니다. AI가 다음 날 01시로 자동 수정하면 원문에 없는 시각을 만들게 됩니다.
시각은 값과 시간대를 함께 확인합니다
Z는 UTC를 표시합니다. 따라서 L1의 09:15 UTC는 KST의 18:15에 해당합니다. 로그를 수집한 시각과 사건이 발생한 시각도 같다고 가정하지 마세요. OpenTelemetry 로그 데이터 모델은 사건의 Timestamp와 수집자가 관찰한 ObservedTimestamp를 구분합니다. 이 예제에 수집 시각은 없으므로 별도 값을 채우지 않습니다.
시간대를 바꿔 보여 주더라도 원문 시각 열은 유지하고 변환 열을 옆에 둡니다. 초 단위만 있는 로그를 밀리초 정밀도로 늘리거나, 시간대가 없는 값을 현재 컴퓨터 설정으로 해석하지 않습니다. 여러 서비스의 순서를 비교하려면 각각의 시간대와 시계 상태도 확인해야 합니다.
같은 입력을 Python에서 확인하는 방법
다음 코드는 이 글의 고정 형식만 처리합니다. 메시지 안의 공백은 나머지 문장 전체로 보존합니다. JSON 로그, 여러 줄 오류 스택, 다른 구분자가 들어간 로그는 해당 형식에 맞는 도구를 써야 합니다.
from datetime import datetime, timezone
import re
# Fictional fixed format: timestamp, code, remaining message.
lines = [
"2026-10-04T09:15:00Z ERR-14 disk space low",
"2026-10-04T09:16:00Z ERR-02 timeout",
"2026-10-04T09:17:00Z OK-00 ready",
"2026-10-04T25:18:00Z ERR-02 timeout",
]
pattern = re.compile(r"(?P<time>\S+) (?P<code>[A-Z]+-[0-9]+) (?P<message>.+)")
def parse(raw, row_id):
out = {"id": row_id, "raw": raw, "status": "보류", "cause": None}
m = pattern.fullmatch(raw)
if not m:
out["reason"] = "형식 불일치"
return out
try:
when = datetime.fromisoformat(m["time"].replace("Z", "+00:00"))
if when.tzinfo is None:
raise ValueError("시간대 없음")
except ValueError:
out["reason"] = "날짜·시각·시간대 확인 필요"
return out
out.update(status="분리 완료", time_original=m["time"],
time_utc=when.astimezone(timezone.utc).isoformat(),
code=m["code"], message=m["message"], reason="")
return out
rows = [parse(raw, f"L{i}") for i, raw in enumerate(lines, 1)]
assert [r["status"] for r in rows] == ["분리 완료"] * 3 + ["보류"]
assert rows[0]["code"] == "ERR-14"
assert rows[0]["message"] == "disk space low"
assert all(r["cause"] is None for r in rows)
assert [r["raw"] for r in rows] == lines
assert parse("2026-10-04T09:15:00 ERR-14 disk space low", "X")["status"] == "보류"
print("형식 분리3행 / 잘못된 시각1행 보류 / 원문·빈 원인 보존 PASS")
로컬 Python에서 정상 3행 의 필드 분리와 잘못된 시각 1행 의 보류, 원문과 빈 원인 보존을 확인했습니다. Python datetime 문서는 날짜·시각 해석의 기준이고, 로그 발생 원인을 판단하는 문서는 아닙니다. 실제 서비스 장애나 AI 응답을 재현한 결과는 아닙니다.
추정이 섞이거나 줄이 빠졌을 때 복구합니다
| 문제 | 복구할 내용 |
|---|---|
| 메시지를 한국어 원인으로 교체 | 원문 메시지 복원, 번역은 별도 열 |
| 시각 없는 줄을 오늘 날짜로 채움 | 원문 그대로 보류, 로그 형식 문서 확인 |
| 파싱 실패 행을 삭제 | 실패 행을 원문ID와 함께 보류표로 복원 |
| 스택 트레이스의 여러 줄을 별개 사건으로 셈 | 사건 경계·연결ID 확인 후 묶음 기준 재작성 |
| ready를 장애 해결 완료라고 단정 | 관찰된 메시지와 서비스 정상 여부 구분 |
로그가timeout이라고 쓰였다는 이유만으로 기다리는 시간을 늘리지 않습니다. 제품·작업·재현 조건, 오류 앞뒤의 줄, 현재 서비스 상태를 확인해 진단합니다. 이후 원인 추정을 요청할 때도 관찰 사실, 가설, 확인할 증거, 조치를 별도 항목으로 받아야 확정되지 않은 말이 운영 지시로 바뀌지 않습니다.
로그 출처와 제품 버전:
공유할 줄과 제외한 민감 정보:
원문 ID와 시각·시간대:
코드와 원문 메시지:
파싱 실패 ID와 이유:
추가로 확인할 문서·관찰:
확정 사실 / 가설 / 미확인:
다음 확인 담당자:
작성·기술 기준일은 2026-10-04 KST입니다. 로그를 외부에 전달하기 전에는 오류 로그의 비밀 값과 경로 줄이기를, 서로 다른 시간대의 값을 옮길 때는 KST·UTC 날짜 경계 확인을 함께 참고하세요.