본문으로 건너뛰기

Contextual Logging

구조화된 로깅(Structured Logging)

로그는 애플리케이션이 동작하는 동안 발생하는 이벤트를 기록하는 것입니다. 로그는 다양한 방식으로 활용되는데,

  • 애플리케이션의 동작을 확인
  • 에러 발생 시 원인을 파악
  • 사용자 행동 데이터로 사용

등의 활용 방안이 있습니다.

많은 양의 로그를 다루기 위해서는 로그를 쿼리할 수 있도록 일정한 형식으로 중앙 저장소에 저장하는 것이 필요합니다. 이를 위해 구조화된 로깅(Structured Logging)을 사용하는데, 여기서 구조화된 로깅이란 사람과 컴퓨터 모두 이해하기 쉽도록 사전 정의된 구조로 기록하는 방법을 말합니다.(읽기는 불편할 수 있습니다)

일반적으로 key-value 쌍으로 구성된 이벤트 데이터가 사용되며, json, logfmt 등의 포멧을 사용합니다.

예시는 아래와 같습니다.

{
"level": "info",
"time": 1684741898.0446076,
"caller": "contextual-logging/test.go:12",
"msg": "hello world",
"request_id": "c5b76167-e82e-48d9-95cc-fdeb4d30dfbc",
"foo": "bar",
"nest": {
"foo": "bar"
}
}

문맥에 따른 로깅(Contextual Logging)

문맥에 따른 로깅(Contextual Logging)은 로깅하는 시점의 컨텍스트를 로그에 포함시키는 것을 말합니다. 이 방법을 사용하면 로그를 분석할 때, 컨텍스트를 기준으로 검색이 가능합니다.

예를 들어, 사용자가 API를 호출할 때 request_id를 생성하고 이를 처리하는 모든 애플리케이션에서 user_id, request_id를 로그에 남겼다고 가정해보겠습니다. 에러 알람이 발생한다면

  • 에러 로그에 포함된 request_id를 확인
  • request_id 값을 필터로 로그를 검색하여 API 호출 시점 부터 에러가 발생한 애플리케이션까지 로그를 시간 순서로 확인
  • 에러 발생 시간, 기간, user_id 값을 필터로 로그를 검색하여 일정 시간 동안 사용자가 어떤 동작을 했는지 파악

이 가능해집니다. 이를 통해 관련 개발자들은 문제 상황을 빠르게 파악할 수 있고, 추가 정보를 얻기 위해 문제를 재현해보거나 바로 수정할 수 있게 됩니다.

문맥에 따른 로깅을 구현하기 위해 애플리케이션간에는 프로토콜의 헤더, 본문 등에 컨텍스트 정보를 포함시키는 방식으로 구현할 수 있고, 함수간에는 많은 언어에서 컨텍스트 관리를 위한 방법을 제공하기 때문에 이를 활용하여 아래와 같은 방식으로 문맥에 따른 로깅을 구현할 수 있습니다.

  • WithContext: 이전 컨텍스트가 있는 경우 이전 컨텍스트를 복사해서 컨텍스트를 만들고, 없으면 새로운 컨텍스트를 만든 후에 인자로 받은 필드를 컨텍스트에 추가 또는 업데이트합니다
  • FieldsFromContext: 컨텍스트에서 필드 리스트를 가져옵니다
  • LoggerFromContext: 컨텍스트에서 필드 리스트가 포함된 로거를 가져옵니다