angularjs $log - 显示行号

Posted

技术标签:

【中文标题】angularjs $log - 显示行号【英文标题】:angularjs $log - show line number 【发布时间】:2014-01-11 09:16:54 【问题描述】:

我在 chrome 中使用 angularjs $log,但它显示的行如下:angular.js:9037。我想显示我调用此方法的行号。 (显示我的 js 名称和正确的行)。有谁知道该怎么做? Angular 没有这个功能。

【问题讨论】:

我不认为 $log 可以输出行号 有点不相关,但这个 chrome 插件有一些很棒的调试器工具:chrome.google.com/webstore/detail/angularjs-batarang/… 在 V8 javascript (Chrome & Node.js) 中访问行号:***.com/questions/11386492/… 见:***.com/questions/16300393/… 【参考方案1】:

行号来自运行时。一般情况下不能设置。

但并非全部丢失。在行号非常重要的地方,您可以使用不同的呼叫。 记得注入$window 然后:

$window.console.log("test1");

您通过这种方式丢失了一些东西,例如格式化、跨浏览器填充代码等,但您确实可以免费获得正确的行号,而无需任何运行时特定的代码。

【讨论】:

【参考方案2】:

您可以通过将装饰器应用于$log 服务来访问它:

module.config(function logConfig($provide, $logProvider) 
    $provide.decorator('$log', function ($delegate) 
        var originalFns = ;

        // Store the original log functions
        angular.forEach($delegate, function (originalFunction, functionName) 
            originalFns[functionName] = originalFunction;
        );

        var functionsToDecorate = ['debug', 'warn'];

        // Apply the decorations
        angular.forEach(functionsToDecorate, function (functionName) 
            $delegate[functionName] = logDecorator(originalFns[functionName]);
        );

        return $delegate;
    );

    function logDecorator(fn) 
        return function () 

            var args = [].slice.call(arguments);

            // Insert a separator between the existing log message(s) and what we're adding.
            args.push(' - ');

            // Use (instance of Error)'s stack to get the current line.
            var stack = (new Error()).stack.split('\n').slice(1);

            // Throw away the first item because it is the `$log.fn()` function, 
            // but we want the code that called `$log.fn()`.
            stack.shift();

            // We only want the top line, thanks.
            stack = stack.slice(1, 2);

            // Put it on the args stack.
            args.push(stack);

            // Call the original function with the new args.
            fn.apply(fn, args);
        ;
    
);

我将此作为一个可包含的模块,但我相信它也可以在应用程序的 .config() 中完成。

我通过将许多不同的在线资源粘合在一起来构建这个(以及一些额外的逻辑);我通常非常擅长保留对它们的引用,但我想我在构建它时没有这样做,所以很遗憾我无法引用我的灵感。如果有人回复,我会放在这里。

注意 1: 这是我实际使用的稍微精简的版本,因此您必须仔细检查logDecorator()s 堆栈 出风头的魔法,虽然它应该像介绍的那样工作。

注意 B: MDN says 认为 Error.prototype.stack 是非标准的(需要 IE10 并且可能在许多移动浏览器上不受支持),因此您可能需要考虑使用类似 stacktracejs 的东西来增强它以获取堆栈本身。

【讨论】:

【参考方案3】:

在 Chrome 中有一个称为黑盒的功能。 您可以使用它从调试会话或开发工作流程中排除/绕过(库)源。

因此,如果您使用黑盒角度,$log 服务的内部将被绕过,控制台会打印正确的行号!

https://developer.chrome.com/devtools/docs/blackboxing

【讨论】:

天哪,太好了。 Firefox 显然也有黑盒,但它似乎不会影响控制台中的行号。也许是时候回去使用 Chrome了... 哇,非常好!我认为 chrome 文档有点过时了 - 运行 Chrome 版本 50.0.2661.94,您不能再右键单击源文件并将其黑盒化。我必须通过开发工具设置添加模式。 超级好的解决方案,它就像一个魅力,非常感谢! @Rob 我正在使用 Angular +2,我想创建自己的日志服务来打印调用者行号。可以应用这个解决方案吗?我可以黑盒我的服务吗?如何?【参考方案4】:

接近floatingLomas's答案

module.config(function($logProvider, $provide) 
    $provide.decorator('$log', function ($delegate) 
        $delegate.info = function () 
            var args = [].slice.call(arguments);
            if (window.console && window.console.table)
                console.trace(args[0], args[1]);
            else
                $delegate.log(null, args)
        ;
        return $delegate;
    );
)

通常第二个 @ 行是您需要的,在本例中为 90618

【讨论】:

【参考方案5】:

我使用了 floatingLomas 解决方案并进行了一些调整,因为它在 FF 上不太适用,堆栈略有不同。而且像IE这样的phantomjs不支持Error.stack就炸了。 日志位置在 chrome 中是可点击的,但在 ff 中是不可点击的。

app.config(function logConfig($provide, $logProvider) 
    $provide.decorator('$log', function ($delegate) 
        var originalFns = ;

        // Store the original log functions
        angular.forEach($delegate, function (originalFunction, functionName) 
            originalFns[functionName] = originalFunction;
        );

        var functionsToDecorate = ['debug', 'warn'];

        // Apply the decorations
        angular.forEach(functionsToDecorate, function (functionName) 
            $delegate[functionName] = logDecorator(originalFns[functionName]);
        );

        return $delegate;
    );

function logDecorator(fn) 
    return function () 

        var args = [].slice.call(arguments);

        // Insert a separator between the existing log message(s) and what we're adding.
        args.push(' - ');

        // Use (instance of Error)'s stack to get the current line.
        var newErr = new Error();

        // phantomjs does not support Error.stack and falls over so we will skip it
        if (typeof newErr.stack !== 'undefined') 
            var stack = newErr.stack.split('\n').slice(1);

            if (navigator.userAgent.indexOf("Chrome") > -1) 
                stack.shift();
            
            stack = stack.slice(0, 1);

            var stackInString = stack + '';
            var splitStack;
            if (navigator.userAgent.indexOf("Chrome") > -1) 
                splitStack = stackInString.split(" ");
             else 
                splitStack = stackInString.split("@");
            
            var lineLocation = splitStack[splitStack.length - 1];
            // Put it on the args stack.
            args.push(lineLocation);

            // Call the original function with the new args.
            fn.apply(fn, args);
        
    ;

【讨论】:

【参考方案6】:

我结合了这个页面上的几个解决方案,以及其他解决方案,在 JSFiddle 中构建了一个简单的演示 - 演示 $log 服务的使用,使用装饰器对其进行增强以添加行号($log 调用所在的行号制成)。我还在 Plunker 中做了一个更全面的解决方案,演示了 $log 服务的使用,使用装饰器对其进行了增强,以添加行号、调用者文件名和实例名。希望这对其他人有用。

JSFiddle 网址 - https://jsfiddle.net/abhatia/6qnz0frh/

这个小提琴已经用以下浏览器测试过:

IE 11 - (JSFiddle Javascript 的第一行编号是 72)。 Firefox 46.0.1 -(JSFiddle Javascript 的第一行编号是 72)。 Chrome 50.0.2661.94 m -(JSFiddle Javscript 的第一行编号为 71)。

结果很好。但是,请注意 Chrome 中的行号与 FF 或 IE 相比会减 1,即因为 JSFiddle 的 javascript 代码的第一行号在 FF/IE 和 Chrome 之间有所不同,如上所示。

Plunker URL - https://embed.plnkr.co/YcfJ7V/

这个plunk很好地展示了这个概念,有详细的解释,并且还提供了带有Angular官方默认$log服务示例的控制台输出,因此可以将两者进行对比。 Plunk 也已经在上面列出的浏览器上进行了测试。

下面的屏幕截图是上面 Plunk 示例的控制台输出。有 3 个突出显示的区域:

红框显示使用默认 $log 服务的控制台输出。从控制器调用的 $log 函数。 蓝色框显示使用扩展 $log 服务的控制台输出。从控制器调用的 $log 函数。您可以看到脚本名称和行号的显示方式,以及控制器名称(在实例化 $log 时使用)。 橙色框对比默认控制台输出和扩展 $log 服务。

当您查看 Plunk 代码时,这一点会变得非常清楚。

这里是 JSFiddle 中使用的 getLineNumber 函数(略微增强的版本使用 Plunker 示例返回调用者文件名):

function getLineNumber(newErr, sliceIndex1, sliceIndex2)

  var lineNumber = -1;
  var lineLocation;

  var stack = newErr.stack.split('\n').slice(2);
  if (navigator.userAgent.indexOf("Chrome") > -1) 
    stack.shift();
  
  stack = stack.slice(sliceIndex1, sliceIndex2);
  var stackInString = stack + '';
  var splitStack;
  if (navigator.userAgent.indexOf("Chrome") > -1) 
    splitStack = stackInString.split(" ");
  
  else 
    splitStack = stackInString.split("@");
  
  lineLocation = splitStack[splitStack.length - 1]; 
  //console.log(lineLocation);
  lineNumber = lineLocation.split(":")[2];
  return lineNumber; 

【讨论】:

为我工作。有点讽刺的是,您正在使用 console.log 进行调试! :) 此外,我不确定在 Chrome 的 getLineNumber 中是否需要对 lineLocation 进行拆分。似乎 lineLocation 字符串是唯一需要的。【参考方案7】:

我使用 chrome 版本 65.0.3325.181

就我而言,

    进入菜单,设置 -> 黑盒 检查黑盒内容脚本 添加方块模式 angular.js

【讨论】:

以上是关于angularjs $log - 显示行号的主要内容,如果未能解决你的问题,请参考以下文章

log4j配置后行号乱码显示为?问号

log4j日志文件名与行号显示乱码? 问号? 参数问号? 日志问号?补

C++ 自定义项目日志库,支持log分级标签耗时统计显示文件名方法名行号信息等,Windows&Linux通用

Log4j2:异步日志中打印方法名和行号信息

JS获取table的行号,并根据行数显示隐藏

命令盘符不能上翻查看log