@leaflink/snitch
v1.2.1
Published
Front end logging inspired by winston.
Downloads
1,869
Keywords
Readme
@leaflink/snitch
Simple and extensible browser logging, inspired by Winston.
Table of Contents
Installation
$ npm i @leaflink/snitch
Transports
Transports are a way of routing log messages to multiple destinations, with the ability to pre-process or format the message. @leaflink/snitch
includes three transports by default (console
, Sentry, and Datadog), but they can be extended using the Transport
type exported by the logger.
Log Levels
Transports can be created with a log level to only handle messages with a certain severity. Log levels supported by @leaflink/snitch
, in decreasing order by severity, are:
error
warn
info
debug
These levels cascade up, so a transport created with level debug
will handle logs with that level as well as info
, warn
, and error
, but a transport created with level error
will not handle logs with the levels warn
, info
, or debug
.
The level a log was called at is passed to transports to help determine how a message should be handled (for example, logging with console.<level>
in the console transport).
Usage
Singleton Logger
The default export exposed by @leaflink/snitch
is a singleton logger instance with no initial transports, which can be shared between modules easily. It does not include any transports by default to allow flexibility in per-environment transports.
import logger from '@leaflink/snitch';
import { ConsoleTransport } from '@leaflink/snitch/transports/console';
if (config.debug) {
logger.addTransport(new ConsoleTransport());
}
New Logger
| Name | Default | Description |
| --- | --- | --- |
| transports
| []
| Define transports when creating new logger instead of adding with .addTransport
|
In other situations, you may want to have a logger instance (or multiple instances) created and managed inside your application. To support this, @leaflink/snitch
also exports a Logger
class that can be used to create logger instances, optionally with predefined transports.
import { Logger } from '@leaflink/snitch';
import { ConsoleTransport } from '@leaflink/snitch/transports/console';
const loggerInstance = new Logger({
transports: [new ConsoleTransport()],
});
// `logger.log` is an alias for `logger.info` for convenience
loggerInstance.log('Example log message');
Console Transport
Parameters:
| Name | Default | Description |
| --- | --- | --- |
| level
| debug
| Minimum log level to handle. |
main.ts
import logger from '@leaflink/snitch';
import { ConsoleTransport } from '@leaflink/snitch/transports/console';
logger.addTransport(new ConsoleTransport());
call in component file
import logger from '@leaflink/snitch';
try {
await someErroringMethod()
} catch (err) {
logger.error(err)
}
Sentry Transport
Parameters:
| Name | Default | Description |
| --- | --- | --- |
| level
| debug
| Minimum log level to handle. |
| sentryInstance
| N/A, required | Initialized Sentry logger instance. |
main.ts
import * as Sentry from '@sentry/vue';
import logger from '@leaflink/snitch';
import { SentryTransport } from '@leaflink/snitch/transports/sentry';
// Important: init Sentry instance before creating transport
Sentry.init({
// ...
});
logger.addTransport(new SentryTransport({
sentryInstance: Sentry,
}));
call in component file
import logger from '@leaflink/snitch';
try {
await someErroringMethod()
} catch (err) {
// optional error context object
const errorContext: Record<string, any> = getErrorContext();
// `err` is Error | string
logger.error(err, errorContext);
}
Datadog Logs Transport
Parameters:
| Name | Default | Description |
| --- | --- | --- |
| level
| info
| Minimum log level to handle. |
| datadogLogsInstance
| N/A, required | Initialized Datadog Logs instance. |
See Datadog Logs documentation for more on custom logging with Datadog.
main.ts
import { datadogLogs } from '@datadog/browser-logs';
import logger from '@leaflink/snitch';
import { DatadogTransport } from '@leaflink/snitch/transports/datadog';
// Important: init Datadog logs instance before creating transport
datadogLogs.init({
// ...
});
logger.addTransport(new DatadogTransport({
datadogLogsInstance: datadogLogs,
}));
call in component file
import logger from '@leaflink/snitch';
logger.info('File loaded!');
try {
await someErroringMethod()
} catch (err) {
// If an Error is passed as the message, this is captured as an exception in Datadog
logger.error(err, { id: 123 });
}
With Log Level
main.ts
import logger from '@leaflink/snitch';
import { ConsoleTransport } from '@leaflink/snitch/transports/console';
logger.addTransport(new ConsoleTransport({
level: 'info'
}));
Custom Transports
custom-transport.ts
import { LogLevel, Transport } from '@leaflink/snitch';
// imagine this has a `report(options<{message, context}>)` method
import CustomDestinationInstance from '@example/destination';
interface CustomTransportOptions {
level?: LogLevel;
}
export class CustomTransport implements Transport {
level: LogLevel;
log: (message: string | object, meta: Record<string, unknown> | undefined, level: LogLevel) => void;
constructor(opts?: ConsoleTransportOptions) {
this.level = opts?.level || 'debug';
this.log = (message, meta) => {
CustomDestinationInstance.report({
message,
context: 'meta',
})
};
}
}
main.ts
import logger from '@leaflink/snitch';
import { CustomTransport } from './custom-transport';
logger.add(new CustomTransport());
Note: You can add a custom transport in your project, but consider opening a PR in this repo instead!
Testing
Stubbing snitch
When there's a need to mock this logger or you want to test if a specific log was printed, you can just mock it inside you test file:
import logger from '@leaflink/snitch';
vi.mock('@leaflink/snitch');
it('should redirect to error page if fetching the user profile fails', async () => {
// ...
expect(logger.error).toHaveBeenCalled();
})