diff --git a/CHANGELOG.md b/CHANGELOG.md index dbf7ee3..7246816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ +## 1.3.0 (5th July, 2016) + - Add `Logger.createDefaultHandler()`, fixes #26 + - Correct typo in README, fixes #28 + - Adds Typescript definitions (`logger.d.ts`), (#27, @pjsb) + ## 1.2.0 (10 September, 2015) - - Support for custom message formatter in Logger.useDefaults() + - Support for custom message formatter in Logger.useDefaults() - Logger.useDefaults() now expects a hash instead of a logLevel. ## 1.1.1 (14th July, 2015) diff --git a/README.md b/README.md index 070a3b6..3d48ec3 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,45 @@ Logger.setHandler(function (messages, context) { ``` ### Default Log Handler Function -When you invoke `Logger.useDefaults()`, you can specify a default LogLevel and a custom -logFormatter function which can alter the messages printed to the console: +js-Logger provides a default handler function which writes to your browser's `console` object using the appropriate logging functions based on the message's log level (ie: `Logger.info()` will result in a call to `console.info()`). The default handler automatically shims for sub-optiomal environments right down to IE7's complete lack of `console` object (it only appears when you open the DevTools - seriosuly, this is one of the anti-user troll things I've seen!) + +Use `Logger.createDefaultHandler()` to return a new log handler function which can then be supplied to `Logger.setHandler()`. + +You can customise the formatting of each log message by supplying a formatter function to `createDefaultLogHandler`: + +```js +Logger.createDefaultHandler({ + formatter: function(messages, context) { + // prefix each log message with a timestamp. + messages.unshift(new Date().toUTCString()) + } +} +}) +``` + +You can use functional composition to extend the default handler with your own custom handler logic: + +```js +var consoleHandler = Logger.createDefaultHandler(); +var myHandler = function (messages, context) { + jQuery.post('/logs', { message: messages[0], level: context.level }); +}; + +Logger.setHandler(function (messages, context) { + consoleHandler(messages, context); + myHandler(messages, context); +}); + +``` + +### useDefaults +`Logger.useDefaults()` is a convenience function which allows you to configure both the default logLevel and handler in one go: ```js Logger.useDefaults({ - logLevel: Logger.WARN, + defaultLevel: Logger.WARN, formatter: function (messages, context) { - messages.unshift('[MyApp]'); - if (context.name) messages.unshift('[' + context.name + ']'); + messages.unshift(new Date().toUTCString()) } }) ``` diff --git a/bower.json b/bower.json index dbcc4f4..a877ba4 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "js-logger", - "version": "1.2.0", + "version": "1.3.0", "main": "src/logger.js", "ignore": [ "**/.*", diff --git a/package.json b/package.json index 032d2ca..3396b1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-logger", - "version": "1.2.0", + "version": "1.3.0", "description": "Lightweight, unobtrusive, configurable JavaScript logger", "author": "Jonny Reeves (http://jonnyreeves.co.uk)", "homepage": "http://github.com/jonnyreeves/js-logger", @@ -20,7 +20,8 @@ ], "main": "src/logger.js", "scripts": { - "test": "gulp test lint" + "test": "gulp test lint", + "build": "gulp default" }, "devDependencies": { "gulp": "~3.8.11", diff --git a/src/logger.js b/src/logger.js index af68d22..30a0906 100644 --- a/src/logger.js +++ b/src/logger.js @@ -10,7 +10,7 @@ var Logger = { }; // For those that are at home that are keeping score. - Logger.VERSION = "1.2.0"; + Logger.VERSION = "1.3.0"; // Function which handles all incoming log messages. var logHandler; @@ -159,9 +159,10 @@ (contextualLoggersByNameMap[name] = new ContextualLogger(merge({ name: name }, globalLogger.context))); }; - // Configure and example a Default implementation which writes to the `window.console` (if present). The - // `options` hash can be used to configure the default logLevel and provide a custom message formatter. - Logger.useDefaults = function(options) { + // CreateDefaultHandler returns a handler function which can be passed to `Logger.setHandler()` which will + // write to the window's console object (if present); the optional options object can be used to customise the + // formatter used to format each log message. + Logger.createDefaultHandler = function (options) { options = options || {}; options.formatter = options.formatter || function defaultMessageFormatter(messages, context) { @@ -171,11 +172,6 @@ } }; - // Check for the presence of a logger. - if (typeof console === "undefined") { - return; - } - // Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments // that don't offer a native console method. var timerStartTimeByLabelMap = {}; @@ -185,8 +181,12 @@ Function.prototype.apply.call(hdlr, console, messages); }; - Logger.setLevel(options.defaultLevel || Logger.DEBUG); - Logger.setHandler(function(messages, context) { + // Check for the presence of a logger. + if (typeof console === "undefined") { + return function () { /* no console */ }; + } + + return function(messages, context) { // Convert arguments object to Array. messages = Array.prototype.slice.call(messages); @@ -227,7 +227,14 @@ options.formatter(messages, context); invokeConsoleMethod(hdlr, messages); } - }); + }; + }; + + // Configure and example a Default implementation which writes to the `window.console` (if present). The + // `options` hash can be used to configure the default logLevel and provide a custom message formatter. + Logger.useDefaults = function(options) { + Logger.setLevel(options && options.defaultLevel || Logger.DEBUG); + Logger.setHandler(Logger.createDefaultHandler(options)); }; // Export to popular environments boilerplate. diff --git a/src/logger.min.js b/src/logger.min.js index 73ada3a..ef7a1d7 100644 --- a/src/logger.min.js +++ b/src/logger.min.js @@ -1 +1 @@ -!function(e){"use strict";var n={};n.VERSION="1.2.0";var t,o={},r=function(e,n){return function(){return n.apply(e,arguments)}},i=function(){var e,n,t=arguments,o=t[0];for(n=1;n=n.value},debug:function(){this.invoke(n.DEBUG,arguments)},info:function(){this.invoke(n.INFO,arguments)},warn:function(){this.invoke(n.WARN,arguments)},error:function(){this.invoke(n.ERROR,arguments)},time:function(e){"string"==typeof e&&e.length>0&&this.invoke(n.TIME,[e,"start"])},timeEnd:function(e){"string"==typeof e&&e.length>0&&this.invoke(n.TIME,[e,"end"])},invoke:function(e,n){t&&this.enabledFor(e)&&t(n,i({level:e},this.context))}};var s=new f({filterLevel:n.OFF});!function(){var e=n;e.enabledFor=r(s,s.enabledFor),e.debug=r(s,s.debug),e.time=r(s,s.time),e.timeEnd=r(s,s.timeEnd),e.info=r(s,s.info),e.warn=r(s,s.warn),e.error=r(s,s.error),e.log=e.info}(),n.setHandler=function(e){t=e},n.setLevel=function(e){s.setLevel(e);for(var n in o)o.hasOwnProperty(n)&&o[n].setLevel(e)},n.get=function(e){return o[e]||(o[e]=new f(i({name:e},s.context)))},n.useDefaults=function(e){if(e=e||{},e.formatter=e.formatter||function(e,n){n.name&&e.unshift("["+n.name+"]")},"undefined"!=typeof console){var t={},o=function(e,n){Function.prototype.apply.call(e,console,n)};n.setLevel(e.defaultLevel||n.DEBUG),n.setHandler(function(r,i){r=Array.prototype.slice.call(r);var l,f=console.log;i.level===n.TIME?(l=(i.name?"["+i.name+"] ":"")+r[0],"start"===r[1]?console.time?console.time(l):t[l]=(new Date).getTime():console.timeEnd?console.timeEnd(l):o(f,[l+": "+((new Date).getTime()-t[l])+"ms"])):(i.level===n.WARN&&console.warn?f=console.warn:i.level===n.ERROR&&console.error?f=console.error:i.level===n.INFO&&console.info&&(f=console.info),e.formatter(r,i),o(f,r))})}},"function"==typeof define&&define.amd?define(n):"undefined"!=typeof module&&module.exports?module.exports=n:(n._prevLogger=e.Logger,n.noConflict=function(){return e.Logger=n._prevLogger,n},e.Logger=n)}(this); \ No newline at end of file +!function(e){"use strict";var n={};n.VERSION="1.3.0";var t,o={},r=function(e,n){return function(){return n.apply(e,arguments)}},i=function(){var e,n,t=arguments,o=t[0];for(n=1;n=n.value},debug:function(){this.invoke(n.DEBUG,arguments)},info:function(){this.invoke(n.INFO,arguments)},warn:function(){this.invoke(n.WARN,arguments)},error:function(){this.invoke(n.ERROR,arguments)},time:function(e){"string"==typeof e&&e.length>0&&this.invoke(n.TIME,[e,"start"])},timeEnd:function(e){"string"==typeof e&&e.length>0&&this.invoke(n.TIME,[e,"end"])},invoke:function(e,n){t&&this.enabledFor(e)&&t(n,i({level:e},this.context))}};var a=new u({filterLevel:n.OFF});!function(){var e=n;e.enabledFor=r(a,a.enabledFor),e.debug=r(a,a.debug),e.time=r(a,a.time),e.timeEnd=r(a,a.timeEnd),e.info=r(a,a.info),e.warn=r(a,a.warn),e.error=r(a,a.error),e.log=e.info}(),n.setHandler=function(e){t=e},n.setLevel=function(e){a.setLevel(e);for(var n in o)o.hasOwnProperty(n)&&o[n].setLevel(e)},n.get=function(e){return o[e]||(o[e]=new u(i({name:e},a.context)))},n.createDefaultHandler=function(e){e=e||{},e.formatter=e.formatter||function(e,n){n.name&&e.unshift("["+n.name+"]")};var t={},o=function(e,n){Function.prototype.apply.call(e,console,n)};return"undefined"==typeof console?function(){}:function(r,i){r=Array.prototype.slice.call(r);var l,u=console.log;i.level===n.TIME?(l=(i.name?"["+i.name+"] ":"")+r[0],"start"===r[1]?console.time?console.time(l):t[l]=(new Date).getTime():console.timeEnd?console.timeEnd(l):o(u,[l+": "+((new Date).getTime()-t[l])+"ms"])):(i.level===n.WARN&&console.warn?u=console.warn:i.level===n.ERROR&&console.error?u=console.error:i.level===n.INFO&&console.info&&(u=console.info),e.formatter(r,i),o(u,r))}},n.useDefaults=function(e){n.setLevel(e&&e.defaultLevel||n.DEBUG),n.setHandler(n.createDefaultHandler(e))},"function"==typeof define&&define.amd?define(n):"undefined"!=typeof module&&module.exports?module.exports=n:(n._prevLogger=e.Logger,n.noConflict=function(){return e.Logger=n._prevLogger,n},e.Logger=n)}(this); \ No newline at end of file