166

現在、アプリケーションを開発しており、グローバルisDebugスイッチを配置しています。console.logもっと便利に使えるようにラッピングしたいです。

//isDebug controls the entire site.
var isDebug = true;

//debug.js
function debug(msg, level){
    var Global = this;
    if(!(Global.isDebug && Global.console && Global.console.log)){
        return;
    }
    level = level||'info';
    Global.console.log(level + ': '+ msg);
}

//main.js
debug('Here is a msg.');

次に、Firefoxコンソールでこの結果を取得します。

info: Here is a msg.                       debug.js (line 8)

debug()呼び出された行番号でログに記録したい場合はどうなりますinfo: Here is a msg. main.js (line 2)か?

4

25 に答える 25

130

これは古い質問であり、提供されるすべての回答は過度にハッキーであり、クロス ブラウザーに大きな問題があり、非常に役立つものは何も提供していません。このソリューションは、すべてのブラウザーで機能し、すべてのコンソール データを正確に報告します。ハックは不要で、コードは 1 行ですcodepen をチェックしてください

var debug = console.log.bind(window.console)

次のようにスイッチを作成します。

isDebug = true // toggle this to turn on / off for global controll

if (isDebug) var debug = console.log.bind(window.console)
else var debug = function(){}

次に、次のように呼び出します。

debug('This is happening.')

次のようなスイッチを使用して、console.log を引き継ぐこともできます。

if (!isDebug) console.log = function(){}

それを使って何か便利なことをしたい場合..すべてのコンソールメソッドを追加して、グローバルコントロールだけでなくクラスレベルも提供する再利用可能な関数にまとめることができます:

var Debugger = function(gState, klass) {

  this.debug = {}

  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!')
debug.trace('Hello trace!')

これで、クラスに追加できます。

var MyClass = function() {
  this.isDebug = true //local state
  this.debug = Debugger(isDebug, this)
  this.debug.warn('It works in classses')
}
于 2015-10-04T00:21:17.887 に答える
27

@fredrik の回答が気に入ったので、Webkit スタックトレースを分割する別の回答をまとめて、 @PaulIrish の安全な console.log ラッパーとマージしました。を「特別なオブジェクト」に「標準化」しfilename:lineて、FF と Chrome で目立ち、ほとんど同じに見えるようにします。

フィドルでのテスト: http://jsfiddle.net/drzaus/pWe6W/

_log = (function (undefined) {
    var Log = Error; // does this do anything?  proper inheritance...?
    Log.prototype.write = function (args) {
        /// <summary>
        /// Paulirish-like console.log wrapper.  Includes stack trace via @fredrik SO suggestion (see remarks for sources).
        /// </summary>
        /// <param name="args" type="Array">list of details to log, as provided by `arguments`</param>
        /// <remarks>Includes line numbers by calling Error object -- see
        /// * http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
        /// * https://stackoverflow.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number
        /// * https://stackoverflow.com/a/3806596/1037948
        /// </remarks>

        // via @fredrik SO trace suggestion; wrapping in special construct so it stands out
        var suffix = {
            "@": (this.lineNumber
                    ? this.fileName + ':' + this.lineNumber + ":1" // add arbitrary column value for chrome linking
                    : extractLineNumberFromStack(this.stack)
            )
        };

        args = args.concat([suffix]);
        // via @paulirish console wrapper
        if (console && console.log) {
            if (console.log.apply) { console.log.apply(console, args); } else { console.log(args); } // nicer display in some browsers
        }
    };
    var extractLineNumberFromStack = function (stack) {
        /// <summary>
        /// Get the line/filename detail from a Webkit stack trace.  See https://stackoverflow.com/a/3806596/1037948
        /// </summary>
        /// <param name="stack" type="String">the stack string</param>

        if(!stack) return '?'; // fix undefined issue reported by @sigod

        // correct line number according to how Log().write implemented
        var line = stack.split('\n')[2];
        // fix for various display text
        line = (line.indexOf(' (') >= 0
            ? line.split(' (')[1].substring(0, line.length - 1)
            : line.split('at ')[1]
            );
        return line;
    };

    return function (params) {
        /// <summary>
        /// Paulirish-like console.log wrapper
        /// </summary>
        /// <param name="params" type="[...]">list your logging parameters</param>

        // only if explicitly true somewhere
        if (typeof DEBUGMODE === typeof undefined || !DEBUGMODE) return;

        // call handler extension which provides stack trace
        Log().write(Array.prototype.slice.call(arguments, 0)); // turn into proper array
    };//--  fn  returned

})();//--- _log

これはノードでも機能し、次の方法でテストできます。

// no debug mode
_log('this should not appear');

// turn it on
DEBUGMODE = true;

_log('you should', 'see this', {a:1, b:2, c:3});
console.log('--- regular log ---');
_log('you should', 'also see this', {a:4, b:8, c:16});

// turn it off
DEBUGMODE = false;

_log('disabled, should not appear');
console.log('--- regular log2 ---');
于 2013-02-12T20:41:32.923 に答える
22

行番号維持し、ログ レベルを出力するには、以下を巧妙に使用しますFunction.prototype.bind

function setDebug(isDebug) {
  if (window.isDebug) {
    window.debug = window.console.log.bind(window.console, '%s: %s');
  } else {
    window.debug = function() {};
  }
}

setDebug(true);

// ...

debug('level', 'This is my message.'); // --> level: This is my message. (line X)

さらに一歩進んで、consoleのエラー/警告/情報の区別を利用し、カスタム レベルを保持することができます。それを試してみてください!

function setDebug(isDebug) {
  if (isDebug) {
    window.debug = {
      log: window.console.log.bind(window.console, '%s: %s'),
      error: window.console.error.bind(window.console, 'error: %s'),
      info: window.console.info.bind(window.console, 'info: %s'),
      warn: window.console.warn.bind(window.console, 'warn: %s')
    };
  } else {
    var __no_op = function() {};

    window.debug = {
      log: __no_op,
      error: __no_op,
      warn: __no_op,
      info: __no_op
    }
  }
}

setDebug(true);

// ...

debug.log('wat', 'Yay custom levels.'); // -> wat: Yay custom levels.    (line X)
debug.info('This is info.');            // -> info: This is info.        (line Y)
debug.error('Bad stuff happened.');     // -> error: Bad stuff happened. (line Z)
于 2013-09-22T02:52:07.910 に答える
9

From: JavaScript 呼び出し元関数の行番号を取得するには? JavaScript 呼び出し元 URL を取得するには? オブジェクトには行番号プロパティがありErrorます (FF)。したがって、次のようなものが機能するはずです。

var err = new Error();
Global.console.log(level + ': '+ msg + 'file: ' + err.fileName + ' line:' + err.lineNumber);

Webkit ブラウザerr.stackでは、現在のコール スタックを表す文字列が表示されます。現在の行番号と詳細情報が表示されます。

アップデート

正しい行番号を取得するには、その行でエラーを呼び出す必要があります。何かのようなもの:

var Log = Error;
Log.prototype.write = function () {
    var args = Array.prototype.slice.call(arguments, 0),
        suffix = this.lineNumber ? 'line: '  + this.lineNumber : 'stack: ' + this.stack;

    console.log.apply(console, args.concat([suffix]));
};

var a = Log().write('monkey' + 1, 'test: ' + 2);

var b = Log().write('hello' + 3, 'test: ' + 4);
于 2012-12-11T07:44:39.190 に答える
7

次のように、デバッグ メソッドに行番号を渡すことができます。

//main.js
debug('Here is a msg.', (new Error).lineNumber);

ここで、コード(new Error).lineNumberの現在の行番号が表示されますjavascript

于 2012-12-11T07:47:05.963 に答える
5

スタック トレース ソリューションでは行番号が表示されますが、クリックしてソースに移動することはできません。これは大きな問題です。この動作を維持する唯一の解決策は、元の関数にバインドすることです。

このロジックは行番号を台無しにするため、バインディングは中間ロジックを含めることを防ぎます。ただし、バインドされた関数を再定義し、コンソール文字列の置換で遊ぶことにより、いくつかの追加の動作がまだ可能です。

この要旨は、モジュール、ログ レベル、フォーマット、および 34 行で適切なクリック可能な行番号を提供する最小限のロギング フレームワークを示しています。あなた自身のニーズの基礎またはインスピレーションとしてそれを使用してください。

var log = Logger.get("module").level(Logger.WARN);
log.error("An error has occured", errorObject);
log("Always show this.");

編集:要点は以下に含まれています

/*
 * Copyright 2016, Matthieu Dumas
 * This work is licensed under the Creative Commons Attribution 4.0 International License.
 * To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/
 */

/* Usage : 
 * var log = Logger.get("myModule") // .level(Logger.ALL) implicit
 * log.info("always a string as first argument", then, other, stuff)
 * log.level(Logger.WARN) // or ALL, DEBUG, INFO, WARN, ERROR, OFF
 * log.debug("does not show")
 * log("but this does because direct call on logger is not filtered by level")
 */
var Logger = (function() {
    var levels = {
        ALL:100,
        DEBUG:100,
        INFO:200,
        WARN:300,
        ERROR:400,
        OFF:500
    };
    var loggerCache = {};
    var cons = window.console;
    var noop = function() {};
    var level = function(level) {
        this.error = level<=levels.ERROR ? cons.error.bind(cons, "["+this.id+"] - ERROR - %s") : noop;
        this.warn = level<=levels.WARN ? cons.warn.bind(cons, "["+this.id+"] - WARN - %s") : noop;
        this.info = level<=levels.INFO ? cons.info.bind(cons, "["+this.id+"] - INFO - %s") : noop;
        this.debug = level<=levels.DEBUG ? cons.log.bind(cons, "["+this.id+"] - DEBUG - %s") : noop;
        this.log = cons.log.bind(cons, "["+this.id+"] %s");
        return this;
    };
    levels.get = function(id) {
        var res = loggerCache[id];
        if (!res) {
            var ctx = {id:id,level:level}; // create a context
            ctx.level(Logger.ALL); // apply level
            res = ctx.log; // extract the log function, copy context to it and returns it
            for (var prop in ctx)
                res[prop] = ctx[prop];
            loggerCache[id] = res;
        }
        return res;
    };
    return levels; // return levels augmented with "get"
})();

于 2016-08-31T14:46:52.820 に答える
4

デバッグを使用するかどうかを制御し、正しい行番号を取得したいだけの場合は、代わりに次のようにすることができます。

if(isDebug && window.console && console.log && console.warn && console.error){
    window.debug = {
        'log': window.console.log,
        'warn': window.console.warn,
        'error': window.console.error
    };
}else{
    window.debug = {
        'log': function(){},
        'warn': function(){},
        'error': function(){}
    };
}

デバッグへのアクセスが必要な場合は、次のようにできます。

debug.log("log");
debug.warn("warn");
debug.error("error");

の場合、etc は実際にはetcのエイリアスであるisDebug == trueため、コンソールに表示される行番号とファイル名は正しくなります。debug.logconsole.log

の場合、 etc は単に何もしない (空の関数)isDebug == falseため、デバッグ メッセージは表示されません。debug.log

既にご存知のように、ラッパー関数は行番号とファイル名を台無しにするので、ラッパー関数を使用しないようにすることをお勧めします。

于 2012-12-11T07:52:39.460 に答える
1
//isDebug controls the entire site.
var isDebug = true;

//debug.js
function debug(msg, level){
    var Global = this;
    if(!(Global.isDebug && Global.console && Global.console.log)){
        return;
    }
    level = level||'info';
    return 'console.log(\'' + level + ': '+ JSON.stringify(msg) + '\')';
}

//main.js
eval(debug('Here is a msg.'));

これは私に与えるでしょうinfo: "Here is a msg." main.js(line:2)

しかし、余分なevalものが必要です、残念です。

于 2012-12-11T07:56:47.893 に答える
1

これが私のロガー関数です(いくつかの回答に基づいています)。誰かがそれを利用できることを願っています:

const DEBUG = true;

let log = function ( lvl, msg, fun ) {};

if ( DEBUG === true ) {
    log = function ( lvl, msg, fun ) {
        const d = new Date();
        const timestamp = '[' + d.getHours() + ':' + d.getMinutes() + ':' +
            d.getSeconds() + '.' + d.getMilliseconds() + ']';
        let stackEntry = new Error().stack.split( '\n' )[2];
        if ( stackEntry === 'undefined' || stackEntry === null ) {
            stackEntry = new Error().stack.split( '\n' )[1];
        }
        if ( typeof fun === 'undefined' || fun === null ) {
            fun = stackEntry.substring( stackEntry.indexOf( 'at' ) + 3,
                stackEntry.lastIndexOf( ' ' ) );
            if ( fun === 'undefined' || fun === null || fun.length <= 1 ) {
                fun = 'anonymous';
            }
        }
        const idx = stackEntry.lastIndexOf( '/' );
        let file;
        if ( idx !== -1 ) {
            file = stackEntry.substring( idx + 1, stackEntry.length - 1 );
        } else {
            file = stackEntry.substring( stackEntry.lastIndexOf( '\\' ) + 1,
                stackEntry.length - 1 );
        }
        if ( file === 'undefined' || file === null ) {
            file = '<>';
        }

        const m = timestamp + ' ' + file + '::' + fun + '(): ' + msg;

        switch ( lvl ) {
        case 'log': console.log( m ); break;
        case 'debug': console.log( m ); break;
        case 'info': console.info( m ); break;
        case 'warn': console.warn( m ); break;
        case 'err': console.error( m ); break;
        default: console.log( m ); break;
        }
    };
}

例:

log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
于 2020-07-01T12:18:15.533 に答える
0

この問題に対する答えのいくつかは、私のニーズに対して少し複雑すぎることがわかりました。これは、Coffeescript でレンダリングされた単純なソリューションです。これはブライアン・グリンステッドのバージョンから改作されたものです。

これは、グローバル コンソール オブジェクトを想定しています。

# exposes a global 'log' function that preserves line numbering and formatting.
(() ->
    methods = [
      'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
      'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
      'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
      'timeStamp', 'trace', 'warn']
    noop = () ->
    # stub undefined methods.
    for m in methods  when  !console[m]
        console[m] = noop

    if Function.prototype.bind?
        window.log = Function.prototype.bind.call(console.log, console);
    else
        window.log = () ->
            Function.prototype.apply.call(console.log, console, arguments)
)()
于 2014-02-12T23:23:22.017 に答える
0

http://www.briangrinstead.com/blog/console-log-helper-functionからのコード:

// Full version of `log` that:
//  * Prevents errors on console methods when no console present.
//  * Exposes a global 'log' function that preserves line numbering and formatting.
(function () {
  var method;
  var noop = function () { };
  var methods = [
      'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
      'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
      'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
      'timeStamp', 'trace', 'warn'
  ];
  var length = methods.length;
  var console = (window.console = window.console || {});

  while (length--) {
    method = methods[length];

    // Only stub undefined methods.
    if (!console[method]) {
        console[method] = noop;
    }
  }


  if (Function.prototype.bind) {
    window.log = Function.prototype.bind.call(console.log, console);
  }
  else {
    window.log = function() { 
      Function.prototype.apply.call(console.log, console, arguments);
    };
  }
})();

var a = {b:1};
var d = "test";
log(a, d);
于 2014-11-25T07:57:22.330 に答える
0

最新の JavaScript と getter を使用すると、次のように記述できます。

window.Logger = {
    debugMode: true,
    get info() {
        if ( window.Logger.debugMode ) {
            return window.console.info.bind( window.console );
        } else {
            return () => {};
        }
    }
}

これの良いところは、静的な値と計算された値の両方を、正しい行番号とともに出力できることです。異なる設定で複数のロガーを定義することもできます:

class LoggerClz {
    name = null;
    debugMode = true;
    constructor( name ) { this.name = name; }
    get info() {
        if ( this.debugMode ) {
            return window.console.info.bind( window.console, 'INFO', new Date().getTime(), this.name );
        } else {
            return () => {};
        }
    }
}

const Logger1 = new LoggerClz( 'foo' );
const Logger2 = new LoggerClz( 'bar' );

function test() {
    Logger1.info( '123' ); // INFO 1644750929128 foo 123 [script.js:18] 
    Logger2.info( '456' ); // INFO 1644750929128 bar 456 [script.js:19] 
}
test();
于 2022-02-13T11:24:30.983 に答える
-1

ここでのすべてのソリューションは、実際の問題を回避します。デバッガーは、スタックの一部を無視して、意味のある行を表示できるはずです。VSCode の js デバッガーでこれを実行できるようになりました。この編集の時点で、この機能は js-debug 拡張機能のナイトリー ビルドを介して利用できます。次の段落のリンクを参照してください。

ここで、起動構成のファイル パスのいずれかに存在するスタックの最上位を無視するVSCode のデバッガーの機能を提案しました。skipFilesこのプロパティは、launch.jsonvscode ワークスペースの構成にあります。したがって、console.log のラップを担当するファイル/モジュールを作成し、それをに追加するskipFilesと、デバッガーは、console.log 自体ではなく、スキップされたファイルを呼び出した行を表示します。

これは、js-debug 拡張機能のナイトリー ビルドにあります。ビジュアル スタジオ コードの次のマイナー リリースに含まれる可能性があるようです。ナイトリービルドで動作確認済みです。ハックな回避策はもう必要ありません。

于 2020-12-08T18:07:17.737 に答える