AngularJS $log - display line numbers

When using angularjs $log in chrome, it displays the line as: angular.js:9037. I'm looking to have the line number where I actually call this method shown instead. (Displaying my js name and the correct line). Is there a way to achieve this since Angular doesn't offer this feature?

Answer №1

If you're using Chrome, you have access to a handy feature known as Blackboxing. This tool allows you to exclude or bypass certain sources (such as libraries) from your debugging sessions and development process.

By blackboxing Angular, you can effectively bypass the internal workings of the $log service, leading to the console displaying the correct line numbers!

Find out more about Blackboxing here.

Answer №2

To access this functionality, you can implement a decorator for the $log service:

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

        // Save the original log functions
        angular.forEach($delegate, function (originalFunction, functionName) {
            originalFunctions[functionName] = originalFunction;
        });

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

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

        return $delegate;
    });

    function logDecorator(fn) {
        return function () {

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

            // Add a separator between the existing log message(s) and the additional content.
            args.push(' - ');

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

            // Discard the first item as it is the `$log.fn()` function, 
            // while we need the code that called `$log.fn()`.
            stack.shift();

            // Retain only the top line.
            stack = stack.slice(1, 2);

            // Add it to the args stack.
            args.push(stack);

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

I have created this as a modular component, but I think it could also be integrated within the .config() of the application.

While building this (alongside some extra logic), I combined various resources from the internet; although I usually keep track of my references, I forgot to do so when creating this, hence I am unable to provide specific sources. If someone points them out, I will acknowledge them here.

NOTE 1: This code is a simplified version of what I actually use, so ensure you verify the workings of the logDecorator() and its stack manipulation carefully.

NOTE B: According to MDN, Error.prototype.stack is not a standard feature (requires IE10 and may lack support on numerous mobile browsers); thus, considering augmenting it with a library like stacktracejs might be prudent in order to obtain the stack itself.

Answer №3

I have gathered various solutions from this page along with others to create a simple demo in JSFiddle. The demo showcases the use of the $log service and how it can be enhanced with decorators to include line numbers (indicating where the $log call was made). Additionally, I have developed a more detailed solution in Plunker, demonstrating the $log service with added features like displaying line numbers, caller file name, and instance name. I hope this will be beneficial to others.

JSFiddle URL - https://jsfiddle.net/abhatia/6qnz0frh/

This JSFiddle demo has been tested on the following browsers:

  • IE 11 - (JSFiddle Javascript's first line number is 72).
  • Firefox 46.0.1 - (JSFiddle Javascript's first line number is 72).
  • Chrome 50.0.2661.94 m - (JSFiddle Javscript's first line number is 71).

The results are satisfactory. However, please note that the line number may vary by 1 in Chrome compared to FF or IE due to differences in JSFiddle's JavaScript code structure as listed above.

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

This Plunker demo illustrates the concept effectively with detailed explanations. It also displays console outputs using Angular's official example of default $log service for comparison. The Plunk has also been cross-tested on the aforementioned browsers.

The screenshot below shows the console output from the Plunker example highlighting 3 key areas:

  • A red box indicating console output using the default $log service, with $log functions invoked from the controller.
  • A blue box showcasing console output using the extended $log service, revealing script names, line numbers, and controller names used during $log instantiation.
  • An orange box contrasting console outputs of default and extended $log services.

https://i.sstatic.net/Ty7gS.jpg

This distinction becomes clearer when reviewing the Plunk's code.

Below is the getLineNumber function utilized in JSFiddle (a slightly improved version is employed in the Plunker example to fetch caller file names):

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

Answer №4

The line number is automatically generated by the runtime and cannot be manually set in most cases.

However, all hope is not lost. In situations where the line number is crucially important, you can utilize a different approach. Ensure that you include the $window and then:

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

This method may result in some drawbacks such as loss of formatting and potential variation across different browsers, but it does provide accurate line numbers without the need for specific code tailored to each individual runtime.

Answer №5

Similar to the response from floatingLomas

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

https://i.sstatic.net/SLWYE.png

Typically, the second @ line is crucial, in this scenario it is 90618

Answer №6

After experimenting with floatingLomas' solution and making some adjustments, I found that it doesn't work quite right on Firefox due to a slightly different stack. Additionally, PhantomJS, like Internet Explorer, does not support Error.stack and crashes when encountered. Interestingly, the log location is clickable in Chrome but not in Firefox.

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

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

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

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

        return $delegate;
    });

function logDecorator(fn) {
    return function () {

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

        // Adding a separator between existing log messages and additional information.
        args.push(' - ');

        // Using the stack of (instance of Error) to retrieve the current line.
        var newErr = new Error();

        // Skipping phantomjs as it does not support Error.stack
        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];
            // Adding it to the args stack.
            args.push(lineLocation);

            // Calling the original function with the new arguments.
            fn.apply(fn, args);
        }
    };
}

Answer №7

My browser of choice is Chrome version 65.0.3325.181

Here's what I do:

  1. Go to the menu, then settings -> blackboxing
  2. Make sure to check the option for blackbox content scripts
  3. Add the blockbox pattern for angular.js

https://i.sstatic.net/toqnk.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Storing dates as collection names is not supported in Firestore

I'm currently facing an issue trying to store stock prices in Firestore. I want the structure to resemble something similar to SQL, like this: const d1 = new Date(); const result = d1.getTime(); console.log('Epochtime',result); database.coll ...

What causes tests to fail with an error message SyntaxError: Unexpected token {?

Hey there! I'm encountering an issue with webpack 5 and babel while trying to run tests that were previously written. Despite following the jest documentation for configuration, I haven't been able to find a solution after exploring various forum ...

Issues with Angular JS page loading when utilizing session and local storage in Google Chrome

I'm currently learning about AngularJS and I stumbled upon this helpful tutorial http://embed.plnkr.co/dd8Nk9PDFotCQu4yrnDg/ for building a simple SPA page. Everything was working smoothly in Firefox and IE, except when it came to using Local and Sess ...

UI is experiencing lag issues post Alert invocation in React Native

// When a text field is pressed, an alert function is called. This function opens an alert and then calls another function on confirmation. However, the application gets stuck when "showAlert1()" is called, and this function is being invoked multiple times ...

html issue with angularjs progress bar not displaying progress updates

I'm currently working on implementing a progress bar in Angular and updating its progress dynamically. Here is a snippet of the code I am using: <progressbar value="{{data.progress}}"></progressbar> Below is the controller code that I ha ...

Struggling to implement dynamic templates in an Angular directive

In the process of developing a small angular application that consists of 3 modes - QA, Production, and Sandbox. In the QA mode, there are multiple buttons for users to select values which then populate "myModel". The other two modes, Production and Sandbo ...

Identical code exhibiting varying behavior between localhost:3000 and the production server at localhost:5000 on the web

I'm currently in the process of learning React Js, but I've been encountering a persistent error that has me stumped. A specific component functions perfectly when running on my local server (localhost:3000), but as soon as I try to deploy it to ...

Session management functions properly in Postman, however, encountering issues when attempting to use it on a web

Working on a NodeJS project using express-session to handle sessions. When sending a post request to http://localhost:5500/login, a session is created with an additional property userid. Upon making a get request to http://localhost:5500/ using Postman, th ...

I am looking to incorporate a child row for each tr element within AngularJS

Here is the code snippet I have: <td class="name"> <i class="mdi mdi-plus s16" ng-click="childRowToggle($event)"></i> <div ng-click="details(assets.code)">{{assets.name}}</div> <span class="seco ...

The Angular project failed to run properly following the ng build command

Just started working with Angularjs 2 and encountered an issue after running ng build. The compiled files were placed in the dist folder, but when I checked the index.html file within that folder, all the scripts had missing references even though they w ...

Looking for a .NET MVC AJAX search solution. How can I enhance the code below?

I am looking to implement a search functionality using AJAX. I have tried using the get method in my controller by passing the search string, but it is not working as expected. Below is a snippet of my controller code, where I retrieve the search value fr ...

React JS for loop not displaying any output

I am trying to create a component that loops from 0 to the value entered as a prop. if (props.number !== "" && props.toPow !== "") { for (let i = 0; i < props.toPow; i++) { return ( <div> & ...

Guide to resolving a blank webpage issue post running 'npm run build'

I am currently in the process of working on a project that involves Vue and Firebase. Unfortunately, I have encountered an issue where my development server is no longer rendering new routes from my Vue router after building and deploying to production. F ...

Accessing the first child node in JsTree

Is it possible to display only the first child of a list using the JStree plugin to create a tree? For example, if I have a list with 5 children, some of which have nested children, I am looking for a way to display only the first child of each <li> ...

What are the consequences of altering the DOM in React?

As a beginner react developer, I am currently working on creating a MERN App. I have a question for the community regarding my project where I needed to make several changes to the DOM as illustrated below: document.getElementsByTagName('body')[ ...

Arrange the Json array by key value in a different order

I have a contact list that is returning in a lengthy form, organized based on order of entry. I am looking to alphabetically sort the list by displayName which is nested within the main array. Can anyone assist with this challenge using JavaScript? Thank ...

AngularJS ngTable fails to refresh with new data

I have implemented Angular routing and ngTable in my application. One of the pages includes a ngTable and a search form. The data is fetched from a MongoDB database using the GET method every time a search is performed. However, I am facing an issue where ...

Having difficulty applying capitalization to the initial word in an input using JavaScript/jQuery

I've read through several other discussions on this forum regarding the same issue. My problem lies in capitalizing the first letter of an input. Here is the link to my code on JSFiddle Despite my efforts, I can't seem to get the substr() funct ...

In both Chrome and Edge, the default value for the <select> tag is successfully set, however, this functionality is not working in

I have defined two values in the created method, 2018 and My Name, and assigned them to separate data properties. These data properties are then passed as v-bind to a component. The issue I am facing is that in Chrome and Edge, both values are set as defa ...

collecting user input in React.js

After doing some research on React.js from this website, I stumbled upon a piece of code that left me puzzled. As far as I can tell, the checkbox for isGoing will be pre-filled as true (checked) and the numberOfGuests will be set to 2. However, I found m ...