To send the same event to multiple destinations (e.g., Axiom for storage and Sentry for errors), create a single drain function that uses Promise.allSettled to dispatch the batch to all destinations in parallel. This ensures that one slow or failing destination does not block the others or cause the entire pipeline to reject.
Best Practices:
- Use
Promise.allSettled so one failing drain doesn't reject the whole batch. - Tune
batch and retry settings once at the pipeline level; these settings apply to all destinations. - For destinations requiring different filtering (e.g., only sending errors to Sentry), use per-drain
minLevel options or wrap the destination in a filter function.
import { createDrainPipeline } from 'evlog/pipeline'
import { createAxiomDrain } from 'evlog/axiom'
import { createDatadogDrain } from 'evlog/datadog'
import { createSentryDrain } from 'evlog/sentry'
import { createFsDrain } from 'evlog/fs'
import type { DrainContext }
const pipeline = createDrainPipeline<DrainContext>({
batch: { size: 50, intervalMs: 5000 },
retry: { maxAttempts: 3 },
maxBufferSize: 1000,
})
const axiom = createAxiomDrain()
const datadog = createDatadogDrain()
const sentry = createSentryDrain({ minLevel: 'error' })
const fs = createFsDrain({ dir: '.evlog/logs', maxFiles: 14 })
export const drain = pipeline(async (batch) => {
await Promise.allSettled([
axiom(batch),
datadog(batch),
sentry(batch),
fs(batch),
])
})