paint-brush
올바른 로깅 얻기: 관찰 가능성의 기초~에 의해@feddena
688 판독값
688 판독값

올바른 로깅 얻기: 관찰 가능성의 기초

~에 의해 Fedor Denisov6m2024/06/22
Read on Terminal Reader

너무 오래; 읽다

로깅은 애플리케이션 개발에서 중요하지만 자주 과소평가되는 구성 요소입니다. 적절한 로깅 방법은 애플리케이션의 가시성을 향상하고 내부 작동에 대한 이해를 심화시킬 수 있습니다. 이 가이드의 목표는 서비스를 보다 효과적으로 모니터링하고 문제를 해결할 수 있도록 기본적인 통찰력과 사례를 제공하는 것입니다.
featured image - 올바른 로깅 얻기: 관찰 가능성의 기초
Fedor Denisov HackerNoon profile picture

이 가이드의 목표는 서비스를 보다 효과적으로 모니터링하고 문제를 해결할 수 있도록 기본적인 통찰력과 사례를 제공하는 것입니다.


애플리케이션 개발에서 로깅은 간과되는 경우가 많지만 강력하고 관찰 가능한 시스템을 구축하는 데 있어 중요한 구성 요소입니다. 적절한 로깅 방법은 애플리케이션의 가시성을 향상시키고, 내부 작동에 대한 이해를 심화시키며, 전반적인 애플리케이션 상태를 향상시킬 수 있습니다.


기본 로깅

애플리케이션의 진입점에 기본 로깅 메커니즘을 통합하는 것은 매우 유익합니다. 이 자동 로깅은 필수 상호 작용을 캡처하고 잠재적으로 진입점의 인수를 포함할 수 있습니다. 그러나 비밀번호와 같은 민감한 정보를 기록하면 개인 정보 보호 및 보안 위험이 발생할 수 있으므로 주의하는 것이 중요합니다.

공통 진입점

  • API 끝점 : 들어오는 요청 및 응답에 대한 세부 정보를 기록합니다.
  • 백그라운드 작업 : 작업 시작 지점, 실행 세부 정보 및 결과를 기록합니다.
  • 비동기 이벤트 : 비동기 이벤트 및 관련 상호 작용 처리를 기록합니다.

포괄적인 로깅

애플리케이션이 수행하는 모든 중요한 작업, 특히 상태를 변경하는 작업은 로그 항목을 생성해야 합니다. 이러한 철저한 로깅 접근 방식은 문제가 발생할 때 신속하게 식별하고 해결하여 애플리케이션의 상태와 기능에 대한 투명한 보기를 제공하는 데 핵심입니다. 이러한 근면한 로깅을 통해 진단 및 유지 관리가 더 쉬워집니다.

적절한 로그 수준 선택

애플리케이션에서 생성된 방대한 양의 데이터를 관리하고 해석하려면 적절한 로그 수준을 채택하는 것이 중요합니다. 심각도와 관련성을 기준으로 로그를 분류하면 중요한 문제를 즉시 식별하고 해결할 수 있으며, 모니터링 노력에 부담을 주지 않으면서도 덜 긴급한 정보에 계속 액세스할 수 있습니다.


다음은 로그 수준을 효과적으로 활용하기 위한 지침입니다.

수준

설명 및 예

허용되는 사용

허용되지 않음

ERROR

시스템 작동을 중단시키는 치명적인 이벤트입니다. 예: 데이터베이스 연결 끊김

심각한 시스템 오류

사용자 로그인 시도 실패 등 심각하지 않은 오류

WARN

문제가 있지만 시스템이 계속 실행되어 요청된 작업을 완료할 수 있습니다.

문제로 이어지는 잠재적인 문제

일상적인 상태 변경

INFO

사용자 계정 생성, 데이터 쓰기 등 일반적인 애플리케이션 기능에 대한 통찰력

상태 변화

변경 없이 읽기 전용 작업

DEBUG

프로세스 시작/종료 등 상세한 진단 정보

로깅 프로세스 단계는 시스템 상태를 변경하지 않습니다.

일상적인 상태 변경 또는 고주파수 작업

TRACE

메소드 시작/종료를 포함한 가장 상세한 수준

프로세스의 흐름과 세부 사항 이해

민감한 정보 로깅

기록할 ID - 계층적 접근 방식

애플리케이션에서 작업을 로깅할 때 직접 관련된 엔터티의 ID를 포함하는 것은 로그 정보를 데이터베이스 데이터에 연결하는 데 중요합니다. 계층적 접근 방식을 사용하면 항목을 상위 그룹 또는 카테고리에 연결하여 애플리케이션의 특정 부분에 연결된 모든 로그를 빠르게 찾을 수 있습니다.


예를 들어, 메시지 전송 실패 시 채팅 아이디만 기록하는 것이 아니라, 해당 채팅방의 아이디와 해당 채팅방이 속한 회사의 아이디도 함께 기록해야 합니다. 이렇게 하면 더 많은 맥락을 얻고 문제의 더 광범위한 영향을 확인할 수 있습니다.

로그 항목 예:

Failed to send the message - chat=$roomId, chatRoomId=chatRoomId, company=$companyId

생산 로그의 예

다음은 계층적 접근 방식을 사용할 때 프로덕션 로그가 어떻게 보일 수 있는지에 대한 예입니다.

제안된 계층적 접근 방식을 사용하는 로그가 포함된 Datadog 로그 UI

일관성과 표준화

표준 접두사

모든 팀에서 로그 형식을 표준화하면 로그를 훨씬 쉽게 읽고 이해할 수 있습니다. 고려해야 할 몇 가지 표준화된 접두사는 다음과 같습니다.

  • 뭔가를 시작하기 시작하다
  • 작업을 수행 하지 못했습니다.
  • 뭔가를 완료했습니다
  • 뭔가를 건너뛰었다
  • 작업을 다시 시도하세요 .

변수 값을 별도로 기록

로그 메시지 본문에서 변수 이름과 값을 분리하면 다음과 같은 이점이 있습니다.

  • 로그 검색 및 구문 분석 단순화: 특정 정보를 더 쉽게 필터링하고 찾을 수 있습니다.
  • 로그 메시지 생성 간소화: 로그 메시지 작성 프로세스를 간단하게 유지합니다.
  • 메시지 혼란 방지: 큰 값은 로그 메시지의 가독성을 방해하지 않습니다.

예제 로그 형식:

 Log message - valueName=value

제안된 방식을 사용하는 로그의 예

이론적 예

다음은 논의된 모범 사례에 따라 잘 구성된 로그 항목의 예입니다.

 2023-10-05 14:32:01 [INFO] Successful login attempt - userId=24543, teamId=1321312 2023-10-05 14:33:17 [WARN] Failed login attempt - userId=536435, teamId=1321312

이 예에서는 다음을 보여줍니다.

  • 표준화된 로그 접두사 : "성공적인 로그인 시도" 및 "실패한 로그인 시도"와 같은 명확하고 일관된 접두사를 사용하면 로그를 쉽게 이해할 수 있습니다.


  • 변수값 분리 : 변수명과 값을 로그 메시지와 분리하여 명확성을 유지하고 검색을 단순화합니다.


  • 가독성 및 일관성 : 구조화된 형식은 로그를 쉽게 읽고 구문 분석할 수 있도록 보장하여 효율적인 문제 해결 및 모니터링에 도움이 됩니다.

생산 로그의 예

다음은 제안된 사례를 사용할 때 프로덕션 로그가 어떻게 보일 수 있는지에 대한 예입니다.

Datadog은 'Starting to' 접두사를 기준으로 필터를 사용하여 UI를 기록합니다.

추적 ID

로그를 특정 사용자 작업과 효과적으로 연결하려면 traceId 포함하거나 로그에 correlationId 라고도 불리는 것이 중요합니다. ID는 해당 진입점에 의해 트리거된 논리에 의해 생성된 모든 로그에서 일관되게 유지되어야 하며 이벤트 시퀀스에 대한 명확한 보기를 제공해야 합니다.

구현 예

Datadog과 같은 일부 모니터링 서비스는 기본적으로 로그 그룹화를 제공하지만 수동으로 구현할 수도 있습니다. Spring을 사용하는 Kotlin 애플리케이션에서는 HandlerInterceptor를 사용하여 REST 요청에 대한 추적 ID를 구현할 수 있습니다.

 @Component class TraceIdInterceptor : HandlerInterceptor { companion object { private const val TRACE_ID = "traceId" } override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { val traceId = UUID.randomUUID().toString() MDC.put(TRACE_ID, traceId) return true } override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) { MDC.remove(TRACE_ID) } }

이 인터셉터는 각 요청에 대해 고유한 traceId 생성하여 요청 시작 시 이를 MDC에 추가하고 요청이 완료된 후 제거합니다.

TraceId가 포함된 로그 예

이러한 로그 집계를 구현하면 아래 예와 유사한 로그를 필터링할 수 있습니다.


자산 삭제 요청 처리 중 생성된 로그

로그에서 UUID와 Long ID 사용

많은 시스템에서 엔터티는 UUID 또는 Long ID를 기본 식별자로 사용할 수 있지만 일부 시스템은 서로 다른 목적으로 두 가지 유형의 ID를 모두 사용할 수 있습니다. 정보를 바탕으로 선택하려면 로깅 목적에 따른 각 유형의 의미를 이해하는 것이 중요합니다.


고려해야 할 사항을 분류하면 다음과 같습니다.


가독성: Long ID는 읽기 쉽고 상당히 짧습니다. 특히 Long 범위의 최상위에 있지 않은 경우 더욱 그렇습니다.


고유 값: UUID ID는 시스템 전반에 걸쳐 고유성을 제공하므로 ID 충돌 문제 없이 ID를 사용하여 로그를 검색할 수 있습니다. 여기서 충돌은 관련되지 않은 DB 테이블의 두 엔터티가 동일한 Long ID를 가질 가능성이 있음을 의미합니다.


시스템 제한 사항 : 긴 기본 키를 엔터티 ID로 사용하는 시스템에서 임의의 UUID ID를 추가하는 것은 일반적으로 간단합니다. UUID 엔터티 ID가 있는 분산 시스템에서는 특별히 로깅을 위해 Long ID를 갖는 것이 어렵거나 비용이 많이 들 수 있습니다.


기존 로그: 적어도 엔터티별로 로그에 사용되는 ID 유형의 일관성이 중요합니다. 시스템이 이미 일부 엔터티에 대한 로그를 생성하고 모든 엔터티 변경을 고려하지 않는 경우 엔터티를 식별하는 데 이미 사용된 유형을 유지하는 것이 좋습니다. 전환 기간 동안 두 ID를 모두 기록하는 것을 고려할 수 있지만 여러 ID를 영구적으로 사용하면 로그가 불필요하게 복잡해집니다.


결론

효과적인 서비스 관찰을 위해서는 적절한 로깅 관행이 필수적입니다. 포괄적인 로깅, 적절한 로그 수준, 추적 ID 및 표준화된 로그 형식을 통합함으로써 애플리케이션을 모니터링하고 문제를 해결하는 능력을 크게 향상시킬 수 있습니다. 이러한 방법을 사용하면 로그의 명확성과 일관성이 향상되어 문제를 더 쉽게 진단하고 신속하게 해결할 수 있습니다.


시간을 내어 이 게시물을 읽어주셔서 감사합니다!