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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@logward-dev/sdk-node

v0.1.0

Published

Official Node.js SDK for LogWard (logward.dev) - Self-hosted log management with advanced features: retry logic, circuit breaker, query API, live streaming, and middleware support

Readme

LogWard Node.js SDK

Official Node.js SDK for LogWard with advanced features: retry logic, circuit breaker, query API, live streaming, and middleware support.

Features

  • Automatic batching with configurable size and interval
  • Retry logic with exponential backoff
  • Circuit breaker pattern for fault tolerance
  • Max buffer size with drop policy to prevent memory leaks
  • Query API for searching and filtering logs
  • Live tail with Server-Sent Events (SSE)
  • Trace ID context for distributed tracing
  • Global metadata added to all logs
  • Structured error serialization
  • Internal metrics (logs sent, errors, latency, etc.)
  • Express & Fastify middleware for auto-logging HTTP requests
  • Full TypeScript support with strict types

Installation

npm install @logward-dev/sdk-node
# or
pnpm add @logward-dev/sdk-node
# or
yarn add @logward-dev/sdk-node

Quick Start

import { LogWardClient } from '@logward-dev/sdk-node';

const client = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
});

// Send logs
client.info('api-gateway', 'Server started', { port: 3000 });
client.error('database', 'Connection failed', new Error('Timeout'));

// Graceful shutdown
process.on('SIGINT', async () => {
  await client.close();
  process.exit(0);
});

Configuration Options

Basic Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiUrl | string | required | Base URL of your LogWard instance | | apiKey | string | required | Project API key (starts with lp_) | | batchSize | number | 100 | Number of logs to batch before sending | | flushInterval | number | 5000 | Interval in ms to auto-flush logs |

Advanced Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxBufferSize | number | 10000 | Max logs in buffer (prevents memory leak) | | maxRetries | number | 3 | Max retry attempts on failure | | retryDelayMs | number | 1000 | Initial retry delay (exponential backoff) | | circuitBreakerThreshold | number | 5 | Failures before opening circuit | | circuitBreakerResetMs | number | 30000 | Time before retrying after circuit opens | | enableMetrics | boolean | true | Track internal metrics | | debug | boolean | false | Enable debug logging to console | | globalMetadata | object | {} | Metadata added to all logs | | autoTraceId | boolean | false | Auto-generate trace IDs for logs |

Example: Full Configuration

const client = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',

  // Batching
  batchSize: 100,
  flushInterval: 5000,

  // Buffer management
  maxBufferSize: 10000,

  // Retry with exponential backoff (1s → 2s → 4s)
  maxRetries: 3,
  retryDelayMs: 1000,

  // Circuit breaker
  circuitBreakerThreshold: 5,
  circuitBreakerResetMs: 30000,

  // Metrics & debugging
  enableMetrics: true,
  debug: true,

  // Global context
  globalMetadata: {
    env: process.env.NODE_ENV,
    version: '1.0.0',
    hostname: process.env.HOSTNAME,
  },

  // Auto trace IDs
  autoTraceId: false,
});

Logging Methods

Basic Logging

client.debug('service-name', 'Debug message');
client.info('service-name', 'Info message', { userId: 123 });
client.warn('service-name', 'Warning message');
client.error('service-name', 'Error message', { custom: 'data' });
client.critical('service-name', 'Critical message');

Error Logging with Auto-Serialization

The SDK automatically serializes Error objects:

try {
  throw new Error('Database timeout');
} catch (error) {
  // Automatically serializes error with stack trace
  client.error('database', 'Query failed', error);
}

Generated log metadata:

{
  "error": {
    "name": "Error",
    "message": "Database timeout",
    "stack": "Error: Database timeout\n    at ..."
  }
}

Custom Log Entry

client.log({
  service: 'custom-service',
  level: 'info',
  message: 'Custom log',
  time: new Date().toISOString(), // Optional
  metadata: { key: 'value' },
  trace_id: 'custom-trace-id', // Optional
});

Trace ID Context

Track requests across services with trace IDs.

Manual Trace ID

client.setTraceId('request-123');

client.info('api', 'Request received');
client.info('database', 'Querying users');
client.info('api', 'Response sent');

client.setTraceId(null); // Clear context

Scoped Trace ID

client.withTraceId('request-456', () => {
  client.info('api', 'Processing in context');
  client.warn('cache', 'Cache miss');
});
// Trace ID automatically restored after block

Auto-Generated Trace ID

client.withNewTraceId(() => {
  client.info('worker', 'Background job started');
  client.info('worker', 'Job completed');
});

Auto Trace ID Mode

const client = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
  autoTraceId: true, // Every log gets a unique trace ID
});

Query API

Search and retrieve logs programmatically.

Basic Query

const result = await client.query({
  service: 'api-gateway',
  level: 'error',
  from: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24h
  to: new Date(),
  limit: 100,
  offset: 0,
});

console.log(`Found ${result.total} logs`);
console.log(result.logs);

Full-Text Search

const result = await client.query({
  q: 'timeout',
  limit: 50,
});

Get Logs by Trace ID

const logs = await client.getByTraceId('trace-123');
console.log(`Trace has ${logs.length} logs`);

Aggregated Statistics

const stats = await client.getAggregatedStats({
  from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
  to: new Date(),
  interval: '1h', // '1m' | '5m' | '1h' | '1d'
  service: 'api-gateway', // Optional
});

console.log(stats.timeseries); // Time-bucketed counts
console.log(stats.top_services); // Top services by log count
console.log(stats.top_errors); // Most common errors

Live Tail (Streaming)

Stream logs in real-time using Server-Sent Events.

const cleanup = client.stream({
  service: 'api-gateway', // Optional filter
  level: 'error', // Optional filter

  onLog: (log) => {
    console.log(`[${log.time}] ${log.level}: ${log.message}`);
  },

  onError: (error) => {
    console.error('Stream error:', error);
  },
});

// Stop streaming when done
setTimeout(() => {
  cleanup();
}, 60000);

Metrics

Track SDK performance and health.

const metrics = client.getMetrics();

console.log(metrics.logsSent); // Total logs sent
console.log(metrics.logsDropped); // Logs dropped (buffer full)
console.log(metrics.errors); // Send errors
console.log(metrics.retries); // Retry attempts
console.log(metrics.avgLatencyMs); // Average send latency
console.log(metrics.circuitBreakerTrips); // Circuit breaker openings

// Get circuit breaker state
console.log(client.getCircuitBreakerState()); // 'CLOSED' | 'OPEN' | 'HALF_OPEN'

// Reset metrics
client.resetMetrics();

Middleware

Express Middleware

Auto-log all HTTP requests and responses.

import express from 'express';
import { LogWardClient, logWardMiddleware } from '@logward-dev/sdk-node';

const app = express();
const logger = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
});

app.use(
  logWardMiddleware({
    client: logger,
    serviceName: 'express-api',
    logRequests: true,
    logResponses: true,
    logErrors: true,
    includeHeaders: false,
    includeBody: false,
    skipHealthCheck: true,
    skipPaths: ['/metrics'],
  }),
);

app.get('/', (req, res) => {
  res.json({ message: 'Hello' });
});

app.listen(3000);

Logged automatically:

  • Request: GET /users/123
  • Response: GET /users/123 200 (45ms)
  • Errors: Request error: Internal Server Error

Fastify Plugin

import Fastify from 'fastify';
import { LogWardClient, logWardFastifyPlugin } from '@logward-dev/sdk-node';

const fastify = Fastify();
const logger = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
});

await fastify.register(logWardFastifyPlugin, {
  client: logger,
  serviceName: 'fastify-api',
  logRequests: true,
  logResponses: true,
  logErrors: true,
  skipHealthCheck: true,
});

fastify.get('/', async () => ({ message: 'Hello' }));

await fastify.listen({ port: 3000 });

Best Practices

1. Always Close on Shutdown

process.on('SIGINT', async () => {
  await client.close(); // Flushes buffered logs
  process.exit(0);
});

process.on('SIGTERM', async () => {
  await client.close();
  process.exit(0);
});

2. Use Global Metadata

const client = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
  globalMetadata: {
    env: process.env.NODE_ENV,
    version: require('./package.json').version,
    region: process.env.AWS_REGION,
    pod: process.env.HOSTNAME,
  },
});

3. Enable Debug Mode in Development

const client = new LogWardClient({
  apiUrl: 'http://localhost:8080',
  apiKey: 'lp_your_api_key_here',
  debug: process.env.NODE_ENV === 'development',
});

4. Monitor Metrics in Production

setInterval(() => {
  const metrics = client.getMetrics();

  if (metrics.logsDropped > 0) {
    console.warn(`Logs dropped: ${metrics.logsDropped}`);
  }

  if (metrics.circuitBreakerTrips > 0) {
    console.error('Circuit breaker is OPEN!');
  }
}, 60000);

5. Use Trace IDs for Request Correlation

app.use((req, res, next) => {
  const traceId = req.headers['x-trace-id'] || randomUUID();
  req.traceId = traceId;

  client.withTraceId(traceId, () => {
    next();
  });
});

API Reference

LogWardClient

Constructor

new LogWardClient(options: LogWardClientOptions)

Logging Methods

  • log(entry: LogEntry): void
  • debug(service: string, message: string, metadata?: object): void
  • info(service: string, message: string, metadata?: object): void
  • warn(service: string, message: string, metadata?: object): void
  • error(service: string, message: string, metadataOrError?: object | Error): void
  • critical(service: string, message: string, metadataOrError?: object | Error): void

Context Methods

  • setTraceId(traceId: string | null): void
  • getTraceId(): string | null
  • withTraceId<T>(traceId: string, fn: () => T): T
  • withNewTraceId<T>(fn: () => T): T

Query Methods

  • query(options: QueryOptions): Promise<LogsResponse>
  • getByTraceId(traceId: string): Promise<InternalLogEntry[]>
  • getAggregatedStats(options: AggregatedStatsOptions): Promise<AggregatedStatsResponse>

Streaming

  • stream(options: StreamOptions): () => void (returns cleanup function)

Metrics

  • getMetrics(): ClientMetrics
  • resetMetrics(): void
  • getCircuitBreakerState(): string

Lifecycle

  • flush(): Promise<void>
  • close(): Promise<void>

Examples

See the examples/ directory for complete working examples:


TypeScript Support

Fully typed with strict TypeScript support:

import type {
  LogWardClient,
  LogEntry,
  QueryOptions,
  LogsResponse,
  ClientMetrics,
} from '@logward-dev/sdk-node';

Testing

Run the test suite:

# Run tests
pnpm test

# Watch mode
pnpm test:watch

# Coverage
pnpm test:coverage

License

MIT


Contributing

Contributions are welcome! Please open an issue or PR on GitHub.


Support