【Sentry Laravel AI】インテグレーションができるまで

Article by: Martin Linzmayer(読了時間:4分)   先日のAgent Hackweek(好きなAIやエージェント関連のプロジェクトに1週間取り組めるSentryの社内イベント)で、同僚からLaravel AIインテグレーションを作らないかと誘われました。他のフレームワーク向けにすでに提供しているAgent TracingのサポートをLaravel AIで構築したエージェントにも広げることが目的です。 いいアイデアだと思いました。彼は以前、PythonベースのエージェントのためにSentryのAgent Tracingを構築しており、ドメイン知識をすでに持っていましたし、このイベントではAIを使うことになっていたので、言語の壁も大きな問題にはなりませんでした。   不要だった防御的なコード Claudeならコーディングはそれなりにこなしてくれるだろうと、かなり自信がありました。Laravelは型付きのデータを持つEventsを公開しているので、データの形はほぼ把握できるはずです。 ところが最初のレビューで、Claudeは実際にはデータの正しい形を把握できておらず、フィールドにできるかぎり汎用的な方法でアクセスするヘルパーを作っていたので、少し驚きました。 しばらくPHPから離れている方のために説明すると、このスニペットは構造に関係なく、配列やオブジェクトから値を取り出そうとする汎用ヘルパーです。$source->{$key} は $key を文字列の値に解決し、そのフィールドにアクセスします。言うまでもなく、これは良いPHPコードとは言えません。たいていの場合、データの形はもっと限定されているため、役に立つ場面はほとんどありません。   Laravel AIのライフサイクルにフックする PythonやJavaScriptでのインストルメンテーションは、比較的簡単なことが多く、関数をラップしたり、パッチを当てたりするだけで済みます。しかし、PHPではそうはいきません。フレームワークやライブラリのフックに頼るか、ユーザーにクラスを独自のものへ置き換えてもらう必要があります。後者をできるだけ避けているのは、ユーザーにコードの書き換えを求めるようでは、インテグレーションとは呼べないからです。幸い、Laravel AIは重要な部分のほとんどでイベントを発行します。ただし、すべてではありません。 Laravel AIにはライフサイクルにフックする手段が十分そろっているように見えました。PromptingAgent と AgentPrompted イベントはエージェントとのやり取り全体を、InvokingTool と ToolInvoked は個々のツール呼び出しをカバーしています。 Agent Tracingには、もう一段細かい粒度が必要です。LLMの呼び出しを1回ずつ、個別のChatスパンとして表示しなければなりません。Laravel AIはこうした呼び出しに対するイベントを公開していないため、ライフサイクルイベントだけに頼ると、トレースに大きな抜けが生じてしまいます。   LLM呼び出しとHTTPリクエストを照合する ほとんどのLLM呼び出しは、最終的にHTTPリクエストになります。Laravelにはそのためのイベントとして RequestSending と ResponseReceived があります。エージェントとのやり取り中に発生したすべてのHTTPリクエストにChatスパンを作成することもできますが、それではツールによるHTTP呼び出しなど、無関係なリクエストまでキャプチャしてしまいます。 LaravelのHTTPイベントにはAI呼び出しのIDが含まれていないため、リクエストを直接関連付けることはできません。そこで、アクティブな呼び出しごとに設定済みのプロバイダーURLのプレフィックスを保存し、送信されるすべてのリクエストのURLと比較することにしました。複数のアクティブな呼び出しが一致した場合は、最後に開始されたものにリクエストを関連付けます。一致したリクエストだけがChatスパンになるため、個々のLLM呼び出しを取りこぼすことなく、無関係なHTTPトラフィックを除外できます。   設定不要のトレーシング Laravel AIインテグレーションは、sentry-laravel 4.27でリリースされました。すでにSentryのトレーシングを有効にしているアプリケーションなら、SDKをアップデートするだけです。インテグレーションの登録も、Sentry固有のコードの追加も必要ありません。通常のLaravel AIエージェントは自動的にトレースされ、Conversational を実装すればConversationsにも対応します。 Sentryのコードはどこにもありません。このクラスからのエージェント呼び出し、LLMリクエスト、ツール呼び出しはAgent Tracingに表示され、会話のコンテキストはExploreのAgentsセクションに表示されます。   Sentryで確認する […]

【dataCollection のご紹介】スイッチ1つからコントロールパネルへ

Article by: Sigrid Huemer(読了時間:6分)     本記事とコード例はJavaScript SDKを対象としています。別のプラットフォームをお使いの場合でも、今回の変更の背景や今後の展開を理解するために、ぜひご一読ください。   Sentry では、真偽値(boolean)の sendDefaultPii を、dataCollection という新しいオプションに置き換えます。従来のスイッチはオンにすればすべて取得、オフにすればごく一部しか取得できない、オールオアナッシングの仕組みでした。cookie は除いて request header だけがほしい、あるいはユーザーのメールアドレスまで送らずに GenAI の入力だけがほしい。そんな場面に出くわしたことがあれば、この仕組みの物足りなさはおわかりでしょう。dataCollection はこの1つのスイッチをいわばコントロールパネルに近いものへと変えます。データのカテゴリごとに、上げる・下げる・絞り込むといった調整ができるダイヤルになるのです。   変わる内容とその時期 dataCollection はすべての Sentry SDK に導入されます。JavaScript SDK では 10.57.0 から利用できるため、すでにこのオプションを見かけた方もいるかもしれません。dataCollection が新しいデフォルトのオプションとなり、sendDefaultPii が完全に廃止されるのは、バージョン11のリリースです。考え方はどのプラットフォームでも共通ですが、具体的なデフォルト値や移行手順は異なる場合があり、SDK ごとの詳細はそれぞれのリリースノートで説明されます。 v11 の JavaScript SDK にとって、これは単なる名称変更ではなく、挙動の変更です。新しいデフォルトは、従来よりも多くのデータを収集します。sendDefaultPii はすでに非推奨となっており、v11 で削除されます。他の Sentry SDK もそれぞれのタイミングで廃止していく予定であり、最終的な行き先はいずれも dataCollection です。   PII とセンシティブデータ SDK は2種類のデータをそれぞれ異なる方法で扱います。PII(個人を特定できる情報、Personally Identifiable Information)とは、ユーザー ID、メールアドレス、ユーザー名、氏名など、個人に結びつくあらゆる情報を指します。センシティブデータとは、パスワード、トークン、API […]

【Unreal Engine Session Replay】クラッシュ前のクラッシュ

Article by: Ivan Tustanivskyi(読了時間:6分)   よくある話です。クラッシュレポートがキューに届きます。スタックトレースはきれいに取れているものの、指しているのはいかにも無害そうな関数だけ。プレイヤーがその直前に何をしていたのかを示す手がかりは、どこにもありません。ボス戦の真っ最中だったのか、ロード画面で Alt+Tab を押していたのか、チュートリアルで立ち止まっていただけなのか、QAでは再現できず、プレイヤーからのバグ報告は「ゲーム落ちたw」の一言。残されたコアダンプとコールスタックを前に、当てものクイズを始めるしかありません。 スタックトレースは、コードがどこでクラッシュしたかは教えてくれます。しかし、なぜクラッシュしたのかまでは教えてくれません。ゲームは、一般的なデスクトップアプリケーションやモバイルアプリケーションに比べて、実行環境による影響をはるかに受けやすいソフトウェアです。だからこそ、「なぜ」の答えは、たいていクラッシュ直前の数秒間にあります。 Session Replayが埋めてくれるのは、まさにそのギャップです。新たに Session Replay に対応したことで、Unreal Engine 向けの Sentry SDK は直近数秒のゲームプレイを継続的に録画し、そのクリップをクラッシュレポートに添付できるようになりました。クラッシュが Sentry に届くと、その映像も一緒に届きます。おかげで物事がおかしくなった瞬間まで、プレイヤーが見ていたものをそのまま見られるのです。   Session Replay で得られるもの リプレイ付きのクラッシュが届くと、クラッシュイベントにひも付いた形で Replays ページに表示されます。そこでは、ゲームの実際のレンダリング済みフレームを再生できるほか、その過程で発生した重要な出来事を時系列に並べた、スクラブ可能なタイムラインも確認できます。 ▶ インタラクティブデモ:https://demo.arcade.software/8AgdLvo1bz99viH3a842/?embed   デバッグの主役は、プレイヤーの隣に並ぶパネルです。映像と AI によるリプレイ要約に加えて、各リプレイでは次の情報も確認できます。 タグとコンテキスト — OSとそのバージョン、リリース、クラッシュの種類、リージョンなど、本来ならプレイヤーに確認しなければ分からない情報です。 Breadcrumbs — エラーやゲームプレイ中のイベント、独自に記録したカスタム breadcrumbs が映像と同期したタイムライン上に表示されます。 ログ — ゲームのログ出力を映像に合わせてタイムスタンプ付きで確認できます。 トレース — クラッシュに至るまでのスパンが共通のトレースIDで結び付けられています。バックエンドが関係するクラッシュであれば、同じトレースに含まれるサーバー側のスパンもここからたどることができます。   上の例では、これだけで何が起きたのかが分かります。開始から3秒後、チェックアウトのHTTPリクエストが不正な値を返し、ensure が発火。プレイヤーはレベル2に到達し、「Wrath」の攻撃モディファイアを選択。そして00:22、ASentryTowerTurret::Shoot で致命的なクラッシュが発生します。 これは、クラッシュそのものが再現手順を教えてくれるようなものです。しかも、映像を確認するためにクラッシュの詳細画面を離れる必要はありません。リプレイはクラッシュイベントのページにそのまま埋め込まれているため、Issueのトリアージは直前数秒のゲームプレイを確認するところから始められます。さらに詳しく調べたくなったら、ワンクリックでリプレイの全画面表示へ切り替えられます。 ▶ インタラクティブデモ:https://demo.arcade.software/wbJ8cKhmNjSzcdAECCz1/?embed […]

【Godot .NET サポート】一般提供開始

Article by: Serhii Snitsaruk(読了時間:2分)     先日、Sentry の Godot Engine SDK のバージョン 2.0.0 をリリースし、C#/.NET サポートとアプリケーションメトリクスを一般提供(GA)しました。これにより、マネージド C# コードからエラーを捉え、開発ビルドと製品版ビルドの両方でカスタムメトリクスを追跡できるようになりました。   C#/.NET サポート Godot は非常に性格の異なる2つのスクリプティングの世界、GDScript と C# をサポートしています。1.x のリリースでは、GDScript、エンジン本体、ネイティブの C/C++ コードから Issue を捉えられるよう SDK をインストルメントし、公式にサポートされるすべてのプラットフォームへとサポートを広げてきました。2.0.0 のリリースでは、Godot Engine 上での .NET 向けの第一級のエラーレポートを導入します。 マネージドコードからのエラーは、GDScript やエンジンの Issue と同じトレース上に並んで表示されるようになり、タグ・breadcrumbs・ユーザーコンテキストといった scope の要素も、現時点で同期されている範囲で付与されます。 では、これが実際にどう動くのかを見てみましょう。以下は私たちの Godot ゲームで実行時に例外を投げる C# コードの短縮版です。   private List<UpgradePathBase>? TryFetchUpgradesFromServer(){var fetchTransaction = SentrySdk.StartTransaction(“fetch_upgrades”, […]

【エラー・トレース・ログ・メトリクス】いつ何を使うか

Article by: Sergiy Dybskiy (読了時間:12分)     コードをインストルメントするとき、「ログを使うべきか、トレースか、メトリクスか」という問いに何度もぶつかります。コーディングエージェントも同じ壁にぶつかっているのを目にします。答えは明白なように思えますが、実はそうでもありません。エラー・トレース・ログ・メトリクス は、アプリの大半を支える4種類のテレメトリです。 4つはいずれも同じ道具箱に入ったツールであり、役割も重なる部分が多いため、正直なところ答えは開発者の口癖である「場合によります」です。ログに記録するはずのコンテキストをスパンの属性として持たせることもできますし、メトリクスを出力する代わりにログイベントをカウントすることもできます。また、duration を追加してスパンと見なすこともできます。 [スパイダーマンのミームを入れようとしたのですが、法務部門から著作権侵害になると言われたので削除しました。] ただし、「できる」と「すべき」は別の話です。各シグナルは異なる問いに答えるために存在しており、届いた後のワークフローもそれぞれ異なります。しっかりとした指針がなければ、慣れ親しんだものや既にあるものに手を伸ばしてしまい、他の種類のシグナルが本来何のためにあるかを見落としてしまいます。 この記事は、自分自身とエージェントのために書きたかった指針です。スキルだけ欲しい方は末尾まで読み飛ばしてください。 Sentry では、エラー・トレース・ログ・メトリクスのすべてがひとつの SDK から取得でき、すべてのプランに含まれています。エラーと Sentry Tracing は長年使われてきた機能ですが(それぞれ 2012年 と 2020年 から)、構造化ログは昨年追加され、Application Metrics は今年5月にラインナップが完成しました。Sentry をしばらく使っているなら、エラーとトレースはすでに送信されているはずです。ログとメトリクスは、テレメトリの全体像を完成させるための、残りの道具です。     エラー・トレース・ログ・メトリクス:それぞれが答える問い エラー:「何が壊れたのか」 スタックトレースと例外の種類が、Issue としてグルーピングされ、重複排除・アサイン・解決まで追跡されます。コードが例外を投げたなら、それはエラーです。 トレース:「リクエストは想定どおりに送信されたのか」 トレースは、タイミング付きのスパンのウォーターフォールです。リクエストがサービスを横断して、どのように送信されたかを追跡し、時間の使われ方を把握するためのものです。遅くなったDBクエリ、タイムアウトしたAPI呼び出し、200msのはずが8秒かかったLLMのツール呼び出しなどが見えてきます。 メトリクス:「時系列でどう推移しているのか」 Counter・Gauge・Distribution として保持され、任意の属性でスライスでき、集計値から背後にあるサンプル(およびトレース)まで掘り下げられます。「今週のチェックアウト件数は12,000件」という数字だけでなく、米国から8,400件・EUから2,600件・その他から1,000件という内訳も、直近のデプロイ前後で数値がどのように推移したかも把握できます。メトリクスは現在だけでなく過去のシグナルでもあるため、ダッシュボードやアラートとの相性が抜群です。(ただし Sentry ではほぼすべてのシグナルにアラートを設定できます。) ログ:「コードのこの箇所で何が起きていたのか」 コードのある瞬間のシステム状態を構造化イベントとして記録したものです。設定値・フィーチャーフラグ・関数の入出力・ユーザーIDなどが含まれます。ログは関数の意思決定ツリーをたどる手掛かりです。コードが分岐する地点に残すマーカーであり、後から人間やエージェントがその判断の流れを追えるようにします。エラーとトレースが「何が壊れたか」「どこに時間がかかったか」を教えてくれた後、「なぜ」を補うのがログです。   実例(に近いもの) React フロントエンドと Python API を持つストアフロントを運営しているとします。サポートからチケットが転送されてくるようになりました。アカウントページの商品レコメンドが、ログイン済みの一部ユーザーに対して汎用的な内容(パーソナライズされたおすすめではなくベストセラー)を表示しているというのです。どうも様子が変です。 何かクラッシュしていないか? 最初に確認するのは Issues です。React アプリに例外はなく、リクエストも失敗しておらず、/recommendations/{user_id} […]

【Next.js / Supabase オブザーバビリティ設計】バイブコーディングから本番運用へ

Article by: Sergiy Dybskiy   ここ数年で、ソフトウェアの作り方は大きく変化しました。一方で変わっていないのは、そのソフトウェアが最終的に「実際の人間」に届くという事実です。あなたや私、そして私の母のような人たちです。 そして、そうしたユーザーが必然的に何かしらの不具合に遭遇したとき、アプリケーションの開発者であるあなたは、何が壊れたのか、どこで壊れたのか、そしてそれをできるだけ早くどう修正するのかを理解するための適切なツールとコンテキスト、そして認識を備えている必要があります。 私たちは日々、「自己修復するソフトウェア」に少しずつ近づいています。Next.jsアプリケーションを構築し、バックエンドサービスとしてSupabaseを利用している場合、以下で説明するツールは、より高品質なソフトウェアを生み出すことと、すり抜けてしまった問題を最小限の影響で修正するという、自己完結的なループに一歩近づく助けになります。   要約 Supabaseはクエリパフォーマンスのインサイト、行レベルセキュリティ(RLS)のアドバイザリ、Edge Functionのログを標準で提供しているが、フルスタックを横断したトレースはできない Sentryはそのギャップを埋める:Next.jsのフロントエンドからSupabase Edge Functions、Postgresまでをまたぐ分散トレースを一箇所に集約できる SupabaseからSentryへログをドレインすることで、エラー・トレース・インフラログの単一の信頼できる情報源を作れる SentryはN+1クエリ、遅いスパン、パフォーマンス劣化を手動設定なしで自動検出する SentryのAIデバッガー「Seer」は新しい問題に対して原因を自動で推定し、修正をコーディングエージェントに引き渡すことができる     エージェントが生み出すスタック問題 AI支援開発には特有の失敗モードがあります。エージェントは動作するコードを生成できますが、そこにオブザーバビリティが組み込まれていないことが多いという点です。その結果、Next.jsアプリがSupabaseと通信する方法が3種類(直接Postgres接続、Supabase JS SDK、そしてDrizzle、エージェントが戦略を切り替え続けたため)混在することもあり得ます。さらにDeno上で動くEdge Functionが加わり、実行時に何が起きているのかを統一的に把握できない状態に陥ります。 もう一つの失敗モードはより見えにくいものです。エージェントはインデックスを忘れることがあります。ローカル環境ではデータが40行程度しかないため問題にならず、N+1クエリを書いてしまうこともあります。しかし本番にデプロイし、データベースが400行に増えると、検索クエリが突然10秒かかるようになります。Sentryはこれを自動的に検出できますが、それは最初から正しく計装されている場合に限られます。 この計装を正しく行うには、SupabaseとSentryがどのように組み合わさるかを理解する必要があります。   Supabaseの組み込みオブザーバビリティとその限界 Supabaseには堅牢な組み込みオブザーバビリティがあります。ダッシュボードのQuery Performanceパネルでは、どのクエリが最も頻繁に実行されているか、どれが最も時間を消費しているかを確認できます。パフォーマンス問題が発生した際に最初に見るべき場所です。 またAdvisorsは、RLSポリシーの不足などのセキュリティ問題を検出し、重要度に応じて優先順位付けします。Index Advisorは不足しているインデックスを指摘し、それらが本番インシデントになる前に可視化します。 Logsセクションでは、Supabaseのすべてのサブシステムから構造化ログを取得できます。対象にはEdge Functions、Postgres REST API(PostgREST)、コネクションプーラー、ストレージ、cronジョブなどが含まれます。これらのログはダッシュボード上でSQLを使って直接クエリすることも可能です。 これは確かに非常に有用です。ただし、Supabaseの内部で観測できる範囲に限定されるという制約があります。つまり、Supabaseの外側で起きていることまでは見えません。例えば、遅いPostgresクエリがNext.jsフロントエンドのどのユーザーアクションによって発生したのか、あるいはEdge FunctionのタイムアウトがAPIレイヤー全体にどのようなエラーの連鎖を引き起こしたのか、といった因果関係は把握できません。こうした情報を得るには、フルスタックを横断した分散トレーシングが必要になります。   SupabaseログをSentryに接続する SupabaseのデータをSentryに取り込む最も簡単な方法は、log drainを使うことです。Supabaseダッシュボードの「Logs > Drain」で送信先を追加し、SentryのDSNを貼り付けると、そのSupabaseプロジェクトのすべてのログが対応するSentryプロジェクトへ流れ込むようになります。 この仕組みについて、いくつか重要な点があります。 現時点では「全量送信(all-or-nothing)」であり、Supabase側でログレベルによるフィルタリングはできません。 ログがSentryに入った後は、Log Explorer上で severity:warn や severity:error のようにフィルタリングできます。 log drainはNext.jsアプリやEdge […]

JavaScript のオブザーバビリティを修正する:ライブラリ単位での改善

Article by: Abdelrahman Awad   ここ数週間、私たちはクロスエコシステムでの取り組みとして、現在すべての JavaScript APM ツールを支えている「モンキーパッチング」をランタイムに組み込まれた仕組みに置き換える作業を進めてきました。ここでは、その背景と仕組み、そして現状について説明します。 この内容はサーバーサイド JavaScript(Node.js、Bun、Deno、Cloudflare Workers)のみに適用されます。ブラウザには diagnostics_channel が存在せず、またそれをポリフィルするために必要な非同期コンテキスト伝播の仕組みも備わっていません。   モンキーパッチングはスケールしない 私のチームメイトである Sigrid は、なぜモンキーパッチングが破綻しつつあるのか、そして TracingChannel がそれをどう解決するのかについて詳しく解説しています。 要点をまとめると、JavaScript のすべての APM ツール(Sentry を含む)は、実行時に require() や import をフックし、import-in-the-middle(IITM)や require-in-the-middle(RITM)を使ってライブラリをインストルメントしています。しかしこの仕組みは ECMAScript Modules(ESM)で壊れやすく、Node 以外のランタイムでは動作せず、バンドラとも衝突し、さらに制御できない内部実装に依存する構造になっています。また SDK は対象ライブラリより先に読み込まれていなければならず、そうでない場合は計測が静かに失敗します。 これは Sentry 固有の問題ではありません。JavaScript のインストルメンテーションを提供するすべての APM ベンダーが、同じ不安定さを抱えています。エコシステム全体が行き詰まっている状態です。 多くのライブラリメンテナーはオブザーバビリティを前提にしていません。何を公開すべきかも分からず、OpenTelemetry のような仕組みを導入することは標準化というより実装負担になります。これまで APM 側がパッチで吸収してきたため、ライブラリ側が対応する必要がありませんでした。 しかし、より良い方法があります。   TracingChannel:パッチ不要のオブザーバビリティ 2025年後半、私たちは Nitro、h3、そして unjs エコシステムの開発者である Pooya Parsa […]

【Android tombstone】ネイティブクラッシュ解析の大幅改善

Article by: Mischan Toosarani-Hausberger , Roman Zavarnitsyn (了読時間:13分)     Androidにおけるネイティブクラッシュは、これまで本来あるべきよりもデバッグが難しいものでした。 Androidには独自のクラッシュレポーター(debuggerd)があり、クラッシュしたスレッド、実行中の他のすべてのスレッド、レジスタ状態、メモリマップを tombstone と呼ばれるファイルに記録します。tombstone は長年Androidの一部であり、実際にはAndroid最初期のコミットの頃から、形を変えつつ存在してきました。 問題は、Androidの歴史の大半において、アプリ内部から tombstone をプログラム的に読み取ることができなかったことです。そのため、SDKベースのネイティブクラッシュレポート機能(私たちのものを含む)は、プラットフォーム側ですでに存在している仕組みを独自に再実装せざるを得ませんでした。その代償として、バイナリサイズの増加、不完全なJavaフレームのシンボリケーション、さらに変化し続けるAOSPに追従するために維持しなければならないC++フォークが発生していました。 Android 11(SDK level 30)では ApplicationExitInfo が導入されました。さらに Android 12(SDK level 31)では、ApplicationExitInfo.REASON_CRASH_NATIVE に対する trace input stream へのアクセスが追加されました。 SentryのAndroid SDKは、バージョン8.30.0以降、Android 12以上を実行しているすべてのデバイスでこのストリームを読み取り、ネイティブクラッシュイベントとして送信します。これにより、ネイティブコードを使用するAndroidアプリのクラッシュレポートは大幅に改善されました。基本的なクラッシュ通知だけが必要なチームにも、詳細なデバッグ情報が必要なチームにも有効です。 ここからは、以前はどのように動作していたのか、既存のNDK統合を壊さずにこれをSDKへ組み込むために何が必要だったのか、そしてこれによってどのような改善がもたらされたのかを見ていきます。   tombstoneサポート以前:変化し続けるターゲットを追い続けるフォーク tombstoneサポート以前、Android SDKでは Native SDK(sentry-native)がネイティブエラーレポートの主要な仕組みとして使用されていました。AndroidはLinuxベースであるため、SDKのかなりの部分を再利用できました。しかし再利用できない部分については、2019年からAndroid固有コードの統合作業が始まりました。 特に、libunwindstack(現在も debuggerd、そして tombstone のスタックトレース生成に使用されているAOSPのプラットフォームアンワインダ)を統合したことは、Sentry Android SDKでネイティブクラッシュをサポートする上で重要な転機となりました。なぜかというと、Native Development Kit(NDK)には汎用的なスタックウォーカーが存在しなかったからです(今でも存在しません)。 libunwindstack はNDKの一部ではなく、Android Open Source Project(AOSP)のプラットフォームコードの一部であるため、通常の方法ではアプリ開発者から直接利用できません。Sentryは、NDKでビルドできるようプラットフォームコードへパッチを当てたリポジトリをフォークし、その後も上流のパッチ版に変更がないまま、そのフォークを維持してきました。 これにより、非常に複雑なAndroid […]

【Application Metrics】Unreal Engine のゲームパフォーマンスを監視する

Article by: Ivan Tustanivskyi     あなたのUnrealゲームはエラーゼロの状態でリリースできたとしても、それだけで優れた体験になるとは限りません。戦闘中のスタッター、大型ボス戦での急激なフレームレート低下、マルチプレイヤーでのラバーバンディング。これらはいずれもクラッシュとしては現れず、Sentry にも表示されません。そのため、実際にプレイヤーが現場で何を体験しているのかを把握する手段がありませんでした。少なくとも、これまでは。 Unreal Engine には、ゲームパフォーマンスを測定し、実行時統計を収集するためのツールがすでに豊富に用意されています。しかし、そのデータはすべて開発者のマシン内に留まったままでした。 Unreal SDK の新しい自動パフォーマンスメトリクス機能は、このギャップを埋めます。FPS、フレーム時間、ネットワーク状態、そのほか一般的なゲームテレメトリを直接 Sentry に送信することで、どこでパフォーマンスが低下しているのか、どのハードウェアで発生しているのか、どのプレイヤーに影響しているのかについて、チームが実用的なインサイトを得られるようになります。Release & Health と組み合わせれば、各リリースが時間経過とともにパフォーマンスへ与える影響も追跡できます。 本題に入る前に、一点だけ触れておきます。すべてのゲーム開発者は、これまでに一度はプロファイラを使ったことがあるでしょう。自動パフォーマンスメトリクスはそれとは異なるものですが、関連するツールです。両者は同じ問題を異なるレイヤーから扱います。メトリクスは「どこでゲームが遅くなっているか」を見つけ、プロファイリングは「なぜ遅くなっているのか」を説明します。     Sentry が現在追跡するもの 現在、Unreal SDK は、全体的なパフォーマンスへ影響するいくつかの主要領域について、メトリクスを自動インストルメントします。対象には、フレーム時間、ネットワーク、ゲーム固有の統計などが含まれます。   フレーム時間 ゲームが快適に感じられるかどうかを最も直接的に示す指標です。フレーム時間は、「各フレームの処理にエンジンがどれだけ時間を使ったか」を示します。また、スレッドごとに分解することで、どのサブシステムがボトルネックになっているかを確認できます。 平均FPS 総フレーム時間 ゲームスレッド処理時間 レンダースレッド処理時間 GPUフレーム時間     ゲームスレッド、レンダリングスレッド、GPUの処理時間を比較することは、CPUがボトルネックになっているのかGPUがボトルネックになっているのか、そしてどのチーム(ゲームプレイ、レンダリング、コンテンツ)が修正を担当すべきかを判断する古典的な方法です。 FPSメトリクスの例(GPU別にグループ化)   ネットワークインサイト マルチプレイヤーのパフォーマンスは、接続品質によって成否が決まります。しかし、クラッシュレポートだけではその状態を把握できません。これらのメトリクスによって、パケットロス、レイテンシ、帯域不足が、気づかれないまま体験品質を低下させていないかを確認できます。 送受信帯域幅 パケットスループットとパケットロス クライアントの ping と jitter アクティブ接続数   サーバービルドではさらに、ロードシェディング分析のために、クライアントごとの平均 ping、クライアントごとの帯域幅、飽和状態の接続数も取得できます(ネットワークメトリクスの完全な一覧を参照)。 これらのメトリクスは、マルチプレイヤーセッションがアクティブな間のみ存在します。ネットワーク機能を持たないシングルプレイヤーゲームでは、ここにデータは送信されません。また、一部の値はクライアント専用(ping、jitter)、あるいはサーバー専用(アクティブクライアント数、接続飽和)です。 Pingメトリクスの例   […]

【Next.js】ロギングが難しい理由と解決策

Article by: Kyle Tryon        一般的なNext.jsのデプロイでは、最大で3つの異なるランタイム(Edge、Node.js、ブラウザ)でコードが実行される可能性があります。 サーバーサイドのコードからログをすでに取得しているかもしれませんが、ミドルウェアからサーバーレンダリング、そしてブラウザに至るまでのリクエスト全体を取得していない場合、問題が発生したときに多くのデバッグ情報を見逃していることになります。 要約:一般的なNext.jsのデプロイは、Node、Edge、ブラウザという最大3つの環境で実行されます。ほとんどのJavaScriptのロギングライブラリはNodeを対象としており、Edgeやブラウザに対応しているものははるかに少ないです。LogTapeとSentryはいずれも、ランタイムに依存しないJavaScriptのロギングを提供します。     なぜNext.jsでのロギングは難しいのか   課題 1:多くのロガーはNode.jsを前提としている 多くのロガーはNode.js専用に構築されており、ブラウザやEdgeランタイムでは利用できないAsyncLocalStorageやfsのようなAPIに依存しています。 Next.jsに最適なロガーとしてPino(またはNext-Loggerのようなラッパー)が推奨されることがよくありますが、実際にはどちらもNext.jsにとって良い選択ではありません。 Pino、ひいてはNext-LoggerはNode.js向けに設計されており、ブラウザで動作させるためにポリフィルを使用しています。しかしそのポリフィルにより、Nodeでのパフォーマンス上の利点は失われ、さらにEdge関数やミドルウェア(Edge上で実行される)ではログを取得することができません。   課題 2:クライアントサイドのロギングが欠落する クライアントサイドのログを取得する必要はないと考えがちです。なぜなら「フロントエンドのコード」はすべてサーバーサイドで動作していると思われがちだからです。 デフォルトでは、Next.jsはすべてのページとコンポーネントにServer Componentsを使用します。そのため、デフォルトでは「フロントエンドのコード」から出力されるログは、実際にはサーバーサイドのログとして取得されます。 しかし、インタラクティブなコンポーネントのためにuse clientの境界を追加すると、そのコードはブラウザで実行されるようになります。 「フロントエンドのコード」は、1つのページをレンダリングするために連携して動作するServer ComponentsとClient Componentsの混在であり、それぞれ異なる場所にログを出力します。 この分断を解消し、どこで実行されるかに関わらず、すべてのフロントエンドコードのログを同じ場所に集約する必要があります。   課題 3:トレースと結びついた構造化ロギング ロギングは可観測性の一部にすぎず、それ単体ではローカルでのデバッグ時に最も有用です。本番環境では、数十、数百、あるいは数千のリクエストからログを収集するようになると、関連するログ同士を結び付けて検索・集約する手段が必要になります。 トレーシングはアプリ内の各リクエストに一意のIDを付与し、そのIDを構造化データとしてすべてのログに付加します。これにより、後からそのIDに基づいてログを検索し、同一リクエストに関連するすべてのログを、Sentryのエラーなど他のテレメトリデータとあわせて確認することができます。 Next.jsへのトレーシングの導入自体は実際には簡単ですが、それでも実施すべきステップであり、いくつかの方法が存在します。 ここでは、JavaScriptのロギングライブラリとSentryを組み合わせて、トレースに紐づいたログをNext.jsに計測として組み込みます。別の記事では、OpenTelemetryを使用した別のトレーシング導入方法について解説・比較する予定です。   Next.js用のロガーに求めるべき要件 ロガーは何を満たすべきでしょうか。私は最近、主要なJavaScriptロギングライブラリを比較し、そもそもなぜロギングライブラリを使うべきなのかを整理しました。基本的な考え方はNext.jsでも同様ですが、より具体的に考える必要があります。 ランタイム対応:Node、ブラウザ、そして(Edgeを使用する場合は)Edgeランタイムで動作する必要があります。 トレーシング対応:Next.jsアプリはデフォルトでマルチサービス構成です。トレーシングにより、複数のソースからのログを単一のトレースに紐づけることができます。 本番向け機能:データのマスキングやノイズ削減のためのフィルタリング、コンテキスト管理や子ロガーによる構造化ロギングの強化、および後の検索・集約の容易化。   想像できる通り、機能面では各ライブラリは互いの優れた実践を取り入れ、似通ってきています。 それでもなお注目すべき最大の違いは、ランタイム対応とパフォーマンスです。 Next.jsアプリ全体をカバーできる現実的な選択肢は2つあり、これらは排他的ではありません。 LogTape(Sentryシンクと組み合わせる) Sentry.logger(Sentry Next.js SDKと組み合わせる)     LogTape […]

;