src/ng/log.js
'use strict';
/**
* @ngdoc service
* @name $log
* @requires $window
*
* @description
* Simple service for logging. Default implementation safely writes the message
* into the browser's console (if present).
*
* The main purpose of this service is to simplify debugging and troubleshooting.
*
* To reveal the location of the calls to `$log` in the JavaScript console,
* you can "blackbox" the AngularJS source in your browser:
*
* [Mozilla description of blackboxing](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Black_box_a_source).
* [Chrome description of blackboxing](https://developer.chrome.com/devtools/docs/blackboxing).
*
* Note: Not all browsers support blackboxing.
*
* The default is to log `debug` messages. You can use
* {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
*
* @example
<example module="logExample" name="log-service">
<file name="script.js">
angular.module('logExample', [])
.controller('LogController', ['$scope', '$log', function($scope, $log) {
$scope.$log = $log;
$scope.message = 'Hello World!';
}]);
</file>
<file name="index.html">
<div ng-controller="LogController">
<p>Reload this page with open console, enter text and hit the log button...</p>
<label>Message:
<input type="text" ng-model="message" /></label>
<button ng-click="$log.log(message)">log</button>
<button ng-click="$log.warn(message)">warn</button>
<button ng-click="$log.info(message)">info</button>
<button ng-click="$log.error(message)">error</button>
<button ng-click="$log.debug(message)">debug</button>
</div>
</file>
</example>
*/
/**
* @ngdoc provider
* @name $logProvider
* @this
*
* @description
* Use the `$logProvider` to configure how the application logs messages
*/
function $LogProvider() {
var debug = true,
self = this;
/**
* @ngdoc method
* @name $logProvider#debugEnabled
* @description
* @param {boolean=} flag enable or disable debug level messages
* @returns {*} current value if used as getter or itself (chaining) if used as setter
*/
this.debugEnabled = function(flag) {
if (isDefined(flag)) {
debug = flag;
return this;
} else {
return debug;
}
};
this.$get = ['$window', function($window) {
// Support: IE 9-11, Edge 12-14+
// IE/Edge display errors in such a way that it requires the user to click in 4 places
// to see the stack trace. There is no way to feature-detect it so there's a chance
// of the user agent sniffing to go wrong but since it's only about logging, this shouldn't
// break apps. Other browsers display errors in a sensible way and some of them map stack
// traces along source maps if available so it makes sense to let browsers display it
// as they want.
var formatStackTrace = msie || /\bEdge\//.test($window.navigator && $window.navigator.userAgent);
return {
/**
* @ngdoc method
* @name $log#log
*
* @description
* Write a log message
*/
log: consoleLog('log'),
/**
* @ngdoc method
* @name $log#info
*
* @description
* Write an information message
*/
info: consoleLog('info'),
/**
* @ngdoc method
* @name $log#warn
*
* @description
* Write a warning message
*/
warn: consoleLog('warn'),
/**
* @ngdoc method
* @name $log#error
*
* @description
* Write an error message
*/
error: consoleLog('error'),
/**
* @ngdoc method
* @name $log#debug
*
* @description
* Write a debug message
*/
debug: (function() {
var fn = consoleLog('debug');
return function() {
if (debug) {
fn.apply(self, arguments);
}
};
})()
};
function formatError(arg) {
if (isError(arg)) {
if (arg.stack && formatStackTrace) {
arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
? 'Error: ' + arg.message + '\n' + arg.stack
: arg.stack;
} else if (arg.sourceURL) {
arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
}
}
return arg;
}
function consoleLog(type) {
var console = $window.console || {},
logFn = console[type] || console.log || noop;
return function() {
var args = [];
forEach(arguments, function(arg) {
args.push(formatError(arg));
});
// Support: IE 9 only
// console methods don't inherit from Function.prototype in IE 9 so we can't
// call `logFn.apply(console, args)` directly.
return Function.prototype.apply.call(logFn, console, args);
};
}
}];
}