Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Honeybadger 브레드크럼(Breadcrumbs) 기능 소개: 프로덕션 오류 추적의 새로운 해결책

프로덕션 환경에서 오류가 발생했는데, 아무리 시도해도 개발이나 스테이징 환경에서는 재현할 수 없는 경험이 있으신가요? 이런 경우 다음 단계로 보통 프로덕션에 디버그 로그를 추가해 더 많은 데이터를 수집하게 됩니다. 하지만 로그와 요청을 연관 지을 좋은 방법이 없다면, 특히 장애 대응 중이라면 상당히 답답한 상황이 됩니다.

이를 돕기 위해 새로운 기능을 추가했습니다. 바로 브레드크럼(Breadcrumbs)입니다.

Honeybadger 브레드크럼(Breadcrumbs) 기능 소개: 프로덕션 오류 추적의 새로운 해결책

브레드크럼은 로그 이벤트와 매우 유사하지만, 오류와 함께 저장되고 보고된다는 점이 다릅니다. 로그처럼 메시지를 포함하며, 메타데이터(해시맵 형태)도 함께 담을 수 있습니다. 브레드크럼들은 요청(또는 작업 실행)의 생명주기 동안 수집되며, 오류가 보고되지 않으면 즉시 폐기됩니다.

코드 어디에서든 Honeybadger.add_breadcrumb를 호출하는 것만으로 간단히 브레드크럼을 스택에 추가할 수 있습니다:

Honeybadger.add_breadcrumb("Loading User", metadata: {
  user_name: user_name,
})

이후 오류가 보고되면 브레드크럼 스택에서 아래와 같이 확인할 수 있습니다:

Honeybadger 브레드크럼(Breadcrumbs) 기능 소개: 프로덕션 오류 추적의 새로운 해결책

user_name이 비어 있는 것이 보이시나요? 이것이 바로 문제의 원인일 수 있습니다.

자동 브레드크럼

Honeybadger Ruby 라이브러리에는 Ruby와 Rails에 연동되어 자동으로 브레드크럼을 수집하는 훅(hook)이 포함되어 있습니다. 예를 들어, 프로덕션에서 발생하는 모든 로그 메시지(Logger 클래스를 통해 전송)는 캡처되어 브레드크럼으로 생성됩니다. 또한 Rails Instrumentation과 연동하여 컨트롤러 액션, SQL 쿼리, Active Job 실행 등에 대한 브레드크럼도 자동으로 수집합니다.

어떻게 사용할 수 있나요?

브레드크럼은 현재 Ruby 클라이언트를 통해 사용할 수 있습니다. 버전 4.4.0 이상으로 업데이트한 후 설정에서 반드시 활성화해야 합니다. gem 5.0.0 버전 출시 전까지는 기본적으로 비활성화되어 있으며, 이는 안정성을 충분히 검증하기 위한 조치입니다.

직접 사용해보시고 문제가 발생하면 피드백을 주시기 바랍니다.

브레드크럼 확장하기

브레드크럼이 정식으로 소개되었으니, 이를 확장하는 방법에 대한 간단한 예제를 살펴보겠습니다. Rails 앱에서 브레드크럼을 활성화하면 기본적인 인스트루멘테이션(instrumentation) 브레드크럼이 무료로 제공되지만, 더 많은 정보를 원한다면 어떻게 해야 할까요?

예를 들어 앱이 HTTP 요청을 보낼 때마다 브레드크럼을 생성하고 싶다고 가정해봅시다. 이 정보는 디버깅 시 매우 유용하게 활용될 수 있습니다.

가장 간단한 방법은 각 요청 호출 시점에 Honeybadger.add_breadcrumb를 직접 호출하는 것입니다.

def send_a_message
  res = conn.post("/message", { user: user.id, body: "Hey!" }.to_json)
  Honeybadger.add_breadcrumb("Request: /message", metadata: { user: user.id })
  res
end

위 코드는 /message로 POST 요청을 보낼 때마다 브레드크럼을 저장합니다. 다음에 메시지 전송 후 앱에서 오류가 발생하면 어떤 사용자가 메시지를 보냈는지, 그리고 오류 발생 시점과의 관계를 손쉽게 파악할 수 있습니다!

다만 이 방식은 다소 번거롭습니다. 요청을 보내는 모든 위치에 add_breadcrumb 호출을 추가해야 하기 때문입니다. 물론 이런 방식에도 분명한 장점이 있습니다. 캡처하고 싶은 메타데이터를 매우 구체적으로 지정할 수 있어, 프로덕션 버그 해결을 위해 목표 지향적인 정보를 수집하는 훌륭한 방법이 되곤 합니다.

사실 저는 요청이 언제, 어디로 나가는지만 알면 됩니다. 그리고 라이브러리가 대부분의 작업을 대신 처리해 준다면 더욱 좋겠죠 ;)

Faraday로 인스트루먼팅하기

약간의 전제를 깔고, 여러분이 널리 사용되는 Faraday 요청 라이브러리를 사용하고 있다고 가정하겠습니다.

직접 미들웨어를 만들어 작업을 수행할 수도 있지만, 여기서는 Rails 인스트루멘테이션을 브로커로 활용해 보겠습니다. 다행히 faraday_middleware 젬에서 이벤트를 발생시켜 주는 미들웨어를 제공합니다. Gemfile에 해당 젬을 추가하고, connection에 instrumentation 미들웨어가 주입되었는지 확인하세요.

connection = Faraday.new do |conn|
  conn.use :instrumentation
  conn.adapter Faraday.default_adapter
end

앱 내에서 connection을 공유하지 않는 구조라면 약간의 추가 작업이 필요할 수 있습니다. 더 간편한 방법으로 ConnectionOptions를 prepend하여 모든 요청에 미들웨어가 활성화되도록 설정할 수도 있습니다. 단, 이렇게 하면 앱 내부는 물론 의존성 젬에서 발생하는 모든 Faraday 요청까지 인스트루먼팅되니 주의가 필요합니다(물론 원하는 경우도 있겠죠!).

Rails 인스트루멘테이션을 활용하면 몇 가지 좋은 부수 효과도 있습니다. 그중 하나는 일반 로깅 등 다른 용도로 여러 구독(subscription)을 동시에 만들 수 있다는 점입니다.

요청 감시하기

이제 Faraday 요청이 인스트루먼팅되었으니, 이벤트를 구독하여 브레드크럼을 생성해 보겠습니다:

ActiveSupport::Notifications.subscribe "request.faraday" do |_, _, _, _, data|
  method = data[:method].to_s.upcase
  metadata = data.to_h.slice(:url, :status).merge({method: method})
  Honeybadger.add_breadcrumb("#{method}: #{metadata[:url]}", category: "request", metadata: metadata)
end

이제 Honeybadger가 외부로 나가는 모든 요청에 대해 자동으로 브레드크럼을 추가합니다!

Honeybadger 브레드크럼(Breadcrumbs) 기능 소개: 프로덕션 오류 추적의 새로운 해결책

여기서는 요청 데이터 중 일부 포인트만 선택적으로 살펴봅니다. 민감한 데이터가 브레드크럼 메타데이터로 유출될 가능성이 있기 때문에, 요청 본문이나 응답 본문 페이로드는 의도적으로 포함하지 않았습니다.

직접 사용해 보세요!

브레드크럼이 여러분의 디버깅 도구 상자에 유용한 무기가 되기를 바랍니다. 지금 바로 적용해 보시고, 추가되었으면 하는 기능이 있다면 언제든 의견을 공유해 주세요.