VibORM

Logging

Configure structured logging with pretty console output or custom callbacks

Configuration

import { VibORM } from "viborm";

// Simple: enable all levels with pretty console output
const client = VibORM.create({
  schema,
  driver,
  instrumentation: {
    logging: true
  }
});

// Custom: configure individual levels
const clientCustom = VibORM.create({
  schema,
  driver,
  instrumentation: {
    logging: {
      query: true,                    // Pretty console output
      error: (event, log) => {        // Custom callback
        errorTracker.capture(event.error);
        log();
      }
      // warning: omitted = disabled
    }
  }
});

Options

OptionTypeDefaultDescription
alltrue | LogCallback-Catch-all handler for all levels
querytrue | LogCallback-Query log handler
warningtrue | LogCallback-Warning log handler
errortrue | LogCallback-Error log handler
includeSqlbooleantrueInclude SQL query text in events
includeParamsbooleanfalseInclude query parameters in events

Log Levels

Each level can be configured independently:

  • true - Use the built-in pretty console formatter
  • (event, log) => {} - Custom callback (receives default logger as second argument)
  • undefined (or omit) - Falls back to all handler, or disabled if no all
LevelDescription
queryEmitted for every database query
warningEmitted for non-fatal issues
errorEmitted when operations fail

Pretty Console Output

When you set a level to true, VibORM uses a colorized console formatter:

logging: {
  query: true,
  error: true
}

Output example:

2024-01-15T10:30:00.000Z User.findMany 12ms
  SELECT * FROM "users" WHERE "active" = $1

The formatter includes:

  • Timestamp in ISO format
  • Model and operation name (color-coded)
  • Duration with color based on speed (green < 10ms, yellow < 100ms, red >= 100ms)
  • SQL query (dimmed)
  • Parameters if enabled (dimmed)

Custom Callbacks

For full control, provide a callback function. The callback receives the event and a log function that invokes the default pretty logger:

logging: {
  query: (event, log) => {
    // Your custom handling
    myLogger.info(event);
    log(); // Also print with default pretty formatter
  },
  error: (event, log) => {
    errorTracker.capture(event.error);
    // Don't call log() - skip default output
  }
}

Catch-All Handler

Use all to handle all log levels with a single handler:

logging: {
  all: true  // Pretty output for everything
}

// Or with a callback
logging: {
  all: (event, log) => {
    myLogger.log(event);
    log();
  }
}

Specific level handlers take precedence over all:

logging: {
  all: true,                    // Default for all levels
  error: (event, log) => {      // Override for errors only
    errorTracker.capture(event.error);
    log();
  }
}

Log Event Structure

Every log event contains the following fields:

interface LogEvent {
  level: "query" | "warning" | "error";
  timestamp: Date;
  duration?: number;       // Query duration in milliseconds
  model?: string;          // Model name (e.g., "User")
  operation?: string;      // Operation (e.g., "findMany")
  error?: VibORMError;     // Error object (for error events)
  sql?: string;            // SQL query (if includeSql enabled)
  params?: unknown[];      // Query parameters (if includeParams enabled)
  meta?: Record<string, unknown>; // Additional metadata
}

Event Examples

Query Events

Emitted for every successful database operation:

{
  level: "query",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  duration: 12,
  model: "User",
  operation: "findMany",
  sql: 'SELECT * FROM "users" WHERE "active" = $1',
  params: [true]
}

Warning Events

Emitted for non-fatal issues that may need attention:

// Slow query warning
{
  level: "warning",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  model: "User",
  operation: "findMany",
  duration: 5000,
  meta: {
    reason: "slow_query",
    threshold: 1000
  }
}

// Deprecation warning
{
  level: "warning",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  meta: {
    reason: "deprecated_feature",
    feature: "rawQuery",
    suggestion: "Use $queryRaw instead"
  }
}

Error Events

Emitted when operations fail:

// Unique constraint violation
{
  level: "error",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  model: "User",
  operation: "create",
  duration: 15,
  error: UniqueConstraintError,  // VibORMError with code V3001
  sql: 'INSERT INTO "users" ("email") VALUES ($1)',
  meta: {
    constraint: "users_email_key",
    field: "email"
  }
}

// Connection error
{
  level: "error",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  error: ConnectionError,  // VibORMError with code V1001
  meta: {
    host: "localhost",
    port: 5432
  }
}

// Record not found (for findUniqueOrThrow)
{
  level: "error",
  timestamp: new Date("2024-01-15T10:30:00.000Z"),
  model: "User",
  operation: "findUniqueOrThrow",
  duration: 8,
  error: NotFoundError,  // VibORMError with code V6001
  sql: 'SELECT * FROM "users" WHERE "id" = $1'
}

Examples

Development Setup

Pretty output for all levels during development:

logging: {
  query: true,
  warning: true,
  error: true
}

Production Setup

JSON logging for queries, error tracking for errors:

logging: {
  query: (event, log) => {
    console.log(JSON.stringify({
      level: event.level,
      timestamp: event.timestamp.toISOString(),
      model: event.model,
      operation: event.operation,
      duration: event.duration
    }));
  },
  error: (event, log) => {
    errorTracker.capture(event.error, {
      model: event.model,
      operation: event.operation
    });
  }
}

Integrate with Pino

import pino from "pino";

const logger = pino();

logging: {
  query: (event, log) => {
    logger.info({
      model: event.model,
      operation: event.operation,
      duration: event.duration
    }, `${event.model}.${event.operation}`);
  },
  error: (event, log) => {
    logger.error({
      model: event.model,
      operation: event.operation,
      error: event.error?.message
    }, `${event.model}.${event.operation} failed`);
  }
}

Errors Only

Log only errors with pretty output:

logging: {
  error: true
}

SQL and Parameters

By default, SQL is included but parameters are excluded:

logging: {
  query: true,
  includeSql: true,      // SQL visible (default)
  includeParams: false   // Params hidden (default)
}

To include parameters (development only):

logging: {
  query: true,
  includeParams: true
}

Never enable includeParams in production. Query parameters may contain passwords, personal information, or other sensitive data.

On this page