📊

SentryのPerformance Monitoringを活用する

2022/03/18に公開1

こんにちは、stand.fm エンジニアの 外松(@toshi-toma)です。
stand.fmでは、Sentryをエラー監視に加えて、パフォーマンスの計測でも活用しています。
今回はSentryのPerformance Monitoringの活用方法について紹介します。特にReact Nativeやフロントエンド・クライアントの計測について扱います。

SentryでPerformance Monitoring

SentryはアプリケーションのPerformance Monitoringを提供しています。

https://docs.sentry.io/product/performance/

Web Vitalsや画面遷移、特定の操作完了までの時間などをSentryのダッシュボードで視覚的に確認したり、詳細な情報を見て分析することができます。エラーに関する情報は「Issues」タブを見てると思いますが、「Performance」タブから情報を確認できます。

既にSentryが導入されているアプリケーションであれば、簡単に導入できるのが魅力の一つです。基本的には追加のパッケージをインストールする必要もありません。

また、分散トレーシングで、フロントエンドからバックエンドまでを一貫したデータとして計測・可視化することも可能です。

stand.fmでの活用

stand.fmは、React Nativeで開発しているアプリのパフォーマンス改善に注力しているので、クライアントアプリのパフォーマンス計測にSentryを活用しています。
改善したい箇所が決まった時、まずは計測できるようにし、ボトルネックを見つけ、改善を実施、効果測定の流れで進めることが多いです。

また、継続して監視したい項目については、リリースバージョン毎のデータを可視化できるビューをSentryに作成しています。

アプリの起動速度改善に取り組んだ流れについて以下の資料で紹介してるので、合わせて見てもらえると嬉しいです。

https://speakerdeck.com/standfm/improvement-of-speed-startup-app-60c9fdab-78ff-40bb-9289-2e6edb406d59

パフォーマンス計測

用語

いくつかSDKのAPIやドキュメントで頻出する用語を紹介します

  • Transaction
    • Sentryに送信したい操作の単位
      • 例)アプリの起動、画面遷移、ボタンを押してから〇〇が完了するまで
    • 0個以上のSpanを持ちます
  • Span
    • Transactionの中の子タスクのようなイメージです
      • 例)APIリクエスト、関数、Reactコンポーネントのmount
    • 開始時刻と終了時刻を持ちます

計測

SentryのSDKがインストール、セットアップされていれば、計測は簡単です。(Sentry SDKのセットアップは各プラットフォームごとにドキュメントが用意されています)
まず、計測を開始したいタイミングでTransactionを開始します。

const transaction = Sentry.startTransaction({ name: "アプリ起動" });

処理の細かい内訳を見たい場合はSpanを追加して、処理が終わるタイミングで終了させます。

const spanA = transaction.startChild({ op: "初期化処理" });
// 初期化処理
// ...
spanA.finish();

const spanB = transaction.startChild({ op: "トップページのAPI呼び出し" });
// トップページのAPI呼び出し
// ...
spanB.finish();

計測したい一連の操作が終わったタイミングでTransactionを終了させると、Sentryに計測データが送信されます。

transaction.finish();

※ 普段利用しているReact NativeのSDKで確認したコードをサンプルにしていますが、React NativeのSDKはJavaScriptのSDKやReact向けのSDKをラップしてるだけなので、基本的なコードは同じはずです

Performanceダッシュボード

Sentryに送られてきた計測データはダッシュボードで可視化できます。
同名のTransactionを集計したグラフを確認したり、特定のTransactionやその中のSpanの内訳などの詳細を確認することが多いです。

色々なビューやフィルタリングがあるので、OSやアプリのバージョンごとのデータを見て分析することもできます。

Alertの設定

一度、目標値までパフォーマンスを改善しても、新機能の実装など、様々な理由でいつの間にか悪化してた。なんてこともあります。継続的に監視していけるようにSentryのAlertをパフォーマンスについても設定できます。

Sentryのダッシュボードから設定することで、閾値を超えたらSlackに通知することができます。

活用時のTips

実際にSentryのPerformance Monitoringを運用していく上で得られたTipsをいくつか紹介します。

JavaScript SDK

Sentryのドキュメントを読むだけだと、各APIの用途や使い方が分からないものが多かったので、以下のJavaScript SDK ドキュメントも合わせて参照しました。
ただ、バージョンが古いので、参考程度に見るのがいいです。

https://getsentry.github.io/sentry-javascript/

複数のTransactionを管理

Transactionを開始して、アプリケーションコード内の任意のタイミングでSpanの開始・終了、Transactionの終了を行いますが、それらを実行したいタイミングはコード上では分散してることが多いと思います。
これらの処理は生成したTransactionオブジェクトに対して行うので、それが簡単に共有できたら良いですが、ドキュメントで紹介されているTransactionオブジェクトの取得は以下の通りです。

const transaction = Sentry.getCurrentHub().getScope().getTransaction();

このgetTransactionで最新のtransactionを取得しますが、複数のTransactionが同時に走っている場合、id指定などで特定のTransactionが取得ができません。単純にやろうとするとグローバルでオブジェクトを共有しないといけなかったので、tagを設定することで疑似的に可能にしました。

まずTransaction開始時にtagを設定します。あとから参照できるようにTransactionをScopeというものに設定しておきます。

const startTransaction = () => {
  const hub = Sentry.getCurrentHub()
  const scope = hub.pushScope()
  const transaction = Sentry.startTransaction({
    name: 'アプリの起動'
  })
  transaction.setTag('myId', 'app_launch')
  scope.setSpan(transaction)
}

あとは任意のタイミングでidをもとにTransactionを取得します。終了済みのものなどをフィルタリングします。

const getTransactionByID = (id) => {
  const hub = Sentry.getCurrentHub()
  if (!hub) {
    return null
  }
  const layers = hub.getStack()
  const filteredLayers = layers.filter(layer => {
    const _transaction = layer?.scope?.getTransaction()
    return (
      _transaction?.tags?.myId === id &&
      !_transaction?.endTimestamp
    )
  })
  if (!filteredLayers.length) {
    return null
  }
  const transaction =
    filteredLayers[filteredLayers.length - 1].scope.getTransaction()
  return transaction
}

この取得方法で、複数のTransactionを管理しています。

タグの設定

先ほど触れたタグの設定は便利で他の用途でも活用しています。
これは任意の情報をTransactionに設定できます。ダッシュボードでビューを作成する際に、特定の条件下のパフォーマンスを可視化したい場合なども考慮して設定しておくと良いです。後からだと溜まったデータを十分に活用できないので、計測を入れる前に一度どういう条件で分析したいかを検討するのがおすすめです。

transaction.setTag('variant', 'A')

Transactionの節約

送信できるTransactionにはプランや課金状況に応じて上限があるので、全てを送信するのではなく、ある程度サンプリングします。init時にtracesSampleRateで設定できます。

Sentry.init({
  tracesSampleRate: 0.2
});

また、TransactionごとにSampleRateを変更したい場合はtracesSamplerで設定できます。

https://docs.sentry.io/platforms/react-native/performance/#configure-the-sample-rate

React Profiler

Reactコンポーネントのマウントや再レンダリングをSpanとして計測したい場合に便利なAPIが提供されています。

https://docs.sentry.io/platforms/javascript/guides/react/components/profiler/

HOCとしてwithProfiler、HooksとしてはuseProfilerが提供されています。

おわりに

SentryのPerformance Monitoringについてとその活用について紹介しました。
継続的にパフォーマンスをモニタリングし、ボトルネックを改善することで、ユーザーにとって快適なアプリケーションを提供していけるよう取り組んでいきます。

・・・

株式会社 stand.fm では、絶賛エンジニアを募集しております!

募集職種はこちらから

https://corp.stand.fm/recruit?utm_source=standfm-web&utm_content=top

Meetyからカジュアル面談も募集しています。

https://meety.net/matches/KcRAWVLnazkL

Discussion

k-satok-sato

👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍