問題の中には、はっきりとその存在を知らせるものもある。中には、「私のマシンでは動作する」と「誰にとっても動作する」の間の隙間に隠れている人もいる。この個体はまさにその隙間にしっかりと根を下ろしていた。
症状は単純そうだった。一部のユーザーが、HubSpotを利用したフォームを読み込めなかったのだ。原因は十分に理にかなっていた。ブラウザのプライバシー設定やトラッキングブロッカーが介入し、トラッカーに似たものは一切通過させなかったのだ。しかし、問題の 測定 を試みた途端、壁にぶつかり、一見簡単な解決策に見えたものが、はるかに興味深いものへと変わってしまった。
通常であればこうした不具合を検出するために用いるツールであるリアルユーザーモニタリングが、フォームを破損させていたのと全く同じ保護機能によってブロックされていた。私たちのニューレリックラムはトラッカーのような見た目をしていますが、それはまさにトラッカーだからです。私たちは、煙が感知すると煙感知器を無効にする装置が作動してしまう部屋に、煙感知器を設置しようとしていたのです。
この記事では、その矛盾をどのように解決したかを解説します。具体的には、New Relicを自社のファーストパーティドメイン経由でプロキシすることで、サードパーティのトラッキングのように見えないようにし、サブドメインに伴う複雑な問題に対処し、テレメトリデータをクリーンに保ち、最後にHubSpotの障害を確実に検出する方法(何も読み込まれないサイレント障害も含む)を構築しました。この過程では、CDNとディスパッチャーの接続、迅速な開発環境でのテスト、Cloud Managerを通じたデプロイ、そして巧妙な回避策を信頼できる指標に変えるためのバーンイン期間について解説します。
プロキシ方式を使用する場合は、エンドユーザーやサイト訪問者に対する契約上、規制上、またはその他の法的義務に基づき、その方式を使用する権利があることを確認することが重要です。
New Relicをファーストパーティ製品にする
New Relicを標準エンドポイントから直接読み込むのではなく、すべてを自社ドメイン経由でプロキシするという解決策を採用した。これにより、リクエストがサードパーティからファーストパーティへと移行し、ほとんどのトラッキング防止策を回避できます。
2つのエンドポイントが導入されました。
/nr/agent/→ New Relicブラウザエージェントにサービスを提供します/nr/data/→ビーコン(テレメトリ)要求を受信する
プロキシ値のハードコーディング
New Relic でファーストパーティプロキシを設定する最も簡単な方法は、プロキシパスを静的文字列としてNREUM.initに直接設定することです。assetsはNew Relicエージェントスクリプトのチャンクを提供するURLを、 beaconテレメトリデータを受信するURLを指定します。どちらもNew RelicのCDNではなく、独自のドメインを経由してルーティングされます。
proxy: {
assets: 'www.arborydigital.com/nr/agent',
beacon: 'www.arborydigital.com/nr/data'
}
これは簡単に理解できる。パスは一目で分かり、実行時ロジックは不要で、エージェントの初期化前に設定されるため、設定が時間内に反映されるかどうかのタイミングに関する懸念はありません。サーバーにその2つのルートが設定され、New Relicに正しく転送されていれば、正常に動作します。サブドメインのトラフィックがなく、単一ドメインで運営されているサイトの場合、これだけで十分な場合が多いです。
サブドメイン間でのプロキシ処理
サイトでblog.arborydigital.comのようなサブドメインを使用する場合、単一のハードコードされたプロキシパスでは不十分です。各サブドメインはそれぞれ独自のオリジンから動作し、ブラウザのセキュリティルールにより、 blog.arborydigital.comからwww.arborydigital.comでホストされているプロキシパスへのリクエストは、技術的にはクロスオリジンリクエストとなります。これは機能するかもしれないが、ブラウザが既に信頼している同じオリジンを通してテレメトリを送信するという、ファーストパーティプロキシの目的の一部を損なうことになる。
この問題を解決するには、プロキシ設定をランタイム時に動的に設定すればよい。固定ドメインを指すのではなく、スクリプトはwindow.location.hostnameをチェックして、ページが現在どのオリジンで実行されているかを判断します。そのホスト名がルートドメインまたはそのサブドメインのいずれかと一致する場合、プロキシエンドポイントはwindow.location.originを使用して構築されます。つまり、 blog.arborydigital.comはNew Relicトラフィックをblog.arborydigital.com/nr-assets/とblog.arborydigital.com/nr-beacon経由でルーティングし、 www.arborydigital.com独自の同等のパスを使用します。
このアプローチでは、各サブドメインに対応するプロキシルートがサーバーまたはCDNレベルで設定されている必要があります。New Relicエージェントの設定( NREUM.infoのbeaconフィールドとerrorBeaconフィールドを含む)も、エージェントがデータの報告先を認識できるように、現在のホスト名を反映するように更新する必要があります。
ajax.deny_list
New Relicのブラウザエージェントは、すべてのテレメトリをNew Relic独自のサーバーbam.nr-data.netではなく、ファーストパーティプロキシblog.arborydigital.com/nr/data経由でルーティングするように構成されています。これにより、既知のNRドメインを標的とする阻害剤を回避できる。
この副作用として、NRエージェントはページ上の すべての 送信XHR/フェッチリクエストを監視し、それらをAJAXイベントとしてキャプチャします。これには、 blog.arborydigital.com/nr/dataへの自身のビーコン呼び出しも含まれます。拒否リストがない場合、NRは自身のテレメトリPOSTをAJAXイベントとして記録し、それがさらにテレメトリとして送信されるため、AJAXデータがNR内部のトラフィックで汚染されることになります。
この問題を解決し、データレートがまるでAKIRAのような状態になるのを避けるには、組み込みのワイルドカードを使用してこれらのビーコン呼び出しをブロックすることができます。これは最終的にblog.arborydigital.com/nr/data/*のようになります。これを実装すると、ブラウザデータが正常にキャプチャされたときに、New Relic はajaxエントリを作成しないように指示されます。POST内の情報はすべて保持され、冗長な ajax エントリはなくなります。
クエリパラメータを機能フラグとして使用する
プロキシを?proxy=yes背後にゲートすることで、他の訪問者に影響を与えることなく、本番環境での動作をテストできます。URLにそのパラメータが含まれていない場合は、ブロックを完全に回避できるため、この場合、New Relicは動作しません。パラメータを追加したタブを開き、DevToolsでリクエストが自分のドメインを経由してルーティングされていることを確認し、すべて問題がなければ、スクリプトからその条件を削除します。そこからホスト名のチェックが引き継がれ、プロキシがすべてのトラフィックに対して自動的に有効になります。
New Relicエージェントの実装
JavaScriptコードは以下の方法で見つけることができます。
- New Relic One(one.newrelic.com)にログインしてください。
- ブラウザ→データの追加→ブラウザ監視に移動
- アプリケーション(アプリID)を選択するか、新しいアプリケーションを作成してください。
- SPAローダーを使用して、コピー/ペーストによるデプロイ方法を選択してください。
- 生成された
<script>スニペット全体をコピーします
RUM スクリプトをリポジトリに追加すると、それが独自のnewrelic.jsファイル内に存在するようにする必要があります。そうすることで、内部でそれを呼び出すことができます。 head.html
- 注:
<script src="/scripts/newrelic.js"></script>、metaタグの直後に初期化する最初のスクリプトである必要があります。
これが完了したら、この文字列に特定のプロキシ設定を追加する必要があります。生成されたスニペットのNREUM.initブロックに、プロキシ設定を追加します。
proxy: {
assets: 'www.arborydigital.com/nr/agent',
beacon: 'www.arborydigital.com/nr/data'
}
プロキシ(EDS/CDNレイヤー)の配線
プロキシ自体はCDNレイヤーに存在します。目標は単純です。受信した/nr/*のリクエストを実際のNew Relicエンドポイントに転送します。
オリジンセレクターは/nr/agent/*と/nr/data/*を除外する必要があります。そうし ない と、これらのリクエストはエッジ配信サービスのオリジンにルーティングされません。その代わりに、それらはデフォルトのAEMパブリッシュオリジンにフォールバックし、そこでApache ProxyPassルールが実行されます。cdn.yamlの中身は次のようになります。
originSelectors:
rules:
- name: arbory-da
when:
allOf:
- reqProperty: path
like: /*
# ...existing exclusions...
- reqProperty: path
doesNotMatch: /nr/agent/*
- reqProperty: path
doesNotMatch: /nr/data/*
action:
type: selectOrigin
originName: arbory-da
VirtualHost ( .vhost ) ファイルも編集する必要があります。
# New Relic Browser Agent Proxy
SSLProxyEngine on
# Proxy New Relic agent JS chunks (lazy-loaded scripts)
<Location "/nr/agent/">
ProxyPass "https://js-agent.newrelic.com/"
ProxyPassReverse "https://js-agent.newrelic.com/"
RewriteEngine Off
</Location>
# Proxy New Relic beacon/telemetry data
<Location "/nr/data/">
ProxyPass "https://bam.nr-data.net/"
ProxyPassReverse "https://bam.nr-data.net/"
RewriteEngine Off
</Location>
主な詳細:
SSLProxyEngine onアップストリームのターゲットがHTTPSであるため必要ですRewriteEngine OffAEMのデフォルトの書き換えルールがプロキシパスに干渉するのを防ぎます
HubSpotの障害を検出する(何も読み込まれない場合でも)
New Relicのブロックが解除されたとしても、次の問題は、HubSpotの障害が必ずしも明確なエラーメッセージを表示するとは限らないことです。特に、スクリプトが読み込まれない場合はなおさらです。
これに対処するため、2つの検出経路が追加されました。
1. スクリプトの読み込み失敗
HubSpotスクリプトの読み込みが完全に失敗した場合を検出する:
script.onerror = () => {
reportError('HubSpot script failed to load');
};
2. 実行時エラー
スクリプトの読み込み後にエラーを捕捉する:
window.addEventListener('error', (e) => {
if (e.filename && e.filename.includes('hsforms')) {
reportError('HubSpot runtime error');
}
});
どちらも同じレポート機能にデータを提供します。
function reportError(errorMsg) {
console.error(errorMsg);
if (window.newrelic) {
window.newrelic.noticeError(new Error(errorMsg));
}
}
実際に機能するかどうかの検証
配線がすべて完了すれば、検証は非常に簡単ですが、それでも重要です。テストは、厳格なトラッキング保護機能や拡張機能が有効になっているブラウザに焦点を当てるべきです。そのような環境では、HubSpotフォームの読み込みに失敗し、コンソールにエラーが表示され、同じエラーがNew Relicにも表示されるはずです。DevToolsで、エージェントが/nr/agent/からロードされ、ビーコンが/nr/data/に送信され、 bam.nr-data.netのようなサードパーティドメインへのリクエストがないことを確認してください。New Relicで、ダッシュボードにエラーが表示されていること、イベントがトリガーされた障害と一致していること、セッションが記録されていることを確認してください。セッションがまだ見つからない場合は、プロキシの設定が正しくない可能性があります。
迅速開発環境(RDE)を用いたテスト
もしあなたが当サイトの常連読者であれば、私が以前書いた、CDN構成変更をテストするためにラピッド開発環境(RDE)を使用することに関する記事を覚えているかもしれません。この新しいラム酒を試飲する際に、まさにそれを使ってみました!
ベストプラクティスに従う場合、開発はブランチ上で行われます。変更がメインではなくブランチに対して行われるようにするには、 cdn.yamlに追加の変更を加える必要があります。
origins:
# ...existing code...
- name: arbory-da
domain: (BRANCH_NAME)--(rest of domain).aem.live
forwardHost: false
変更をプッシュする準備ができたら、主に2つのコマンドを実行する必要があります。
aio aem:rde:install -t env-config ./config : これにより、 /configの内容と、以前に行った除外が反映されます。
aio aem:rde:install -t dispatcher-config ./dispatcher/src : これにより、 /srcの内容、つまりディスパッチャ構成.vhostの変更がプッシュされます。
RDEは他の環境とは異なるドメインで動作するため、プロキシ経由の新しいURLを指定する必要があります。そうしないと、第三者のドメインとみなされます。
proxy: {
assets: 'your-rde-domain.aem.live/nr/agent',
beacon: 'your-rde-domain.aem.live/nr/data'
}
Cloud Managerパイプラインのデプロイ(開発環境+本番環境)
これをAdobe Cloud Manager経由で展開するには、通常のコード変更よりも多少の調整が必要になります。プロキシの動作は複数のレイヤー(CDN、ディスパッチャ、ブラウザ)に依存しており、それらすべてが同じデプロイメント内で整合している必要があります。
導入の仕組み
パイプラインの実行では、以下のことが行われます。
- アプリケーションを構築して検証する
- ディスパッチャ構成(
.vhost、フィルタ、プロキシルールを含む)をデプロイします。 - CDN構成をデプロイします(
cdn.yaml、オリジンセレクタを含む) - キャッシュを無効化し、環境全体にわたって変更を反映させる
この実装では、ディスパッチャーとCDNの変更は密接に結びついています。プロキシは、両方の情報が存在し、かつ一貫性が保たれていない限り、正しく機能しません。
必須の変更点(必ず同時にデプロイしてください)
以下の更新は、同一のパイプライン実行に含める必要があります。
-
CDN (
cdn.yaml)- エッジ配信ルーティングから
/nr/agent/*と/nr/data/*を除外する
- エッジ配信ルーティングから
-
ディスパッチャー(
.vhost)ProxyPassNew Relicエンドポイントに対するルールはProxyPassReverse。SSLProxyEngine on- プロキシパスの書き換えを無効にする
-
ディスパッチャーフィルター
- 明示的な許可ルール
/nr/*
- 明示的な許可ルール
これらのいずれかが欠落しているか同期が取れていない場合、リクエストは誤った経路にルーティングされるか、ブロックされるか、またはサードパーティのエンドポイントにフォールバックされます。
バーンイン期間
プロキシの設定とデプロイが完了したら、すべてが期待どおりに動作することを確認するために、バーンイン期間を設ける必要があります。不具合はプライバシー設定、拡張機能、ネットワーク動作など、実際のユーザー環境に依存するため、全体像を把握するには時間がかかります。
時間をかけてデータが正しく取り込まれていることを確認したら、次のステップはそのデータをレビューすることです。想定されるトラフィックに対してエラー率を検証し、環境全体でカバレッジが確保されていることを確認し、ギャップ(見逃されたイベント、一貫性のないドメイン、エッジケースのブロッカーなど)を解消します。そこから、これを信頼できる指標として扱い、経時的な傾向を分析し、逸話的な報告ではなく、実際のユーザーへの影響を定量化するために活用できるようになります。
最後に
「ちょっと監視機能を追加するだけ」という軽い気持ちで始まったものが、ブラウザのプライバシーモデル、ファーストパーティプロキシ、CDNルーティング、そして、設計上測定を拒むものを測定するという繊細な技術を巡る旅へと発展していった。
重要な点は、監視対象と監視 に 使用するツールがどちらもブラウザによって歓迎されないとみなされる場合、市販のツールでは監視を成功させることはできないということだ。ブラウザがテレメトリデータを認識する方法を変更する必要があります。New Relicを自社ドメイン経由でプロキシすることで、まさにその目的が達成されました。リクエストをサードパーティから自社ドメインに移行し、障害を回避し、これまで見えなかった障害を明確に把握できるようになったのです。
しかし、代理人による代理行為は戦いの半分に過ぎなかった。HubSpotの障害、特にスクリプトが読み込まれないようなサイレント障害を検出するには、読み込みエラーと実行時エラーの両方を慎重に処理し、それらをすべて単一のレポートパスに集約する必要がありました。そして、実際のユーザー環境下でデータが検証され、仮説が証拠に置き換えられるまでは、それらのことはすべて無意味です。
その見返りは、逸話を数字に置き換える能力を得ることだ。「一部のユーザーがフォームが読み込まれないと言っている」という状況ではなく、実際のユーザーへの影響を定量化できる、測定可能で傾向を把握できるシグナルが得られるようになりました。最も価値のある解決策は、問題を完全に解決するものではなく、最終的に問題を明確に 認識させ てくれるものだったりする。そしてそこから、実際に改善を始めることができるのです。
トラブルシューティング
<https://https//...><https://> プロキシ値に含まれるarborydigital.com/nr/agentNREUM.init.session_replayでsampling_rate増やすか、エラーでテストして100%キャプチャをトリガーしますnewrelic オブジェクトが未定義ですnewrelic.jsが最初の<script>であることを確認してください head.html著者について
聞いた内容は気に入りましたか?自分にとって何が最適なのか、疑問がありますか?ぜひお話させてください!お問い合わせはこちら