dev-resources.site
for different kinds of informations.
LogLayer: A Modern Logging Library for TypeScript / JavaScript
Ever found yourself wrestling with different logging libraries across projects? Or maybe you've spent hours trying to standardize how errors and metadata are logged across your codebase?
I built LogLayer, an open-source solution to solve these common logging challenges by improving the developer experience around writing logs.
What is LogLayer?
LogLayer is a unified logging layer that sits on top of your favorite logging libraries (like Pino, Winston, Bunyan) and cloud providers (AWS, Google Cloud, DataDog, etc).
It provides a consistent, fluent API for logging messages, metadata, and errors while routing your logs to wherever they need to go.
Here's a quick example of what logging with LogLayer looks like:
import { LogLayer } from 'loglayer'
import { PinoTransport } from '@loglayer/transport-pino'
import pino from 'pino'
// Setup LogLayer with Pino
const log = new LogLayer({
transport: new PinoTransport({
logger: pino()
})
})
// Log with metadata
log.withMetadata({ userId: '123', action: 'login' })
.info('User logged in successfully')
// Logging with context (persists across log calls)
log.withContext({ requestId: '123' })
log.info('Processing request') // Will include requestId
try {
// ... some code that might throw
} catch (error) {
log.withError(error)
.withMetadata({ userId: '123' })
.error('Failed to process user request')
}
Benefits of using LogLayer
Swap Logging Libraries
Maybe you've discovered late in the game that Next.js and Pino don't play very well without additional configuration when you're building your Next.js project for the first time. You might want to immediately switch to another library to save yourself the trouble, but doing that might mean you would need to refactor all your logging code.
With LogLayer, you can easily swap logging libraries without changing your code.
Consistent API Across All Logging Libraries
No more remembering different parameter orders or method names:
// With LogLayer - consistent API everywhere
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
Multi-Transport Support Out of the Box
Want to send logs to both DataDog and your logger? No problem:
import { LogLayer } from 'loglayer'
import { datadogLogs } from '@datadog/browser-logs'
import { PinoTransport } from "@loglayer/transport-pino"
import { DatadogBrowserLogsTransport } from "@loglayer/transport-datadog-browser-logs"
// Initialize Datadog
datadogLogs.init({
clientToken: '<CLIENT_TOKEN>',
site: '<DATADOG_SITE>',
forwardErrorsToLogs: true,
sampleRate: 100
})
const log = new LogLayer({
transport: [
new PinoTransport({
logger: pino()
}),
new DatadogBrowserLogsTransport({
logger: datadogLogs
})
]
})
// Logs go to both Pino and DataDog
log.info('User logged in successfully')
Clean Error Handling
Standardized error handling that works the same way across all logging libraries:
// Error handling works consistently
log.withError(new Error('test'))
.withMetadata({ userId: '123' })
.error('Operation failed')
Powerful Plugin System
Extend functionality with plugins for things like redacting sensitive information:
const log = new LogLayer({
plugins: [{
onBeforeDataOut: (params) => {
// Redact sensitive information before logging
if (params.data?.password) {
params.data.password = '***'
}
return params.data
}
}]
})
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()
Getting Started
Installation is straightforward:
npm install loglayer
import { LogLayer, ConsoleTransport } from 'loglayer'
const log = new LogLayer({
transport: new ConsoleTransport({
logger: console,
}),
})
log.info('Hello world!')
Learn More
- π Official Documentation
- π GitHub Repository
- π¦ NPM Package
Featured ones: