npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

meta2-logger

v2.1.1

Published

Simple logging library for NodeJS with TypeScript support and multiple targets including GrayLog.

Downloads

55

Readme

meta2-logger

Simple logging library for NodeJS with support of facilities and multiple transports.

Logger has also first-class support for TypeScript and is fully documented.

Table of Contents:

Features

Built-in transports:

  • Console
  • Text file
  • JSON file
  • Memory
  • GrayLog

Log levels:

Library supports all of standard syslog levels.

  • debug
  • info
  • notice
  • warn
  • error
  • critical
  • alert
  • emergency

Other features:

  • Facilities
  • Meta-data
  • Custom targets
  • Colorized console output
  • TypeScript decorators to simply enable logging on classes and methods
  • Remote management server with UI and REST API provided by meta2-logger-server package

Installation

# Using NPM
npm install meta2-logger

# To save as dependency
npm install --save meta2-logger

Usage (TypeScript)

import {Logger, LOG_LEVEL, default as logger} from "meta2-logger";

// Use global logger
logger.info("From global logger");

// Or create new instance
const myLogger = new Logger({
	level: LOG_LEVEL.DEBUG
});

// Setup targets
logger.toConsole({
	level: LOG_LEVEL.INFO,
	timestamp: true,
	colorize: true
}).toFile("demo.log", {
	level: LOG_LEVEL.WARN,
	timestamp: true,
	facilities: [ "test" ]
}).toJsonFile("demo.json", {
	level: LOG_LEVEL.ERROR
}).toGrayLog({
	level: LOG_LEVEL.DEBUG,
	graylogHostname: "localhost"
	host: "myApp"
});

// Log some messages
logger.debug("Hello %s", "debug");
logger.info("Hello %s", "info");
logger.notice("Hello %s", "notice");
logger.warn("Hello %s", "warn"); // or logger.warning("Hello %s", "warn");
logger.error("Hello %s", "error");
logger.crit("Hello %s", "critical");
logger.alert("Hello %s", "alert");
logger.emerg("Hello %s", "emergency"); // or logger.panic("Hello %s", "emergency");

// Create facility
const facility = logger.facility("http", {
	level: LOG_LEVEL.INFO
});

facility.notice("Server started on port %d", 8080);

// Passing meta-data using object as first argument
facility.warn({ reqId: 123 }, "Bad request");

Usage (vanilla JS)

const Logger = require("meta2-logger");

// Accessing global logger instance
const logger = Logger.default;

// Or create new instance
const logger = new Logger.Logger();

// Setup targets
logger.toConsole({
	level: Logger.LOG_LEVEL.INFO,
	timestamp: true,
	colorize: true
}).toFile("demo.log", {
	level: Logger.LOG_LEVEL.WARN,
	timestamp: true,
	facilities: [ "test" ]
}).toJsonFile("demo.json", {
	level: Logger.LOG_LEVEL.ERROR
}).toGrayLog({
	level: Logger.LOG_LEVEL.DEBUG,
	graylogHostname: "localhost"
	host: "myApp"
});

// Log some messages
logger.debug("Hello %s", "debug");
logger.info("Hello %s", "info");
logger.notice("Hello %s", "notice");
logger.warn("Hello %s", "warn"); // or logger.warning("Hello %s", "warn");
logger.error("Hello %s", "error");
logger.crit("Hello %s", "critical");
logger.alert("Hello %s", "alert");
logger.emerg("Hello %s", "emergency"); // or logger.panic("Hello %s", "emergency");

// Create facility
const facility = logger.facility("http");

facility.notice("Server started on port %d", 8080);

// Passing meta-data using object as first argument
facility.warn({ reqId: 123 }, "Bad request");

Facilities

Logging facility provides a way to decouple logging based on their purpose.

Creating facility from logger:

import {default as logger, LOG_LEVEL} from "meta2-logger";

// Create facility from main logger - options are optional
const facility = logger.facility("facilityName", {
	level: LOG_LEVEL.INFO
});

// We can change facility log level later
facility.setLevel(LOG_LEVEL.NOTICE);
facility.getLevel(); // -> LOG_LEVEL.NOTICE

// Log to facility
facility.info("Message");

// We can get existing facility instance by calling facility method again
const facilityAgain = logger.facility("facilityName");

// We can get map of all registered facilities
logger.getAllFacilities(); // -> { facilityName: LoggerFacility }

Creating facility manually:

import {default as logger, LOG_LEVEL, LoggerFacility} from "meta2-logger";

// Create facility and pass logger as first argument, options are optional
const facility = new LoggerFacility(logger, "facilityName", {
	level: LOG_LEVEL.INFO
});

// Log to facility
facility.info("Message");

Setting log level

Log levels can be set on logger, facility and on targets.

Classes Logger, LoggerFacility and logging targets support setLevel and getLevel methods.

Example:

import {default as logger, LOG_LEVEL} from "meta2-logger";

logger.setLevel(LOG_LEVEL.INFO);

logger.debug("Message"); //Does not log
logger.warn("Message"); //Does log

logger.getLevel(); //Returns LOG_LEVEL.INFO;

// Changing log level on target(s)
logger.toConsole({
	level: LOG_LEVEL.NOTICE
});

logger.getTarget("__console__").setLevel(LOG_LEVEL.DEBUG);
logger.getTarget("__console__").getLevel(); // -> LOG_LEVEL.DEBUG

// Also works on LoggerFacility
const facility = logger.facility("http");

facility.setLevel(LOG_LEVEL.WARN);
facility.getLevel(); // -> LOG_LEVEL.WARN

Configuring Logging Targets

Logging target represents destination transport for log messages.

import {default as logger, ConsoleTarget, LOG_LEVEL} from "meta2-logger";

logger.to("uniqueLoggerId", new ConsoleTarget({
	level: Logger.LOG_LEVEL.INFO,
	timestamp: true,
	colorize: true
}));

See built-in targets below. Logging target class must implement ILoggerTarget interface.

Console Target

Prints log messages to stdout (console).

import {default as logger, ConsoleTarget, LOG_LEVEL} from "meta2-logger";

logger.toConsole({
	// Log level
	level: LOG_LEVEL.DEBUG,

	// Facilities - null to accept all facilities
	facilities: [ "http", "broker", "etc" ],

	// If to print time and date
	timestamp: true,

	// If to print with colors
	colorize: true
});

// Or
logger.to("myConsole", new ConsoleTarget(opts));

Sample output:

2018-01-10 14:24:30 warn: [http] (reqId=123) Bad request
2018-01-10 14:24:30 info: Something happend

eg.:
date time level: [facility] (meta=data) Formatted message

Notice: Method toConsole overrides previous console target settings. Use logger.to(...) method to define more targets.

File Target

Appends log messages to specified file.

Messages are formatted the same way as to the console.

File target can be set for multiple files with different configurations.

import {default as logger, FileTarget, LOG_LEVEL} from "meta2-logger";

logger.toFile("filename.log", {
	// Log level
	level: LOG_LEVEL.DEBUG,

	// Facilities - null to accept all facilities
	facilities: [ "http", "broker", "etc" ],

	// If to print time and date
	timestamp: true,
});

// Or
logger.to("myFile", new FileTarget("filename.log", opts));

Sample output:

2018-01-10 14:24:30 warn: [http] (reqId=123) Bad request
2018-01-10 14:24:30 info: Something happend

JSON File Target

Appends log messages to specified JSON file.

File target can be set for multiple files with different configurations.

import {default as logger, JsonFileTarget, LOG_LEVEL} from "meta2-logger";

logger.toJsonFile("filename.json", {
	// Log level
	level: LOG_LEVEL.DEBUG,

	// Facilities - null to accept all facilities
	facilities: [ "http", "broker", "etc" ]
});

// Or
logger.to("myJsonFile", new JsonFileTarget("filename.json", opts));

Sample output:

{},
{ timestamp: 1515557050.342, level: 5, facility: "http", msg: "Bad request", meta: { reqId: 123 } },
{ timestamp: 1515557086.342, level: 7, facility: null, msg: "Something happend", meta: {} }

Recommended way to parse JSON log file:

const fs = require("fs");

const logFile = fs.readFileSync("filename.json", { encoding: "utf-8" });
const logMessages = JSON.parse("[" + logFile + "]").slice(1);

Memory Target

Stores log messages in memory.

import {default as logger, MemoryTarget, LOG_LEVEL} from "meta2-logger";

logger.toMemory({
	// Log level
	level: LOG_LEVEL.DEBUG,

	// Facilities - null to accept all facilities
	facilities: [ "http", "broker", "etc" ],

	// How many messages to store, default 1000
	limit: 1000
});

// Get messages
logger.getTarget("__memory__").getMessages();

// Or
const memTarget = new MemoryTarget(opts);

logger.to("myMemory", memTarget);

memTarget.getMessages();

GrayLog Target

Sends log messages to GrayLog server using GELF protocol.

import {default as logger, GraylogTarget, LOG_LEVEL} from "meta2-logger";

logger.toGrayLog({
	// Log level
	level: LOG_LEVEL.DEBUG,

	// Facilities - null to accept all facilities
	facilities: [ "http", "broker", "etc" ],

	// GrayLog server port
	graylogPort: 12201,

	// GrayLog server hostname
	graylogHostname: "localhost",

	// Connection type, 'lan' or 'wan'
	connection: "lan",

	// Max chunk size for WAN type
	maxChunkSizeWan: 1420,

	// Max chunk size for LAN type
	maxChunkSizeLan: 8154,

	// Host (application) identifier
	host: "_unspecified_",

	// GELF protocol version
	version: "1.0",

	// Facility prefix string - is added before facility name
	facilityPrefix: "",

	// If to log gelf client debug messages to stdout
	debugGelfClient: false,

	// Additional static message fields
	additionalFields: { "myfield": "myValue" }
});

// Or
logger.to("myGrayLogTarget", new GraylogTarget(opts));

Notice: Message meta-data are added as additional fields.

Custom Logging Target

To create custom logging target define class which implements ILoggerTarget interface. Or extend class BaseTarget.

import * as util from "util";

import {
	LOG_LEVEL, ILoggerTarget, ILoggerMetaData, BaseTarget, IBaseTargetOptions,
	default as logger
} from "./interfaces";

export interface ISuchTargetOptions extends IBaseTargetOptions {
	soFunny?: boolean;
}

export class SuchTarget extends BaseTarget {

	protected soFunny: boolean:

	public constructor(options: ISuchTargetOptions) {

		super(options);

		this.soFunny = options.soFunny || false;

	}

	/**
	 * Log message
	 *
	 * @param level Log level
	 * @param facility Facility
	 * @param args Message arguments
	 * @param meta Meta-data
	 */
	public log(level: LOG_LEVEL, facility: string, args: any, meta: ILoggerMetaData) {

		// Check such level
		if (level > this.level) return;
		if (this.facilities.length > 0 && this.facilities.indexOf(facility) < 0) return;

		// Format wow message
		const wowMessage = util.format.apply(this, args);

		// Create message parts
		const messageParts = [
			"Wow", Date.now(),
			"such", this.levelLabels[LOG_LEVEL.DEBUG].toUpperCase(),
			"many", facility,
			wowMessage,
			"plz",
			JSON.stringify(meta)
		];

		if(this.soFunny)
			messageParts.push("so funny");

		// Write message
		this.write(level, facility, messageParts, meta);

	}

	/**
	 * Write formatted log message
	 *
	 * @param level Log level
	 * @param facility Facility
	 * @param msg Formated message parts
	 * @param meta Meta-data
	 */
	protected write(level: LOG_LEVEL, facility: string, message: Array<string>, meta: ILoggerMetaData) {

		console.log("So scare", message.join(" "));

	}

}

// Use such target
logger.to("suchTarget", new SuchTarget({
	level: LOG_LEVEL.DEBUG,
	soFunny: true
}));

Utility Functions

parseLogLevel

This function parses log level from string to number. Is case insensitive.

Usage:

import {default as logger, parseLogLevel} from "meta2-logger";

logger.toConsole({
	level: parseLogLevel("criTIcal")
});

@Logging decorator

Decorator to configure and assign LoggerFacility instance to a class.

Note: decorators are experimental TypeScript feature.

Usage:

import {Logger, Logging, LoggerFacility, LOG_LEVEL} from "meta2-logger";

const myLogger = new Logger();

// Second argument can be omitted
@Logging("facilityName", {
	logger: myLogger, // When omitted default logger will be used
	level: LOG_LEVEL.DEBUG
})
class MyClass {

	public log: LoggerFacility;

	public doSomething(){

		this.log.info("Hello");

	}

}

const obj = new MyClass();
obj.doSomething(); // -> will log debug: [facilityName] Hello

@LogMethodCall decorator

Decorator to log every method call. When @Logging decorator is applied it's configuration will be used.

Note: decorators are experimental TypeScript feature.

Usage:

import {Logger, Logging, LogMethodCall, LoggerFacility, LOG_LEVEL} from "meta2-logger";

const myLogger = new Logger();

// Second argument can be omitted
@Logging("facilityName", {
	logger: myLogger, // When omitted default logger will be used
	level: LOG_LEVEL.DEBUG
})
class MyClass {

	public log: LoggerFacility;

	/*
	 * Decorator arguments (all are optional):
	 * - LOG_LEVEL
	 * - If to capture arguments
	 * - Message prefix
	 */
	@LogMethodCall(LOG_LEVEL.DEBUG, true, "Hey")
	public doSomething(...args){
		return true;
	}

}

const obj = new MyClass();
obj.doSomething("hello", "world");

will log:

debug: [facilityName] (method=doSomething) (class=MyClass) Hey Method MyClass.doSomething called with arguments [ 'hello', 'world' ]
	at class_1.descriptor.value [as doSomething] (/path/to/app/node_modules/meta2-logger/dist/src/util.ts:90:38)
    at Logger.info (/path/to/app/node_modules/meta2-logger/dist/src/Logger.js:286:14)
    at Object.<anonymous> (/path/to/app/index.js:30:24)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)

Logging Stack Trace (experimental)

Logger has built-in feature to capture stack trace for every log message. If enabled call stack will be available as trace meta value. Note that internal logger function calls are excluded.

Warning: Capturing of stack traces has a significant impact on performance and should be used only for temporary debugging.

This feature is currently experimental.

Also, note that this feature does not affect possibility to log stack trace by passing an error object as an argument to a log method - eg ... catch(err){ logger.error("Operation failed:", err); } will work always.

Following example:

import {default as logger} from "meta2-logger";

logger.enableTrace();
logger.toConsole();

logger.info("Hello!");

// To turn it off
logger.enableTrace(false);

will print to console:

info: hello
  >>
    at Logger.info (/path/to/app/node_modules/meta2-logger/dist/src/Logger.js:286:14)
    at Object.<anonymous> (/path/to/app/index.js:30:24)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)

API Reference

class Logger {
	getLevel(): LOG_LEVEL;
	setLevel(level: LOG_LEVEL);
	log(level: LOG_LEBEL, ...args): void;
	debug(...args): void;
	info(...args): void;
	notice(...args): void;
	warn(...args): void;
	warning(...args): void;
	error(...args): void;
	crit(...args): void;
	alert(...args): void;
	emerg(...args): void;
	panic(...args): void;
	facility(name: string): LoggerFacility;
	getAllFacilities(): { [K: string]: LoggerFacility };
	to(id: string, target: ILoggerTarget): Logger;
	getAllTargets(): { [K: string]: ILoggerTarget };
	getTarget(id: string): ILoggerTarget|null;
	toConsole(options: IConsoleTargetOptions = {}): Logger;
	toFile(filename: string, options: IFileTargetOptions = {}): Logger;
	toJsonFile(filename: string, options: IFileTargetOptions = {}): Logger;
	toGrayLog(options: IGraylogTargetOptions): Logger;
	enableTrace(enabled: boolean);
	isTraceEnabled(): boolean;

	// Close all I/O and socket handles
	close();
}

class LoggerFacility {
	constructor(protected logger: Logger, protected prefix: string);
	getLevel(): LOG_LEVEL;
	setLevel(level: LOG_LEVEL);
	debug(...args): void;
	info(...args): void;
	notice(...args): void;
	warn(...args): void;
	warning(...args): void;
	error(...args): void;
	crit(...args): void;
	alert(...args): void;
	emerg(...args): void;
	panic(...args): void;
}

enum LOG_LEVEL {
	DEBUG = 7,
	INFO = 6,
	NOTICE = 5,
	WARN = 4,
	ERROR = 3,
	CRITICAL = 2,
	ALERT = 1,
	EMERGENCY = 0
}

interface ILogger {
	log(...args);
	debug(...args);
	info(...args);
	notice(...args);
	warn(...args);
	warning(...args);
	error(...args);
	crit(...args);
	alert(...args);
	emerg(...args);
	panic(...args);
	getLevel(): LOG_LEVEL;
	setLevel(level: LOG_LEVEL);
}

interface ILoggerMetaData {
	[ K: string ]: string|number|boolean|Date;
	[ K: number ]: string|number|boolean|Date;
}

interface ILoggerTarget {
	log: (level: LOG_LEVEL, facility: string, args: Array<any>, meta: ILoggerMetaData) => void;
	close: () => void;
	getLevel(): LOG_LEVEL;
	setLevel(level: LOG_LEVEL);
}

function parseLogLevel(level: string): LOG_LEVEL;

Development

# Install dependencies
npm install

# Transpile TypeScript
npm run build

# Run linter
npm run lint

# Run tests
npm test

License

This library is published under MIT license.

Copyright (c) 2017 - 2018 Jiri Hybek, [email protected]