Skip to content

Custom Transports

Send logs to external services, files, or anywhere.

Basic Transport

A transport is a function that receives log entries:

typescript
import { createLogger, LogEntry } from '@nextrush/log';

const log = createLogger('App');

log.addTransport((entry: LogEntry) => {
  // Send to your service
  fetch('/api/logs', {
    method: 'POST',
    body: JSON.stringify(entry),
  });
});

Batch Transport

Send logs in batches for better performance:

typescript
import { createLogger, createBatchTransport } from '@nextrush/log';

const { transport, flush, destroy } = createBatchTransport(
  async (entries) => {
    await fetch('/api/logs', {
      method: 'POST',
      body: JSON.stringify(entries),
    });
  },
  {
    batchSize: 50,       // Flush after 50 entries
    flushInterval: 5000, // Or every 5 seconds
    maxRetries: 3,       // Retry failed flushes
    onError: (error, entries) => {
      console.error('Failed to send logs:', error);
    },
  }
);

const log = createLogger('App');
log.addTransport(transport);

// Graceful shutdown
process.on('SIGTERM', async () => {
  await flush();
  destroy();
  process.exit(0);
});

Filtered Transport

Only send specific log levels:

typescript
import { createFilteredTransport } from '@nextrush/log';

// Only send errors to error tracking service
const errorTransport = createFilteredTransport(
  (entry) => sendToSentry(entry),
  'error' // Only error and fatal
);

log.addTransport(errorTransport);

Predicate Transport

Custom filtering logic:

typescript
import { createPredicateTransport } from '@nextrush/log';

// Only log entries from API context
const apiTransport = createPredicateTransport(
  (entry) => sendToApiLogs(entry),
  (entry) => entry.context.startsWith('API')
);

log.addTransport(apiTransport);

Rate-Limited Transport

Prevent log flooding with token bucket rate limiting:

typescript
import { createRateLimitedTransport } from '@nextrush/log';

const { transport, getStats, reset } = createRateLimitedTransport(
  myTransport,
  {
    maxLogsPerSecond: 100,  // Base rate
    burstAllowance: 50,     // Extra burst capacity
    bypassLevels: ['error', 'fatal'], // Always allow errors
    onDrop: (entry, stats) => {
      console.warn(`Dropped log. Total dropped: ${stats.totalDropped}`);
    },
  }
);

log.addTransport(transport);

// Check stats
setInterval(() => {
  const stats = getStats();
  console.log(`Processed: ${stats.totalProcessed}, Dropped: ${stats.totalDropped}`);
}, 60000);

Per-Namespace Rate Limits

typescript
import { createNamespaceRateLimitedTransport } from '@nextrush/log';

const transport = createNamespaceRateLimitedTransport(myTransport, {
  'api:*': { maxLogsPerSecond: 100, burstAllowance: 50 },
  'db:*': { maxLogsPerSecond: 50 },
  '*': { maxLogsPerSecond: 200 }, // Default for unmatched
});

log.addTransport(transport);

Multiple Transports

typescript
const log = createLogger('App');

// Send all logs to central logging
log.addTransport(centralLoggingTransport);

// Send only errors to Sentry
log.addTransport(createFilteredTransport(sentryTransport, 'error'));

// Send API logs to separate service
log.addTransport(createPredicateTransport(
  apiLogsTransport,
  (entry) => entry.context.includes('API')
));

Datadog

typescript
log.addTransport(async (entry) => {
  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({
      ...entry,
      ddsource: 'nodejs',
      service: 'my-app',
    }),
  });
});

File Transport (Node.js)

typescript
import { appendFileSync } from 'fs';

log.addTransport((entry) => {
  appendFileSync('app.log', JSON.stringify(entry) + '\n');
});

Console Override

typescript
// Don't output to console, only to transports
const log = createLogger('App', { silent: true });
log.addTransport(myTransport);

LogEntry Type

typescript
interface LogEntry {
  timestamp: string;
  level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
  context: string;
  message: string;
  data?: Record<string, unknown>;
  error?: SerializedError;
  correlationId?: string;
  performance?: { duration: number };
  runtime: string;
  pid?: number;
}

Released under the MIT License.