UNPKG

lux-framework

Version:

Build scalable, Node.js-powered REST APIs with almost no code.

274 lines (250 loc) 5.98 kB
// @flow import { LUX_CONSOLE } from '../../constants'; import K from '../../utils/k'; import { LEVELS } from './constants'; import { createWriter } from './writer'; import { createRequestLogger } from './request-logger'; import type { Logger$RequestLogger } from './request-logger/interfaces'; import type { Logger$config, Logger$format, Logger$level, Logger$logFn, Logger$filter } from './interfaces'; /** * @class Logger * @public */ class Logger { /** * The level your application should log (DEBUG, INFO, WARN, or ERROR). * * @property level * @type {String} * @public */ level: Logger$level; /** * The output format of log data (text or json). * * @property format * @type {String} * @public */ format: Logger$format; /** * Hackers love logs. It's easy to get sensitive user information from log * data if your server has been breached. To prevent leaking sensitive * information in a potential attack, blacklist certain keys that should be * filtered out of the logs. * * ```javascript * // config/environments/development.js * export default { * logging: { * level: 'DEBUG', * format: 'text', * enabled: true, * filter: { * params: ['password'] * } * } * }; * ``` * * Now that we've added password to the array of parameters we want to filter * out of the logs, let's try to create a new user. * * ```http * POST /users HTTP/1.1 * Content-Type: application/vnd.api+json * Host: 127.0.0.1:4000 * Connection: close * User-Agent: Paw/3.0.14 (Macintosh; OS X/10.12.1) GCDHTTPRequest * Content-Length: 188 * * { * "data": { * "type": "users", * "attributes": { * "name": "Zachary Golba", * "email": "zachary.golba@postlight.com", * "password": "vcZxniFYyfnFDcLn%nhe8Vrt" * } * } * } * ``` * * The request above will yield the following log message. * * ```text * [2016-12-10T18:28:04.610Z] Processed POST "/users" from ::ffff:127.0.0.1 * with 201 Created by UsersController#create * * Params * * { * "data": { * "type": "users", * "attributes": { * "name": "Zachary Golba", * "email": "zachary.golba@postlight.com", * "password": "[FILTERED]" * } * } * } * ``` * * It worked! The password value did not leak into the log message. * * @property filter * @type {Object} * @public */ filter: Logger$filter; /** * A boolean flag that determines whether or not the logger is enabled. * * @property enabled * @type {Boolean} * @public */ enabled: boolean; /** * Log a message at the DEBUG level. * * ```javascript * logger.debug('Hello World!'); * // => [6/4/16 5:46:53 PM] Hello World! * ``` * * @method debug * @param {any} data - The data you wish to log. * @return {void} * @public */ debug: Logger$logFn; /** * Log a message at the INFO level. * * ```javascript * logger.info('Hello World!'); * // => [6/4/16 5:46:53 PM] Hello World! * ``` * * @method info * @param {any} data - The data you wish to log. * @return {void} * @public */ info: Logger$logFn; /** * Log a message at the WARN level. * * ```javascript * logger.warn('Good Bye World!'); * // => [6/4/16 5:46:53 PM] Good Bye World! * ``` * * @method warn * @param {any} data - The data you wish to log. * @return {void} * @public */ warn: Logger$logFn; /** * Log a message at the ERROR level. * * ```javascript * logger.warn('HELP!'); * // => [6/4/16 5:46:53 PM] HELP! * ``` * * @method error * @param {any} data - The data you wish to log. * @return {void} * @public */ error: Logger$logFn; /** * Internal method used for logging requests. * * @method request * @param {Request} request * @param {Response} response * @param {Object} opts - An options object. * @param {Number} opts.startTime - The timestamp from when the request was * received. * @return {void} * @private */ request: Logger$RequestLogger; constructor({ level, format, filter, enabled }: Logger$config) { let write = K; let request = K; if (!LUX_CONSOLE && enabled) { write = createWriter(format); request = createRequestLogger(this); } Object.defineProperties(this, { level: { value: level, writable: false, enumerable: true, configurable: false }, format: { value: format, writable: false, enumerable: true, configurable: false }, filter: { value: filter, writable: false, enumerable: true, configurable: false }, enabled: { value: Boolean(enabled), writable: false, enumerable: true, configurable: false }, request: { value: request, writable: false, enumerable: false, configurable: false } }); const levelNum = LEVELS.get(level) || 0; LEVELS.forEach((val, key: Logger$level) => { Reflect.defineProperty(this, key.toLowerCase(), { writable: false, enumerable: false, configurable: false, value: val >= levelNum ? (message: void | ?mixed) => { write({ message, level: key, timestamp: this.getTimestamp() }); } : K }); }); } /** * @method getTimestamp * @return {String} The current time as an ISO8601 string. * @private */ getTimestamp() { return new Date().toISOString(); } } export default Logger; export { default as line } from './utils/line'; export { default as sql } from './utils/sql'; export type { Logger$config } from './interfaces';