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

unnbound-logger-sdk

v3.0.34

Published

A structured logging library with TypeScript support using Pino. Provides consistent, well-typed logging with automatic logId, workflowId, traceId, and deploymentId tracking across operational contexts.

Readme

Unnbound Logger

A structured logging library with TypeScript support built on Pino. Provides consistent, well-typed logging across different operational contexts with automatic trace and span tracking. All logs are output in JSON format for better machine readability and parsing.

Installation

npm install unnbound-logger-sdk

Basic Usage

import { logger } from 'unnbound-logger-sdk';

// Log with string messages
logger.info('Application started');
logger.warn('Resource usage high');
logger.error({ err: new Error('Database connection failed') }, 'Something bad happened');
logger.debug('Debug information');
logger.trace('Trace information');

// Log with object messages (merged into top level)
logger.info({ event: 'user_login', userId: '123' }, 'Event received.');
// Results in: { "event": "user_login", "userId": "123", "message": "Application started", ... }

// Log with both string message and metadata (metadata merged into top level)
logger.info({ userId: '123' }, 'User logged in');
// Results in: { "userId": "123", "message": "User logged in", ... }

Log Format

All logs follow a standardized format based on Pino with additional context:

interface Log<T extends LogType = 'general'> {
  logId: string; // Automatically generated unique ID for each log entry
  level: LogLevel; // "info" | "debug" | "error" | "warn" | "trace"
  message: string;
  type: T; // "general" | "http" | "sftp"
  traceId?: string; // Automatically included when in trace context
  spanId?: string; // Automatically included when in span context
  serviceId?: string; // From UNNBOUND_SERVICE_ID environment variable
  deploymentId?: string; // From UNNBOUND_DEPLOYMENT_ID environment variable
  workflowId?: string; // From UNNBOUND_WORKFLOW_ID environment variable
  environment?: string; // From ENVIRONMENT environment variable
  err?: unknown; // Only present for Error objects
  duration?: number; // Duration in milliseconds for span operations
  http?: T extends 'http' ? HttpPayload : never;
  sftp?: T extends 'sftp' ? SftpPayload : never;
}

Workflow and Deployment Tracking

Workflow Tracking

The logger includes a workflowId field in all log entries for tracking operations across services:

# Set the workflow ID in your environment
export UNNBOUND_WORKFLOW_ID="order-processing-12345"
export UNNBOUND_WORKFLOW_URL="https://workflows.example.com/order-processing-12345"
export UNNBOUND_SERVICE_ID="order-service"

# Or in your deployment configuration
UNNBOUND_WORKFLOW_ID=order-processing-12345
UNNBOUND_WORKFLOW_URL=https://workflows.example.com/order-processing-12345
UNNBOUND_SERVICE_ID=order-service
// Import the logger - workflowId and serviceId are automatically set from environment
import { logger } from 'unnbound-logger-sdk';

Deployment Tracking

The logger automatically includes a deploymentId field in all log entries. This field is populated from the UNNBOUND_DEPLOYMENT_ID environment variable, allowing you to track logs per deployment.

# Set the deployment ID in your environment
export UNNBOUND_DEPLOYMENT_ID="v1.2.3-prod-20231201"

# Or in your deployment configuration
UNNBOUND_DEPLOYMENT_ID=v1.2.3-prod-20231201

If the environment variables are not set, the fields will be empty strings. These fields help with:

  • Workflow ID: Unique identifier for the workflow (logged in each entry)
  • Workflow URL: Used internally for URL construction in webhook endpoints (not logged as a field)
  • Service ID: Identifier for the specific service/component (logged in each entry)
  • Deployment ID: Tracking logs across different application deployments (logged in each entry)
  • Correlating issues: Link problems to specific workflows and releases
  • Monitoring: Track health and performance across workflows and deployments

Object Logging Behavior

The logger uses Pino's standard behavior for handling different message types:

String Messages with Metadata

When you pass a string message with additional metadata, the metadata is merged into the top level:

logger.info('User action completed', { userId: '123', action: 'login' });
// Result: { "message": "User action completed", "userId": "123", "action": "login", ... }

Object Messages

When you pass an object as the message, it's merged into the top level:

logger.info({ userId: '123', action: 'login' });
// Result: { "userId": "123", "action": "login", "message": "Application started", ... }

Error Objects

Error objects are handled specially and include serialized error information:

logger.error({ err: new Error('Something went wrong') });
// Result: { "message": "Error", "err": { "name": "Error", "message": "Something went wrong", "stack": "..." }, ... }

This follows Pino's standard behavior where all object properties are merged into the top level of the log entry.

HTTP Request/Response Logging

import { logger, traceMiddleware } from 'unnbound-logger-sdk';
import express from 'express';

const app = express();

// Apply trace middleware for automatic HTTP logging
app.use(traceMiddleware());

// Example route
app.post('/api/users', (req, res) => {
  // Your route handler code here
  res.status(201).json({ id: '123', status: 'created' });
});

The trace middleware automatically captures:

  • Request method, URL, body, and headers (filtered for security)
  • Response status code, body, and headers (filtered for security)
  • Request duration
  • Trace ID and span ID for correlation
  • Automatic span tracking for the entire request lifecycle

Full URL Logging for Webhook Endpoints

When webhook endpoints receive incoming requests, the logger automatically constructs and logs the full URL using a smart fallback strategy:

  1. Preferred: Uses UNNBOUND_WORKFLOW_URL - If set, this becomes the base URL for all logged requests
  2. Fallback: Constructs from request headers - Uses protocol, host, and forwarded headers from the incoming request
# Set your workflow URL to ensure full URLs in logs
export UNNBOUND_WORKFLOW_URL="https://api.yourservice.com"

# Example webhook endpoints will be logged as:
# POST https://api.yourservice.com/webhooks/stripe
# POST https://api.yourservice.com/webhooks/github
import express from 'express';
import { traceMiddleware } from 'unnbound-logger-sdk';

const app = express();

// Apply trace middleware for automatic logging
app.use(traceMiddleware());

// Webhook endpoints - URLs automatically logged with full domain
app.post('/webhooks/stripe', (req, res) => {
  // Request logged as: https://api.yourservice.com/webhooks/stripe
  res.status(200).send('OK');
});

app.post('/webhooks/github', (req, res) => {
  // Request logged as: https://api.yourservice.com/webhooks/github
  res.status(200).send('OK');
});

This ensures webhook logs contain the complete URL for easy debugging and monitoring.

SFTP Operations Logging

The logger supports structured logging for SFTP operations with automatic span tracking:

import { logger, startSpan } from 'unnbound-logger-sdk';

// Example SFTP operation with automatic logging
const uploadFile = async (filePath: string, content: string) => {
  return await startSpan(
    'SFTP upload operation',
    async () => {
      // Your SFTP upload logic here
      logger.info('Uploading file', { filePath, contentLength: content.length });
      return { success: true, filePath };
    },
    (result) => ({
      type: 'sftp',
      sftp: {
        host: 'sftp.example.com',
        operation: 'upload',
        path: filePath,
        content: content,
        bytes: content.length,
      },
    })
  );
};

The SFTP logging automatically captures:

  • Host information
  • Operation type (connect, upload, download, list, delete, etc.)
  • File paths and content
  • Byte counts for transfers
  • Operation duration
  • Success/failure status

Middleware Usage

Express Trace Middleware

The library provides a comprehensive trace middleware for Express applications that automatically handles trace context and HTTP logging:

import { traceMiddleware } from 'unnbound-logger-sdk';
import express from 'express';

const app = express();

// Apply the comprehensive trace middleware globally
app.use(traceMiddleware());

The trace middleware automatically:

  • Generates and maintains trace IDs across the request lifecycle
  • Logs incoming requests with method, URL, headers, and body
  • Logs outgoing responses with status code, headers, body, and duration
  • Measures request duration automatically
  • Handles errors and logs them appropriately
  • Captures response bodies for logging
  • Creates spans for the entire request lifecycle

Axios Trace Middleware

For comprehensive logging of outgoing HTTP requests made with Axios:

import { traceAxios } from 'unnbound-logger-sdk';
import axios from 'axios';

// Create an axios instance and wrap it with tracing
const client = traceAxios(axios.create());

// All requests made with this client will be automatically logged
client.get('https://api.example.com/data');

The Axios middleware:

  • Logs outgoing requests with method, URL, headers, and body
  • Maintains trace context across requests by propagating trace IDs
  • Logs successful responses with status, headers, body, and duration
  • Logs error responses with detailed error information
  • Creates spans for each HTTP request
  • Supports request/response filtering through configuration

Manual tracing

In case the function doesn't run inside an HTTP handler (for example a cron job), you can assign a trace id manually by using the withTrace function:

import { withTrace } from 'unnbound-logger-sdk';

const operation = async (value: number) => {
  // This will log a { traceId, value }
  logger.info('Processing value', { value });
  return value * 2;
};

setInterval(() => withTrace(() => operation(13)), 1000);

Function Tracing with startSpan

The startSpan function allows you to wrap any async operation with automatic span tracking and logging. This is particularly useful for maintaining consistent trace IDs across async operations and distributed systems:

import { logger, startSpan } from 'unnbound-logger-sdk';

// Example: Wrapping a function with span tracking
const operation = async (value: number) => {
  logger.info('Processing value', { value });
  return value * 2;
};

// Wrap the function with span tracking
const result = await startSpan('Processing operation', operation, () => ({
  operationType: 'calculation',
}));

// Execute the function
const result = await startSpan('Processing operation', () => operation(21)); // Returns 42

Note: In case the traceId is missing from the context, startSpan will generate one. It is recommended to use a single traceId across your handler though, so always consider using traceMiddleware and withTrace to inject the traceId instead of relying on startSpan to create one.

Async Operations

The span context is maintained across async operations:

const asyncOperation = async (value: number) => {
  logger.info('First step', { value });

  await someAsyncWork();

  logger.info('Second step', { value });
  return value * 2;
};

const result = await startSpan('Async operation', asyncOperation, () => ({
  operationType: 'async_calculation',
}));

Benefits

  • Automatic span ID generation and tracking
  • Consistent trace context across async operations
  • Automatic duration measurement
  • Error handling and logging
  • Type-safe implementation
  • Works with async functions
  • Maintains separate span contexts for different operations

Note: When using the logger within spans, you don't need to manually manage trace IDs. The logger automatically includes the current trace ID and span ID in all log entries.

API Reference

logger

The main logger instance that provides all logging functionality using Pino.

Usage

import { logger } from 'unnbound-logger-sdk';

The logger is a Pino instance with additional context automatically included from environment variables and trace context.

Methods

  • logger.trace(object: {}, message: string): void
  • logger.trace(message: string): void
  • logger.debug(object: {}, message: string): void
  • logger.debug(message: string): void
  • logger.info(object: {}, message: string): void
  • logger.info(message: string): void
  • logger.warn(object: {}, message: string): void
  • logger.warn(message: string): void
  • logger.error<O extends { err: unknown }>(object: O, message: string): void

traceMiddleware

Express middleware for automatic HTTP request/response logging and trace context management.

Usage

import { traceMiddleware } from 'unnbound-logger-sdk';

app.use(traceMiddleware(options?: HttpOptions));

HttpOptions:

  • traceHeaderKey?: string - Custom trace header name (default: 'x-unnbound-trace-id')
  • messageHeaderKey?: string - Custom message header name (default: 'x-message-id')
  • ignoreTraceRoutes?: string[] - Routes to ignore in middleware (default: ['/health', '/healthcheck'])

traceAxios

Wraps an Axios instance with automatic request/response logging and trace context propagation.

Usage

import { traceAxios } from 'unnbound-logger-sdk';
import axios from 'axios';

const client = traceAxios(axios.create(), options?: HttpOptions);

startSpan

Creates a span for tracking async operations with automatic logging and duration measurement.

Usage

import { startSpan } from 'unnbound-logger-sdk';

const result = await startSpan<T>(
  spanName: string,
  callback: () => Promise<T>,
  getter?: LogPayloadGetter<T>
);

Parameters:

  • spanName: The name of the span for logging
  • callback: The async function to execute within the span
  • getter: Optional function to generate log payload based on operation result/error

getTraceId

Generates a new trace ID for manual trace context management.

Usage

import { getTraceId } from 'unnbound-logger-sdk';

const traceId = getTraceId();
console.log(traceId); // "550e8400-e29b-41d4-a716-446655440000"

Environment Variables

  • UNNBOUND_WORKFLOW_ID - Workflow identifier (included in all logs)
  • UNNBOUND_SERVICE_ID - Service identifier (included in all logs)
  • UNNBOUND_DEPLOYMENT_ID - Deployment identifier (included in all logs)
  • UNNBOUND_WORKFLOW_URL - Base URL for webhook endpoint logging
  • ENVIRONMENT - Environment name (included in all logs)
  • LOG_LEVEL - Log level (default: 'info')