ブラウザRUMエージェントが収集したエラー

Splunk Observability Cloud リアルユーザーモニタリング / RUM の ブラウザ RUM エージェントが収集するエラーを理解します。

ブラウザ RUM エージェントは、期間がゼロのスパンとしてエラーを収集します。エラースパンは、エラーが発生した時刻に基づいたタイムスタンプを持ちます。

デフォルトでは、インストルメンテーションは以下のソースからエラーを収集します。

  • window オブジェクトの "error" イベントリスナーからの捕捉されなかったエラーと処理されなかったエラー。

  • window オブジェクトの unhandledrejection イベントリスナーからの未処理のプロミス拒否。

  • document オブジェクトの "error" イベントリスナーからのリソースのロードに失敗したことによるエラーイベント。

  • console.error コンソールに記録されるエラー

  • SplunkRum.error ログには記録されないが、エージェントによって収集されるエラー

シングルページアプリケーション(SPA)フレームワークから JavaScript エラーを収集するには、「シングルページアプリケーションのフレームワークでエラーを収集する」を参照してください。

捕捉されなかったエラーと処理されなかったエラー

ブラウザ RUM エージェントは、捕捉されなかったエラーや処理されなかったエラーを、onerror という名前のスパンとして登録します。以下は、捕捉されなかったり、処理されなかったりするエラーの典型的な例です。

  • try {}catch {} ブロックで捕捉されないエラー

  • エラーは catch ブロックで再度スローされますが、再度捕捉されることはありません。

  • ファイルの構文エラー

以下の例は、ブラウザ RUMエージェントがどのように捕捉されなかったエラーや処理されなかったエラーを収集するかを示しています:

構文エラーの例

次のような構文エラーを考えてみます:

var abc=;

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.messageUnexpected token ';'

  • error.objectSyntaxError

  • error.stackSyntaxError: Unexpected token ';'

注: error.message および error.stack メッセージはブラウザ固有です。

Null リファレンスの例

次の null 参照エラーを考えてみます:

var test = null;
test.prop1 = true;

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.messageCannot set property 'prop1' of null

  • error.objectTypeError

  • error.stackTypeError: Cannot set property 'prop1' of null at...

注: error.message および error.stack メッセージはブラウザ固有です。

捕捉されなかったプロミスの拒否

ブラウザ RUM エージェントは、捕捉されなかったプロミスの拒否を unhandledrejection という名前のスパンとして登録します。捕捉されないプロミスの拒否は、次の状況で発生する可能性があります。

  • 最後の .catch メソッドがないプロミスチェーンにおいて

  • catch ブロックでの再投了を含む、プロミス連鎖のエラーとして、後続の catch ブロックがない場合

  • async 関数の throw ブロックとして

以下の例は、ブラウザ RUMエージェントが捕捉されなかったプロミス拒否を収集する方法を示しています:

標準エラーの例

次のコードを考えてみます:

new Promise((resolve, reject) => {
   reject(new Error('broken'))
})

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.messagebroken

  • error.object"error"

  • error.stackError: broken at...

注: error.message および error.stack メッセージはブラウザ固有です。

タイプエラーの例

次のコードを考えてみます:

new Promise((resolve, reject) => {
   resolve(null)
}).then((val) => {
   val.prop = 1
})

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.messageCannot set property 'prop' of null

  • error.objectTypeError

  • error.stackTypeError: Cannot set property 'prop' of null at...

注: error.message および error.stack メッセージはブラウザ固有です。

リソースの読み込みに失敗

ブラウザ RUM エージェントは、読み込みの失敗を eventListener.error という名前のスパンとして登録します。画像やスクリプトの読み込み時にサーバーが 4xx または 5xx ステータスコードを返すと、ブラウザはリソースの読み込みに失敗します。

次の例を考えてみます:

<!DOCTYPE html>
<html>
   <head>
      [...]
   </head>
   <body>
      <img src="/missing-image.png" />
   </body>
</html>

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.message"IMG"

  • error.object"https://example.com/missing-image.png"

  • error.stack""//html/body/img""

注: error.message および error.stack メッセージはブラウザ固有です。

コンソールエラー

ブラウザ RUM エージェントは、コンソールを使用してログに記録された各エラーを console.error という名前のスパンとして登録します。ブラウザは通常、コンソールエラーを使用して開発者コンソールにメッセージを表示します。RUM エージェントは try...catch ブロックからコンソールエラーを収集します。このブロックのエラーは上位のスタックにスローされません

注: ブラウザコンソールは、コンソールエラーをブラウザ RUM エージェントエラーとして誤って報告する場合があります。スタックトレースを確認し、エラーの原因が Splunk RUM にあるのか、インストルメンテーション対象のアプリケーションで生成された console.error 呼び出しにあるのかを確認してください。

以下の例は、ブラウザ RUMエージェントがどのようにコンソールエラーを収集するかを示しています:

フィールドの値をnullに設定する例

次のコードを考えてみます:

try {
   someNull.anyField = 'value';
} catch(e) {
   console.error('failed to update', e);
}

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.messagefailed to update TypeError: Cannot set property 'anyField' of null

  • error.objectString

  • error.stack"TypeError: Cannot set property 'anyField' of null at...

注: error.message および error.stack メッセージはブラウザ固有です。

エラー404の例

次のコードを考えてみます:

axios.get('/users').then(users => {
   showUsers(users)
}).catch(error => {
   showErrorMessage()
   console.error('error getting users', error)
})

ブラウザ RUMエージェントは、以下の属性を使用してエラーを収集します:

  • component"error"

  • "error"true

  • error.message"error getting users Error: Request failed with status code 404"

  • error.object"String"

  • error.stack"Error: Request failed with status code 404 [...] at XMLHttpRequest.l.onreadystatechange  axios.min.js:2:8373)"

注: error.message および error.stack メッセージはブラウザ固有です。

Splunk RUM エラー

ブラウザ RUM エージェントは、SplunkRum.reportError を呼び出すことによってログに記録された各エラーを、名前が SplunkRum.reportError のスパンとして登録します。SplunkRum.reportError を使用しても、ブラウザの開発者コンソールにエラーが記録されません。エラーは他の RUM テレメトリとともに送信され、Splunk RUM UI で表示されます。

`SplunkRum.reportError` API 署名:

reportError: (
    error: string | Event | Error | ErrorEvent,
    context?: Record<string, string | number | boolean>,
) => voi
注: context はオプションのパラメータです。これを使用して、エラー スパンに追加の属性を添付できます。これは、次のセクションで説明する splunkContext と同じです。

次の例を考えてみます:

axios.get('/users').then(users => {
   showUsers(users)
}).catch(error => {
   showErrorMessage()
   if (window.SplunkRum) {
      SplunkRum.reportError()
      SplunKRum.reportError(error, {"info": "error getting users"})
   }
})

結果として発生するエラーは、ブラウザ RUMエージェントが収集した console.error と同様の属性を持ちます。

エラーコンテキスト

splunkContext と呼ばれる追加情報を任意のエラーオブジェクトに付加できます。splunkContext は、キーと値のペア({ key: value } など)で構成される単純なオブジェクトです。

  • key は文字列です。
  • value は、文字列、数値、またはブール値にすることができます。

エラースパンが作成されると、システムで splunkContext が検索され、そのスパンの属性としてそのキーと値のペアのすべてが自動的に追加されます。

const requestStart = performance.now()    
try {
    callAPI('/users')
} catch(e) {
   e.splunkContext = {
      "requestDurationBeforeFail": performance.now() - start,
   }
    console.error(e)
}

onError フック

インストルメンテーション設定では、エラースパンがバックエンドに送信される前に実行される onError フックをアタッチできます。これは、次を行う場合に役立ちます。

  • 高基数エラーのグループ化などの目的で、エラーメッセージなどのエラースパンの属性を変更します。

  • 特定のエラーが報告されないようにします。送信したくないエラーについては、単にフックで null を返します。

   SplunkRum.init({
      realm: '<realm>',
      rumAccessToken: '<your_rum_token>',
      applicationName: '<application-name>',
      deploymentEnvironment: '<deployment-env>',
	  instrumentations: {
          errors: {
            onError: (error, context) => {
              // pick the right prefix or Regexp to match what you need
              if (error instanceof Error && error.message.startsWith("Test")) {
                error.message = 'unified message'
              }
              
              // you need to return both the error and the context even if no changes were made
              // You can also return null - the span will be ignored and not sent.
              return {error, context}
            }
          },
        },
   });