Next.js を datadogで監視する

最近業務でdatadogによる監視を入れてくれ！という依頼があり、Nextjs + Rails(api)という構成のアプリケーションにdatadogを導入しました。

せっかくなのでその手順等を残します。

また、長くなるのでfront・apiで記事を分けます。こちらはNextjsに関する記事です。

:::note info
公式ドキュメント参照推奨です！
全般そうかもですが、datadogは割と充実している印象です。
:::

datadog - Nextjsモニタリング

https://docs.datadoghq.com/ja/real_user_monitoring/guide/monitor-your-nextjs-app-with-rum/?tab=npm

# 環境
```
next: "^14.2.15"
MacOs: Sonoma14.5
```

# 概要
まず、「Nextjsにdatadogを導入する」というのは何をすることを指すのか整理します。
datadogの監視ツールでよく利用されるものに、「APM（Application Performance Monitoring ）」や「RUM（Real User Monitoring）」があります。（他もありますが、今回利用するのはこれら二つです）

Nextjsはフロントエンドなので、今回は「Nextjsに、datadogが提供するRUMを導入し、ユーザー体験を監視する」ということになりそうです。

（apmはapi側で出てきますが、rumはブラウザのレンダリング時間など実際のユーザー目線の監視、apmはサーバーサイドにおける詳細なログ（クエリやエラーなど）の監視と捉えておくと良い気がします）

# 方針

もう少し具体的な想定をしてからの方が実装で何をしているかわかりやすいと思い、セクションを用意しました。

先ほどリンクを載せた datadog - nextjs のページを読むとわかりますが、nextjs13以降（app router導入以後）はnpm等によるdatadogライブラリ利用 **ではなく、CDNの利用を推奨しています**。

> If your application relies on the newer Next.js App Router (versions 13+), Datadog recommends using the CDN RUM instrumentation to ensure that the RUM initialization occurs in the client. 

CDN利用の場合、クライアントコンポーネントを作成する必要がなくlayout.jsなどにそのまま組み込めるというのと、ライブラリのバージョン管理などから一定解放されるため良さそうです。

（※AIに頼むと、割とインストールをしているような実装が出てきやすいです。外部ツールにはまだ弱さがあると感じます。）

CDN利用にもasync, syncの二つがあります。asyncはその名の通り非同期でdatadog監視が導入されるため、初期レンダリングなど一部漏れる可能性があります。しかし、ディレイは少なくなります。

syncの場合、動機的にdatadog監視を開始してくれるのでそれを初期レンダリングで待つ必要がありますが、ほぼ全ての動きを監視してくれます。

パフォーマンスを落とさず導入したいならasync, 全て網羅したいのであればsyncの選択をする感じでしょうか。実装難易度は大差ないので、現場の要求に合わせるで良いと思います。

今回は、網羅的な監視をしたいのでsyncを選びました。

# 実装詳細
RUMは非常に簡単です。以下手順です。
1. datadog webコンソールから新しいRUMアプリケーションを作成する → client_token & application_idが発行される
1. nextアプリケーションにdatadog向けのスクリプトを入れる → そこに先ほどのtokenなどを設定する

これだけです。実際に見ていきます。

### 1. 新規RUMアプリケーションの作成
datadogのwebコンソールから、Digital Experience -> Real User Monitoring -> Manage Applications と進みます。

![スクリーンショット 2025-05-11 10.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/bad8099e-b550-4f03-9484-0423447c94f7.png)

New Applicationボタンがあるので、押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/8470e023-c135-4fce-a383-137b1d3036d6.png)

アプリケーション名には任意の名前を設定し、JSを選択した上でCreate Applicationボタンを押します。
※nextjsだからreactっぽい気もしますが、公式ドキュメントでもjsを選択しています。（20250511時点）情報が古くなっている可能性があるので、ご注意ください。

![datadog_front_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/e1101d0d-fd0b-431f-aeeb-f61e1e63e2d1.png)

成功すると、「success」のようなメッセージが表示されたのち、設定画面が出ます。
この時点でトークンやアプリケーションIDの組み込まれたscriptがすでに表示され、environmentなども入力すると自動でスクリプトに反映されます。

![SCR-20250511-jvwh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/66dbdf04-67ec-45a3-8aba-fadc8d3c6ce3.png)

※ここでの入力がdatadogアプリケーションに設定され、動かせないわけではなく、スクリプトに自動反映してくれて最初の導入が楽になるよね、くらいです。
よくみると、右側のserviceにtestと入っていたり、sessionSampleRateなどの値があることを確認でき、条件分岐などで環境ごと自由に設定できることが伺えます。

これでdatadogの作業は終了です。

### 2. nextアプリケーションに反映する
rumの場合、api keyなどは不要で、先ほどのapplicationIdやclientTokenがあればOKです。

webコンソールでは`<script>`タグを利用していますが、ドキュメントでは`<Script>`を利用しているので、そこだけドキュメントを優先する形にします。
※おそらくどちらでも動きます。

また、公式ではlayout.tsxなどに直接スクリプトを載せていますが、見た目が鬱陶しいので別途datadogScript.tsxファイルを用意し、それをlayout.tsxに載せました。

```tsx:src/app/DatadogScript.tsx（新規作成）
import Script from 'next/script'

export const DatadogScript = () => {
  return (
    <>
      <Script
        id="dd-rum-sync"
        src="https://www.datadoghq-browser-agent.com/us1/v6/datadog-rum.js"
        type="text/javascript"
        strategy="beforeInteractive"
      />
      <Script id="datadog-rum">
        {`
          window.DD_RUM && window.DD_RUM.init({
            # ローカルでとりあえず動かす、という場合先ほどのclient_tokenやapplicaiton_idををそのまま設定してください
            # github等にはあげないことを推奨します。
            clientToken: '${process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN}',
            applicationId: '${process.env.NEXT_PUBLIC_DD_APPLICATION_ID}',
            site: 'datadoghq.com',
            # サービス名を入れます。datadogで作成した際のサービス名で良いと思います。
            service: '${サービス名}',
            # こちらも、とりあえず動かしたい場合localなど、適当に設定してOKです。
            env: '${process.env.NEXT_PUBLIC_DATADOG_ENV}',
            sessionSampleRate: 100,
            sessionReplaySampleRate: 10,
            defaultPrivacyLevel: 'mask-user-input',
          });
        `}
      </Script>
    </>
  )
}
```

```tsx:src/app/layout.tsx
    <html lang="ja">
      <body>
        <DatadogScript />
        <ClientLayout>{children}</ClientLayout>
      </body>
    </html>
```

少し差はあると思いますが、bodyの下にDatadogScript画配置されれば良いです。
また、ローカルでのテストを終え、逆にローカルでは動かしたくない場合などはprocess.env.node_env !== "develop" && ~ みたいにすると良いかもです。

これで完了です。
うまく行けばコンソールに表示されているはずです。（一部でごめんなさい）
また、envなどで絞り込みできます。

![SCR-20250511-kdxj.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/26c7e52e-e397-430a-9a54-1f2ebb054e52.png)


以上で終了です。frontはcdn利用をするとだいぶ簡単に実装できます。

お疲れ様でした！