Logger

CloudWatch and serverless-offline friendly logger.

Overview

Sadly, console.log is the #1 debugging tool when writing serverless code. Logger extends it with levels, timestamps, context/category names, and object formatting. It’s just a few small incremental improvements, and yet together takes logging a leap forward.

If your transpiling, be sure to enable source maps (in Typescript, Babel) and use the source-map-support library so that you get meaningful stack traces.

Install

npm install @sailplane/logger

Examples

import {Logger, LogLevels} from "@sailplane/logger";
const logger = new Logger('name-of-module');

logger.info("Hello World!");
// INFO name-of-module: Hello World!

Logger.globalLogLevel = LogLevels.INFO;
logger.debug("DEBUG < INFO.");
// No output

Logger.logTimestamps = true;
logger.info("Useful local log");
// 2018-11-15T18:26:20 INFO name-of-module: Useful local log

logger.warnObject("Exception ", {message: "oops"});
// 2018-11-15T18:29:38 INFO name-of-module: Exception {message:"oops"}

Logger.formatObjects = true;
logger.errorObject("Exception ", {message: "oops"});
// 2018-11-15T18:30:49 INFO name-of-module: Exception {
//   message: "oops"
// }

Configuration / Behavior

The output of Logger varies based on some global settings, whether the Lambda is executing in AWS or local (serverless-offline, SAM offline), and whether the runtime is Node.js 10 vs earlier versions.

globalLogLevel

Only this level and higher will be output. Options are ‘DEBUG’, ‘INFO’, ‘WARN’, ‘ERROR’, ‘NONE’. Default is ‘DEBUG’.

Override programmatically: Logger.globalLogLevel = 'WARN';

Override from environment variable: export LOG_LEVEL=INFO

outputLevels

If true, output level text on each line.

Default is true when running outside of AWS Lambda environment, and in a Lambda runtime earlier than Node.js v10. Starting with Node.js v10, the Lambda runtime itself adds log levels to the output sent to CloudWatch. This is detected and outputLevels is set to false.

Override programmatically: Logger.outputLevels = false;

logTimestamps

Output date & time prefix on logged lines?

Timestamps are enabled outside of AWS Lambda, and disabled in AWS Lambda where CloudWatch provides time stamping.

Override programmatically: Logger.logTimestamps = false;

formatObjects

If true, objects logged by debugObject(), infoObject(), warnObject() and errorObject() will be formatted with proper indentation. If false, no formatting is performed.

Formatting is enabled outside of AWS Lambda, and disabled in AWS Lambda where CloudWatch provides formatting.

Type Declarations

export declare enum LogLevels {
    NONE = 0,
    ERROR = 1,
    WARN = 2,
    INFO = 3,
    DEBUG = 4
}
/**
 * Custom logger class.
 *
 * Works much like console's logging, but includes levels, date/time,
 * and category (file) on each line.
 *
 * Usage:
 *   import {Logger} from "@sailplane/logger";
 *   const logger = new Logger('name-of-module');
 *   logger.info("Hello World!");
 */
export declare class Logger {
    private category;
    /**
     * Global logging level.
     * May be initialized via LOG_LEVEL environment variable, or set by code.
     */
    static globalLogLevel: LogLevels;
    /**
     * Include the level in log output?
     * Defaults to true if not streaming to CloudWatch or running Node.js v9 or older.
     * May also be set directly by code.
     * Note: AWS behavior changed with nodejs10.x runtime - it now includes log levels automatically.
     */
    static outputLevels: boolean;
    /**
     * Include timestamps in log output?
     * Defaults to false if streaming to CloudWatch, true otherwise.
     * (CloudWatch provides timestamps.)
     * May override by setting the LOG_TIMESTAMPS environment variable to 'true' or 'false',
     * or set by code.
     */
    static logTimestamps: boolean;
    /**
     * Pretty format objects when stringified to JSON?
     * Defaults to false if streaming to CloudWatch, true otherwise.
     * (Best to let CloudWatch provide the formatting.)
     * May override by setting the LOG_FORMAT_OBJECTS environment variable to 'true' or 'false',
     * or set by code.
     */
    static formatObjects: boolean;
    /**
     * Construct.
     * @param category logging category to include in each line.
     *                 Source file name or class name are good choices.
     */
    constructor(category: string);
    /**
     * Format a log line. Helper for #debug, #info, #warn, and #error.
     *
     * @param level logging level
     * @param message text to log
     * @param optionalParams A list of JavaScript objects to output.
     *                       The string representations of each of these objects are
     *                       appended together in the order listed and output.
     * @return array to pass to a console function, or null to output nothing.
     */
    private formatLog;
    /**
     * Format a log ine with a stringified object.
     * Helper for #debugObject, #infoObject, #warnObject, and #errorObject.
     *
     * @param level logging level
     * @param message text to log - may want to end with a space,
     *                as `{` will immediately follow.
     * @param object object to stringify to JSON and append to message
     * @return array to pass to a console function, or null to output nothing.
     */
    private formatLogStringified;
    /**
     * Log a line at DEBUG level.
     *
     * @param message text to log
     * @param optionalParams A list of JavaScript objects to output.
     *                       The string representations of each of these objects are
     *                       appended together in the order listed and output.
     */
    debug(message: any, ...optionalParams: any[]): void;
    /**
     * Log a line at INFO level.
     *
     * @param message text to log
     * @param optionalParams A list of JavaScript objects to output.
     *                       The string representations of each of these objects are
     *                       appended together in the order listed and output.
     */
    info(message: any, ...optionalParams: any[]): void;
    /**
     * Log a line at WARN level.
     *
     * @param message text to log
     * @param optionalParams A list of JavaScript objects to output.
     *                       The string representations of each of these objects are
     *                       appended together in the order listed and output.
     */
    warn(message: any, ...optionalParams: any[]): void;
    /**
     * Log a line at ERROR level.
     *
     * @param message text to log
     * @param optionalParams A list of JavaScript objects to output.
     *                       The string representations of each of these objects are
     *                       appended together in the order listed and output.
     */
    error(message: any, ...optionalParams: any[]): void;
    /**
     * Log a line at DEBUG level with a stringified object.
     *
     * @param message text to log - may want to end with a space,
     *                as `{` will immediately follow.
     * @param object object to stringify to JSON and append to message
     */
    debugObject(message: string, object: any): void;
    /**
     * Log a line at INFO level with a stringified object.
     *
     * @param message text to log - may want to end with a space,
     *                as `{` will immediately follow.
     * @param object object to stringify to JSON and append to message
     */
    infoObject(message: string, object: any): void;
    /**
     * Log a line at WARN level with a stringified object.
     *
     * @param message text to log - may want to end with a space,
     *                as `{` will immediately follow.
     * @param object object to stringify to JSON and append to message
     */
    warnObject(message: string, object: any): void;
    /**
     * Log a line at ERROR level with a stringified object.
     *
     * @param message text to log - may want to end with a space,
     *                as `{` will immediately follow.
     * @param object object to stringify to JSON and append to message
     */
    errorObject(message: string, object: any): void;
}