4 min read

py-runner APM 로깅 시스템 리서치

1. 태스크 요구사항 분석

1.1 목표

  • py-runner 컨테이너 로그를 포지큐브 표준 입출력 형태로 변환
  • APM(Application Performance Monitoring) 시스템과 통합하기 위한 로그 포맷 구현

1.2 요구사항 상세

  • 로그는 JSON serialize 형태로 출력되어야 함
  • 필수 포함 정보:
    • API 요청(request) 정보: header, path, origin, x-forwarded-for, remoteAddress 등
    • API 응답(response) 정보: HTTP 상태 코드, 지연 시간(latency), message
  • 아테나 로깅 예시와 동일한 포맷으로 통일해야 함

2. 현황 분석

2.1 py-runner 현재 로깅 시스템

  • 현재 py-runner는 기본 Python logging 모듈을 사용
  • Agent, Sandbox, Dev 서버 각각 개별 로거 사용
  • 로그 형식은 텍스트 기반이며 JSON 포맷이 아님

각 서버의 로그 설정:

# 예: apps/agent.py
logger = logging.getLogger("[AGENT]")
# uvicorn 로깅 설정
log_config = uvicorn.config.LOGGING_CONFIG
log_config["formatters"]["default"] = {"()": DefaultFormatter, "fmt": "%(levelprefix)s [AGENT]: %(message)s", "use_colors": True}
log_config["formatters"]["access"] = {"()": DefaultFormatter, "fmt": "%(levelprefix)s [AGENT]: %(message)s", "use_colors": True}

2.2 요구되는 로그 포맷 (아테나 로그 예시 분석)

아테나 로그 예시를 분석한 결과, 다음의 구조로 구성됨:

{
  "level": "INFO",
  "timestamp": "2025-03-06T02:23:14.883Z",
  "pid": 7,
  "hostname": "athena-deploy-57cf9ffcc8-lrg9q",
  "req": {
    "id": 230,
    "method": "GET",
    "url": "/chats/m1/logs/list?chat_threads_id=16390&sort=id%3ADESC&max_tokens=3000",
    "query": { ... },
    "params": { ... },
    "headers": { ... },
    "remoteAddress": "10.0.19.187",
    "remotePort": 56328
  },
  "trace_id": "50d06b8a57aeccd5f44c2b4862420833",
  "span_id": "ce80d5ec7359ee4b",
  "trace_flags": "01",
  "res": {
    "statusCode": 200,
    "headers": { ... }
  },
  "responseTime": 70,
  "module": "athena",
  "message": "request completed"
}

3. 로깅 구현 접근 방법 조사

3.1 FastAPI에서의 로깅 옵션

3.1.1 미들웨어 방식

  • FastAPI의 미들웨어 기능을 사용하여 모든 요청/응답을 로깅
  • 장점: 모든 엔드포인트에 일괄 적용 가능, 코드 분리 용이
  • 단점: 요청 본문 등 일부 정보 접근에 추가 처리 필요

3.1.2 이벤트 핸들러 방식 ← soon deprecated

  • FastAPI의 이벤트 핸들러(@app.on_event)를 활용
  • 장점: 요청/응답 라이프사이클 이벤트에 따른 세밀한 제어 가능
  • 단점: 구현이 복잡할 수 있음, 현재 deprecation 진행중임

3.1.3 로깅 라이브러리 통합 방식

  • python-json-logger와 같은 라이브러리 활용
  • 장점: 기존 로깅 시스템 활용, 구현 간단
  • 단점: HTTP 요청/응답 정보 수집을 위한 추가 작업 필요

3.2 로그 포맷팅 옵션

3.2.1 JSON 로그 포맷터

  • python-json-logger 라이브러리 사용 (이미 프로젝트에 포함됨)
  • 장점: JSON 형식으로 로그 출력 지원, 커스텀 포맷 구성 용이
  • 단점: 추가 설정 작업 필요

3.2.2 커스텀 로그 포맷터

  • Python의 logging.Formatter 확장
  • 장점: 완전한 커스터마이징 가능
  • 단점: 구현 복잡도 증가

4. 구현 방안 제안

4.1 미들웨어 기반 접근법

  1. 로깅 미들웨어 클래스 구현
    • BaseHTTPMiddleware 확장
    • 요청 시작 시간 기록 및 응답 완료 시간 계산
    • 필요한 정보 수집 및 JSON 형식으로 로그 출력
  2. 로깅 설정 통합
    • python-json-logger 사용하여 JSON 포맷 구성
    • 세 서버 모두에 동일한 로깅 설정 적용
  3. 트레이싱 정보 추출 유틸리티
    • 헤더에서 트레이싱 관련 정보 추출
    • B3 포맷 및 W3C 트레이스컨텍스트 포맷 지원

4.2 로그 수집 항목

4.2.1 기본 메타데이터

  • level: 로그 레벨
  • timestamp: ISO 8601 형식의 타임스탬프
  • pid: 프로세스 ID
  • hostname: 호스트 이름
  • module: 모듈 이름 ("py-runner")

4.2.2 요청 정보 (req)

  • id: 요청 ID
  • method: HTTP 메서드
  • url: 전체 URL
  • query: 쿼리 파라미터
  • params: 경로 파라미터
  • headers: 요청 헤더
  • remoteAddress: 클라이언트 IP
  • remotePort: 클라이언트 포트

4.2.3 응답 정보 (res)

  • statusCode: HTTP 상태 코드
  • headers: 응답 헤더

4.2.4 성능 및 추적 정보

  • responseTime: 응답 시간 (ms)
  • trace_id: 트레이스 ID
  • span_id: 스팬 ID
  • trace_flags: 트레이스 플래그

5. 고려 사항 및 주의점

5.1 성능 영향

  • 로깅이 애플리케이션 성능에 미치는 영향 고려
  • 로그 수준 조정으로 프로덕션 환경에서의 최적화 가능성

5.2 보안 고려사항

  • 로그에 민감한 정보 포함 여부 검토
  • 헤더 및 쿼리 파라미터에서 민감 정보 필터링 필요성

5.3 로그 크기 및 저장

  • JSON 로그는 텍스트 로그보다 크기가 큼
  • 로그 순환 및 압축 전략 필요

5.4 기존 로깅과의 통합

  • 기존 py-runner 로깅 시스템과의 공존 방법
  • 개발 및 디버깅을 위한 텍스트 로그 유지 필요성

6. 참고 자료

6.1 관련 라이브러리

6.2 APM 관련 문서