JavaScript logger with isomorphicity in mind.
Supports Bunyan and Sentry.
iso-log is build with different runtime environments and platforms (browser vs. Node.js) in mind:
On the server:
- iso-log uses @haensl/log in development and bunyan on QA and production environments (if installed). If Sentry configuration is provided and
@sentry/node
is installed, iso-log will use the@sentry/node
package for crash reporting.
On the client:
- iso-log uses @haensl/log. If Sentry configuration is provided, iso-log will use the
@sentry/browser
package for crash reporting if installed.
Attention: Even though the package is named "iso-" and has isomorphicity, i.e. use on both server and client, in mind, the code does not come transpiled for all platforms by default. This package is exposed as a CommonJS module. The code should, however, work without problems in ESM environments. Please file a bug if it doesn't.
$ npm install -S @haensl/iso-log @sentry/node @sentry/browser bunyan
$ yarn add @haensl/iso-log @sentry/node @sentry/browser bunyan
-
Use iso-log in your projects:
ESM, i.e.
import
import log from '@haensl/iso-log'; // iso-log needs initialization once in your app log.init({ environment: 'production', name: 'my log' }); // use it like you use console.log, console.error, ... log.info('Log ready for operations');
CJS, i.e.
require
const log = require('@haensl/iso-log'); // iso-log needs initialization once in your app log.init({ environment: 'development', name: 'my log' }); // use it like you use console.log, console.error, ... log.info('Log ready for operations');
iso-log offers the same API console
does plus an init()
function:
debug(...args)
: Log at debug log level.
error(...args)
: Log at error log level.
info(...args)
: Log at info log level.
log(...args)
: Alias for info
.
warn(...args)
: Log at warning log level.
init({ environment, name, sentry })
: Initialize the log. (See Configuration).
The log needs to be initialized before first use to work properly. It will buffer calls made before the module was init()
ialized.
const log = require('@haensl/iso-log');
const environments = require('@haensl/environments');
// calls to log.error(), log.info(), log.debug(), etc are buffered until `init()` is called.
log.init({
// Set the environment your app runs in.
// String.
// If omitted, log behaves like on production.
environment: environments.qa,
// Provide a name for the log.
// String.
// Optional.
name: 'My log',
// Provide Sentry configuration.
// Object.
// Optional.
// This config object is handed to Sentry: `Sentry.init(sentry)`
sentry: {
dsn: 'your sentry DSN here'
}
});
// log will process all buffered calls once it is initialized.
// log is now ready for use.
When calling init()
, you can provide the runtime environment via the environment
option:
const log = require('@haensl/iso-log');
log.init({
environment: 'development' // Set the environment your app runs in. String.
});
Currently supported values are: 'development'
, 'qa'
, 'production'
and 'test'
.
You can use @haensl/environments
for convenience.
iso-log determines the runtime platform by presence/absence of a global window
object at the time init()
is called:
window
available -> browser- no
window
-> server
Report errors and warnings to Sentry
You can provide a sentry
configuration object to the initialization call. If you do, all Error
objects handed to log.error
and log.warn
will be forwarded to Sentry.
You can attach additional information about the error by setting theses props on the Error
object:
-
user
: Seterror.user
to e.g. a user ID to pin the user for which the error occurred:const log = require('@haensl/iso-log'); // ... try { const data = await user.getData(); } catch (error) { // Attach user id to the error. error.user = user.id; log.error('Failing to retrieve user data', error); }
-
request
: Seterror.request
to provide information about any network request the error pertains to.const log = require('@haensl/iso-log'); // ... try { const data = await getData(); } catch (error) { // Attach request information. error.request = { url: 'https://url.to.data' }; log.error('Failing to retrieve data', error); }
-
response
: Seterror.response
to provide information about any network responses associated with the error.const log = require('@haensl/iso-log'); const fetch = require('node-fetch'); // ... const response = await fetch(apiRequest); if (!response.ok) { const error = new Error('API request failing'); error.response = { status: response.status, statusText: response.statusText, body: typeof response.text === 'function' ? await response.text() : undefined } log.error(error); }
-
ctx
: Provide additional context to the error by adding props toerror.ctx
.const log = require('@haensl/iso-log'); const fetch = require('node-fetch'); try { } catch (error) { // Provide any additional helpful data in `error.ctx` to give context to the error. error.ctx = { userInput: 'inputValue', foo: 1 }; log.error(error); }
-
koa
: If you're using Koa, iso-log will try to pull context information fromerror.koa
.const log = require('@haensl/iso-log'); // Example error middleware const errorMiddleware = () => async (ctx, next) => { try { await next(); } catch (error) { error.koa = ctx; log.error(error); } };
See e.g.
koa-error-middleware
.