Một trình bao bọc thích hợp cho console.log với số dòng chính xác?


132

Tôi hiện đang phát triển một ứng dụng và đặt một isDebugcông tắc toàn cầu . Tôi muốn bọc console.logđể sử dụng thuận tiện hơn.

//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.');

Sau đó, tôi nhận được kết quả này trong bảng điều khiển Firefox.

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

Điều gì xảy ra nếu tôi muốn đăng nhập với số dòng nơi debug()được gọi, như thế info: Here is a msg. main.js (line 2)nào?


Bạn có thể sử dụng console.logcho thông tin, console.warnđể cảnh báo và console.errorbáo lỗi, thay vì thêm một cái gì đó console.logthông qua chức năng bao bọc.
Alvin Wong

2
@AlvinWong Vâng Tôi biết điều đó, nhưng vấn đề là tôi cần một công tắc gỡ lỗi toàn cầu, điều khiển việc có consolecần sử dụng hay không. Để đạt được mục tiêu như vậy, một bọc có vẻ là cách duy nhất?
Rufus

Đối với Google Chrome, hãy xem stackoverflow.com/a/25729203/1429301 Trong trường hợp của bạn, mẫu sẽ là debug.js
Frison Alexander

Câu trả lời:


117

Đây là một câu hỏi cũ và Tất cả các câu trả lời được cung cấp đều quá hackey, có các vấn đề trình duyệt chéo MAJOR và không cung cấp bất cứ điều gì siêu hữu ích. Giải pháp này hoạt động trong mọi trình duyệt và báo cáo tất cả dữ liệu bảng điều khiển chính xác như mong muốn. Không cần hack và một dòng mã Kiểm tra codepen .

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

Tạo công tắc như thế này:

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

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

Sau đó, chỉ cần gọi như sau:

debug('This is happening.')

Bạn thậm chí có thể tiếp quản console.log bằng một công tắc như thế này:

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

Nếu bạn muốn làm điều gì đó hữu ích với điều đó .. Bạn có thể thêm tất cả các phương thức giao diện điều khiển và gói nó trong một chức năng có thể sử dụng lại, không chỉ kiểm soát toàn cầu, mà cả cấp độ lớp:

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

Bây giờ bạn có thể thêm nó vào các lớp học của bạn:

var MyClass = function() {
  this.isDebug = true //local state
  this.debug = Debugger(isDebug, this)
  this.debug.warn('It works in classses')
}

16
Chỉnh sửa cho tôi nếu tôi sai, nhưng điều này không cho phép bạn thêm bất kỳ chức năng bổ sung nào, đúng không? Về cơ bản bạn chỉ răng cưa đối tượng console? Một ví dụ thô sơ - không có cách nào để console.log () sự kiện hai lần cho mỗi debug.log ()?
AB Carroll

3
@ABCarroll Bạn có thể console.loghai lần bằng cách ràng buộc một log()chức năng tùy chỉnh có chứa hai cuộc gọi đến console.log, tuy nhiên số dòng sẽ phản ánh dòng console.logthực sự cư trú, không phải nơi debug.logđược gọi. Tuy nhiên, bạn có thể làm những việc như thêm tiền tố / hậu tố động, v.v. Ngoài ra còn có nhiều cách để bù cho vấn đề số dòng, nhưng đó là một câu hỏi khác tôi nghĩ. Kiểm tra dự án này để biết ví dụ: github.com/arctelix/iDebugConsole/blob/master/README.md
arctelix

2
Phương pháp này không hoạt động trong Firefox từ phiên bản 47 đến 49. Và đã được sửa chỉ trong phiên bản 50.0a2. Vâng FF50 sẽ được phát hành trong 2 tuần, nhưng tôi dành vài giờ để nhận ra lý do tại sao nó không hoạt động. Vì vậy, tôi nghĩ rằng thông tin này có thể hữu ích cho một ai đó. liên kết
Vladimir Liubimov

Tôi tin rằng ý nghĩa của @ABCarroll là mọi thứ bên trong thể hiện không thể được sử dụng trong thời gian chạy. đối với một trường hợp khác, trạng thái toàn cầu chỉ có thể được xác định trong khởi tạo, vì vậy nếu sau này bạn đổi this.isDebugthành false, nó sẽ không thành vấn đề. Tôi chỉ không biết có cách nào khác không, có lẽ đó là do thiết kế. Theo nghĩa đó, isDebuglà một khá sai lầm varvà nên là một constthay thế.
cregox

2
Điều này không trả lời câu hỏi "Điều gì sẽ xảy ra nếu tôi muốn đăng nhập với số dòng nơi gỡ lỗi () được gọi?"
Technomage

24

Tôi thích câu trả lời của @ fredrik , vì vậy tôi đã đưa ra câu trả lời khác bằng cách chia ngăn xếp Webkit và kết hợp nó với trình bao bọc console.log an toàn của @ PaulIrish . "Chuẩn hóa"filename:line "đối tượng đặc biệt" để nó nổi bật và trông gần giống nhau trong FF và Chrome.

Kiểm tra trong fiddle: 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

Điều này cũng hoạt động trong nút và bạn có thể kiểm tra nó với:

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

một câu trả lời hơi tiên tiến hơn vào tài khoản cho thêm consolecác phương pháp như warn, error, vv - stackoverflow.com/a/14842659/1037948
drzaus

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

@sigod - có thể tùy thuộc vào trình duyệt hoặc tôi đã viết cái này 2 năm trước và (các) trình duyệt đã thay đổi. kịch bản của bạn là gì?
drzaus

1
một trong những đồng nghiệp của tôi đã sao chép mã của bạn vào dự án của chúng tôi. Nó đã phá vỡ trang web trong IE11 và Safari 5. Không chắc chắn về các phiên bản khác của trình duyệt này. Có lẽ bạn sẽ thêm một kiểm tra cho các mục sao chép trong tương lai?
sigod

1
@sigod còn bây giờ thì sao? đã thêm vào if(!stack) return '?'phương thức không thành công, thay vì nơi nó được gọi (vì vậy nếu có ai sử dụng chính phương thức đó thì họ cũng được "bảo vệ")
drzaus

18

Bạn có thể duy trì số dòng xuất mức nhật ký với một số cách sử dụng thông minh 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)

Tiến lên một bước nữa, bạn có thể sử dụng các consolekhác biệt về lỗi / cảnh báo / thông tin và vẫn có các mức tùy chỉnh. Thử nó!

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
Tôi đã cố gắng một thời bây giờ để tự động thêm tiền tố đầu ra từ console.debug(...)với function namearguments- bất kỳ suy nghĩ về cách để làm điều đó?
Daniel Sokolowski

3
Tôi đã xem xét vô số các trình bao bọc / miếng chêm / vv. và đây là lần đầu tiên tôi bắt gặp kết hợp việc bảo toàn số dòng với việc tùy chỉnh đầu ra. Đó là một cách sử dụng thông minh của thực tế là .bind cũng thực hiện một số thao tác cho bạn, bạn có thể liên kết một hoặc nhiều đối số ngoài ngữ cảnh . Bạn có thể tiến thêm một bước và truyền cho nó một hàm noop với phương thức .toString có thể chạy mã khi phương thức nhật ký được gọi! Xem jsfiddle này
Sam Hasler

2
Có thể không có trong tất cả các trình duyệt (chưa xem xét về nó), nhưng thay thế %sbằng %oChrome sẽ in các tham số theo cách bạn mong đợi (các đối tượng có thể mở rộng, số và chuỗi được tô màu, v.v.).
anson

thích giải pháp này. Tôi đã thực hiện một vài thay đổi hoạt động tốt hơn cho ứng dụng của mình, nhưng phần lớn trong số đó vẫn còn nguyên vẹn và chạy rất đẹp. Cảm ơn
Phường

9

Từ: Làm thế nào để có được số dòng chức năng của người gọi JavaScript? Làm cách nào để có URL nguồn của người gọi JavaScript? các Errorđối tượng có thuộc tính số dòng (trong FF). Vì vậy, một cái gì đó như thế này sẽ làm việc:

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

Trong trình duyệt Webkit, bạn có err.stackmột chuỗi đại diện cho ngăn xếp cuộc gọi hiện tại. Nó sẽ hiển thị số dòng hiện tại và nhiều thông tin hơn.

CẬP NHẬT

Để có được vải lanh chính xác, bạn cần phải gọi lỗi trên dòng đó. Cái gì đó như:

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();cho tôi bối cảnh nơi nó thực thi, nếu tôi đặt nó vào debug.js, thì tôi sẽ nhận được info: Here is a msg. file: http://localhost/js/debug.js line:7.
Rufus

1
Điểm của là Log = Errorgì? Bạn vẫn đang sửa đổi lớp Lỗi, phải không?
drzaus

Kết hợp câu trả lời của bạn với một vài người khác - xem bên dưới stackoverflow.com/a/14841411/1037948
drzaus

8

Một cách để giữ số dòng ở đây: https://gist.github.com/bgrins/5108712 . Nó ít nhiều sôi lên vì điều này:

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

Bạn có thể gói cái này lại isDebugvà đặt window.logthành function() { }nếu bạn không gỡ lỗi.


7

Bạn có thể chuyển số dòng cho phương thức gỡ lỗi của mình, như thế này:

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

Ở đây, (new Error).lineNumbersẽ cung cấp cho bạn số dòng hiện tại trong javascriptmã của bạn .


2
Một chút dài dòng, phải không?
Rufus

2
Tôi nghĩ rằng nó là đủ để trả lời câu hỏi của bạn. :)
Subodh

1
thuộc tính lineNumber là không chuẩn và chỉ hoạt động trên firefox ngay bây giờ, xem tại đây
Matthias

6

Chrome Devtools cho phép bạn đạt được điều này với Blackboxing . Bạn có thể tạo trình bao bọc console.log có thể có tác dụng phụ, gọi các hàm khác, v.v. và vẫn giữ số dòng được gọi là hàm bao bọc.

Chỉ cần đặt một trình bao bọc console.log nhỏ vào một tệp riêng, ví dụ:

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

Đặt tên nó là log-blackbox.js

Sau đó, đi tới cài đặt Devtools của Chrome và tìm phần "Hộp đen", thêm mẫu cho tên tệp bạn muốn vào hộp đen, trong trường hợp này là log-blackbox.js


Lưu ý: Hãy chắc chắn rằng bạn không có bất kỳ mã bạn sẽ muốn hiển thị trong stack trace trong cùng một tập tin, vì nó cũng sẽ bị xóa khỏi dấu vết.
jam Beautollowell

6

Tôi tìm thấy một giải pháp đơn giản để kết hợp câu trả lời được chấp nhận (ràng buộc với console.log / error / etc) với một số logic bên ngoài để lọc những gì thực sự được ghi lại.

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

Sử dụng:

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
  • Lưu ý rằng console.assertsử dụng đăng nhập có điều kiện.
  • Hãy chắc chắn rằng các công cụ dev của trình duyệt của bạn hiển thị tất cả các cấp độ tin nhắn!

Bởi vì nó không đưa ra bất kỳ số dòng nào cũng như các ví dụ hoạt động thể hiện mức độ nhật ký.
not2qubit

Số dòng sẽ giống như khi sử dụng bàn điều khiển trực tiếp. Tôi cập nhật câu trả lời với các ví dụ sử dụng. Nó không có nhiều phiếu bầu vì tôi đã trả lời hai năm sau đó :)
Jacob Phillips

4

Nếu bạn chỉ muốn kiểm soát xem gỡ lỗi có được sử dụng và có số dòng chính xác hay không, bạn có thể thực hiện việc này thay thế:

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

Khi bạn cần truy cập để gỡ lỗi, bạn có thể làm điều này:

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

Nếu isDebug == true, Số dòng và tên tệp được hiển thị trong bảng điều khiển sẽ chính xác, bởi vì debug.logvv thực sự là bí danh của console.logv.v.

Nếu isDebug == false, không có thông báo gỡ lỗi nào được hiển thị, bởi vìdebug.log vv đơn giản là không có gì (một hàm trống).

Như bạn đã biết, một hàm bao bọc sẽ làm rối loạn các số dòng và tên tệp, vì vậy, nên tránh sử dụng các hàm bao bọc.


Tuyệt vời, tôi cần phải cẩn thận về thứ tự isDebug = truedebug.js, nhưng câu trả lời này không hoạt động!
Rufus

3
window.debug = window.consolesẽ sạch sẽ hơn một chút.
fredrik

@fredrik sau đó tôi sẽ cần "thực hiện" tất cả các chức năng thành viên nếu isDebug == false. : {
Alvin Wong

@AlvinWong Mình chỉ menat cho nếu isDebug===true. Hoặc sự kiện này: jsfiddle.net/fredrik/x6Jw5
fredrik

4

Giải pháp theo dõi ngăn xếp hiển thị số dòng nhưng không cho phép nhấp để đi đến nguồn, đây là một vấn đề lớn. Giải pháp duy nhất để giữ hành vi này là liên kết với chức năng ban đầu.

Ràng buộc ngăn chặn bao gồm logic trung gian, bởi vì logic này sẽ gây rối với số dòng. Tuy nhiên, bằng cách xác định lại các chức năng bị ràng buộc và chơi với sự thay thế chuỗi bàn điều khiển , một số hành vi bổ sung vẫn có thể.

Ý chính này cho thấy một khung ghi nhật ký tối giản cung cấp các mô-đun, mức ghi nhật ký, định dạng và số dòng có thể nhấp thích hợp trong 34 dòng. Sử dụng nó như một cơ sở hoặc cảm hứng cho nhu cầu của riêng bạn.

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

EDIT: ý chính bao gồm bên dưới

/*
 * 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"
})();


Câu trả lời này chỉ có 3 lượt upvote nhưng cực kỳ phong phú và sạch sẽ hơn bất kỳ câu hỏi nào khác trong trang
Tom

tuy nhiên, có vẻ như tất cả các phần hữu ích nằm trên một ý chính bên ngoài.
Ryan The Leach

3

Ý tưởng với ràng buộc Function.prototype.bindlà tuyệt vời. Bạn cũng có thể sử dụng npm thư viện dòng-logger . Nó hiển thị các tệp nguồn gốc:

Tạo logger bất cứ ai một lần trong dự án của bạn:

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

Nhật ký in:

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

nhập mô tả hình ảnh ở đây


2

Đây là một cách để giữ các consolebáo cáo ghi nhật ký hiện tại của bạn trong khi thêm tên tệp và số dòng hoặc thông tin theo dõi ngăn xếp khác vào đầu ra:

(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;
  }, {}));
}());

Sau đó sử dụng nó như thế này:

<!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>

Điều này hoạt động trong Firefox, Opera, Safari, Chrome và IE 10 (chưa được thử nghiệm trên IE11 hoặc Edge).


Công việc tốt, nhưng vẫn không 100% những gì tôi cần. Tôi muốn có thông tin tên tệp và số dòng ở bên phải của giao diện điều khiển, nơi nó có thể được bấm để mở nguồn. Giải pháp này hiển thị thông tin như một phần của thông báo (như thế này my test log message (myscript.js:42) VM167 mypage.html:15:), không tốt để đọc cộng với nó không được liên kết. Vẫn làm việc tốt như vậy một upvote.
Frederic Leitenberger

Vâng, trong khi đó là lý tưởng, không có cách nào, AFAIK, để giả mạo liên kết tên tệp xuất hiện trong bảng điều khiển ...
Brett Zamir

@BrettZamir đã đăng câu hỏi về mã này tại đây: stackoverflow.com/questions/52618368/
Kẻ

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

Điều này sẽ cho tôi info: "Here is a msg." main.js(line:2).

Nhưng sự bổ sung evallà cần thiết, đáng tiếc.


2
Ác ma là ác! Cứ thế mà ác.
fredrik

1

Mã từ http://www.briangrinstead.com/blog/console-log-helper-feft :

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

Điều này dường như không hiển thị số dòng ban đầu logđược gọi từ
ragamufin

Tôi gần như chắc chắn rằng nó hoạt động khi tôi thử nghiệm, nhưng tôi đã thay thế mã bằng phiên bản "đầy đủ" từ cùng một trang. Đã làm việc ít nhất trong Chrome 45.
Timo Kähkönen

Hiểu. Với những thay đổi mà bạn có bây giờ, về cơ bản nó giống như một vài câu trả lời và hoạt động khác. Tôi chỉ tò mò về mã trước đây của bạn bởi vì cuối cùng bạn đã áp dụng một số khả năng thú vị để tôi sử dụng mã này nhiều hơn nhưng vì nó không hiển thị số dòng nên tôi đã quay lại số một. Cảm ơn mặc dù!
ragamufin

1

Gần đây tôi đã xem xét vấn đề này. Cần một cái gì đó rất thẳng về phía trước để kiểm soát đăng nhập, nhưng cũng để giữ lại số dòng. Giải pháp của tôi không có vẻ thanh lịch trong mã, nhưng cung cấp những gì cần thiết cho tôi. Nếu một người đủ cẩn thận với việc đóng cửa và giữ lại.

Tôi đã thêm một trình bao bọc nhỏ vào đầu ứng dụng:

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

Để sau này tôi có thể làm một cách đơn giản:

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

Tôi đã thử nghiệm firefox và crome và cả hai trình duyệt dường như hiển thị nhật ký giao diện điều khiển như dự định. Nếu bạn điền như vậy, bạn luôn có thể mở rộng phương thức 'd' và truyền các tham số khác cho nó, để nó có thể thực hiện một số ghi nhật ký bổ sung.

Chưa tìm thấy bất kỳ nhược điểm nghiêm trọng nào cho cách tiếp cận của tôi, ngoại trừ dòng mã xấu xí để đăng nhập.


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

đây là giải pháp của tôi về câu hỏi này Khi bạn gọi phương thức: log, nó sẽ in số dòng nơi bạn in nhật ký của mình


1

Một biến thể nhỏ là để debug () trả về một hàm, sau đó được thực thi ở nơi bạn cần - debug (message) (); và do đó hiển thị đúng số dòng và tập lệnh gọi trong cửa sổ giao diện điều khiển, đồng thời cho phép các biến thể như chuyển hướng như một cảnh báo hoặc lưu vào tệp.

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

}

Vì nó trả về một hàm, nên hàm đó cần được thực thi tại dòng gỡ lỗi với ();. Thứ hai, tin nhắn được gửi đến chức năng gỡ lỗi, thay vì vào hàm trả về cho phép xử lý trước hoặc kiểm tra mà bạn có thể cần, chẳng hạn như kiểm tra trạng thái cấp nhật ký, làm cho tin nhắn dễ đọc hơn, bỏ qua các loại khác nhau hoặc chỉ báo cáo các mục đáp ứng tiêu chí cấp độ log;

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

1

Bạn có thể đơn giản hóa logic ở đây. Điều này giả định cờ gỡ lỗi toàn cầu của bạn KHÔNG động và được đặt khi tải ứng dụng hoặc được chuyển qua dưới dạng một số cấu hình. Điều này được dự định sẽ được sử dụng để gắn cờ môi trường (ví dụ: chỉ in khi ở chế độ dev và không sản xuất)

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

Mô-đun:

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

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

export default Logger;

Góc 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;
    }
  ]);

Tất cả những gì bạn cần làm bây giờ là thay thế tất cả các refs console bằng Logger


1

Việc triển khai này dựa trên câu trả lời đã chọn và giúp giảm lượng tiếng ồn trong bảng điều khiển lỗi: 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

Tôi tìm thấy một số câu trả lời cho vấn đề này hơi phức tạp đối với nhu cầu của tôi. Đây là một giải pháp đơn giản, được hiển thị trong Coffeescript. Nó được chuyển thể từ phiên bản của Brian Grinstead tại đây

Nó giả định đối tượng giao diện điều khiển toàn cầu.

# 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

Cách tôi giải quyết là tạo một đối tượng, sau đó tạo một thuộc tính mới trên đối tượng bằng Object.defineProperty () và trả về thuộc tính giao diện điều khiển, sau đó được sử dụng như một chức năng bình thường, nhưng bây giờ với lỗi mở rộng.

var c = {};
var debugMode = true;

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

Sau đó, để xác định một tài sản bạn chỉ cần làm ...

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

Và bây giờ bạn có thể sử dụng chức năng của mình giống như

c.error("Error!");

0

Dựa trên các câu trả lời khác (chủ yếu là @arctelix one) Tôi đã tạo cái này cho Node ES6, nhưng một thử nghiệm nhanh cũng cho thấy kết quả tốt trong trình duyệt. Tôi chỉ chuyển các chức năng khác như một tài liệu tham khảo.

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

0

Đây là chức năng logger của tôi (dựa trên một số câu trả lời). Hy vọng ai đó có thể sử dụng nó:

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

Ví dụ:

log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.