AWS RUMをNext.jsに入れようとして詰まった話

AWS RUMをNext.jsに入れてクラッシュログを収集しようとしたときに、詰まったので同じように詰まっている人の為に、情報を残しておきます。

## tl;dr
- RUMを作成するterraformのコード記載例をそのまま使ってもうまく動かない。
- RUMには何らかの認証情報が必要。元々Cognitoを使った認証をしていないなら、新規で匿名認証を使う。
- Cognitoの制御を`aws-rum-web`では出来ないので、Identity poolを切り替えたりした場合は何らかの方法でLocal storageを削除するなどの方法で回避する必要がある。


## AWS RUMとは？
Amazon CloudWatch RUM（Real User Monitoring）は、Webアプリケーションのパフォーマンスに関するクライアント側のデータをリアルタイムで収集し、ユーザーモニタリング結果を提供するサービスです。
SentryやGoogle Analyticsのように、フロント側に仕込んでおいて、クライアント側で何が起こっているかを収集する類のサービスです。

Cloud WatchのApplication Signalsというサービスの中の1機能として位置づけられている(?)ようですが、RUM自体は2021年から使える機能です。

https://dev.classmethod.jp/articles/amazon-cloudwatch-application-signals-public-preview/

## 何が起こったのか
私ははじめ単純にクライアントにタグを埋め込んだらそれだけで基本的な部分は使えるようになると思っていました。

IaCとしてTerraformを使っていたので、以下の公式ドキュメントを参考にRUMのリソースを作成しました。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rum_app_monitor

```hcl
resource "aws_rum_app_monitor" "rum" {
  name   = "${var.environment}-rum"
  domain = var.domain

  app_monitor_configuration {
    allow_cookies       = true
    session_sample_rate = 1.0
    telemetries         = ["performance", "errors", "http"]
  }
}
```

一応これでエラーなく作成でき、マネジメントコンソールからスニペットが表示されるので、それをコピーしてNext.jsの`_app.tsx`に追加しました。

しかし、フロント側でエラーが出ることもなく、いくら待っても一向にデータが飛んできませんでした。

### Cognitoによる認証が必須だった
スニペットを書き換えたり、ログを仕込んで見たり色々デバッグして試行錯誤していましたが、そんな中以下のブログにあるマネジメントコンソールから作る方法を試した際に、`Authorization`の項目が選択式になっていることに気づきました。

https://dev.classmethod.jp/articles/using-cloudwatch-rum-with-nextjs-app/

![スクリーンショット 2023-12-06 9.45.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141823/5d97bf57-8f7d-f431-6a7e-f926d08ee302.png)

この選択肢を見ると、新しくidentity poolを作成するか、既存のidentity poolを指定するか、もしくは別の認証の仕組みを使うかして、とにかく認証を通す必要がありそうでした。

なので、コンソールから`Create new identity pool`を選択して、スニペットを書き換えると無事ログが飛んでくるようになりました。
terraform上はoptionalとなっていたので任意項目だと思っていましたが、RUMでは必ず何らかの認証を通す必要がありました。


### Cognitoの認証が通らなくなる
上記で問題が解決したので、terraform側で改めて匿名認証用のCognitoのidentity poolを作成して、RUMに設定しました。

```hcl
resource "aws_cognito_identity_pool" "identity_pool" {
  identity_pool_name               = "${var.environment}-rum-identity-pool"
  allow_unauthenticated_identities = true
  allow_classic_flow               = true
}

resource "aws_cognito_identity_pool_roles_attachment" "identity_pool_role_attachment" {
  identity_pool_id = aws_cognito_identity_pool.identity_pool.id
  roles = {
    "unauthenticated" = aws_iam_role.rum-role.arn
  }
}

resource "aws_rum_app_monitor" "rum" {
  name   = "${var.environment}-rum"
  domain = var.domain

  app_monitor_configuration {
    allow_cookies       = true
    session_sample_rate = 1.0
    telemetries         = ["performance", "errors", "http"]
    identity_pool_id    = aws_cognito_identity_pool.identity_pool.id
  }
}
```

これでapplyしたところ、なんとまたログが飛ばなくなってしまいました😭


こちらも原因を探るのにかなり時間を要したのですが、結論から言うとスニペットで利用している`aws-rum-web`というパッケージが新しいIdentity Poolに切り替えれていないためでした。

[`aws-rum-web`のドキュメント](https://github.com/aws-observability/aws-rum-web/blob/main/docs/cdn_troubleshooting.md#no-aws-credentials)にこんな記載が、、、
> The web client requires AWS credentials to sign RUM payloads. When the RUM web client does not have AWS credentials, it will not attempt to send events to CloudWatch RUM. Your application must either (1) provide the web client with an anonymous Cognito identity using identityPoolId and guestRoleArn, or (2) provide the web client with AWS credentials using the cwr('setAwsCredentials', credentials); command.

要するにRUMは内部でAWSの認証情報を利用していて、cwrコマンドでクレデンシャルを渡すか、identityPoolIdをつかって認証させる必要があるとのこと。

IdentityPoolが切り替えれずに認証に失敗しているのが原因ぽかったので、以下のブログに書いてある方法を試せればよかったのですが、Cognitoのパッケージを使っているわけではないので、こういった解決策も使えませんでした。

https://qiita.com/tkns3/items/3ee6e78d80b72b527955#%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95%E3%81%9D%E3%81%AE%EF%BC%91

## 最終的には切り替え前から存在するCognito認証用のlocalStorageを削除したら治った

cookieとLocal storageにそれぞれ`cwr_i`や`cwr_c`というようなキーの情報が保存されるようになります。
Local storageを削除すると、無事新しい方のidentity poolに認証しにいくようになり、解消しました。
Cognito のidentity poolを切り替えたために発生したと思うので、そのような場合にはこの辺を調べていただくと、なにか解決のヒントが得られるかもしれません。