
development
’フロントエンドロギングのための導入記1'
- sentry
- frontend
개요
최근 회사에서 Socket통신을 활용한 채팅 서비스 프론트엔드에 적절한 에러로깅 툴이 없어서, 디버깅에 어려움을 겪고 있는것을 발견 하였습니다. 해당 문제를 해결하고자 Sentry를 적용하여 예상되는 버그, 또는 예상하지 못했던 예외상황을 발견하고 잠재적인 문제를 예방할 수 있도록 하였습니다. 1, 2편으로 나누어 먼저 Sentry가 무엇인지에 대해 알아보고, 실제 실무에서의 적용기에 대해 작성해 보고자 합니다.
센트리란?
센트리는 소프트웨어 개발에서 발생하는 에러와 성능 이슈를 실시간으로 모니터링하고 로깅하는 서비스 입니다. 이미 발생한 이슈를 해결하는것을 넘어서, 지속적인 로깅과 모니터링 분석을 통해 문제를 미리 예방할 수 있습니다. 클라이언트/서버, 웹/모바일앱 등 다양한 환경을 지원하며 연동하고자 하는 서비스에 SDK 연동은 코드 몇줄, 또는 CLI를 통한 자동화 연동이 가능합니다.
발생하는 이슈를 분석하여 하나의 그룹으로 집계하여 노이즈를 줄이고, 담당자를 할당하여 이슈를 관리하거나 제공되는 모니터링 정보를 통해 데이터 기반 의사결정이 가능합니다. 오류로깅 뿐만이 아니라, 사용자 이벤트를 통해 서비스의 성능을 분석하거나 사용자의 실제 UI동작을 녹화, 전송하여 이슈의 원인을 쉽게 파악할 수 있습니다. 센트리를 연동하는데 있어서 센트리에서 제공하는 SasS를 사용하느냐, 직접 호스팅하느냐로 나뉘는데 전자는 센트리측의 유료플랜에 가입 하여야 합니다. 후자의 경우 직접 docker를 사용하여 호스팅할 수 있도록 제공하고 있으며 이 경우 센트리측에 돈을 지불할 필요는 없습니다. 저는 이번에 직접 장비에 배포하여 사용하는 방법을 채택 하였습니다.
프로젝트 연동 방법
대부분의 클라이언트/서버 언어및 프레임워크에서 간단하게 SDK설치가 가능하며, 이를위한 install wizard cli를 제공하고 있습니다. 제공하지 않는 경우에도 각 언어의 패키지매니저를 통해 특정 언어/프레임워크의 SDK를 추가하고, 간단한 설정 파일을 몇줄 작성하는것 만으로 에러수집을 시작할 수 있습니다.
프로젝트 목록 페이지에서 Create Project 버튼을 클릭합니다.
1번에서 프로젝트의 기술 기반을 선택하고, 3번의 프로젝트명을 입력하고 Create Proejct 버튼을 클릭합니다.
대화형 cli installer를 지원하는 프레임워크의 예 입니다. 설정파일부터 토큰, 에러를 테스트할 수 있는 해당 프레임워크의 예제 코드까지 대화형 커맨드라인 명령어로 자동으로 생성해줍니다. Take me to Issues를 클릭하면 설정 튜토리얼을 종료하고 해당 프로젝트 페이지로 이동하여 첫번쨰 에러가 발생하길 기다립니다.
대화형 cli installer가 없는 프레임워크의 예 입니다. 의존성 추가와 몇가지 간단한 설정으로 SDK 설정이 완료됩니다.
기능구조도
UML을 통해 간단한 구조도를 표현해 봤습니다.
@startuml Sentry 데이터 모델
package "Organization / Team" as OrgStructure {
[Project] as PROJ
}
component "Event" as EVENT
package "Issue" as ISSUE {
component "Error Event 1" as ERROR1
component "Error Event 2" as ERROR2
component "Error Event 3"
}
package "Trace" as TRACE {
component "Transaction Event 1" as TX1
component "Transaction Event 2" as TX2
component "Transaction Event 3" as TX3
}
component "Span" as SPAN
component "Child Span" as CHILD_SPAN
component "Nested Transaction" as NESTED_TX
PROJ ....> EVENT : 수집
EVENT --> ISSUE : 종류
EVENT --> TRACE : 종류
TX1 --> SPAN : contains
SPAN --> CHILD_SPAN : "포함할 수 있음"
SPAN --> NESTED_TX : "포함할 수 있음"
ERROR1 ..> TX1 : "연결될 수 있음"
ERROR2 ..> SPAN : "연결될 수 있음"
@enduml
용어/개념
Organization
- 센트리에서 가장 최상위 개념입니다.
- 하위에 여러개의 Team을 가질 수 있습니다.
Team
- Organization의 하위 개념으로 보통 부서 단위로 나뉘거나, Frontend/Backend/Mobile 등의 기능 영역 단위로 나누어 권한을 부여할 수 있습니다.
Project
- Team의 하위 개념으로 하나의 독립적인 애플리케이션, 서비스를 연동할 수 있는 단위입니다.
- 각 프로젝트는 고유한 DSN(Data Source Name)을 가지게 됩니다.
- 프로젝트는 독립적인 알림, 데이터 스크러빙, 트레이스 레이트등의 설정을 가질 수 있습니다.
- 프로젝트 단위로 코드 릴리즈를 추적할 수 있으며, 그 단위는 commit hash등이 될 수 있습니다.
- 하나의 프로젝트에서 여러개의 환경을 가질 수 있습니다. Contiple의 경우 하나의 프로젝트에 dev, alpha, beta, real환경 구성을 기본으로 하고 있습니다.
DSN
(DNS 아님)
- 하나의 Project마다 갖게되는 URL입니다.
- 다음과 같은 형식을 가집니다.
- https://{PUBLIC_KEY}@o{ORGANIZATION_ID}.ingest.sentry.io/{PROJECT_ID}
- 각 어플리케이션은 SDK에서 DSN을 통해 어느 Project로 로그를 전송해야할지 결정합니다.
Issue
이슈는 유사한 원인으로 발생한 여러 오류 이벤트를 하나로 그룹화한것 입니다. 동일한 문제로 인해 발생한 에러 알림에대한 노이즈를 최소화하기 위해 이러한 그룹화 매커니즘이 존재합니다. 동일 에러들을 하나의 이슈로 만드는 메커니즘은 fingerprinting이라는 프로세스를 통해 이루어집니다.
- 기본적으로 아래의 정보를 바탕으로 에러의 fingerprint를 생성하여, 동일한 fingerprint일 경우 하나의 이슈로 그룹화 합니다.
- Exception Type
- Stack Trace
- Error Message
- 또한 커스텀 데이터를 사용하여 fingerprint 생성에 관여할 수 있습니다.
- 예를들어 사용자 uuid를 추가하여 이슈를 사용자별로 그룹화하여 생성할 수 있습니다.
이슈는 각각의 상태를 갖고, 담당자를 지정하여 이슈를 관리할 수 있습니다. Slack등의 협업툴과 연동하여 알림을 보낼 수 있으며 Github, GitLab등과도 연동이 가능합니다.
이슈에는 이외에도 다양한 메타데이터가 함께 수집되어 보여지게 됩니다. 이를통해 담당자는 수월하게 해당 이슈에 대한 정보를 수집할 수 있습니다.
- 운영체제, 브라우저, 기기정보
- 어플리케이션의 버전 및 릴리즈 정보와 커밋 해쉬
- 사용자 ID, Eamil, IP 정보 등..
- 사용자의 에러 발생전 까지의 행동 추적 기록(http request, dom event 등..
- 이슈의 발생 빈도 및 시간, 추세, 환경별 통계
- HTTP 헤더, 메소드 등의 네트워크 요청 기록
- 기타 어플리케이션에서 지정한 특정 동적 데이터
하나의 이슈에서는 다양한 정보를 확인할 수 있습니다.
Event
센트리에서 이벤트는 어플리케이션에서 발생한 무언가를 의미합니다. 이벤트의 종류로는 Error Event와 Transaction Event가 있습니다.
- Error Event
- 애플리케이션의 에러를 추적하고 기록합니다.
- Transaction Event
- 애플리케이션의 일상적인 이벤트를 수집합니다. 이는 성능과 사용자 경험을 측정하고 분석하는데 초점을 맞춥니다.
Error
Error는 Sentry의 가장 핵심적인 컨셉이며 기능중 하나입니다. Error Event는 어플리케이션에서 예외가 발생하거나 코드상에서 명시적으로 실행한 에러캡쳐 메서드를 통해 수집됩니다.
import \* as Sentry from '@sentry/nextjs'
try {
drinkCoke();
} catch (error) {
console.error(error)
Sentry.captureException(error); // <=== 여기서 수집!
}
Transaction
Transaction은 Sentry의 성능 모니터링기능의 핵심 요소입니다. Transaction은 애플리케이션에서 발생하는 일련의 작업이나 사용자 상호작용을 나타냅니다. 각각의 Transaction은 시작 시간과 종료 시간을 가지며, 전체 실행시간을 측정하여 어플리케이션의 성능을 유추할 수 있습니다.
Transaction의 경우
- Transaction Event는 LCP(Largest Contentful Paint), TTFB(Time To First Byte), ;FCP(First Contentful Paint)등 다양한 성능 지표를 포함하고 있습니다.
- 하나의 Transaction은 복수의 Span을 가질 수 있습니다. 다시, 하나의 Span은 복수의 Span이나 Transaction을 가질 수 있습니다. 결국 하나의 Transaction은 Tree구조를 갖고 있습니다.
概要
最近、社内でSocket通信を活用したチャットサービスのフロントエンドにおいて、適切なエラーロギングツールがなく、デバッグに困難を感じていました。
この問題を解決するためにSentryを導入し、予測されるバグや予測不能な例外状況を検知・記録し、潜在的な問題を未然に防げるようにしました。
本記事は2部構成となっており、まずSentryとは何かについて紹介し、実務での導入記録をお伝えします。
Sentryとは?
Sentryは、ソフトウェア開発で発生するエラーやパフォーマンス問題をリアルタイムで監視・ロギングできるサービスです。
すでに発生した問題の解決にとどまらず、継続的なロギングとモニタリング分析により、問題の予防にもつなげることが可能です。
クライアント/サーバー、Web/モバイルアプリなど様々な環境をサポートしており、対象サービスへの連携も数行のコードまたはCLIを通じた自動連携で完了できます。
発生した問題は自動的にグループ化され、ノイズを削減できます。担当者を割り当てて管理したり、提供されるモニタリング情報をもとにデータドリブンな意思決定も可能です。
エラーロギングに加えて、ユーザーイベントからサービスのパフォーマンスを分析したり、実際のUI操作を録画・送信して問題の原因を把握することもできます。
Sentryの連携方法には、Sentry社が提供するSaaSプランを利用する方法と、自身でホスティングする方法があります。
前者は有料プランの契約が必要ですが、後者はDockerを用いて自前でホスティングでき、費用をかけずに利用可能です。
今回は後者の、自社サーバーへのデプロイを選択しました。
プロジェクト連携方法
多くのクライアント/サーバー言語・フレームワークで簡単にSDKをインストールできるようになっており、インストールウィザードのCLIも提供されています。
公式にサポートされていない場合でも、各言語のパッケージマネージャーを使用し、数行の設定を記述するだけでエラー収集を開始できます。
プロジェクト一覧ページで Create Project ボタンをクリックします。
ステップ1で技術スタックを選択し、ステップ3でプロジェクト名を入力して Create Project ボタンをクリックします。
これは対話型CLIインストーラーをサポートしているフレームワークの例です。
設定ファイルの生成、トークン設定、テスト用のサンプルコードなどをコマンドラインで自動生成してくれます。
Take me to Issues をクリックすると、チュートリアルを終了して該当プロジェクトページへ移動し、最初のエラー発生を待ちます。
こちらは対話型CLIインストーラーが提供されていないフレームワークの例です。
依存関係の追加と簡単な設定のみでSDK連携が完了します。
機能構成図
UMLを用いてSentryの簡易構成を表現しました。
@startuml Sentry データモデル
package "Organization / Team" as OrgStructure {
[Project] as PROJ
}
component "Event" as EVENT
package "Issue" as ISSUE {
component "Error Event 1" as ERROR1
component "Error Event 2" as ERROR2
component "Error Event 3"
}
package "Trace" as TRACE {
component "Transaction Event 1" as TX1
component "Transaction Event 2" as TX2
component "Transaction Event 3" as TX3
}
component "Span" as SPAN
component "Child Span" as CHILD_SPAN
component "Nested Transaction" as NESTED_TX
PROJ ....> EVENT : 収集
EVENT --> ISSUE : 分類
EVENT --> TRACE : 分類
TX1 --> SPAN : 含む
SPAN --> CHILD_SPAN : "含まれる場合あり"
SPAN --> NESTED_TX : "含まれる場合あり"
ERROR1 ..> TX1 : "関連あり"
ERROR2 ..> SPAN : "関連あり"
@enduml
用語・概念
Organization
- Sentryにおける最上位の概念です。
- 複数のTeamを配下に持つことができます。
Team
- Organizationの下位概念で、部署単位や、フロントエンド/バックエンド/モバイルなど機能領域単位で分け、権限を管理できます。
Project
- Team配下に属する単位で、ひとつの独立したアプリケーションやサービスを連携できます。
- 各プロジェクトは固有のDSN(Data Source Name)を持ちます。
- プロジェクト単位で通知設定やトレースレート、データスクラビング設定を持つことができます。
- コードリリースの追跡も可能で、コミットハッシュなどが単位になります。
- 環境を分けて管理することも可能です(例:dev, alpha, beta, real など)。
DSN
(DNSではありません)
- 各Projectに一意に割り当てられるURLです。
- 以下の形式になります:
- https://{PUBLIC_KEY}@o{ORGANIZATION_ID}.ingest.sentry.io/{PROJECT_ID}
- アプリケーションは、このDSNを使って、どのProjectにログを送信するかを決定します。
Issue
Issueは、類似した原因によって発生した複数のエラーイベントを一つにグループ化したものです。
同一エラーによるノイズを減らすため、このようなグルーピングメカニズムが存在します。
このグルーピングは fingerprinting
プロセスを通じて行われます。
- 以下の情報から自動的にfingerprintを生成し、一致するfingerprintのイベントは同じIssueにまとめられます:
- Exception Type
- Stack Trace
- Error Message
- ユーザーIDなどのカスタムデータもfingerprint生成に含めることができます。
- 例:ユーザーごとにIssueをグループ化する
Issueには担当者を割り当て、状態管理を行えます。Slackなどの協業ツールとも連携可能で、GitHubやGitLabなどとも連携できます。
Issueごとに様々なメタデータが収集・表示されるため、担当者は迅速に対応できます。
- OS、ブラウザ、デバイス情報
- アプリケーションのバージョン・リリース情報・コミットハッシュ
- ユーザーID、メールアドレス、IPアドレスなど
- エラー発生前のユーザー行動記録(HTTPリクエスト、DOMイベントなど)
- 発生頻度、時系列推移、環境ごとの統計
- HTTPヘッダ、メソッドなどのネットワーク情報
- その他、アプリ側で指定した任意の動的データ
一つのIssueでは、これらの情報を総合的に確認できます。
Event
Sentryにおける「イベント」とは、アプリケーション内で発生した何らかの事象を指します。
イベントには以下の2種類があります:
-
Error Event
アプリケーション内のエラーを記録します。 -
Transaction Event
アプリのパフォーマンスやUX測定のための一般的なイベントを記録します。
Error
ErrorはSentryの中核となる機能です。
Error Eventは、コード内で発生した例外、または明示的にエラーを捕捉した箇所から収集されます。
import * as Sentry from '@sentry/nextjs';
try {
drinkCoke();
} catch (error) {
console.error(error);
Sentry.captureException(error); // <=== ログがここで収集される!
}
Transaction
Transactionはパフォーマンスモニタリングの中核機能です。
ユーザーの操作や内部処理の一連の流れを表し、開始時間と終了時間を持ち、実行時間の測定が可能です。
- LCP(Largest Contentful Paint)、TTFB(Time To First Byte)、FCP(First Contentful Paint)などの指標が記録されます。
- 一つのTransactionは複数のSpanを含み、Spanも再帰的にSpanやTransactionを含むことができます。
- 結果として、Transactionはツリー構造になります。