package/.gitattributes000644 0000000031 3560116604 012145 0ustar00000000 000000 package-lock.json binary package/.node-version000644 0000000010 3560116604 011660 0ustar00000000 000000 10.15.1 package/LICENSE000644 0000002117 3560116604 010266 0ustar00000000 000000 The MIT License (MIT) Copyright (c) 2015 Charlie Robbins & the contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package/test/clone.test.js000644 0000001147 3560116604 012656 0ustar00000000 000000 'use strict'; var assume = require('assume'), compat = require('../'); describe('clone()', function () { it('clone(Error)', function () { var original = new Error("foo"), copy; original.name = "bar"; copy = compat.clone(original); assume(original).not.equals(copy); assume(original.message).equals(copy.message); assume(original.name).equals(copy.name); }); it('clone(Date)', function () { var original = new Date(1000); var copy = compat.clone(original); assume(original).not.equals(copy); assume(original.getTime()).equals(copy.getTime()); }); }); package/test/helpers.js000644 0000015734 3560116604 012251 0ustar00000000 000000 /* * helpers.js: Test helpers for winston * * (C) 2010 Charlie Robbins * MIT LICENSE * */ var assert = require('assert'), fs = require('fs'), path = require('path'), spawn = require('child_process').spawn, util = require('util'), vows = require('vows'), winston = require('winston'); var helpers = exports; helpers.size = function (obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) { size++; } } return size; }; helpers.tryUnlink = function (file) { try { fs.unlinkSync(file) } catch (ex) { } }; helpers.assertDateInfo = function (info) { assert.isNumber(Date.parse(info)); }; helpers.assertProcessInfo = function (info) { assert.isNumber(info.pid); assert.isNumber(info.uid); assert.isNumber(info.gid); assert.isString(info.cwd); assert.isString(info.execPath); assert.isString(info.version); assert.isArray(info.argv); assert.isObject(info.memoryUsage); }; helpers.assertOsInfo = function (info) { assert.isArray(info.loadavg); assert.isNumber(info.uptime); }; helpers.assertTrace = function (trace) { trace.forEach(function (site) { assert.isTrue(!site.column || typeof site.column === 'number'); assert.isTrue(!site.line || typeof site.line === 'number'); assert.isTrue(!site.file || typeof site.file === 'string'); assert.isTrue(!site.method || typeof site.method === 'string'); assert.isTrue(!site.function || typeof site.function === 'string'); assert.isTrue(typeof site.native === 'boolean'); }); }; helpers.assertLogger = function (logger, level) { assert.instanceOf(logger, winston.Logger); assert.isFunction(logger.log); assert.isFunction(logger.add); assert.isFunction(logger.remove); assert.equal(logger.level, level || "info"); Object.keys(logger.levels).forEach(function (method) { assert.isFunction(logger[method]); }); }; helpers.assertConsole = function (transport) { assert.instanceOf(transport, winston.transports.Console); assert.isFunction(transport.log); }; helpers.assertMemory = function (transport) { assert.instanceOf(transport, winston.transports.Memory); assert.isFunction(transport.log); }; helpers.assertFile = function (transport) { assert.instanceOf(transport, winston.transports.File); assert.isFunction(transport.log); }; helpers.assertCouchdb = function (transport) { assert.instanceOf(transport, winston.transports.Couchdb); assert.isFunction(transport.log); }; helpers.assertHandleExceptions = function (options) { return { topic: function () { var that = this, child = spawn('node', [options.script]); helpers.tryUnlink(options.logfile); child.on('exit', function () { fs.readFile(options.logfile, that.callback); }); }, "should save the error information to the specified file": function (err, data) { assert.isTrue(!err); data = JSON.parse(data); assert.isObject(data); helpers.assertProcessInfo(data.process); helpers.assertOsInfo(data.os); helpers.assertTrace(data.trace); if (options.message) { assert.equal('uncaughtException: ' + options.message, data.message); } } }; }; helpers.assertFailedTransport = function (transport) { return { topic: function () { var self = this; transport.on('error', function(emitErr){ transport.log('error', 'test message 2', {}, function(logErr, logged){ self.callback(emitErr, logErr); }); }); transport.log('error', 'test message'); }, "should emit an error": function (emitErr, logErr) { assert.instanceOf(emitErr, Error); assert.equal(emitErr.code, 'ENOENT'); }, "should enter noop failed state": function (emitErr, logErr) { assert.instanceOf(logErr, Error); assert.equal(transport._failures, transport.maxRetries); } }; }; helpers.testNpmLevels = function (transport, assertMsg, assertFn) { return helpers.testLevels(winston.config.npm.levels, transport, assertMsg, assertFn); }; helpers.testSyslogLevels = function (transport, assertMsg, assertFn) { return helpers.testLevels(winston.config.syslog.levels, transport, assertMsg, assertFn); }; helpers.testLevels = function (levels, transport, assertMsg, assertFn) { var tests = {}; Object.keys(levels).forEach(function (level) { var test = { topic: function () { transport.log(level, 'test message', {}, this.callback.bind(this, null)); } }; test[assertMsg] = assertFn; tests['with the ' + level + ' level'] = test; }); var metadatatest = { topic: function () { transport.log('info', 'test message', { metadata: true }, this.callback.bind(this, null)); } }; metadatatest[assertMsg] = assertFn; tests['when passed metadata'] = metadatatest; var primmetadatatest = { topic: function () { transport.log('info', 'test message', 'metadata', this.callback.bind(this, null)); } }; primmetadatatest[assertMsg] = assertFn; tests['when passed primitive metadata'] = primmetadatatest; var circmetadata = { }; circmetadata['metadata'] = circmetadata; var circmetadatatest = { topic: function () { transport.log('info', 'test message', circmetadata, this.callback.bind(this, null)); } }; circmetadatatest[assertMsg] = assertFn; tests['when passed circular metadata'] = circmetadatatest; return tests; }; helpers.assertOptionsThrow = function (options, errMsg) { return function () { assert.throws( function () { try { new (winston.transports.Console)(options); } catch (err) { throw(err); } }, new RegExp('^' + errMsg.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$') ); } }; helpers.assertStderrLevels = function (transport, stderrLevels) { return function () { assert.equal( JSON.stringify(Object.keys(transport.stderrLevels).sort()), JSON.stringify(stderrLevels.sort()) ); } }; helpers.testLoggingToStreams = function (levels, transport, stderrLevels, stdMocks) { return { topic: function () { stdMocks.use(); transport.showLevel = true; Object.keys(levels).forEach(function (level) { transport.log( level, level + ' should go to ' + (stderrLevels.indexOf(level) > -1 ? 'stderr' : 'stdout'), {}, function () {} ); }); var output = stdMocks.flush(); stdMocks.restore(); this.callback(null, output, levels); }, "output should go to the appropriate streams": function (ign, output, levels) { var outCount = 0, errCount = 0; Object.keys(levels).forEach(function (level) { var line; if (stderrLevels.indexOf(level) > -1) { line = output.stderr[errCount++]; assert.equal(line, level + ': ' + level + ' should go to stderr\n'); } else { line = output.stdout[outCount++]; assert.equal(line, level + ': ' + level + ' should go to stdout\n'); } }); } } }; package/index.js000644 0000020103 3560116604 010721 0ustar00000000 000000 'use strict'; var cycle = require('cycle'); var util = require('util'); var { levels, format } = require('logform'); var { configs } = require('triple-beam'); var { colorize } = format; levels(configs.cli); levels(configs.npm); levels(configs.syslog); // // Expose base Transport // exports.Transport = require('./lib/transport'); // // ### function clone (obj) // #### @obj {Object} Object to clone. // Helper method for deep cloning pure JSON objects // i.e. JSON objects that are either literals or objects (no Arrays, etc) // exports.clone = function (obj) { // // We only need to clone reference types (Object) // var copy = {}; if (obj instanceof Error) { // With potential custom Error objects, this might not be exactly correct, // but probably close-enough for purposes of this lib. copy = new Error(obj.message); Object.getOwnPropertyNames(obj).forEach(function (key) { copy[key] = obj[key]; }); return copy; } else if (!(obj instanceof Object)) { return obj; } else if (obj instanceof Date) { return new Date(obj.getTime()); } for (var i in obj) { if (obj.hasOwnProperty(i)) { if (Array.isArray(obj[i])) { copy[i] = obj[i].slice(0); } else if (obj[i] instanceof Buffer) { copy[i] = obj[i].slice(0); } else if (typeof obj[i] != 'function') { copy[i] = obj[i] instanceof Object ? exports.clone(obj[i]) : obj[i]; } else if (typeof obj[i] === 'function') { copy[i] = obj[i]; } } } return copy; }; // // ### function log (options) // #### @options {Object} All information about the log serialization. // Generic logging function for returning timestamped strings // with the following options: // // { // level: 'level to add to serialized message', // message: 'message to serialize', // meta: 'additional logging metadata to serialize', // colorize: false, // Colorizes output (only if `.json` is false) // align: false // Align message level. // timestamp: true // Adds a timestamp to the serialized message // label: 'label to prepend the message' // } // exports.log = function (options) { var timestampFn = typeof options.timestamp === 'function' ? options.timestamp : exports.timestamp, timestamp = options.timestamp ? timestampFn() : null, showLevel = options.showLevel === undefined ? true : options.showLevel, meta = options.meta !== null && options.meta !== undefined && !(options.meta instanceof Error) ? exports.clone(cycle.decycle(options.meta)) : options.meta || null, output; // // raw mode is intended for outputing winston as streaming JSON to STDOUT // if (options.raw) { if (typeof meta !== 'object' && meta != null) { meta = { meta: meta }; } output = exports.clone(meta) || {}; output.level = options.level; // // Remark (jcrugzz): This used to be output.message = options.message.stripColors. // I do not know why this is, it does not make sense but im handling that // case here as well as handling the case that does make sense which is to // make the `output.message = options.message` // output.message = options.message.stripColors ? options.message.stripColors : options.message; return JSON.stringify(output); } // // json mode is intended for pretty printing multi-line json to the terminal // if (options.json || true === options.logstash) { if (typeof meta !== 'object' && meta != null) { meta = { meta: meta }; } output = exports.clone(meta) || {}; output.level = options.level; output.message = output.message || ''; if (options.label) { output.label = options.label; } if (options.message) { output.message = options.message; } if (timestamp) { output.timestamp = timestamp; } if (options.logstash === true) { // use logstash format var logstashOutput = {}; if (output.message !== undefined) { logstashOutput['@message'] = output.message; delete output.message; } if (output.timestamp !== undefined) { logstashOutput['@timestamp'] = output.timestamp; delete output.timestamp; } logstashOutput['@fields'] = exports.clone(output); output = logstashOutput; } if (typeof options.stringify === 'function') { return options.stringify(output); } return JSON.stringify(output, function (key, value) { return value instanceof Buffer ? value.toString('base64') : value; }); } // // Remark: this should really be a call to `util.format`. // if (typeof options.formatter == 'function') { return String(options.formatter(exports.clone(options))); } output = timestamp ? timestamp + ' - ' : ''; if (showLevel) { var opts = {}; opts.level = options.colorize === 'level'; opts.all = options.colorize === 'all' || options.colorize === true; output += opts.level || opts.all ? colorize().transform(options, opts).level : options.level; } output += (options.align) ? '\t' : ''; output += (timestamp || showLevel) ? ': ' : ''; output += options.label ? ('[' + options.label + '] ') : ''; var opts = {}; opts.message = options.colorize === 'message'; opts.all = options.colorize === 'all'; output += opts.all || opts.message ? colorize.transform(options, opts).message : options.message; if (meta !== null && meta !== undefined) { if (meta && meta instanceof Error && meta.stack) { meta = meta.stack; } if (typeof meta !== 'object') { output += ' ' + meta; } else if (Object.keys(meta).length > 0) { if (typeof options.prettyPrint === 'function') { output += ' ' + options.prettyPrint(meta); } else if (options.prettyPrint) { output += ' ' + '\n' + util.inspect(meta, false, options.depth || null, options.colorize); } else if ( options.humanReadableUnhandledException && Object.keys(meta).length === 5 && meta.hasOwnProperty('date') && meta.hasOwnProperty('process') && meta.hasOwnProperty('os') && meta.hasOwnProperty('trace') && meta.hasOwnProperty('stack')) { // // If meta carries unhandled exception data serialize the stack nicely // var stack = meta.stack; delete meta.stack; delete meta.trace; output += ' ' + exports.serialize(meta); if (stack) { output += '\n' + stack.join('\n'); } } else { output += ' ' + exports.serialize(meta); } } } return output; }; // // ### function serialize (obj, key) // #### @obj {Object|literal} Object to serialize // #### @key {string} **Optional** Optional key represented by obj in a larger object // Performs simple comma-separated, `key=value` serialization for Loggly when // logging to non-JSON inputs. // exports.serialize = function (obj, key) { if (obj === null) { obj = 'null'; } else if (obj === undefined) { obj = 'undefined'; } else if (obj === false) { obj = 'false'; } if (typeof obj !== 'object') { return key ? key + '=' + obj : obj; } if (obj instanceof Buffer) { return key ? key + '=' + obj.toString('base64') : obj.toString('base64'); } var msg = '', keys = Object.keys(obj), length = keys.length; for (var i = 0; i < length; i++) { if (Array.isArray(obj[keys[i]])) { msg += keys[i] + '=['; for (var j = 0, l = obj[keys[i]].length; j < l; j++) { msg += exports.serialize(obj[keys[i]][j]); if (j < l - 1) { msg += ', '; } } msg += ']'; } else if (obj[keys[i]] instanceof Date) { msg += keys[i] + '=' + obj[keys[i]]; } else { msg += exports.serialize(obj[keys[i]], keys[i]); } if (i < length - 1) { msg += ', '; } } return msg; }; // // ### function timestamp () // Returns a timestamp string for the current time. // exports.timestamp = function () { return new Date().toISOString(); }; package/test/timestamp.test.js000644 0000000507 3560116604 013560 0ustar00000000 000000 'use strict'; var assume = require('assume'), compat = require('../'); describe('timestamp()', function () { it('creates an ISO string', function () { var timestamp = compat.timestamp(); var date = new Date(timestamp); assume(date).is.a('date'); assume(date.toISOString()).equals(timestamp); }); }); package/lib/transport.js000644 0000007216 3560116604 012426 0ustar00000000 000000 /* * transport.js: Base Transport object for all Winston transports. * * (C) 2010 Charlie Robbins * MIT LICENCE * */ var events = require('events'), util = require('util'); // // ### function Transport (options) // #### @options {Object} Options for this instance. // Constructor function for the Tranport object responsible // base functionality for all winston transports. // var Transport = module.exports = function (options) { events.EventEmitter.call(this); options = options || {}; this.silent = options.silent || false; this.raw = options.raw || false; this.name = options.name || this.name; this.formatter = options.formatter; // // Do not set a default level. When `level` is falsey on any // `Transport` instance, any `Logger` instance uses the // configured level (instead of the Transport level) // this.level = options.level; this.handleExceptions = options.handleExceptions || false; this.exceptionsLevel = options.exceptionsLevel || 'error'; this.humanReadableUnhandledException = options.humanReadableUnhandledException || false; }; // // Inherit from `events.EventEmitter`. // util.inherits(Transport, events.EventEmitter); // // ### function formatQuery (query) // #### @query {string|Object} Query to format // Formats the specified `query` Object (or string) to conform // with the underlying implementation of this transport. // Transport.prototype.formatQuery = function (query) { return query; }; // // ### function normalizeQuery (query) // #### @options {string|Object} Query to normalize // Normalize options for query // Transport.prototype.normalizeQuery = function (options) { // // Use options similar to loggly. // [See Loggly Search API](http://wiki.loggly.com/retrieve_events#optional) // options = options || {}; // limit options.rows = options.rows || options.limit || 10; // starting row offset options.start = options.start || 0; // now options.until = options.until || new Date; if (typeof options.until !== 'object') { options.until = new Date(options.until); } // now - 24 options.from = options.from || (options.until - (24 * 60 * 60 * 1000)); if (typeof options.from !== 'object') { options.from = new Date(options.from); } // 'asc' or 'desc' options.order = options.order || 'desc'; // which fields to select options.fields = options.fields; return options; }; // // ### function formatResults (results, options) // #### @results {Object|Array} Results returned from `.query`. // #### @options {Object} **Optional** Formatting options // Formats the specified `results` with the given `options` accordinging // to the implementation of this transport. // Transport.prototype.formatResults = function (results, options) { return results; }; // // ### function logException (msg, meta, callback) // #### @msg {string} Message to log // #### @meta {Object} **Optional** Additional metadata to attach // #### @callback {function} Continuation to respond to when complete. // Logs the specified `msg`, `meta` and responds to the callback once the log // operation is complete to ensure that the event loop will not exit before // all logging has completed. // Transport.prototype.logException = function (msg, meta, callback) { var self = this, called; if (this.silent) { return callback(); } function onComplete () { if (!called) { called = true; self.removeListener('logged', onComplete); self.removeListener('error', onComplete); callback(); } } this.once('logged', onComplete); this.once('error', onComplete); this.log(self.exceptionsLevel, msg, meta, function () { }); }; package/test/transports/transport.js000644 0000015150 3560116604 015052 0ustar00000000 000000 var assert = require('assert'), winston = require('winston'), helpers = require('../helpers'); module.exports = function (transport, options) { var logger = transport; if (typeof transport.cli !== 'function') { logger = new winston.Logger({ transports: [new transport(options)] }); } var transport = logger.transports[logger._names[0]]; var out = { 'topic': logger, 'when passed valid options': { 'should have the proper methods defined': function () { switch (transport.name) { case 'console': helpers.assertConsole(transport); break; case 'file': helpers.assertFile(transport); break; case 'couchdb': helpers.assertCouchdb(transport); break; } assert.isFunction(transport.log); } }, 'the log() method': helpers.testNpmLevels(transport, 'should respond with true', function (ign, err, logged) { assert.isNull(err); assert.isNotNull(logged); } ), 'the stream() method': { 'using no options': { 'topic': function () { if (!transport.stream) return; logger.log('info', 'hello world', {}); var cb = this.callback, j = 10, i = 10, results = [], stream = logger.stream(); stream.on('log', function (log) { results.push(log); results.stream = stream; if (!--j) cb(null, results); }); stream.on('error', function (err) { j = -1; //don't call the callback again cb(err); }); while (i--) logger.log('info', 'hello world ' + i, {}); }, 'should stream logs': function (err, results) { if (!transport.stream) return; assert.isNull(err); results.forEach(function (log) { assert.ok(log.message.indexOf('hello world') === 0 || log.message.indexOf('test message') === 0); }); results.stream.destroy(); } }, 'using the `start` option': { 'topic': function () { if (!transport.stream) return; var cb = this.callback, stream = logger.stream({ start: 0 }); stream.on('log', function (log) { log.stream = stream; if (cb) cb(null, log); cb = null; }); }, 'should stream logs': function (err, log) { if (!transport.stream) return; assert.isNull(err); assert.isNotNull(log.message); log.stream.destroy(); } } }, 'after the logs have flushed': { topic: function () { setTimeout(this.callback, 1000); }, 'the query() method': { 'using basic querying': { 'topic': function () { if (!transport.query) return; var cb = this.callback; logger.log('info', 'hello world', {}, function () { logger.query(cb); }); }, 'should return matching results': function (err, results) { if (!transport.query) return; assert.isNull(err); results = results[transport.name]; while (!Array.isArray(results)) { results = results[Object.keys(results).pop()]; } var log = results.pop(); assert.ok(log.message.indexOf('hello world') === 0 || log.message.indexOf('test message') === 0); } }, 'using the `rows` option': { 'topic': function () { if (!transport.query) return; var cb = this.callback; logger.log('info', 'hello world', {}, function () { logger.query({ rows: 1 }, cb); }); }, 'should return one result': function (err, results) { if (!transport.query) return; assert.isNull(err); results = results[transport.name]; while (!Array.isArray(results)) { results = results[Object.keys(results).pop()]; } assert.equal(results.length, 1); } }, 'using `fields` and `order` option': { 'topic': function () { if (!transport.query) return; var cb = this.callback; logger.log('info', 'hello world', {}, function () { logger.query({ order: 'asc', fields: ['timestamp'] }, cb); }); }, 'should return matching results': function (err, results) { if (!transport.query) return; assert.isNull(err); results = results[transport.name]; while (!Array.isArray(results)) { results = results[Object.keys(results).pop()]; } assert.equal(Object.keys(results[0]).length, 1); assert.ok(new Date(results.shift().timestamp) < new Date(results.pop().timestamp)); } }, 'using the `from` and `until` option': { 'topic': function () { if (!transport.query) return; var cb = this.callback; var start = Date.now() - (100 * 1000); var end = Date.now() + (100 * 1000); logger.query({ from: start, until: end }, cb); }, 'should return matching results': function (err, results) { if (!transport.query) return; assert.isNull(err); results = results[transport.name]; while (!Array.isArray(results)) { results = results[Object.keys(results).pop()]; } assert.ok(results.length >= 1); } }, 'using a bad `from` and `until` option': { 'topic': function () { if (!transport.query) return; var cb = this.callback; logger.log('info', 'bad from and until', {}, function () { var now = Date.now() + 1000000; logger.query({ from: now, until: now }, cb); }); }, 'should return no results': function (err, results) { if (!transport.query) return; assert.isNull(err); results = results[transport.name]; while (!Array.isArray(results)) { results = results[Object.keys(results).pop()]; } results = [results.filter(function(log) { return log.message === 'bad from and until'; }).pop()]; assert.isUndefined(results[0]); } } } } }; return out; }; package/test/winston-compat.test.js000644 0000000726 3560116604 014542 0ustar00000000 000000 'use strict'; var assume = require('assume'), compat = require('../'); describe('winston-compat', function () { it("require('winston-compat/test/helpers.js')", function () { assume(function () { var helpers = require('./helpers'); }).does.not.throw() }); it("require('winston-compat/test/transports/transport')", function () { assume(function () { var transport = require('./transports/transport'); }).does.not.throw() }); }); package/package.json000644 0000002044 3560116604 011546 0ustar00000000 000000 { "name": "winston-compat", "version": "0.1.5", "description": "Core functionality from winston < 3.0.0 commonly used by user-created transports.", "main": "index.js", "scripts": { "test": "nyc mocha test/*.test.js", "preversion": "npm test", "postversion": "git push && git push --tags && npm publish" }, "repository": { "type": "git", "url": "git+https://github.com/winstonjs/winston-compat.git" }, "keywords": [ "winston", "winston2", "winston1" ], "author": "Charlie Robbins ", "license": "MIT", "bugs": { "url": "https://github.com/winstonjs/winston-compat/issues" }, "homepage": "https://github.com/winstonjs/winston-compat#readme", "dependencies": { "cycle": "~1.0.3", "logform": "^1.6.0", "triple-beam": "^1.2.0" }, "devDependencies": { "assume": "^1.3.1", "eslint-config-populist": "^4.2.0", "mocha": "^7.1.0", "nyc": "^15.0.0", "vows": "^0.8.3", "winston": "^2.1.1" }, "engines": { "node": ">= 6.4.0" } } package/CHANGELOG.md000644 0000000263 3560116604 011072 0ustar00000000 000000 # CHANGELOG ### 0.1.2 - [#7] require `'util'`. ### 0.1.1 - Move `vows` to `devDependencies`. ### 0.1.0 - Add legacy `vows`-based test helpers. ### 0.0.1 - Initial release package/README.md000644 0000000143 3560116604 010535 0ustar00000000 000000 # winston-compat Core functionality from winston < 3.0.0 commonly used by user-created transports.