Logger for browser and node
The nightingale is a bird best known for its powerful and beautiful song.
Unlike most popular loggers (winston, bunyan) handlers (also called transporters) are not defined at the logger, but rather with the configure
method in nightingale
or nightingale-app-*
. That means libraries can freely use the nightingale-logger
package without much dependencies and letting the application to configure all loggers ! It's more closer to the debug philosophy (the DEBUG
env variable is in fact supported by nightingale-console
, the basic handler for node). nightingale
is and always will be compatible with all versions of nightingale-logger
.
npm install --save nightingale
npm install --save nightingale-console # for console handler in nodejs
npm install --save nightingale-browser-console # for console handler in browser
You can also use pre-configured isomorphic nightingale-app-console. If you use react-native or expo, check out nightingale-app-react-native.
npm install --save nightingale nightingale-console
import { configure, Logger, Level, ConsoleHandler } from "nightingale";
configure([
{
handlers: [new ConsoleHandler(Level.WARN)],
},
{
keys: ["mylib", "myotherlib"],
handlers: [new ConsoleHandler(Level.ALL)],
},
{
pattern: /^app\.server$/,
handlers: [new ConsoleHandler(Level.ALL)],
stop: true, // means the following config won't be used, if the pattern matches.
},
{
pattern: /^app(?!\.server)/,
handlers: [new ConsoleHandler(Level.INFO)],
},
]);
// in one of your controllers
const logger = new Logger("app.controllers");
logger.debug("This is a log"); // will not be displayed
// in your server.js file
const logger = new Logger("app.server");
logger.debug("This is a log"); // will be displayed
You can configure several handlers with different Level
, like console, slack, sentry.
Ensure the configure is always called before the first log! For example:
import "./configure-logger";
import "./myApp";
npm install --save nightingale-logger
import Logger from "nightingale-logger";
const logger = new Logger("mylib");
logger.info("This is a log");
logger.warn("This is a warning !");
logger.success("It works !");
You can also use pre-configured isomorphic nightingale-app-console.
npm install --save nightingale nightingale-browser-console
import { configure, levels } from "nightingale";
import { BrowserConsoleHandler } from "nightingale-browser-console";
configure([
{
key: "app",
handlers: [new BrowserConsoleHandler(Level.INFO)],
},
]);
See the Logger API, with all the methods you call to log things.
DEBUG=worker1 node example/debug
?DEBUG=worker1
localStorage.DEBUG='worker1'
Values are minimatch patterns and separated by ,
.
import Koa from "koa";
import Logger, { configure, Level } from "nightingale";
import { ConsoleHandler } from "nightinale-console";
import webProcessor from "nightinale-web-processor";
const app = new Koa();
const logger = new Logger("app");
configure([
{
key: "app",
handlers: [new ConsoleHandler(Level.ALL)],
processors: [webProcessor],
},
]);
app.use(async (ctx) => {
logger.info("something to log !", { context: ctx });
});
app.use(async (ctx) => {
ctx.logger.info("something to log !", { context: ctx });
});
How a log is processed: has a layout and an output. Also define a minimum level.
Log using console
.
import { configure, levels, ConsoleHandler } from "nightingale";
configure([
{
key: "app",
handlers: [new ConsoleHandler(Level.INFO)],
},
]);
DEBUG
DEBUG=* node .
DEBUG='*'; # debug everything
DEBUG=app # debug for logger with key 'app'
DEBUG=app:* # debug for logger with key 'app' and all its children
DEBUG=app,nightingale # debug for logger with key 'app' and 'nightingale'
DEBUG=/^app/ # debug for logger with key starting with 'app'
DEBUG=/^(app|nightingale$)/ # debug for logger with key starting with 'app' and key 'nightingale'
DEBUG='*,-app'; # debug everything except app
DEBUG='*,-app:*'; # debug everything except app and all its children
Use source maps to display error stack trace
Since node 12.12.0, you can use --enable-source-maps
while running node.
Usage
import { configure, levels } from "nightingale";
import { ConsoleHandler } from "nightingale-browser-console";
configure([{ handlers: [new ConsoleHandler(Level.INFO)] }]);
Theme
If you have a dark console theme, you can set this config in your localStorage :
localStorage.NIGHTINGALE_THEME = "dark";
You can also force this option:
import { ConsoleHandler } from "nightingale-browser-console";
configure([{ handlers: [new ConsoleHandler(Level.INFO, { theme: "dark" })] }]);
Debug with localStorage
localStorage.debug = "*"; // debug everything
localStorage.debug = "app"; // debug for logger with key 'app'
localStorage.debug = "app,nightingale"; // debug for logger with key 'app' and 'nightingale'
localStorage.debug = "/^app/"; //debug for logger with key starting with 'app'
localStorage.debug = "/^(app|nightingale$)/"; // debug for logger with key starting with 'app' and key 'nightingale'
localStorage.debug = "*,-app"; // debug everything except app
localStorage.debug = "*,-app:*"; // debug everything except app and all its children
Debug with query, in the url
?DEBUG='*'; // debug everything
?DEBUG=app // debug for logger with key 'app'
?DEBUG=app,nightingale // debug for logger with key 'app' and 'nightingale'
?DEBUG=/^app/ // debug for logger with key starting with 'app'
?DEBUG=/^(app|nightingale$)/ // debug for logger with key starting with 'app' and key 'nightingale'
?DEBUG=*,-app // debug everything except app
?DEBUG=*,-app:* // debug everything except app and all its children
Use source maps to display error stack trace
In production:
Send your log to an external tool like sentry. Sentry allows you to send the source maps after building (if you use webpack, you can use hidden-source-map
to generate .map
files, send them to sentry, and remove them so they are not accessible).
In development:
devtool
configuration. For best stack trace, use source-map
but it's the slowest option.source-map-support/register
.Useful for testing purposes
import { configure, levels, StringHandler } from "nightingale";
import { BrowserConsoleHandler } from "nightingale-browser-console";
const stringHandler = new StringHandler(Level.INFO);
configure([
{
key: "app",
handlers: [stringHandler],
},
]);
console.log(stringHandler.string);
You can find handlers on npm
How the record is formatted, with its colors.
import { RawFormatter } from "nightingale";
RawFormatter.format(record);
import { MarkdownFormatter } from "nightingale";
MarkdownFormatter.format(record);
import { JSONFormatter } from "nightingale";
JSONFormatter.format(record);
You can find formatters on npm
Where the log is sent: console, file, ...
Output using console.log/error
or process.stdout/stderr
You can find outputs on npm
Add extra data in the record
import { Logger } from "nightingale";
class MyCustomLogger extends Logger {
myCustomMethod(message) {
return this.info(`custom message: ${message}`);
}
}
const logger = new MyCustomLogger("app");
import { configure } from "nightingale";
import errorProcessor from "./myErrorProcessor";
configure([{ processors: [errorProcessor] }]);
import { addGlobalHandler, levels } from "nightingale";
import { SentryHandler } from "nightingale-sentry";
configure([{ handlers: [new SentryHandler(Level.ERROR)] }]);
You can create children.
import { Logger } from "nightingale";
const loggerApp = new Logger("app");
const loggerMyService = loggerApp.child("myService");
// loggerMyService key is `app.myService`
You can use context to add data to each log.
import { Logger } from "nightingale";
const loggerMyService = new Logger("app.myService");
export function someAction(arg1) {
const logger = loggerMyService.context({ arg1 });
logger.info("starting");
// do stuff
logger.info("done");
}