Home Reference Source

src/addLogger.js

/**
 * A class decorator that adds a logger object to class instances.
 * The logger object prepends a specified name to all log output.
 *
 * Unless you specify a custom `accessor`, the logger object is available via `this.logger` and you can use it as in `this.logger.warn('oh noes!')`.
 * A special case is `accessor: 'this'`- it leads to the log methods being available onthe decorated instance directly and you can use it as in `this.warn('oh noes!')`.
 *
 * @param {string|function} [name='logger'] - The name prefix. Prepended to all output of the created logger. If it is a function, the function should return a string.
 * @param {object} [config] - An optional configuration object.
 * @param {object|array} [config.logger = window.console] - The logger object that will be used. Can also be an array of logger objects.
 * @param {array} [config.functions = ['log', 'warn', 'info', 'error', 'debug', 'trace']] - An array of function names supported by the `logger` object..
 * @param {string} [config.accessor='logger'] - The name by which the logger object can be accessed on the decorated instance.
 * @param {function} [config.prefixer = (name) => `[${name}]`] - A function that creates the prefix. Receives the `name` string and should return a string.
 * @return {bool} - Always returns `true`. (Allows usage as in `(args) => this.logger.log(args) && doSomething(args)`)
 *
 * @example
 * import React from 'react';
 * import addLogger from '@xailabs/addLogger';
 * @addLogger('App')
 * class App extends React.Component {
 *      componentDidMount() {
 *          this.logger.warn('watch out!'); // logs '[App] watch out!'
 *      }
 * }
 */
export default function addLogger(name = 'logger', {
    logger = console,
    functions = ['log', 'warn', 'info', 'error', 'debug', 'trace'],
    accessor = 'logger',
    prefixer = (name) => `[${name}]`
} = {}) {
    return function decorateClass(target) {
        const customLogger = functions.reduce((result, fn) => {
            return Object.assign(result, {
                [fn]: (...args) => {
                    const prefix = prefixer(typeof name === 'function' ? name({target, args}) : name);
                    const logArgs = [prefix, ...args];
                    const loggers = Array.isArray(logger) ? logger : [logger];
                    loggers.forEach(logger => logger[fn].apply(logger, logArgs));
                    return true;
                }
            });
        }, {});
        if (accessor === 'this') {
            Object.assign(target.prototype, customLogger);
        }
        else {
            target.prototype[accessor] = customLogger;
        }
    };
}