npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zipteams/flush-logger

v1.0.0

Published

NestJS buffered logger — silently discards debug logs on success, flushes full trace on error

Readme

@zipteams/flush-logger

Buffered NestJS logger that silently discards debug logs on success and flushes the full trace on error. Cut observability costs without losing context.

The Problem

Traditional loggers force a tradeoff:

  • Log everything → expensive (Datadog/CloudWatch ingest costs)
  • Log only errors → blind when debugging (no context leading up to the error)

How It Works

Every debug() and info() call below the configured LOG_LEVEL is buffered in memory. When an error() or critical() is logged, the buffer is flushed to stdout — giving you the full trace of what led to the error. On success, the buffer is silently discarded.

Request starts
  logger.debug('Fetching account')     → buffered
  logger.info('Account found')         → buffered
  logger.info('Charging card')         → buffered

Success path:
  logger.clearBuffer()                 → discarded silently ✓

Failure path:
  logger.error('Gateway timeout')      → prints immediately
                                       → flushes buffer (all 3 prior lines) ✓

Installation

npm install @zipteams/flush-logger

Peer dependencies (already installed in a NestJS project):

npm install @nestjs/common @nestjs/core

Quick Start

Standalone

import { BufferedLogger } from '@zipteams/flush-logger';

const logger = BufferedLogger.create('PaymentService');

logger.debug('Fetching user account'); // buffered (below LOG_LEVEL=WARNING)
logger.info('Account found, processing payment'); // buffered
logger.error('Payment gateway timeout'); // prints error + flushes buffer

NestJS Module (per-request scoped)

// app.module.ts
import { BufferedLoggerModule } from '@zipteams/flush-logger';

@Module({
  imports: [
    BufferedLoggerModule.forRoot({
      serviceName: 'MyApp',
      isGlobal: true,
      getTraceId: () => asyncLocalStorage.getStore()?.get('traceId') ?? '-',
    }),
  ],
})
export class AppModule {}
// your.service.ts
import { BufferedLoggerService } from '@zipteams/flush-logger';

@Injectable()
export class YourService {
  constructor(private readonly logger: BufferedLoggerService) {}

  async processOrder(id: string) {
    this.logger.debug(`Processing order ${id}`);
    this.logger.info('Validating inventory');
    // If anything throws, use logException() for automatic flush+rethrow
    try {
      await this.doWork();
    } catch (err) {
      this.logger.logException(err as Error, 'processOrder');
    }
  }
}

With trace IDs from AsyncLocalStorage

import { AsyncLocalStorage } from 'async_hooks';

const storage = new AsyncLocalStorage<Map<string, string>>();

BufferedLoggerModule.forRoot({
  serviceName: 'MyApp',
  isGlobal: true,
  getTraceId: () => storage.getStore()?.get('x-request-id') ?? '-',
});

Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | serviceName | string | 'Application' | Label in log output | | maxBufferSize | number | 1000 | Max buffered entries before evicting oldest | | getTraceId | () => string | () => '-' | Fn to get current request trace ID | | isGlobal | boolean | false | Register module globally (NestJS only) |

Environment Variables

| Var | Values | Default | Description | |-----|--------|---------|-------------| | LOG_LEVEL | DEBUG\|INFO\|WARNING\|ERROR\|CRITICAL | WARNING | Logs below this level are buffered |

API

BufferedLogger

| Method | Description | |--------|-------------| | debug(msg, ctx?) | Buffer if below LOG_LEVEL | | info(msg, ctx?) | Buffer if below LOG_LEVEL | | forceInfo(msg, ctx?) | Always print, never buffer | | warning(msg, ctx?) / warn(msg, ctx?) | Print if at or above LOG_LEVEL | | error(msg, ctx?) | Always print + flush buffer | | critical(msg, ctx?) | Always print + flush buffer | | logException(err, ctx?) | Log error + flush buffer + re-throws | | logExceptionSafe(err, ctx?) | Log error + flush buffer, does not throw | | flushBuffer() | Manually flush buffer to stdout | | clearBuffer() | Discard buffer without printing | | getBufferSize() | Returns current buffer entry count | | setContext(ctx) | Set default context label for all messages |

createScopedLogger(serviceName, context, maxBufferSize?, getTraceId?)

Helper that creates a BufferedLogger with a pre-set context label — useful for operation-scoped logging.

import { createScopedLogger } from '@zipteams/flush-logger';

const logger = createScopedLogger('OrderService', 'checkout-flow');
logger.debug('Cart validated'); // output includes [checkout-flow]

BufferedLoggerModule.forRoot(options)

NestJS DynamicModule. Registers BufferedLoggerService as a REQUEST-scoped provider so each HTTP request gets its own isolated buffer.

Log Output Format

[ServiceName] <pid> - <ISO timestamp> [<traceId>] LEVEL[Context] Message

Example:

[PaymentService] 12345 - 2024-01-15T10:30:00.000Z [req-abc-123] ERROR[processPayment] Gateway timeout
=== LOG BUFFER (what led to this point) ===
[PaymentService] 12345 - 2024-01-15T10:29:59.800Z [req-abc-123] DEBUG[processPayment] Fetching account id=42
[PaymentService] 12345 - 2024-01-15T10:29:59.900Z [req-abc-123] INFO[processPayment] Account found, charging $99.00
=== END LOG BUFFER ===

License

MIT