Database Instrumentation
Instrument pg, Prisma, Drizzle, Mongoose, MongoDB, and Sequelize with the Trasys SDK — automatic for most clients, with manual wrappers for Prisma and Drizzle.
Database Instrumentation
Quick reference
| Client | Setup | Notes |
|---|---|---|
| pg (node-postgres) | Automatic | Nothing required |
| Mongoose | Automatic | Nothing required |
| Sequelize | Automatic | Requires @opentelemetry/instrumentation-sequelize |
| MongoDB driver | Opt-in | Set autoInstrument.mongodbDriver: true |
| Prisma | Manual | Call sdk.wrapPrisma(client) |
| Drizzle | Manual | Pass sdk.drizzleLogger() to your Drizzle setup |
PostgreSQL (pg / node-postgres)
Instrumented automatically via @opentelemetry/instrumentation-pg. Every pool.query() and client.query() call becomes a span. No code changes required.
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
// Automatically traced — no changes needed
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);Span attributes captured:
| Attribute | Value |
|---|---|
db.system | postgresql |
db.statement | SQL with $1, $2 placeholders; actual values are never stored |
db.operation | SELECT, INSERT, UPDATE, DELETE |
db.slow_query | true when above slowQueryThresholdMs |
Sequelize
Instrumented automatically, but requires two setup steps.
Step 1 — install the instrumentation package:
npm install @opentelemetry/instrumentation-sequelizeStep 2 — require the SDK before Sequelize:
// index.js — correct order
require('dotenv').config();
const { sdk } = require('./trasys'); // ← SDK first
const { Sequelize } = require('sequelize'); // ← then SequelizeIf Sequelize loads before the SDK initializes, the instrumentation patch does not apply and queries will not appear in your traces. Import order is the most common cause of missing Sequelize spans.
No changes needed to your Sequelize setup or model definitions once the import order is correct.
To disable Sequelize instrumentation:
createSdk({ autoInstrument: { sequelize: false } });Prisma
Prisma requires a one-time manual wrapper because its instrumentation uses $use — a Prisma-specific middleware API that must be attached to each client instance.
const { PrismaClient } = require('@prisma/client');
const { sdk } = require('./trasys');
const prisma = sdk.wrapPrisma(new PrismaClient());// TypeScript
import { PrismaClient } from '@prisma/client';
import { sdk } from './trasys';
const prisma = sdk.wrapPrisma(new PrismaClient());
export default prisma;wrapPrisma returns the same client — no type changes, no casting required. Every query on the wrapped client is then traced:
const user = await prisma.user.findUnique({ where: { id } });
// → span: prisma.User.findUnique
const result = await prisma.order.create({ data: { ... } });
// → span: prisma.Order.createSpan attributes captured:
| Attribute | Example |
|---|---|
prisma.model | User |
prisma.action | findUnique |
db.system | postgresql |
db.slow_query | true when above threshold |
prisma.in_tx | true for transactional queries |
Drizzle
Drizzle exposes a logger option at construction time. Pass sdk.drizzleLogger() to wire it in:
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import { sdk } from './trasys';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle(pool, { logger: sdk.drizzleLogger() });
// All queries are now traced
const users = await db.select().from(usersTable);Mongoose
Mongoose is auto-instrumented when the mongoose package is installed. The SDK detects it at startup and registers a connection-level plugin.
const mongoose = require('mongoose');
await mongoose.connect(process.env.MONGODB_URI);
// All queries on this connection are now tracedFor specific connections or manual control:
// Specific connection
const conn = await mongoose.createConnection(process.env.MONGODB_URI).asPromise();
sdk.wrapMongoose(conn);
// Per-schema plugin
const UserSchema = new mongoose.Schema({ ... });
UserSchema.plugin(sdk.mongoosePlugin());Operations instrumented: find, findOne, findOneAndUpdate, findOneAndDelete, updateOne, updateMany, deleteOne, deleteMany, countDocuments, aggregate, and more.
MongoDB Driver (raw)
Disabled by default — Mongoose takes priority. Enable it only when using the raw driver without Mongoose:
createSdk({
autoInstrument: {
mongoose: false, // disable Mongoose
mongodbDriver: true, // enable raw driver
},
});Slow query threshold
Queries exceeding database.slowQueryThresholdMs (default: 1000 ms) are flagged with db.slow_query: true in the dashboard.
createSdk({
database: {
slowQueryThresholdMs: 500, // flag anything over 500ms
},
});Sensitive column masking
Column names listed in database.maskColumns cause the SDK to mask the WHERE clause of any query that references them. The query structure is preserved; only the value context is masked.
Default masked columns: password, token, secret, card_number, ssn, api_key
createSdk({
database: {
maskColumns: ['password', 'token', 'recovery_code', 'totp_secret'],
},
});Next steps
- Distributed Tracing — see database spans in the context of the full request trace
- Logging — correlate log entries with database query spans
NestJS
Instrument a NestJS application on either the Express or Fastify adapter by applying the Trasys SDK middleware in main.ts before the app starts listening.
AI Observability
Trace every LLM call, model, tokens, cost, prompts, responses, tool calls, across OpenAI, Anthropic, Gemini, Groq, Mistral, Cohere, and Ollama via sdk.wrapAI.

