VibORM

Tracing

Set up OpenTelemetry tracing for distributed observability

Prerequisites

Install the OpenTelemetry API package:

npm install @opentelemetry/api

The @opentelemetry/api package is an optional peer dependency. VibORM gracefully degrades to no-op when it's not installed.

Configuration

import { VibORM } from "viborm";

// Simple: enable with defaults
const client = VibORM.create({
  schema,
  driver,
  instrumentation: {
    tracing: true
  }
});

// Custom: configure options
const clientCustom = VibORM.create({
  schema,
  driver,
  instrumentation: {
    tracing: {
      includeSql: true,     // Include SQL in spans (default: true)
      includeParams: false  // Exclude params (default: false)
    }
  }
});

Options

OptionTypeDefaultDescription
includeSqlbooleantrueInclude SQL query text in span attributes
includeParamsbooleanfalseInclude query parameters in span attributes
ignoreSpanTypesArray<string | RegExp>[]Span names to skip

Span Hierarchy

VibORM creates a hierarchy of spans for each operation:

viborm.operation (root span for client method call)
├── viborm.validate  (input validation)
├── viborm.build     (SQL construction)
├── viborm.execute   (query execution wrapper)
│   └── viborm.driver.execute (actual database call)
└── viborm.parse     (result parsing)

For transactions:

viborm.transaction (transaction wrapper)
├── viborm.operation
├── viborm.operation
└── ...

Span Names

Span NameDescription
viborm.operationHigh-level client method call
viborm.validateSchema validation of arguments
viborm.buildSQL query construction
viborm.executeQuery execution wrapper
viborm.driver.executeActual database round-trip
viborm.parseResult hydration
viborm.transactionTransaction boundaries
viborm.connectConnection establishment
viborm.disconnectConnection teardown

Span Attributes

VibORM follows OTel database semantic conventions where possible.

Attributes by Span Type

All spans include these base attributes:

AttributeDescription
db.system.nameDatabase system (postgresql, sqlite)
db.system.driverDriver name (postgres, pg, pglite, sqlite3)

Operation spans (viborm.operation, viborm.validate, viborm.build, viborm.execute, viborm.parse) add:

AttributeDescription
db.collection.nameTable name (e.g., users)
db.operation.nameOperation (findMany, create, update, etc.)

Driver execute span (viborm.driver.execute) adds SQL details when configured:

AttributeConditionDescription
db.query.textincludeSql: trueSQL query text
db.query.parameter.<index>includeParams: trueIndividual query parameters

Example Span Attributes

// viborm.operation span
{
  "db.system.name": "postgresql",
  "db.system.driver": "pg",
  "db.collection.name": "users",
  "db.operation.name": "findMany"
}

// viborm.driver.execute span (with includeSql: true)
{
  "db.system.name": "postgresql",
  "db.system.driver": "pg",
  "db.collection.name": "users",
  "db.operation.name": "findMany",
  "db.query.text": "SELECT * FROM \"users\" WHERE \"active\" = $1"
}

// viborm.transaction span
{
  "db.system.name": "postgresql",
  "db.system.driver": "pg"
}

Full Setup Example

To export traces, you need to configure an OpenTelemetry SDK:

import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";

// Set up the trace provider
const provider = new NodeTracerProvider();

// Export traces to your backend (Jaeger, Honeycomb, etc.)
provider.addSpanProcessor(
  new SimpleSpanProcessor(new OTLPTraceExporter())
);

provider.register();

// Now create your VibORM client
const client = VibORM.create({
  schema,
  driver,
  instrumentation: {
    tracing: true
  }
});

Filtering Spans

Use ignoreSpanTypes to skip specific spans:

tracing: {
  ignoreSpanTypes: [
    "viborm.validate",  // Skip validation spans
    /viborm\.parse/     // Regex patterns also work
  ]
}

Graceful Degradation

VibORM uses dynamic imports for OpenTelemetry. If the package is not installed:

  • No errors are thrown
  • Operations execute normally
  • Spans are simply not created

This allows you to enable tracing only in environments where it's needed without affecting other deployments.

Serverless Compatibility

VibORM's tracer is designed for serverless environments:

  • No module-level mutable state
  • Each client instance has isolated tracer state
  • Safe for Cloudflare Workers, Vercel Edge, and similar runtimes

SQL and Parameters

By default, SQL is included in spans but parameters are excluded:

// Default behavior
tracing: {
  includeSql: true,      // SQL visible in spans
  includeParams: false   // Params hidden
}

Only enable includeParams in development. Query parameters in traces may contain sensitive data and could be stored in your tracing backend.

Testing with In-Memory Exporter

For testing, use an in-memory exporter:

import { InMemorySpanExporter, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";

const exporter = new InMemorySpanExporter();
const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();

// Run your queries...
await client.user.findMany({});

// Check the spans
const spans = exporter.getFinishedSpans();
const spanNames = spans.map(s => s.name);

expect(spanNames).toContain("viborm.operation");
expect(spanNames).toContain("viborm.execute");

On this page