【CloudWatch RUM × X-Ray】フロントエンドからバックエンドを一気通貫でトレースする方法
はじめに
CloudWatch RUM (Real User Monitoring)はフロントエンドのモニタリングに関するサービスです。 ページを開くまでに掛かる時間やAPI実行時のエラー発生を検知することができます。
CloudWatch RUMではX-Rayを利用してフロントエンドからのHTTP通信をトレースを確認することができ、さらにX-Rayに対応したバックエンドサービスにトレースIDを送信することで、フロントエンドからバックエンドまで同一のトレースIDで確認することが可能になります。
今回はそのための構成と実装についてサンプルコードと共に紹介します。
ソース
今回検証に利用したソースはこちらにあげています。
本記事では紹介しませんが、エラーを起こすためのボタンや外部APIに接続して500Errorを発生させるための画面を用意しているので、CloudWatch RUMの動作を簡単に確認したい時に使ってみてください。
構成
全体の構成を紹介します。 特にひねりのない構成です。
フロントエンド
- Reactで実装し静的ビルドファイルを配置
- CloudFront
- S3
バックエンド
- ApiGateway(RestApi)
- Lambda(Node.js, Typescript)
監視
- CloudWatch RUM
- X-Ray
IaC
- AWS CDK
完成イメージ
実際に取得できたトレースを紹介します。
こちらはX-Rayの画面です。
このように、フロントエンドからバックエンドまで1つのトレースとして表示できます。
さらにX-Rayトレースでメタデータを確認すると、セッションIDを取得することができます。
このセッションIDをCloudWatch RUMの画面で利用すると、該当のセッションが確認できます。
こちらはCloudWatch RUMの画面です。
このように、バックエンドでエラーが起きた際にX-Rayで調査し、そのままフロントエンドのページ遷移や離脱も追うことができるので、障害調査で重宝しそうですね。
実装方法
ここからソースを抜粋して紹介します。
動作するコードを見たい場合は以下リポジトリを参考にしてください。
CloudWatch RUMの設定
設定方法はこちらのブログを参考にさせていただきました!
特殊な設定は必要ないですが、X-Rayの設定を有効化する必要があります。
APIGatewayの設定 (AWS CDK)
デフォルトでは X-Amzn-Trace-Id
のヘッダーフィールドを受け取るとCORSに引っかかってしまうので、許可設定を追加してあげる必要があります。
// API Gateway定義 const defaultAllowHeader = [ "Content-Type", "X-Amz-Date", "Authorization", "X-Api-Key", "X-Amz-Security-Token", "X-Amz-User-Agent", ]; const api = new RestApi(scope, "RumSampleApi", { restApiName: "RumSampleApi", deploy: true, defaultCorsPreflightOptions: { allowOrigins: ["*"], allowMethods: ["GET", "OPTIONS", "POST", "PUT", "DELETE", "PATCH"], allowHeaders: [...defaultAllowHeader, "X-Amzn-Trace-Id"], // ⭐️こちらで設定 }, deployOptions: { stageName: "dev", tracingEnabled: true, // ⭐️ X-Rayを有効化 }, });
フロントエンドの実装
const SettingRum = () => { try { const config: AwsRumConfig = { sessionSampleRate: 1, identityPoolId: "<AwsRumの認証を行うCognitoのID>", endpoint: "https://dataplane.rum.ap-northeast-1.amazonaws.com", telemetries: [ "performance", "errors", [ "http", { addXRayTraceIdHeader: true, // ⭐️ }, ], ], allowCookies: true, enableXRay: true, // ⭐️ }; const APPLICATION_ID: string = "<AwsRumのアプリケーションID>"; const APPLICATION_VERSION: string = "1.0.0"; const APPLICATION_REGION: string = "ap-northeast-1"; const awsRum: AwsRum = new AwsRum( APPLICATION_ID, APPLICATION_VERSION, APPLICATION_REGION, config ); } catch (error) { // Ignore errors thrown during CloudWatch RUM web client initialization } return <></>; };
root.render( <> <SettingRum /> // ⭐ こちらで呼び出し <BrowserRouter> <Routes> <Route path="/" element={<Layout />}> <Route index element={<App />} /> <Route path="/about" element={<About />} />{" "} <Route path="/api" element={<SampleExternalApi />} /> <Route path="/api-gateway" element={<SampleApiGateway />} /> <Route path="/jsError" element={<JsError />} /> </Route> </Routes> </BrowserRouter> </> );
※ React Routerを使って実装しています。
addXRayTraceIdHeader: true
を設定することで、自動で全てのHTTP通信にX-Rayトレース用のヘッダーフィールドを付与してくれるようになります。
具体的には X-Amzn-Trace-Id
というヘッダーフィールドです。
設定値はこちらを参考にしました。
今回は特に制限なくトレースIDを送るように設定していますが、urlsToInclude
, urlsToExclude
の設定を行うことで、トレースIDを送る対象のドメインを絞ることが可能です。
基本的には urlsToInclude
に対象のAPIGatewayのドメインを設定することになるでしょう。
注意点
X-RayのトレースIDをヘッダーに付与して送信する際に、CORSに引っ掛かる可能性があります。特に、複数のAPIに対してフロントからリクエストを行うサービスでは思わぬところでX-Ray用のヘッダーを送ってしまい、エラーが出る可能性があるので注意が必要です。 必要のないAPIに対してはヘッダーを付与しないようにするなどの対策を行いましょう。