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

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

【问题讨论】:

标签: javascript angularjs google-chrome


【解决方案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

          就我而言,

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

          【讨论】:

            猜你喜欢
            • 2013-06-25
            • 2015-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-08
            • 2018-04-21
            相关资源
            最近更新 更多