Introduction
loglayer
is a unified logger that routes logs to various logging libraries and cloud providers while providing a fluent API for specifying log messages, metadata and errors, enhancing and standardizing the developer experience around writing logs.
Why LogLayer?
Challenges with logging—choosing, using, and maintaining the right logger for various projects—are a common experience. While most loggers offer the usual methods like info
, warn
, and error
, they vary significantly in handling structured metadata or Error
objects. This can lead to ad-hoc solutions, like serializing errors or writing custom pipelines, just to get logs formatted correctly.
LogLayer was built to address these pain points by introducing a fluid, expressive API. With methods like withMetadata
and withError
, LogLayer separates object injection from the log message itself, making logging code both cleaner and more maintainable.
Logs are processed through a LogLayer Transport, which acts as an adapter for the preferred logging library. This design offers several key advantages:
Multi-Transport Support: Send logs to multiple destinations (e.g., DataDog and New Relic) simultaneously. This feature can be used to ship logs directly to DataDog without relying on their APM package or sidecars.
Easy Logger Swapping: If Pino has been used with Next.js, issues might arise where it doesn’t work out of the box after a production build without webpack hacks. With LogLayer, a better-suited library can be swapped in without touching the logging code.
Battle Tested
LogLayer has been in production use for at least three years at Airtop.ai (formerly Switchboard) in multiple backend and frontend systems.
LogLayer is not affiliated with Airtop.
Bring Your Own Logger
LogLayer is designed to sit on top of your logging library(s) of choice, such as pino
, winston
, bunyan
, and more.
Learn more about logging transports.
Consistent API
No need to remember different parameter orders or method names between logging libraries:
// With loglayer - consistent API regardless of logging library
log.withMetadata({ some: 'data' }).info('my message')
// Without loglayer - different APIs for different libraries
winston.info('my message', { some: 'data' }) // winston
bunyan.info({ some: 'data' }, 'my message') // bunyan
Start with basic logging.
Standardized Error Handling
loglayer
provides consistent error handling across all logging libraries:
// Error handling works the same way regardless of logging library
log.withError(new Error('test')).error('Operation failed')
See more about error handling.
Powerful Plugin System
Extend functionality with plugins:
const log = new LogLayer({
plugins: [{
onBeforeDataOut: (params) => {
// Redact sensitive information before logging
if (params.data?.password) {
params.data.password = '***'
}
return params.data
}
}]
})
See more about using and creating plugins.
Multiple Logger Support
Send your logs to multiple destinations simultaneously:
import { LogLayer } from 'loglayer'
import { PinoTransport } from "@loglayer/transport-pino"
import { DatadogBrowserLogsTransport } from "@loglayer/transport-datadog-browser-logs"
import { datadogLogs } from '@datadog/browser-logs'
import pino from 'pino'
// Initialize Datadog
datadogLogs.init({
clientToken: '<CLIENT_TOKEN>',
site: '<DATADOG_SITE>',
forwardErrorsToLogs: true,
})
const log = new LogLayer({
transport: [
new PinoTransport({
logger: pino()
}),
new DatadogBrowserLogsTransport({
id: "datadog",
logger: datadogLogs
})
]
})
// Logs will be sent to both Pino and Datadog
log.info('User logged in successfully')
See more about multi-transport support.
Easy Testing
Built-in mocks make testing a breeze:
import { MockLogLayer } from 'loglayer'
// Use MockLogLayer in your tests - no real logging will occur
const log = new MockLogLayer()
See more about testing.