正しい行番号を持つconsole.logの適切なラッパー?


132

現在、アプリケーションを開発しており、グローバル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)か?


ラッパー関数を介して何かを追加する代わりに、console.log情報、console.warn警告、console.errorエラーに使用できますconsole.log
Alvin Wong

2
@AlvinWongええ私は知っていますが、問題は、console使用する必要があるかどうかを制御するグローバルデバッグスイッチが必要なことです。そのような目標を達成するには、ラッパーが唯一の方法のように思われますか?
ルーファス

Google Chromeについては、stackoverflow.com / a / 25729203/1429301を参照してください。この場合、パターンはdebug.jsになります
Frison Alexander

回答:


117

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

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')
}

16
私が間違っている場合は私を修正しますが、これでは追加の機能を追加できません、そうですか?あなたは本質的にコンソールオブジェクトのエイリアスをしているだけですか?大雑把な例-すべてのdebug.log()に対して2回イベントをconsole.log()する方法はありませんか?
ABキャロル

3
@ABCarrollへの2つの呼び出しを含むconsole.logカスタムlog()関数をバインドすることで、2回実行できますがconsole.log、行番号はconsole.logdebug.logが呼び出される場所ではなく、実際に存在する行を反映します。ただし、動的な接頭辞/接尾辞などを追加することもできます。行番号の問題を補正する方法もありますが、それは別の質問だと思います。このプロジェクトの例を確認してください:github.com/arctelix/iDebugConsole/blob/master/README.md
arctelix

2
このメソッドは、バージョン47から49までのFirefoxでは機能しません。また、バージョン50.0a2でのみ修正されました。FF50は2週間でリリースされますが、なぜ機能しないのか理解するのに数時間かかります。だから私はこの情報が誰かのために役立つかもしれないと思います。リンク
Vladimir Liubimov 2016年

@ABCarrollの意味するところは、インスタンス内のすべてがランタイムで使用できないことです。別のインスタンスの場合、グローバル状態はインスタンス化でのみ定義できるため、後でに変更this.isDebugfalseても問題はありません。これを回避する方法があるかどうかはわかりませんが、それは仕様によるものかもしれません。その意味では、これisDebugはかなり誤解を招くものでvarあり、const代わりにする必要があります。
cregox 2017年

2
これは、「debug()が呼び出される行番号でログを記録したい場合はどうしますか?」という質問には答えません。
テクノマージュ

24

私は@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/
        /// * /programming/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 ---');

余分のためのアカウントに少しより高度な答えconsoleのような方法warnerrorなど、 - stackoverflow.com/a/14842659/1037948
drzaus

1
var line = stack.split('\n')[2];'undefined' is not an object
sigod

@sigod-おそらくブラウザに依存しているか、2年前に私がこれを書いていて、ブラウザが変わった。あなたのシナリオは何ですか?
drzaus

1
私の同僚の1人があなたのコードを私たちのプロジェクトにコピーアンドペーストしました。IE11とSafari 5でサイトを破壊しました。このブラウザの他のバージョンについては不明です。たぶん、あなたは将来のコピーペーストのチェックを追加しますか?
sigod 2015

1
@sigod今はどう?if(!stack) return '?'呼び出された場所ではなく、失敗したメソッドに追加されます(つまり、メソッド自体を使用する場合、それらも「保護」されます)
drzaus

18

行番号維持し、ログレベルを出力するには、以下を巧みに使用します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)

1
私は、自動的に出力を前に付けるために、今しばらくの間しようとしてきたconsole.debug(...)function nameし、argumentsそれを行う方法上の任意の考えを- ?
Daniel Sokolowski、

3
私はコンソールラッパー/シムなどを多数見てきました。これは、行番号の保持と出力のカスタマイズを組み合わせた最初の問題です。.bindもカリー化するという賢い使い方です。コンテキストに加えて、1つ以上の引数をバインドできます。あなたはそれをさらに一歩進めて、ログメソッドが呼び出されたときにコードを実行できる.toStringメソッドでnoop関数を渡すことができます!参照してください。このjsfiddle
サム・ハスラー

2
たぶんすべてのブラウザではないかもしれませんが(まだ調べていません)、Chromeでを置き換える%s%o、パラメータが期待どおりに印刷されます(オブジェクトは展開可能で、数値や文字列は色付きなど)。
anson

このソリューションが大好きです。私は自分のアプリケーションに適したいくつかの変更を加えましたが、その大部分はそのままで、美しく実行されています。おかげで

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);

1
new Error();それが実行されるコンテキストを私に与えます、私がそれを入れたらdebug.js、私は得info: Here is a msg. file: http://localhost/js/debug.js line:7ます。
ルーファス

1
のポイントはLog = Error何ですか?まだErrorクラスを変更していますよね?
drzaus 2013

カップルの他の人とあなたの答えの組み合わせ-下記参照stackoverflow.com/a/14841411/1037948
drzaus

8

行番号を保持する方法は、https//gist.github.com/bgrins/5108712です。それは多かれ少なかれこれに要約されます:

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);
    };
}

あなたはでこれを包むことができisDebug、設定window.logfunction() { }デバッグしていない場合。


7

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

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

ここで(new Error).lineNumberは、javascriptコードの現在の行番号がわかります。


2
少し冗長ですね。
ルーファス

2
私はあなたの質問に答えるのに十分だと思います。:)
Subodh

1
lineNumberプロパティは非標準であり、現在はFirefoxでのみ機能します。ここを
Matthias

6

Chrome Devtoolsでは、ブラックボックス化でこれを実現できます。副作用があり、他の関数を呼び出すことができるconsole.logラッパーを作成し、ラッパー関数を呼び出した行番号を保持することができます。

小さなconsole.logラッパーを別のファイルに入れるだけです。

(function() {
    var consolelog = console.log
    console.log = function() {
        // you may do something with side effects here.
        // log to a remote server, whatever you want. here
        // for example we append the log message to the DOM
        var p = document.createElement('p')
        var args = Array.prototype.slice.apply(arguments)
        p.innerText = JSON.stringify(args)
        document.body.appendChild(p)

        // call the original console.log function
        consolelog.apply(console,arguments)
    }
})()

log-blackbox.jsのような名前を付けます

次に、Chrome Devtools設定に移動し、「Blackboxing」セクションを見つけ、ブラックボックス化するファイル名のパターンを追加します。この場合は、log-blackbox.jsです。


注:あなたはあなたがどんなコードがありません作るだろう、それはまた、トレースから削除されるように、同じファイルにスタックトレースに表示したいの。
jamesthollowell

6

受け入れられた回答(console.log / error / etcへのバインド)をいくつかの外部ロジックと組み合わせて、実際にログに記録されるものをフィルタリングする簡単な解決策を見つけました。

// or window.log = {...}
var log = {
  ASSERT: 1, ERROR: 2, WARN: 3, INFO: 4, DEBUG: 5, VERBOSE: 6,
  set level(level) {
    if (level >= this.ASSERT) this.a = console.assert.bind(window.console);
    else this.a = function() {};
    if (level >= this.ERROR) this.e = console.error.bind(window.console);
    else this.e = function() {};
    if (level >= this.WARN) this.w = console.warn.bind(window.console);
    else this.w = function() {};
    if (level >= this.INFO) this.i = console.info.bind(window.console);
    else this.i = function() {};
    if (level >= this.DEBUG) this.d = console.debug.bind(window.console);
    else this.d = function() {};
    if (level >= this.VERBOSE) this.v = console.log.bind(window.console);
    else this.v = function() {};
    this.loggingLevel = level;
  },
  get level() { return this.loggingLevel; }
};
log.level = log.DEBUG;

使用法:

log.e('Error doing the thing!', e); // console.error
log.w('Bonus feature failed to load.'); // console.warn
log.i('Signed in.'); // console.info
log.d('Is this working as expected?'); // console.debug
log.v('Old debug messages, output dominating messages'); // console.log; ignored because `log.level` is set to `DEBUG`
log.a(someVar == 2) // console.assert
  • console.assertは条件付きロギングを使用することに注意してください。
  • ブラウザの開発ツールがすべてのメッセージレベルを表示していることを確認してください。

これは、行番号もログレベルを示す実際の例も示していないためです。
not2qubit 2018年

行番号は、コンソールを直接使用する場合と同じです。使用例で回答を更新しました。2年後に答えたので、投票数は多くありません:)
Jacob Phillips

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");

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

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

ご存知のとおり、ラッパー関数は行番号とファイル名をめちゃくちゃにするので、ラッパー関数の使用を防ぐことをお勧めします。


グレートは、私がのために注意する必要があるisDebug = truedebug.js、この答えは、作業を行います!
ルーファス

3
window.debug = window.console少しきれいになります。
fredrik

@fredrikの場合は、すべてのメンバー関数を「実装」する必要がありますisDebug == false。:{
Alvin Wong

@AlvinWong私はちょうどのためにmenat isDebug===true。または、これに対する
fredrik

4

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

このロジックは行番号を混乱させるため、バインドは中間ロジックを含めることを防ぎます。ただし、バインドされた関数を再定義し、コンソール文字列置換を試してみると、いくつかの追加の動作がまだ可能です。

この要点は、モジュール、ログレベル、フォーマット、および適切なクリック可能な行番号を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"
})();


この回答には3つの賛成票しかありませんが、ページ内の他のどれよりも信じられないほどリッチでクリーンです
Tom

ただし、すべての有用な部品が外部要旨にあるようです。
ライアンザリーチ

3

bindのアイデアFunction.prototype.bindは素晴らしいです。npmライブラリlines-loggerを使用することもできます。元のソースファイルが表示されます。

プロジェクトで一度ロガーを作成します。

var LoggerFactory = require('lines-logger').LoggerFactory;
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.getLoggerColor('global', '#753e01');

ログを印刷:

logger.log('Hello world!')();

ここに画像の説明を入力してください


2

consoleファイル名と行番号またはその他のスタックトレース情報を出力に追加しながら、既存のロギングステートメントを保持する方法は次のとおりです。

(function () {
  'use strict';
  var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
  var isChrome = !!window.chrome && !!window.chrome.webstore;
  var isIE = /*@cc_on!@*/false || !!document.documentMode;
  var isEdge = !isIE && !!window.StyleMedia;
  var isPhantom = (/PhantomJS/).test(navigator.userAgent);
  Object.defineProperties(console, ['log', 'info', 'warn', 'error'].reduce(function (props, method) {
    var _consoleMethod = console[method].bind(console);
    props[method] = {
      value: function MyError () {
        var stackPos = isOpera || isChrome ? 2 : 1;
        var err = new Error();
        if (isIE || isEdge || isPhantom) { // Untested in Edge
          try { // Stack not yet defined until thrown per https://docs.microsoft.com/en-us/scripting/javascript/reference/stack-property-error-javascript
            throw err;
          } catch (e) {
            err = e;
          }
          stackPos = isPhantom ? 1 : 2;
        }

        var a = arguments;
        if (err.stack) {
          var st = err.stack.split('\n')[stackPos]; // We could utilize the whole stack after the 0th index
          var argEnd = a.length - 1;
          [].slice.call(a).reverse().some(function(arg, i) {
            var pos = argEnd - i;
            if (typeof a[pos] !== 'string') {
              return false;
            }
            if (typeof a[0] === 'string' && a[0].indexOf('%') > -1) { pos = 0 } // If formatting
            a[pos] += ' \u00a0 (' + st.slice(0, st.lastIndexOf(':')) // Strip out character count
              .slice(st.lastIndexOf('/') + 1) + ')'; // Leave only path and line (which also avoids ":" changing Safari console formatting)
            return true;
          });
        }
        return _consoleMethod.apply(null, a);
      }
    };
    return props;
  }, {}));
}());

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

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <script src="console-log.js"></script>
</head>
<body>
  <script>
  function a () {
    console.log('xyz'); // xyz   (console-log.html:10)
  }
  console.info('abc'); // abc   (console-log.html:12)
  console.log('%cdef', "color:red;"); // (IN RED:) // def   (console-log.html:13)
  a();
  console.warn('uuu'); // uuu   (console-log.html:15)
  console.error('yyy'); // yyy   (console-log.html:16)
  </script>
</body>
</html>

これは、Firefox、Opera、Safari、Chrome、IE 10で動作します(IE11またはEdgeではまだテストされていません)。


いい仕事ですが、それでも100%必要なものはありません。コンソールビューの右側にファイル名と行番号の情報があり、クリックしてソースを開くことができます。このソリューションは、メッセージの一部として情報を表示します(このようにmy test log message (myscript.js:42) VM167 mypage.html:15:)。これは、読むのに適さず、リンクされていません。それでも良い仕事は賛成です。
Frederic Leitenberger

それは理想的である一方、うん、方法はありません、私の知る限りでは、そのコンソールでショーアップ...ファイル名のリンクを偽装するために
ブレットザミール

@BrettZamirは、ここで、このコードについての質問を投稿:stackoverflow.com/questions/52618368/...
Mahks

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が必要です、残念。


2
evalは悪です!だからすべての悪。
fredrik

1

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);

これは、log呼び出し元の元の行番号を示していないようです
ragamufin '12年

私がテストしたときにそれが機能したことはほぼ確信していますが、コードを同じページの「フル」バージョンに置き換えました。クローム45に少なくともで働いていた
ティモKähkönen

わかった。変更により、基本的に他のいくつかの回答と同じように機能します。以前のコードに興味を持ったのは、最後に適用して、これをさらに使用する興味深い可能性をもたらしたからです。ただし、行番号が表示されなかったので、1に戻しました。ありがとうございます!
ragamufin

1

私は最近、この問題を自分で調べています。ロギングを制御するだけでなく、行番号を保持するために非常に単純なものが必要でした。私のソリューションはコードでエレガントに見えませんが、私に必要なものを提供します。閉鎖と保持に十分注意すれば。

アプリケーションの最初に小さなラッパーを追加しました:

window.log = {
    log_level: 5,
    d: function (level, cb) {
        if (level < this.log_level) {
            cb();
        }
    }
};

そのため、後で簡単に行うことができます。

log.d(3, function(){console.log("file loaded: utils.js");});

私はそれをfirefoxとcromeでテストしましたが、どちらのブラウザーも意図したとおりにコンソールログを表示するようです。そのように入力した場合は、常に「d」メソッドを拡張して他のパラメーターをそれに渡すことができるため、追加のロギングを実行できます。

ログのコードの醜い行を除いて、私のアプローチには重大な欠点をまだ発見していません。


1

window.line = function () {
    var error = new Error(''),
        brower = {
            ie: !-[1,], // !!window.ActiveXObject || "ActiveXObject" in window
            opera: ~window.navigator.userAgent.indexOf("Opera"),
            firefox: ~window.navigator.userAgent.indexOf("Firefox"),
            chrome: ~window.navigator.userAgent.indexOf("Chrome"),
            safari: ~window.navigator.userAgent.indexOf("Safari"), // /^((?!chrome).)*safari/i.test(navigator.userAgent)?
        },
        todo = function () {
            // TODO: 
            console.error('a new island was found, please told the line()\'s author(roastwind)');        
        },
        line = (function(error, origin){
            // line, column, sourceURL
            if(error.stack){
                var line,
                    baseStr = '',
                    stacks = error.stack.split('\n');
                    stackLength = stacks.length,
                    isSupport = false;
                // mac版本chrome(55.0.2883.95 (64-bit))
                if(stackLength == 11 || brower.chrome){
                    line = stacks[3];
                    isSupport = true;
                // mac版本safari(10.0.1 (12602.2.14.0.7))
                }else if(brower.safari){
                    line = stacks[2];
                    isSupport = true;
                }else{
                    todo();
                }
                if(isSupport){
                    line = ~line.indexOf(origin) ? line.replace(origin, '') : line;
                    line = ~line.indexOf('/') ? line.substring(line.indexOf('/')+1, line.lastIndexOf(':')) : line;
                }
                return line;
            }else{
                todo();
            }
            return '😭';
        })(error, window.location.origin);
    return line;
}
window.log = function () {
    var _line = window.line.apply(arguments.callee.caller),
        args = Array.prototype.slice.call(arguments, 0).concat(['\t\t\t@'+_line]);
    window.console.log.apply(window.console, args);
}
log('hello');

これがこの質問に対する私の解決策でした。メソッド:logを呼び出すと、ログを印刷する行番号が出力されます


1

少しのバリエーションとして、debug()に関数を返させ、必要な場所で実行するというものがあります-debug(message)(); コンソールウィンドウに正しい行番号と呼び出しスクリプトを適切に表示し、アラートとしてリダイレクトしたり、ファイルに保存したりするなどのバリエーションを可能にします。

var debugmode='console';
var debugloglevel=3;

function debug(msg, type, level) {

  if(level && level>=debugloglevel) {
    return(function() {});
  }

  switch(debugmode) {
    case 'alert':
      return(alert.bind(window, type+": "+msg));
    break;
    case 'console':
      return(console.log.bind(window.console, type+": "+msg));
    break;
    default:
      return (function() {});
  }

}

関数を返すため、その関数はデバッグ行で();を使用して実行する必要があります。次に、メッセージは返された関数ではなくデバッグ関数に送信され、ログレベルの状態のチェック、メッセージの可読性の向上、異なるタイプのスキップ、アイテムのレポートなど、必要な前処理またはチェックが可能になります。ログレベルの基準を満たす。

debug(message, "serious", 1)();
debug(message, "minor", 4)();

1

ここでロジックを簡略化できます。これは、グローバルデバッグフラグが動的ではなく、アプリのロード時に設定されるか、何らかの構成として渡されることを前提としています。これは、環境フラグを設定するために使用することを目的としています(たとえば、本番環境ではなく、開発モードでのみ印刷します)。

バニラJS:

(function(window){ 
  var Logger = {},
      noop = function(){};

  ['log', 'debug', 'info', 'warn', 'error'].forEach(function(level){
    Logger[level] = window.isDebug ? window.console[level] : noop;
  });

  window.Logger = Logger;
})(this);

ES6:

((window) => {
  const Logger = {};
  const noop = function(){};

  ['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
    Logger[level] = window.isDebug ? window.console[level] : noop;
  });

  window.Logger = Logger;
})(this);

モジュール:

const Logger = {};
const noop = function(){};

['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
  Logger[level] = window.isDebug ? window.console[level] : noop;
});

export default Logger;

Angular 1.x:

angular
  .module('logger', [])
  .factory('Logger', ['$window',
    function Logger($window) {
      const noop = function(){};
      const logger = {};

      ['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
        logger[level] = $window.isDebug ? $window.console[level] : noop;
      });

      return logger;
    }
  ]);

ここで必要なのは、すべてのコンソール参照をロガーに置き換えることだけです。


1

この実装は選択された回答に基づいており、エラーコンソールのノイズの量を減らすのに役立ちます:https : //stackoverflow.com/a/32928812/516126

var Logging = Logging || {};

const LOG_LEVEL_ERROR = 0,
    LOG_LEVEL_WARNING = 1,
    LOG_LEVEL_INFO = 2,
    LOG_LEVEL_DEBUG = 3;

Logging.setLogLevel = function (level) {
    const NOOP = function () { }
    Logging.logLevel = level;
    Logging.debug = (Logging.logLevel >= LOG_LEVEL_DEBUG) ? console.log.bind(window.console) : NOOP;
    Logging.info = (Logging.logLevel >= LOG_LEVEL_INFO) ? console.log.bind(window.console) : NOOP;
    Logging.warning = (Logging.logLevel >= LOG_LEVEL_WARNING) ? console.log.bind(window.console) : NOOP;
    Logging.error = (Logging.logLevel >= LOG_LEVEL_ERROR) ? console.log.bind(window.console) : NOOP;

}

Logging.setLogLevel(LOG_LEVEL_INFO);

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)
)()

0

私が解決した方法は、オブジェクトを作成し、次にObject.defineProperty()を使用してオブジェクトに新しいプロパティを作成し、コンソールプロパティを返すことでした。これは、通常の関数として使用されていましたが、拡張された機能を備えています。

var c = {};
var debugMode = true;

var createConsoleFunction = function(property) {
    Object.defineProperty(c, property, {
        get: function() {
            if(debugMode)
                return console[property];
            else
                return function() {};
        }
    });
};

次に、プロパティを定義するには、次のようにします...

createConsoleFunction("warn");
createConsoleFunction("log");
createConsoleFunction("trace");
createConsoleFunction("clear");
createConsoleFunction("error");
createConsoleFunction("info");

そして今、あなたはちょうどあなたのような関数を使うことができます

c.error("Error!");

0

他の回答(主に@arctelixの回答)に基づいて、Node ES6用にこれを作成しましたが、簡単なテストでブラウザでも良好な結果が得られました。他の関数を参照として渡しているだけです。

let debug = () => {};
if (process.argv.includes('-v')) {
    debug = console.log;
    // debug = console; // For full object access
}

0

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

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' );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.