51

次のようなコンソール ログ ラッパーを作成するにはどうすればよいですか。

  • ログステートメントの記録された行番号とファイル名をそのまま保持する
  • すべてのログ重大度メソッド (エラー、ログ、デバッグなど) へのアクセスを提供し、ログに記録されたとおりにコンソールに表示します
  • いくつかのフォールバックを提供します (たとえば、ブラウザがエラーをサポートしていない場合に log メソッドを呼び出します)
  • 中央の場所でオフにできるため、本番用のログをオフにできます
  • コンソールが存在しない場合を処理し、エラーをスローしません

Java Script でのログインは非常に一貫性がないため、何らかの解決策が必要です。自分で実装するのは少し面倒ですが、良いライブラリがないようです。

現在、すべての機能を提供するこのロガーを見つけましたが、行番号がめちゃくちゃです。http://benalman.com/projects/javascript-debug-console-log/

4

8 に答える 8

17

私自身のlog4javascriptがあります。これには独自のログ コンソールがありますが、ラッパーも提供されますconsole.logconsole.log()行番号をそのまま保持することを除いて、すべての基準を満たします。これは、別の関数で etc. の呼び出しをラップしている場合は達成できません。

var log = log4javascript.getLogger("main");
var appender = new log4javascript.BrowserConsoleAppender();
log.addAppender(appender);
log.debug("Hello world");
于 2012-07-03T10:18:31.930 に答える
8

また、log4javascript をお勧めし、少なくとも Chrome では、印刷されたファイル名と行に関する情報を保持する方法を説明します。

Chrome によって出力されるファイル名と行を変更することについて話しているわけではありませんが、関心のある情報を取得して、ログ ステートメントに追加することができます。私の解決策は簡単なハックでしたが、もう少し作業をすれば、適切にフォーマットされたログステートメントを取得できると思います。おそらくパフォーマンスにも大きな影響がありますが、本番環境でログを有効にしたままにしないので、これはそれほど問題にはなりません。

コンセプト

Chrome では、現在のスタックの場所を示すスタック プロパティを提供する Error オブジェクトを作成し、スタック文字列のどこかに呼び出しスクリプトのファイルと行番号を見つけることができます。

  > new Error().stack
  "Error
    at eval at <anonymous> (eval at evaluate (unknown source))
    at eval at evaluate (unknown source)
    at FrameMirror.evaluate (native)
    at Object.evaluate (unknown source)
    at Object._evaluateOn (unknown source)
    at Object._evaluateAndWrap (unknown source)
    at Object.evaluateOnCallFrame (unknown source)
    at meinAjaxAufruf (http://localhost:8080/numberajax.js:21:9)
    at HTMLInputElement.onkeyup (http://localhost:8080/numberajax.html:15:188)"

log4javascript 呼び出しの場合、スタック トレースは次のようになります。

"Error
    at Object.append (http://localhost:8080/log4javascript_uncompressed.js:1921:17)
    at Object.doAppend (http://localhost:8080/log4javascript_uncompressed.js:1047:9)
    at Object.callAppenders (http://localhost:8080/log4javascript_uncompressed.js:647:27)
    at Object.log (http://localhost:8080/log4javascript_uncompressed.js:640:10)
    at Object.debug (http://localhost:8080/log4javascript_uncompressed.js:748:9)
    at meinAjaxAufruf (http://localhost:8080/numberajax.js:36:16)
    at HTMLInputElement.onkeyup (http://localhost:8080/numberajax.html:16:188)"

そして、log4javascript呼び出しを行い、私が興味を持っているファイルと行は

at meinAjaxAufruf (http://localhost:8080/numberajax.js:36:16)

ソリューション

console関心のあるスクリプトから実際の呼び出しが行われる場所までのスタックの深さは常に同じであると推測しています。BrowserConsoleAppenderしたがって、がアクセスする場所を見つけて、window.console関心のある行を書式設定された文字列に追加するだけです。log4javascript_uncompressed.js(バージョン 1.4.2 行 1913)に次の変更を加えました。

} else if (window.console && window.console.log) { // Safari and Firebug
        var formattedMesage = getFormattedMessage();

        //---my additions
        var isChrome = navigator.userAgent.indexOf("Chrome") !== -1;
        if(isChrome){
            var stack = new Error().stack;
            var lineAccessingLogger = stack.split("\n")[6];
            formattedMesage += "\n" + lineAccessingLogger;
        }
        //---

        // Log to Firebug using its logging methods or revert to the console.log
        // method in Safari
        if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {
            window.console.debug(formattedMesage);
        } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {
        ...

今では代わりに

17:53:22,872 DEBUG - sending /NumberServlet?zahl=1&text=
                                                 log4javascript.js:154

私は得る

17:55:53,008 DEBUG - sending /NumberServlet?zahl=1&text=

    at meinAjaxAufruf (http://localhost:8080/numberajax.js:36:16) log4javascript_uncompressed.js:1930

それは確かに良い解決策ではありません:)、しかし私は必要なものを手に入れました。

フレームワークについてもう少し知識があれば、ファイル名/場所と行番号を印刷する方法を定義できるように PatternLayout を変更できると思います。

編集以前のソリューションの代わりに、PatternLayout.prototype.format 関数にいくつかの変更を加えたので、追加のオプション %l を使用して、呼び出しファイルとその行を出力する場所と方法を定義できます。変更点と使用例をGistとして公開しました。

于 2012-08-23T16:00:44.283 に答える
8

ログラッパーにもこの問題がありましたが、部分関数アプリケーションを使用した素晴らしい簡単な回避策があることがわかりました。

if(DEBUG_ENABLED && (typeof console != 'undefined')) {
    this.debug = console.log.bind(console);
}
else {
    this.debug = function(message) {};
}

これにより、ブラウザーは、ログに記録したいソースの正しい行番号とファイルを検出します。

于 2014-06-13T16:14:47.213 に答える
2

Google Chrome には、このスレッドにとって興味深い機能がまもなく搭載される予定です。

次の方法で有効にできます。

  1. chrome://flags/#enable-devtools-experiments を有効にする
  2. 開発ツールの歯車をクリック
  3. [実験] タブに移動
  4. 「Javascript フレームワークのデバッグ」にチェックを入れる
  5. 一般タブに移動
  6. ソースセクションの下
  7. 「特定の名前のソースのステップ実行をスキップする」にチェックを入れる
  8. パターン入力ボックスに、現在表示されているファイル名 (app.log.js) を入力します。

再起動してお楽しみください:)

参考文献:

chrome devtools からのテスト

開発ツールの問題スレッド

開発ツールのコードレビュー

于 2014-09-08T16:49:38.553 に答える
2

ここでこの質問に答えましたが、完全な実装についてはcodepenを参照してください。ただし、これは、クロスブラウザー、エラーなし、正しい行番号、すべての使用可能なコンソールメソッド、グローバルおよびローカルコントロールなど、必要なすべてを実行します。

var Debugger = function(gState, klass) {
  this.debug = {}
  if (!window.console) return function(){}
  if (gState && klass.isDebug) {
    for (var m in console)
      if (typeof console[m] == 'function')
        this.debug[m] = console[m].bind(window.console, klass.toString()+": ")
  }else{
    for (var m in console)
      if (typeof console[m] == 'function')
        this.debug[m] = function(){}
  }
  return this.debug
}

そして、次のように使用します。

isDebug = true //global debug state

debug = Debugger(isDebug, this)

debug.log('Hello Log!')
于 2015-10-04T01:28:34.470 に答える
2

To keep it simple, I've the below wrapper for console methods:

var noop = function () {};
window.consolex = {
    debug : window.console && window.console.debug && console.debug.bind(console) || noop,
    log : window.console && window.console.log && console.log.bind(console) || noop,
    warn: window.WARN = window.console && window.console.warn && console.warn.bind(console) || noop,
    error: window.ERROR = window.console && window.console.error && console.error.bind(console) || noop
};

Also, for better logs in IE and older browsers, please read: Detailed console logging

于 2013-05-28T05:54:36.043 に答える
-2

Web で解決策 (jquery が必要) を見つけましたが、ほとんどのブラウザーでは機能しません。変更したところ、Firefox (Mac、Linux、Android)、Chrome (Mac、Linux、Android)、Safari、およびその他の Android Webkit ブラウザーで動作します。

次のコードを debug.js などのファイルに記述し、Web ページの <head> セクションに「jquery.js」を含めた後に含めるだけで、ページが読み込まれた後(document.ready) に動作します。すべてがロードされる前にデバッグを許可する方法を見つける必要があります(例: <head>...</head> のみ)。Web ページは URL に ?d=1 を指定して呼び出す必要があり、Safari を使用する場合は ?d=1s を使用します。これは、ユーザー エージェントで Safari と別の Webkit ブラウザーを区別できず、Safari の行番号とファイル名の動作が異なるためです。他の Webkit ブラウザーよりも処理が速くなります。

関数 p_r(expression) は、ID #js_debug のウィンドウとコンソール (開いている場合) に、ファイル名と行番号と共にログを記録します。

var g_d = null;


function sortObj(theObj)
{
  var sortable = [];
  for (var i in theObj) {
    sortable.push(i);
  }
  sortable.sort();

  var copy = new Object;
  for (var i in sortable) {
    var ind = sortable[i];
    copy[ind] = theObj[ind];
  }

  return copy;

}

function p_r(s, comment, level)
{
  if (!g_d) return;
  var res = s;
  var pre = new Array("","  " , "    ", "      ", "        ");
  if (comment) comment += ' : ';
  if (arguments.length<2) comment='';
  if (arguments.length<3) level = 0;
//  if (console) console.log(s);
  if (typeof(s) == 'object') {
    var copy = sortObj(s);
    comment += '\n';
    res = '[object]\n';
    if (level < 2) {
      for (var i in copy) {
        if (typeof(copy[i]) != "function")
          res += pre[level] + (i) + " : " + p_r(copy[i], '', level+1) +  " : " + typeof(copy[i]) + "\n";
      }
      res += pre[level] + "[/object]\n";
    }
  }
  else if (typeof(s) == 'function')
    res = 'function';
  else if (typeof(s) != 'string')
    res = '' + s;
  res = res.replace(/&/g, '&amp;');
  res = res.replace(/\x3C/g, '&lt;');
  res = res.replace(/>/g, '&gt;');
  if (level == 0) {
window.LOG=res;
console.log(window.LOG + comment + res);
    g_d.innerHTML += (window.LOG + comment + res + '\n');
  }
  return res;
}

if (location.href.match(/d\=[1-9]/)) {

  $(document).ready(function() {
    $("body").prepend("<div id=\"js_debugclick\" onclick=\"$('#js_debug').toggle();\">JS DEBUG</div>\
  <pre onclick=\"$('#js_debug').toggle();\" id='js_debug'></pre>\
");

    $("head").append("<style type=\"text/css\">\
pre#js_debug {\
border: solid black 1px; background-color: #1CF; color: #000; display:none; position:absolute; top: 20px;\
font-family: Lucida Console, monospace; font-size: 9pt; height: 400px; overflow:scroll; width:100%;\
z-index:100;\
} \
#js_debugclick { \
  color:red; font-weight:bold; \
} \
</style>\
");
    g_d = document.getElementById('js_debug');
  });

  var __moredebug = location.href.match(/d\=[2-9]/);

    var __issafari = /safari/.test(navigator.userAgent.toLowerCase()) && location.href.match(/d\=[1-9]s/);
    var __iswebkit = /webkit/.test(navigator.userAgent.toLowerCase());
    var __isopera  = /opera/.test(navigator.userAgent.toLowerCase());
  if (__moredebug) console.log(__issafari, __iswebkit);

/*@const*/ //for closure-compiler
//DEBUG=2 // 0=off, 1=msg:file:line:column, 2=msg:stack-trace

/*@const @constructor*/
Object.defineProperty(window,'__stack__',{get:function(){
    try{i.dont.exist()}catch(e){
if (__moredebug)  var x=e.stack.split(":"); for (i in x){console.log(i,x[i]);}
//    console.log(e.stack.split(":")[13].match(/(\d+)/)[1]);
    return e.stack.split(":")}
}})

/*@const @constructor*/
Object.defineProperty(window,'__file__',{get:function(){
    var s=__stack__,l=s.length
    var f= __issafari ? s[9] : (__isopera ? s[12] : (__iswebkit ? s[14] : s[9]));
    return f.replace(/^.+?\/([^\/]+?)\?.+?$/, "$1");
}})

/*@const @constructor*/
Object.defineProperty(window,'__line__',{get:function(){
    var s=__stack__,l=s.length
    return __issafari ? s[10].match(/(\d+)/)[1] :(__isopera ? s[13].match(/(\d+)/)[1] : (__iswebkit ? s[15] : s[10].replace(/\n/, " ").replace(/(\d+).+?$/, "$1")));
}})

/*@const @constructor*/
Object.defineProperty(window,'__col__',{get:function(){
    var s=__stack__,l=s.length
    return (isNaN(s[l-2]))?"NA":s[l-1]
}})

/*@const @constructor*/
Object.defineProperty(window,'LOG',{
    get:function(){return out},
    set:function(msg){if(0)out=msg+"\t-\t"+__stack__
        else out=__file__+" "+__line__+": ";
        }
})



}//end if(DEBUG)
于 2013-07-17T19:18:12.047 に答える