Express.js Integration
Auto-instrument Express.js with one npm install. Route handler spans, middleware timing, database query traces, and error capture — all with zero code changes to your routes.
How It Works
Install the SDK
Run npm install @tigerops/node. The SDK auto-instruments Express via the OpenTelemetry express-instrumentation plugin, which patches app.use() to track middleware registration and wrap route handlers.
Require Before Express
Add require("@tigerops/node/register") as the very first line of your entry point — before require("express"). This order is critical for the middleware and route instrumentation patches to apply correctly.
Set Environment Variables
Export TIGEROPS_API_KEY, TIGEROPS_SERVICE_NAME, and TIGEROPS_ENVIRONMENT. The SDK reads these at startup and configures the OTLP exporter. dotenv is supported for local development.
Routes, Middleware & DB Span
Within seconds TigerOps receives Express route spans with express.route.path and handler.name, individual middleware timing, database query child spans, and outbound HTTP spans from axios and node-fetch.
What You Get Out of the Box
Route Handler Tracing
Every Express route handler (GET, POST, PUT, DELETE) creates a root span with the route pattern (e.g. /users/:id), HTTP method, status code, and response time. Named middleware functions appear as child spans.
Middleware Timing
Each middleware function in the chain is individually timed and reported as a span event. Slow authentication, validation, or body parsing middleware are immediately visible in the request trace waterfall.
Router & Sub-App Nesting
Express.Router and mounted sub-apps are fully instrumented. Nested route spans correctly show the full path (e.g. /api/v1/orders/:id) including the router prefix, even when using express.Router() mounting.
Error Middleware Capture
Express error handling middleware (4-argument functions) is auto-instrumented. Errors passed via next(err) are captured with the error message, stack trace, and the route that triggered the error.
Database Query Spans
Automatic instrumentation for pg, mysql2, mongodb, ioredis, and Prisma ORM. Every database call from within an Express handler creates a child span with the normalized query and execution time.
Outbound HTTP Tracing
Calls made via axios, node-fetch, got, and the native http/https modules become child spans with the target URL, method, and status code. W3C TraceContext headers are injected for service-to-service tracing.
Install & Initialize
One npm install. One require. Full Express.js observability.
# Install the TigerOps Node.js SDK
npm install @tigerops/node
# Set environment variables
export TIGEROPS_API_KEY="your-api-key"
export TIGEROPS_SERVICE_NAME="my-express-api"
export TIGEROPS_ENVIRONMENT="production"
# app.js — IMPORTANT: require register BEFORE express
require('@tigerops/node/register')
const express = require('express')
const { Pool } = require('pg')
const app = express()
const db = new Pool({ connectionString: process.env.DATABASE_URL })
app.use(express.json())
// This route is automatically traced
// Span: GET /orders/:id
app.get('/orders/:id', async (req, res, next) => {
try {
// pg query is automatically a child span
const { rows } = await db.query(
'SELECT * FROM orders WHERE id = $1',
[req.params.id]
)
if (!rows[0]) return res.status(404).json({ error: 'Not found' })
res.json(rows[0])
} catch (err) {
next(err)
}
})
// Error middleware — errors passed to next() are auto-captured
app.use((err, req, res, next) => {
// TigerOps already recorded this error on the active span
res.status(500).json({ error: err.message })
})
app.listen(3000)
// Custom span for business logic
const { trace } = require('@tigerops/node')
const tracer = trace.getTracer('order-service')
async function applyDiscount(orderId, couponCode) {
return tracer.startActiveSpan('discount.apply', async (span) => {
span.setAttribute('order.id', orderId)
span.setAttribute('coupon.code', couponCode)
try {
const discount = await lookupCoupon(couponCode)
await applyToOrder(orderId, discount.percent)
span.setAttribute('discount.percent', discount.percent)
return discount
} finally {
span.end()
}
})
}Common Questions
Does @tigerops/node work with both Express 4 and Express 5?
Yes. Express 4.x is fully supported. Express 5.x (beta/RC) is supported on a best-effort basis. The instrumentation patches router.Layer and Route prototypes, which are stable across both major versions.
My Express app uses a custom error handler — will errors still be traced?
Yes. TigerOps patches the error middleware dispatch mechanism, not specific error handler functions. Any error passed to next(err) is captured regardless of how many custom error handlers are registered.
Can I use TigerOps with Express-based frameworks like LoopBack or Sails.js?
LoopBack 4 is based on Express and is fully supported. Sails.js uses Express under the hood and is also supported. NestJS (which wraps Express by default) has dedicated instrumentation via the @tigerops/nestjs package.
How does TigerOps handle streaming responses in Express?
For streaming responses (res.write() followed by res.end()), the span ends when res.end() is called. Stream duration, bytes written, and any errors during streaming are captured as span events.
Does TigerOps work with express-validator and Joi validation middleware?
Yes. Validation middleware is instrumented as part of the middleware chain. Validation errors returned via next(err) are captured automatically. You can also add custom span attributes in your validators using the TigerOps API.
Full Express.js Observability in One npm Install
Route spans, middleware timing, database query traces, and error capture — no code changes to your routes.