web-dev-qa-db-ja.com

実行時にJavascript関数呼び出し/トレースを取得する方法

AJAXベースのアプリケーション[〜#〜] runtime [〜#〜]と対話するときに、コンソールが呼び出しているすべての関数を吐き出したい。(スタックトレース、ブレークポイント、プロファイリングなどはありません)

たとえば、ページ上のボタンを押したとしましょう。それが起こったときに通過したすべての関数を返すようにしたい:

だから私はコンソールに次のようなものを見ます(ボタンを押したとき):

_1. button1Clicked();
2.     calculating();
3.          printingResults();
_

これは基本的に、button1Clicked()がprintingResults()を呼び出すcalculating()を呼び出すことを意味します

これを行うためのユーティリティ、プラグイン、ブラウザ、または言語の何らかの方法がありますか? google chromeを使用しています。

p.sおよびNO各関数を調べて、"console.log("inside function X")" b/cを追加したくない

追加のボーナスとしてのp.p.sも引数が関数に渡されるのを見たいと思いますが、それはおそらくそれを押し進めているでしょう。 :>

35
foreyez

すべての関数呼び出しをグローバルにインターセプトしてロギングを挿入する素晴らしい方法は考えられません(ただし、以下の更新セクションに適切な回避策があります)。

代わりに、気になる特定の名前空間の関数にのみログを追加するのはどうですか?これを行うには、次のセットアップコードを使用します。

_var functionLogger = {};

functionLogger.log = true;//Set this to false to disable logging 

/**
 * Gets a function that when called will log information about itself if logging is turned on.
 *
 * @param func The function to add logging to.
 * @param name The name of the function.
 *
 * @return A function that will perform logging and then call the function. 
 */
functionLogger.getLoggableFunction = function(func, name) {
    return function() {
        if (functionLogger.log) {
            var logText = name + '(';

            for (var i = 0; i < arguments.length; i++) {
                if (i > 0) {
                    logText += ', ';
                }
                logText += arguments[i];
            }
            logText += ');';

            console.log(logText);
        }

        return func.apply(this, arguments);
    }
};

/**
 * After this is called, all direct children of the provided namespace object that are 
 * functions will log their name as well as the values of the parameters passed in.
 *
 * @param namespaceObject The object whose child functions you'd like to add logging to.
 */
functionLogger.addLoggingToNamespace = function(namespaceObject){
    for(var name in namespaceObject){
        var potentialFunction = namespaceObject[name];

        if(Object.prototype.toString.call(potentialFunction) === '[object Function]'){
            namespaceObject[name] = functionLogger.getLoggableFunction(potentialFunction, name);
        }
    }
};
_

次に、ロギングを追加するnamespaceObjectに対して、次のように呼び出します。

_functionLogger.addLoggingToNamespace(yourNamespaceObject);
_

これはフィドルです 動作を確認します。

[〜#〜] update [〜#〜]
_functionLogger.addLoggingToNamespace(window);を呼び出して、呼び出し時にすべてのグローバル関数にロギングを追加できることに注意してください。また、本当に必要な場合は、ツリーを走査して関数を見つけ、それに応じて更新することができます。このメソッドの1つの欠点は、その時点で存在する関数でのみ機能することです。したがって、それはまだ最大の解決策ではありませんが、ロギングステートメントを手動で追加するよりも作業がはるかに少ないです:)

34
Briguy37

これはプロファイリングと呼ばれ、ChromeとFirebugに組み込まれています。 Chrome開発者ツール で、[プロファイル]タブに移動し、レコード(丸)ボタンをクリックします。 ajaxを選択し、応答後、記録ボタンをもう一度クリックして停止すると、プロファイリングの結果が右側のペインに表示されます。

注:これによりeverythingが得られるため、jQueryのようなライブラリを使用している場合、関数呼び出しの大部分は不要になります君は。私はこれを数回試してみましたが、console.log('inside <method>')を実行する方がはるかに役立つことがわかりました。

16
Jeff

Briguy37のソリューションのバリエーションとして、各メソッドの前に呼び出す関数を受け入れるものを作成しました。また、for ... inによってメソッドが列挙されないECMAScript 6クラスでも機能します。これを使用して、オブジェクトプロトタイプを変更し、オブジェクトのすべての新しいインスタンスにロギングを追加します。

function inject(obj, beforeFn) {
    for (let propName of Object.getOwnPropertyNames(obj)) {
        let prop = obj[propName];
        if (Object.prototype.toString.call(prop) === '[object Function]') {
            obj[propName] = (function(fnName) {
                return function() {
                    beforeFn.call(this, fnName, arguments);
                    return prop.apply(this, arguments);
                }
            })(propName);
        }
    }
}

function logFnCall(name, args) {
    let s = name + '(';
    for (let i = 0; i < args.length; i++) {
        if (i > 0)
            s += ', ';
        s += String(args[i]);
    }
    s += ')';
    console.log(s);
}

inject(Foo.prototype, logFnCall);
2
Peter Tseng

Diyism_trace_for_javascript.htmを試してください:

https://code.google.com/p/diyism-trace/downloads/list

eval('window.c=function(){3+5;}');
declare_ticks_for(window);

function a(k, c) {
  return k + 2;
}

function b() {
  4 + 3;
  a(3, {'a':'c','b':'d'});
  c();
  return 5 + 4;
}

b();

chromeまたはfirefoxのコンソールタブでログを表示

2
diyism

たぶん、console.logを追加する作業の一部をJavaScriptに実行させることができます。

console.logをすべての機能に自動的に追加

また、ポール・アイリッシュによるこのブログは役に立つかもしれません:

http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/

引数のロギングを特に対象としたJavaScriptへのリンクが含まれています。

http://pastie.org/1033665

2
Jason Sperske

@ Briguy37のソリューションを改善して使用しました。私の場合、一部のライブラリから関数をトレースしたくないため、それらを除外するコードを追加しました。使用方法は次のとおりです。

  • 最初に、トレースしたくない関数の定義を含めます。
  • excludeLoggingToNamespaceは、これまでに定義された関数をリストし、それらを除外します。
  • トレースする関数の定義を含めます。
  • AddLoggingToNamespaceを呼び出して、上記の手順で定義した関数にログ機能を追加します。

例:

<script src="js/someLibrary.js"></script>
<script>
    functionLogger.excludeLoggingToNamespace(window);
</script>
<script src="js/codeIWantToTraceHere.js"></script>
<script>
    functionLogger.addLoggingToNamespace(window);
</script>

@ Briguy37のソリューションに追加したコードは次のとおりです。

var excludedFunctions = {};

        functionLogger.excludeLoggingToNamespace = function(namespaceObject){
            for(var name in namespaceObject){
                var potentialFunction = namespaceObject[name];

                if(Object.prototype.toString.call(potentialFunction) === '[object Function]') {
                    excludedFunctions[name] = name;
                }
            }
        }; 

また、excludedFunctionsハッシュを取り込むために、@ Briguy37のaddLoggingToNamespaceメソッドを変更する必要がありました。

functionLogger.addLoggingToNamespace = function(namespaceObject){
    for(var name in namespaceObject){
        var potentialFunction = namespaceObject[name];

        if(Object.prototype.toString.call(potentialFunction) === '[object Function]' && 
           !excludedFunctions[name]) {
            namespaceObject[name] = functionLogger.getLoggableFunction(potentialFunction, name);
        }
    }
};