如何编写控制台日志包装器:
由于Java Script中的日志记录不一致,因此必须有一些解决方案。自己实现它有点乏味,但似乎没有好的库。
我目前发现这个记录器提供了所有功能,但它确实搞乱了行号。 http://benalman.com/projects/javascript-debug-console-log/
答案 0 :(得分:15)
我有自己的log4javascript,它有自己的日志记录控制台,但也提供了console.log
的包装器。它符合您的所有标准,除了保持行号完好无损,如果您在另一个函数中包含对console.log()
等的调用,则无法实现。
var log = log4javascript.getLogger("main");
var appender = new log4javascript.BrowserConsoleAppender();
log.addAppender(appender);
log.debug("Hello world");
答案 1 :(得分: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。
答案 2 :(得分:7)
我们的日志包装器也遇到了这个问题,结果发现使用部分功能应用程序有一个非常简单的解决方法:
if(DEBUG_ENABLED && (typeof console != 'undefined')) {
this.debug = console.log.bind(console);
}
else {
this.debug = function(message) {};
}
通过此操作,您的浏览器将检测您要记录的源的正确行号和文件。
答案 3 :(得分:6)
从相关问题(A proper wrapper for console.log with correct line number?)转发,但使用更新的解决方案来解决多种方法。
我喜欢@fredrik's answer,因此我使用another answer which splits the Webkit stacktrace汇总了它,并将其与@PaulIrish's safe console.log wrapper合并。将filename:line
“标准化”为“特殊对象”,因此它在FF和Chrome中显得与众不同。
小提琴测试:http://jsfiddle.net/drzaus/pWe6W/9/
_log = (function (methods, undefined) {
var Log = Error; // does this do anything? proper inheritance...?
Log.prototype.write = function (args, method) {
/// <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>
/// <param name="method" type="string">the console method to use: debug, log, warn, info, error</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[method]) {
if (console[method].apply) { console[method].apply(console, args); } else { console[method](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>
// correct line number according to how Log().write implemented
var line = stack.split('\n')[3];
// fix for various display text
line = (line.indexOf(' (') >= 0
? line.split(' (')[1].substring(0, line.length - 1)
: line.split('at ')[1]
);
return line;
};
// method builder
var logMethod = function(method) {
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), method); // turn into proper array & declare method to use
};//-- fn logMethod
};
var result = logMethod('log'); // base for backwards compatibility, simplicity
// add some extra juice
for(var i in methods) result[methods[i]] = logMethod(methods[i]);
return result; // expose
})(['error', 'debug', 'info', 'warn']);//--- _log
答案 4 :(得分:2)
为了简单起见,我使用了下面的控制台方法包装器:
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
};
此外,为了更好地浏览IE和旧版浏览器,请阅读:Detailed console logging
答案 5 :(得分:2)
我回答了这个问题here,但简而言之,请参阅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!')
答案 6 :(得分:1)
谷歌浏览器很快就会有一个这个线程感兴趣的功能。
您现在可以通过以下方式启用它:
重启并享受:)
参考文献:
答案 7 :(得分:0)
我在Web上找到了一个解决方案(需要jquery),但它在大多数浏览器中都不起作用。 我更改了它,它适用于Firefox(Mac,Linux。Android),Chrome(Mac,Linux。Android)和Safari以及其他Android webkit浏览器。
只需将以下代码写入名为eg的文件即可debug.js并在&lt; head&gt;中包含'jquery.js'之后包含它您的网页的一部分,它将在页面加载后 (document.ready)。我仍然必须找到允许在加载所有内容之前调试(例如只有&lt; head&gt; ...&lt; / head&gt;)。 网页必须在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, '&');
res = res.replace(/\x3C/g, '<');
res = res.replace(/>/g, '>');
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)