
Security News
OWASP 2025 Top 10 Adds Software Supply Chain Failures, Ranked Top Community Concern
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.
@leaflink/snitch
Advanced tools
Simple and extensible browser logging, inspired by Winston.
$ npm i @leaflink/snitch
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.
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:
errorwarninfodebugThese 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).
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());
}
| 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');
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)
}
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);
}
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 });
}
main.ts
import logger from '@leaflink/snitch';
import { ConsoleTransport } from '@leaflink/snitch/transports/console';
logger.addTransport(new ConsoleTransport({
level: 'info'
}));
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!
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();
})
FAQs
Front end logging inspired by winston.
We found that @leaflink/snitch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.