RubyLLM 요청을 추적하기 위한 초기 접근 방식은 RubyLLM이 기본으로 제공하는 이벤트 핸들러를 활용하는 것이었습니다. 예를 들어, chat.on_end_message 콜백을 사용하여 LLM 메시지 완료 시 Event 레코드를 생성하고 토큰 정보를 기록하는 방식입니다. 이 방법은 간단했지만, 다음과 같은 심각한 한계점을 가지고 있었습니다.
RubyLLM 이벤트 핸들러의 한계점
-
수동 추적의 부담: 모든 chat 인스턴스에 콜백을 수동으로 설정해야 했으며, 이를 누락할 경우 중요한 데이터가 손실될 위험이 있었습니다.
-
강한 결합: 계측 코드와 핵심 비즈니스 로직이 밀접하게 결합되어 코드의 유지보수성과 가독성을 저해했습니다.
-
제한된 적용 범위: RubyLLM::Chat 인스턴스에만 적용되며, 임베딩, 이미지 생성 등 다른 LLM 작업에는 별도의 계측 메커니즘이 필요했습니다.
-
복잡한 메트릭 추적: 지연 시간과 같은 전체 요청 메트릭을 추적하려면 더 복잡하고 침투적인 코드가 요구되었습니다.
이러한 한계를 극복하고 더 포괄적이며 자동화된 계측을 위해 Rails에 내장된 ActiveSupport::Notifications가 핵심 대안으로 채택되었습니다.
ActiveSupport::Notifications 활용
-
ActiveSupport::Notifications는 Rails의 내부 계측 API로, 데이터베이스 쿼리, 뷰 렌더링, 컨트롤러 실행 등 Rails의 핵심 동작을 추적하는 데 내부적으로 사용됩니다.
-
이 메커니즘은 instrument 메서드를 통해 이벤트를 발행하고, subscribe 메서드를 통해 이벤트를 소비하는 방식으로 작동합니다. 이를 통해 로깅, 모니터링 등 다양한 후속 작업을 수행할 수 있습니다.
-
특히, 라이브러리의 비즈니스 로직과 이를 사용하는 애플리케이션의 비즈니스 로직 간의 결합도를 낮추는 데 매우 효과적입니다. RubyLLM::Monitoring의 경우, 모니터링 로직이 RubyLLM과 독립적으로 존재하며 필요한 이벤트를 구독함으로써 높은 유연성을 확보합니다.
RubyLLM::Instrumentation 구현
-
RubyLLM::Instrumentation은 ActiveSupport::Notifications를 기반으로 RubyLLM의 모든 LLM 호출 이후 이벤트를 발행하도록 구현되었습니다.
-
사용자는 단순히 이 젬을 Gemfile에 추가하고 bundle install만 하면, RubyLLM이 자동으로 이벤트를 발행하기 시작합니다.
-
RubyLLM::Monitoring은 이 RubyLLM::Instrumentation이 발행하는 이벤트를 구독하여 LLM 요청 데이터를 캡처하고 대시보드에 제공합니다.
-
예시 코드에서 보듯이, ActiveSupport::Notifications.subscribe(/ruby_llm/)를 통해 모든 ruby_llm 이벤트를 중앙에서 캡처하고 데이터베이스에 저장하는 방식으로, 계측 코드가 비즈니스 로직과 완전히 분리되어 훨씬 간결하고 재사용 가능한 형태가 됩니다. 특정 이벤트에만 구독하는 것도 가능하며, 발행되는 이벤트와 페이로드에 대한 자세한 정보는 프로젝트 저장소에서 확인할 수 있습니다.