BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Footsteps: JavaScriptの決定論的ロギングと再生

Footsteps: JavaScriptの決定論的ロギングと再生

ブックマーク

原文(投稿日:2011/04/18)へのリンク

イベント駆動アプリケーションをデバッグするのは本当に難しい。アプリケーションへのユーザからメッセージはランダムに発生するので、エラーを再現するのは困難だ。JavaScriptの場合、さらに大変だ。あまり互換性のないソフトウエアと非同期で送信されるサーバへのリクエストが混ざっているからだ。

Footstepsプロジェクトはロギングと再現フレームワークを使ってこの再現性の問題に対処する。クライアント側のFootstepsはJavaScriptライブラリで、マウスクリックや乱数生成のような非決定的なイベントを記録する。プラグインや特別なブラウザは必要ない。JavaScriptだけで簡潔する。

FootstepsをページかiframeトップでJavaScriptライブラリを参照することで利用できる。DateやsetTimeoutのようなメソッドはオリジナルのメソッドをラップする新しいバージョンで置き換えられる。マウスやキーボード、サーバのイベントも同様だ。ラップの方法も様々だ。Dateのような関数のラップは単純だが、setTimeoutのように深刻な問題を抱えている場合もあった。たとえば、すべてのブラウザで、オリジナルのsetTimeout関数を参照するために使う変数がガベージコレクトされてしまっていた。ラッパーがオリジナルの関数を呼ぼうとしたときに関数が定義されていないという例外が発生してしまうのだ。見えないiframeの中でsetTimeout関数への参照を保持するしか回避策はない。

マウスイベントはさらに厄介だ。Firefoxでは、DOM0ハンドラはDOM2ハンドラの前に呼ばれる。しかがって、ある関数で利用できるのは単一のDOM0ハンドラだけの場合もあり得る。しかし、例えば、DOM0ハンドラはロギングでは利用できない。上書きされてしまうからだ。DOM2ハンドラでも同様に利用できない。そのイベントがキャンセルされてしまうかもしれないからだ。IEの場合はまた違う問題がある。IEには利用できるハンドラがないので、選択肢にすらならないのだ。すべてのイベントが浮上してくるわけではなく、ログにヒットする前にキャンセルされるイベントもある。このような問題群にどのように対処したのかはリサーチペーパーに書いてある。興味深い部分を抜粋すると、

Firefox

理想的には、MugshotではDOM2のロギングハンドラを各イベントタイプのeに定義し、ユーザが定義するハンドラをMugshotが提供するロギング関数でラップしたwindow.eプロパティにセッターを定義するつもりでした。アプリケーションがDOM0ハンドラを提供しないなら、MugshotのDOM2コールバックでイベントがロギングされます。さもなければ、ラップされたDOM0ハンドラがイベントをロギングしてイベンんとオブジェクトに特別なフラグを立てます。このフラグはMugshotが提供するDOM2のハンドラが重複してロギングしないようにするためです。しかし残念ながら、この方法はうまくいきませんでした。Firefoxのゲッター/セッターの実装にバグがあるからです。MugshotはDOMノードのイベントプロパティにゲッター/セッターのペアを作成し、アプリケーションはそのプロパティを適切に利用できるはずです。しかし、実際にイベントタイプeが生成されると、ブラウザは関連する関数を呼び出しません。言い換えれば、セッターのコードはアプリケーションレベルでは完璧に動作するのに、ブラウザ側のコードからイベントハンドラを隠してしまうのです。

Internet Explorer

浮上してこないイベントをロギングするために、MugshotはDOMノードのオブジェクトプロトタイプを拡張するというIEの機能を利用します。イメージやインプットのような浮上しないイベントをサポートするDOMタイプのために、MugshotはDOM0のイベントプロパティ用にカスタムのセッターを定義するようクラスの定義を修正します。また、アプリケーションがノードに対してDOM2ハンドラを登録する仕組みを利用してattachEvent()とdetachEvent()を定義し直します。DOM0のセッターとラップされたDOM2の登録メソッドはアプリケーションがDOMのノード/イベントのペアのための最低でもひとつのハンドラが定義していたら、Mugshotが関連するイベントを正確にロギングすることを保証します。

理想的には、Mugshotは浮上するイベントを捉えるのと同じ方法が使えるはずです。しかし、残念ながらDOM拡張機能は貧弱です。ある組み合わせでDOM0のプロパティを再定義すると予想できない動きになります。したがってMugshotはwindowレベルのハンドラを使って浮上してくるイベントをロギングします。しかし、これは上述した問題のある方法で一時的にログが不正な状態になってしまいます。幸い、Mugshotはこの問題を軽減することができます。IEが現在のDOMのイベントをグローバル変数であるwindow.eventに保存しているからです。Mugshotが非決定的なイベントをロギングする場合は、まず、window.eventが定義されているかどうか確認して、それがまだロギングしていないイベントを参照しているかどうか確認します。もし、そうならMugshotは関連するイベントを探す前にそのイベントをロギングします。

Mugshotのwindowレベルのハンドラに達する前にEvent.cancelBubbleプロパティをtrueにすることでアプリケーションが浮上するイベントをキャンセルするかもしれません。それでもそのイベントをロギングしなければならない場合のために、MugshotはEventオブジェクト用にクラスのプロトタイプを拡張して、cancelBubbleのセッターを上書きしキャンセルの前にロギングします。

ロギングが有効の場合、性能は通常の約90%になる。Jamesによるとほとんどのユーザは性能劣化に気付かない。メモリの使用量はログの使用方法によって違いがある。人が読めるようにすれば冗長なログ出力になるだろうし、単に再生に必要な分だけログ出力することもできる。

エラーが発生した場合は開発者にログが通知される。そうすると開発者はイベントを再生してアプリケーションが動作不良を起こしたときにユーザが何を見たのか確認できる。“panic”ボタンをクリックしてログを送信の確認をした場合でもログは送信される。

開発者がログを受け取るとそれを再生することでアプリケーションの動作中に何が発生したのか正確に確認できる。イベントリアルタイムでもステップごとにも再生できる。リアルタイムで再生する場合は実際には40%くらいの速度で再生される。

FootstepsはMugshotという初期研究プロジェクトを基にしている。リサーチペーパーの共著者はJames Mickens氏、Jeremy Elson氏、Jon Howell氏だ。Siloについての詳細はChannel 9で確認できる。

この記事に星をつける

おすすめ度
スタイル

BT