Adapters
Send logs anywhere with custom adapters
Adapters connect afterlog to your logging infrastructure. afterlog doesn't send logs anywhere by default - you provide the adapter.
Console Adapter
Built-in adapter for development:
import { createConsoleAdapter } from "afterlog"
const adapter = createConsoleAdapter({
method: "log", // console method: log, info, warn, error, debug
pretty: false, // pretty print JSON
includeTimestamp: false,
})
afterlog.configure({ adapter })Custom Adapter
Implement the LoggerAdapter interface:
const myAdapter = {
async emit(event) {
await fetch("https://logs.example.com/v1/input", {
method: "POST",
body: JSON.stringify(event),
})
},
}Interface
interface LoggerAdapter<T extends BaseWideEvent> {
emit(event: Finalized<T>): void | Promise<void>
flush?(): Promise<void>
destroy?(): Promise<void>
isHealthy?(): boolean | Promise<boolean>
}Only emit is required.
Datadog Adapter
const datadogAdapter = {
async emit(event) {
await fetch("https://http-intake.logs.datadoghq.com/v1/input", {
method: "POST",
headers: {
"Content-Type": "application/json",
"DD-API-KEY": process.env.DD_API_KEY,
},
body: JSON.stringify({
...event,
ddsource: "nodejs",
service: process.env.SERVICE_NAME,
}),
})
},
}File Adapter
import fs from "fs"
const fileAdapter = {
stream: fs.createWriteStream("/var/log/app.jsonl", { flags: "a" }),
emit(event) {
return new Promise((resolve, reject) => {
this.stream.write(JSON.stringify(event) + "\n", (err) => {
if (err) reject(err)
else resolve()
})
})
},
flush() {
return new Promise((resolve) => {
this.stream.end(resolve)
})
},
}Lifecycle Methods
flush()
Called during graceful shutdown:
adapter: {
async flush() {
await this.buffer.flush()
}
}destroy()
Called when afterlog instance is destroyed:
adapter: {
async destroy() {
await this.client.close()
}
}isHealthy()
Health check for monitoring:
adapter: {
async isHealthy() {
return this.client.isConnected()
}
}Metrics
AdapterManager tracks metrics automatically:
const metrics = afterlog.getMetrics()
// {
// eventsEmitted: 1000,
// eventsFailed: 2,
// bytesEmitted: 50000,
// lastEmitTime: Date,
// lastErrorTime: Date | null,
// averageEmitDurationMs: 5.2
// }Hooks
Add hooks via AdapterManager:
const manager = afterlog.getAdapterManager()
manager.onEmit((event) => {
console.log("Event emitted:", event.request_id)
})
manager.onError((error, event) => {
console.error("Emit failed:", error.message)
})Environment-Based Config
const isProd = process.env.NODE_ENV === "production"
afterlog.configure({
adapter: isProd ? datadogAdapter : createConsoleAdapter({ pretty: true }),
service: process.env.SERVICE_NAME,
sampling: {
defaultRate: isProd ? 0.05 : 1.0,
},
})