🌤️

Sentryを使用したSvelteKitアプリケーションのエラー追跡

2024/05/07に公開

導入

実運用アプリケーションでは、機能の実装だけでなくエラーの管理・追跡も重要です。
いつ、どこで、どんなエラーが発生したかを記録することで、障害の早期対応やデバッグのしやすさに繋がります。

自前でエラー管理システムを構築することも可能ですが、エラー管理というどのアプリケーションにも共通する事柄であれば、できるだけ既存のサービスを使用したいところです。

今回はエラー管理SaaSの1つ、SentryをSvelteKitで使用する方法のまとめと、2024年現在公式対応されていない、エッジロケーションでの利用方法をまとめたいと思います。

なお、対象となるSvelteKitアプリケーションは実装が完了してる前提です。
SvelteKitアプリケーションの構築方法については以下の公式ドキュメントをご覧ください。

https://kit.svelte.dev/docs/creating-a-project

準備

  1. Sentry.ioのページにアクセスしサインアップとログインを完了させます。

https://sentry.io

  1. 左メニューから「Projects」→「+ Create Project」ボタンをクリックし新規プロジェクトを作成します。

  2. プロジェクトの設定を入力し、作成を完了します。

    1. Choose your platform:Browser → Sveltekit
    2. Set your alert frequency:Alert me on every new issue
    3. Name your project and assign it a team:プロジェクト名を入力

example-project

  1. 完了すると、以下のような画面に移動します。セットアップウィザードを推奨されますが、ここではマニュアル統合を使用します。まずは「Take me to Issues」をクリックし、Issuesに移動します。

create-result

  1. Issuesの画面はこんな感じです。ここに記録されたエラーが追加されていきます。
    まだ、何もエラーが発生してないのでリストは空のはずです。

issues

アプリケーションへの統合

まずは以下の公式のガイドに従って各種実装を完了させます。

https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup

詳細な手順は公式ドキュメントを見ていただくとして、ここでは大まかな最小限の実装の流れとサンプルコードの紹介のみに留めます。

1. 依存関係の追加

プロジェクトルートで以下を実行します。

npm i @sentry/sveltekit

2. クライアント側実装

src/hooks.client.jsを作成し、以下を記述します。
__SENTRY_DSN_PLACEHOLDER__はあとで書き換える場所です。

hooks.client.js
import * as Sentry from "@sentry/sveltekit";

Sentry.init({
  dsn: "__SENTRY_DSN_PLACEHOLDER__",
  tracesSampleRate: 1.0,
  integrations: [Sentry.replayIntegration()],
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
});

const myErrorHandler = ({ error, event }) => {
  console.error("An error occurred on the client side:", error, event);
};

export const handleError = Sentry.handleErrorWithSentry(myErrorHandler);

// エラー時の処理を省略する場合は以下のようにも記述できます。
// export const handleError = Sentry.handleErrorWithSentry();

3. サーバー側実装

src/hooks.server.jsを作成し、以下を記述します。
__SENTRY_DSN_PLACEHOLDER__はあとで書き換える場所です。

hooks.server.js
import * as Sentry from "@sentry/sveltekit";

Sentry.init({
  dsn: "__SENTRY_DSN_PLACEHOLDER__",
  tracesSampleRate: 1.0,
});

export const handle = Sentry.sentryHandle();

// 複数のhandleを使用するには`@sveltejs/kit`から`sequence`関数をimportして使用します。
// export const handle = sequence(Sentry.sentryHandle(), yourHandler());

const myErrorHandler = ({ error, event }) => {
  console.error("An error occurred on the server side:", error, event);
};

export const handleError = Sentry.handleErrorWithSentry(myErrorHandler);

// エラー時の処理を省略する場合は以下のようにも記述できます。
// export const handleError = Sentry.handleErrorWithSentry();

これで最低限の実装は完了です。

ソースマップのアップロードなどを行う場合は以下の公式ガイドのVite Setup以降を参照してください。

https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/#vite-setup

4. DSNの確認・変更

先ほど実装したコード中の__SENTRY_DSN_PLACEHOLDER__を実際の値に変更します。

  1. まずはプロジェクトのDSN値を確認します。
    Sentryのwebページ左メニューから「Projects」→「作成したプロジェクトの⚙️(歯車アイコン)」→「SDK Setup」の「Client keys(DSN)」を選択します。

DSN Page

  1. ページ中程にあるDSNの値で2箇所の__SENTRY_DSN_PLACEHOLDER__を置き換えます。
Sentry.init({
-  dsn: "__SENTRY_DSN_PLACEHOLDER__",
+  dsn: "https://1abb592bdf4af9f41339ff763dec1086@o4505814639312896.ingest.us.sentry.io/4507209193160704",
// ...
});

以上で統合が完了しました。
試しにボタンを押したらnew Error("Test")をthrowするように簡単にコードを記述してテストしてみます。

+page.svelte
<button
  on:click={() => {
    throw new Error("Test");
  }}
>
  Throw Error
</button>

すると、Issuesリストにエラーが記録されます。

Issues

クリックするとエラーが発生した場所やデバイス情報などの詳細を確認できます。

Issue Detail

また、同時に通知メールが飛んできてエラーの概要を知らせてくれます。

Email

以上がSentryの簡単な概要です。

エッジロケーション(非Node環境)での利用

さて、そんな便利なSentryですが、エッジロケーション(非Node環境)で使用しようとすると少し困ったことが起こります。

それは@sentry/sveltekitがNodeランタイムに依存しているため、Vercel Edge FunctionやCloudflare Pagesといった非Node環境で動作する場合にサーバー側のエラー追跡ができないことです。

これを解決するためには、Nodeに依存しないライブラリが必要ですが、現在公式クライアントは対応作業中ということで2024年現在は利用できません。

https://github.com/getsentry/sentry-javascript/issues/8291

そこで、今回紹介するのが私が作成した非Node環境で動作するクライアントライブラリ、@jill64/sentry-sveltekit-edge及び@jill64/sentry-sveltekit-cloudflareです。

https://github.com/jill64/sentry-sveltekit-edge#readme

https://github.com/jill64/sentry-sveltekit-cloudflare#readme

これらはいずれもfetchをサポートするエッジロケーションであれば動作可能なように、公式クライアントを改変したものです。詳細についてはREAMEを参照いただくとして、ここでは簡単な導入方法を紹介します。

なお、@jill64/sentry-sveltekit-cloudflareはCloudflare Pagesでの動作に特化したライブラリで、使用方法は2つともほぼ同じです。

1. 依存関係の追加

プロジェクトルートで以下を実行します。

npm i @jill64/sentry-sveltekit-edge

2. 準備

vite.config.jsに以下の行を追加します。

vite.config.js
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [sveltekit()],
+  ssr: {
+    noExternal: ['@jill64/sentry-sveltekit-edge']
+  }
  // ...
})

3. クライアント側実装

src/hooks.client.jsに以下を記述します。
__SENTRY_DSN_PLACEHOLDER__はDSNを記述します。

hooks.client.js
// hooks.client.js
import { init } from '@jill64/sentry-sveltekit-edge/client'
// もしくは
// import { clientInit } from '@jill64/sentry-sveltekit-edge'

const onError = init(
  '__SENTRY_DSN_PLACEHOLDER__'
  // ,
  // {
  //   sentryOptions: {
  //     // Sentryの設定を記述します(任意)
  //   },
  //
  //   /* 開発モード中にエラーログを送信するかどうか(デフォルト:false) */
  //   enableInDevMode: boolean
  // }
)

export const handleError = onError((e, errorEventId) => {
  // エラー発生時の処理(任意)
})

4. サーバー側実装

src/hooks.server.jsに以下を記述します。
__SENTRY_DSN_PLACEHOLDER__はDSNを記述します。

hooks.server.js
// hooks.server.js
import { init } from '@jill64/sentry-sveltekit-edge/server'
// もしくは
// import { serverInit } from '@jill64/sentry-sveltekit-edge'

const { onHandle, onError } = init(
  '__SENTRY_DSN_PLACEHOLDER__'
  // ,
  // {
  //   sentryOptions?: {
  //     // Sentryの設定を記述します(Node環境ベース)
  //   },
  //   handleOptions?: {
  //     handleUnknownRoutes: boolean (default: false)
  //   },
  //   /* 開発モード中にエラーログを送信するかどうか(デフォルト:false) */
  //   enableInDevMode?: boolean
  // }
)

export const handle = onHandle(({ event, resolve }) => {
  // handle hook処理(任意)
})

export const handleError = onError((e) => {
  // エラー発生時の処理(任意)
})

あとは公式のクライアントと同様に、エラーをthrowするだけで、自動でエラーログが記録されていきます。

総括

いかがだったでしょうか。
エラー追跡は最初の導入に労力がかかる部分ですが、Sentryの使用に慣れてしまえばテンプレートをもとに複数のプロジェクトのエラーを一元管理できるので便利です。

この記事がSvelteKitでエラー追跡の管理をしようとしている方の助けになれば幸いです。

またOSSプロジェクトについてバグや不明点がありましたらぜひ以下からIssueを開いてください。

https://github.com/jill64/sentry-sveltekit-edge/issues

https://github.com/jill64/sentry-sveltekit-cloudflare/issues

Discussion