├── .gitignore ├── .travis.yml ├── component.json ├── package.json ├── readme.md ├── test.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ns-log", 3 | "description": "Easy (yet complete) logging for node and browser", 4 | "version": "0.0.4", 5 | "keywords": [], 6 | "dependencies": {}, 7 | "development": {}, 8 | "license": "MIT", 9 | "main": "index.js", 10 | "scripts": [ 11 | "index.js" 12 | ], 13 | "repository": "em/ns-log" 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ns-log", 3 | "version": "0.0.4", 4 | "description": "Easy (yet complete) logging for node and browser", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "mocha" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/em/elem.git" 15 | }, 16 | "keywords": [ 17 | "logger", 18 | "that", 19 | "does", 20 | "not", 21 | "suck" 22 | ], 23 | "author": "Emery Denuccio", 24 | "license": "MIT", 25 | "devDependencies": { 26 | "chai": "^3.5.0", 27 | "mocha": "^3.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://drone.io/github.com/em/ns-log/status.png)](https://drone.io/github.com/em/ns-log/latest) 2 | 3 | # Namespaced Logger 4 | 5 | Very simple logger for node and browser. 6 | 7 | - Outputs log messages with prefixes 8 | - Globally filter logs by string matching 9 | 10 | You can do everything with this. 11 | 12 | # Example Usage 13 | ``` 14 | npm install ns-log 15 | ``` 16 | 17 | ``` 18 | let log = require('ns-log'); 19 | log.enable('[ERROR] [INFO] [WARN]'); // This is just an all-inclusive string match 20 | ``` 21 | 22 | ``` 23 | let log = require('ns-log').ns('mymodule'); // This just adds 'mymodule' to the beginning of each log line 24 | log.info('Hello'); 25 | => [INFO] my:module 2016-12-1 10:10:10 (UTC) Hello 26 | ``` 27 | 28 | # Log Levels 29 | These are built-in namespaces. 30 | 31 | - log.error = log.ns('[ERROR]'); 32 | - log.info = log.ns('[INFO]'); 33 | - log.warn = log.ns('[WARN]'); 34 | - log.debug = log.ns.prefix('[DEBUG]'); 35 | 36 | ``` 37 | log.error('error'); 38 | log.warn('warn'); 39 | log.info('info'); 40 | log.debug('debug'); 41 | ``` 42 | 43 | # Browser usage 44 | TODO 45 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var nslog = require('./'); 3 | 4 | describe('nslog', function() { 5 | // Last console calls 6 | var last = {}; 7 | 8 | // Hook each console method 9 | ['log', 'info', 'warn', 'error', 'debug'] 10 | .forEach(function(type) { 11 | nslog.global.console[type] = function() { 12 | last[type] = [].slice.call(arguments).join(' '); 13 | } 14 | }); 15 | 16 | // Override timestamp generator 17 | nslog.global.timestamp = function() {return '(time)'}; 18 | nslog.global.filter = ''; 19 | 20 | beforeEach(function() { 21 | last = {}; 22 | }); 23 | 24 | describe('direct call', function() { 25 | it('outputs with no type-prefix', function() { 26 | nslog.enable(); 27 | nslog('hello'); 28 | expect(last.log).eql('hello'); 29 | }); 30 | 31 | it('does nothing if not enabled', function() { 32 | nslog.disable(); 33 | nslog('hello'); 34 | expect(last.log).eql(undefined); 35 | }); 36 | }); 37 | 38 | describe('enable', function() { 39 | it('defaults to "*" if undefined', function() { 40 | nslog.enable(); 41 | expect(nslog.global.filter).eql(["*"]); 42 | }); 43 | it('sets global.enabled', function() { 44 | nslog.enable(); 45 | expect(nslog.global.enabled).eql(true); 46 | }); 47 | }); 48 | 49 | describe('ns', function() { 50 | it('prefixes logs with namespace', function() { 51 | nslog.enable(); 52 | nslog.ns('yo')('dawg'); 53 | expect(last.log).eq('yo dawg'); 54 | }); 55 | }); 56 | 57 | describe('debug', function() { 58 | it('calls console.debug prefixed with [debug]', function() { 59 | nslog.enable(); 60 | nslog.debug('yo'); 61 | expect(last.debug).eq('[debug] yo'); 62 | }); 63 | }); 64 | 65 | describe('info', function() { 66 | it('calls console.info prefixed with [info]', function() { 67 | nslog.enable(); 68 | nslog.info('yo'); 69 | expect(last.info).eq('[info] yo'); 70 | }); 71 | }); 72 | 73 | describe('warn', function() { 74 | it('calls console.warn prefixed with [warn]', function() { 75 | nslog.enable(); 76 | nslog.warn('yo'); 77 | expect(last.warn).eq('[warn] yo'); 78 | }); 79 | }); 80 | 81 | describe('error', function() { 82 | it('calls console.error prefixed with [error]', function() { 83 | nslog.enable(); 84 | nslog.error('yo'); 85 | expect(last.error).eq('[error] yo'); 86 | }); 87 | }); 88 | 89 | describe('global.filter', function() { 90 | it('ignores non-matches', function() { 91 | nslog.enable('notinlog'); 92 | nslog('hello world'); 93 | expect(last.log).eq(undefined); 94 | }); 95 | 96 | it('allows matches through', function() { 97 | nslog.enable('yo'); 98 | nslog.ns('yo')('dawg'); 99 | expect(last.log).eq('yo dawg'); 100 | }); 101 | 102 | it('uses OR logic', function() { 103 | nslog.enable('yo orthis'); 104 | nslog.ns('yo')('dawg'); 105 | expect(last.log).eq('yo dawg'); 106 | }); 107 | }); 108 | 109 | describe('global.prefixes', function() { 110 | it('affects all ns logs', function() { 111 | var log = nslog.ns('yo'); 112 | log.global.prefixes.push('global'); 113 | log.info('dawg'); 114 | expect(last.info).eq('[info] yo global dawg'); 115 | }); 116 | }); 117 | }); 118 | 119 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview 3 | * 4 | * The simplest logger ever. 5 | * 6 | * 1. Prefixes log messages with strings. 7 | * 2. Filters output by matching strings. 8 | * 9 | * Example usage: 10 | * 11 | * // Make a log function with my:module prefix 12 | * var log = require('log').ns('api/login'); 13 | * 14 | * // Only output logs containing "module=main" or "ERROR" 15 | * log.enable('ERROR'); 16 | * 17 | * // log.error logs messages with [ERROR] prefix 18 | * log.error('omgbbq'); 19 | * => '[ERROR] api/login omgbbq' 20 | */ 21 | 22 | /** 23 | * Globals exposed through log.global 24 | * in every namespaced logger. 25 | */ 26 | var global = {}; 27 | 28 | /** 29 | * Disabled by default 30 | */ 31 | global.enabled = false; 32 | 33 | /** 34 | * No filter by default. 35 | * (everything gets outputed) 36 | */ 37 | global.filter = []; 38 | 39 | 40 | /** 41 | * Global prefixes on the root logger. 42 | */ 43 | global.prefixes = []; 44 | 45 | /** 46 | * Make a virtual `console` object with 47 | * all methods available. Falling back 48 | * gracefully to whatever is available. 49 | * 50 | * This also offers us a common interface 51 | * to test the library by stubbing. 52 | */ 53 | var noop = function() {}; 54 | global.console = {}; 55 | global.console.log = console && console.log ? console.log.bind(console) : noop; 56 | global.console.error = console && console.error ? console.error.bind(console) : global.console.log; 57 | global.console.warn = console && console.warn ? console.warn.bind(console) : global.console.log; 58 | global.console.info = console && console.info ? console.info.bind(console) : global.console.log; 59 | global.console.debug = console && console.debug ? console.debug.bind(console) : global.console.log; 60 | 61 | /** 62 | * Timestamp generator function. 63 | * The initial log() we export will 64 | * start out with this prefix. 65 | */ 66 | global.timestamp = function() { 67 | var date = new Date(); 68 | var year = date.getFullYear(); 69 | var month = date.getMonth(); 70 | var day = date.getDate(); 71 | var hour = date.getHours(); 72 | var min = date.getMinutes(); 73 | var sec = date.getSeconds(); 74 | 75 | return year+'-'+month+'-'+day+'T'+hour+':'+min+':'+sec+'Z'; 76 | } 77 | 78 | /** 79 | * Generate a log function that appends 80 | * a prefix to all messages. 81 | * 82 | * @param {String} prefix 83 | * 84 | * Example: 85 | * log.prefix('module')('Hello'); 86 | * => 'module Hello' 87 | */ 88 | var makeLogFn = function(prefixes) { 89 | 90 | var log = function() { 91 | log.process(arguments); 92 | }; 93 | 94 | log.error = function() { 95 | log.process(arguments, 'error'); 96 | }; 97 | 98 | log.warn = function() { 99 | log.process(arguments, 'warn'); 100 | }; 101 | 102 | log.info = function() { 103 | log.process(arguments, 'info'); 104 | }; 105 | 106 | log.debug = function() { 107 | log.process(arguments, 'debug'); 108 | }; 109 | 110 | /** 111 | * Generate another new log function 112 | * with an additional prefix(es). 113 | * 114 | * @param {String...} prefixes 115 | */ 116 | log.ns = function() { 117 | return makeLogFn( 118 | [].slice.call(arguments).concat(prefixes) 119 | ) 120 | } 121 | 122 | /** 123 | * Enable logging and optionally 124 | * set a filter for what gets logged. 125 | * 126 | * The filter is applied using AND logic 127 | * i.e. ALL keywords must match for a 128 | * message to get logged. 129 | * 130 | * @param {String} filter Space-separated keywords 131 | */ 132 | log.enable = function(filter) { 133 | global.enabled = true; 134 | filter = filter || '*'; 135 | filter = filter.split(/\s+/); // Pre-split it 136 | global.filter = filter; 137 | } 138 | 139 | /** 140 | * Disable all logging. 141 | */ 142 | log.disable = function() { 143 | global.enabled = false; 144 | } 145 | 146 | /** 147 | * Process arguments and return 148 | * a string to output. 149 | * 150 | * @param {Array} args Array of arguments to log 151 | * @param {String} type (log|error|warn|info|debug) 152 | */ 153 | log.process = function(args, type) { 154 | if (!global.enabled) return; 155 | 156 | // Get writer function based on type 157 | var writefn = global.console[type] || global.console.log; 158 | 159 | // Convert Arguments to Array 160 | args = [].slice.call(args); 161 | 162 | // Prepend all prefixes 163 | args = prefixes.concat(global.prefixes, args); 164 | 165 | // Prepend type 166 | if (type) { 167 | args = ['['+type+']'].concat(args); 168 | } 169 | 170 | // Run any functions in args 171 | // for generated messages 172 | args = args.map(function(a) { 173 | if(typeof a === 'function') { 174 | return a(); 175 | } 176 | return a; 177 | }); 178 | 179 | // Determine if message matches filter. 180 | for (var i=0, l = global.filter.length; i