APILensAPILens
All posts
Express.jsMonitoringNode.jsAPI

How to Monitor Your Express.js API in 60 Seconds — No Config Required

Most API monitoring guides need Prometheus, Grafana, and an afternoon. Here's how to get full observability with one line of middleware — latency, errors, DB queries, and traces.

Rahul Patel·7 min read·April 8, 2026

The Problem With API Monitoring Today

You've built an Express API. It works. It's deployed. Then someone asks: "Which endpoints are slow? What's our error rate? How many database queries does that route make?"

Your options:

- Datadog — $23/host/month, 30+ minutes to configure, requires an agent

- New Relic — needs a credit card to start, complex setup

- Prometheus + Grafana — free, but half a day to wire up

- console.log — the classic. Works until it doesn't

What if you could get structured logs, latency tracking, error rates, DB query profiling, and distributed traces — with one line of code and zero configuration?


The 60-Second Setup

Step 1: Install (10 seconds)

npm install auto-api-observe

Step 2: Add one line (5 seconds)

const express = require('express');
const observe = require('auto-api-observe');

const app = express();
app.use(observe());  // That's it. Done.

app.get('/api/users', async (req, res) => {
  const users = await db.query('SELECT * FROM users');
  res.json(users);
});

app.listen(3000);

Step 3: Hit any endpoint (5 seconds)

curl http://localhost:3000/api/users

That's it. Every request now outputs a structured JSON log with everything you need.


What You Get Automatically

Every single request produces this:

{
  "timestamp": "2026-04-08T10:30:00.000Z",
  "traceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "method": "GET",
  "route": "/api/users",
  "status": 200,
  "latency": 85,
  "latencyMs": "85ms",
  "ip": "127.0.0.1",
  "slow": false,
  "dbCalls": {
    "calls": 1,
    "totalTime": 42,
    "slowestQuery": 42,
    "queries": [
      {
        "query": "SELECT * FROM users",
        "source": "pg",
        "queryTime": 42
      }
    ]
  }
}

No configuration. No environment variables. No YAML files. No agents.

Here's what each field gives you:

FieldWhat It Tells You
method + routeWhich endpoint was called
statusSuccess or failure (4xx/5xx)
latencyHow long the request took (ms)
traceIdUnique ID to follow requests across services
dbCalls.callsHow many database queries this request made
dbCalls.totalTimeTime spent in the database (ms)
dbCalls.slowestQueryYour bottleneck query time
dbCalls.queriesEvery query with masked SQL and timing
slowFlagged if latency exceeds threshold (default: 1000ms)

Auto DB Instrumentation — Zero Code Changes

This is the part that saves hours. The middleware automatically patches 8 database libraries at the driver level:

- pg (node-postgres)

- mysql2

- mongoose (MongoDB)

- @prisma/client (Prisma)

- knex

- sequelize

- ioredis (Redis)

- better-sqlite3

You don't configure anything. Just use your database libraries as normal:

// Your code stays exactly the same
app.get('/api/orders', async (req, res) => {
  const orders = await db.query('SELECT * FROM orders WHERE user_id = $1', [req.user.id]);
  const products = await db.query('SELECT * FROM products WHERE id = ANY($1)', [orders.map(o => o.product_id)]);
  res.json({ orders, products });
});
// Output automatically shows: dbCalls: { calls: 2, totalTime: 67, queries: [...] }

How does it work? AsyncLocalStorage creates a per-request context. Prototype monkey-patching intercepts queries at the driver level — not the ORM level. This means it works with Prisma, Sequelize, TypeORM, Drizzle, Knex, or raw SQL. No per-ORM configuration needed.

Query values are automatically masked ($1 becomes ?) for security. The overhead is ~50 nanoseconds per DB call — negligible compared to actual query time.


Spot Problems Before Users Do

Find Slow Endpoints

Any request exceeding the threshold (default: 1000ms) gets flagged:

{
  "route": "/api/reports/monthly",
  "latency": 3200,
  "slow": true,
  "dbCalls": { "calls": 12, "totalTime": 2900 }
}

You can immediately see: this endpoint is slow because it makes 12 DB queries taking 2.9 seconds.

Detect N+1 Queries

When dbCalls.calls is suspiciously high for a GET request, you've found an N+1:

{
  "route": "/api/orders",
  "latency": 1850,
  "dbCalls": { "calls": 51, "totalTime": 1720 }
}

51 database calls? That's 1 query for orders + 50 queries for each order's product. Classic N+1 problem. Fix it with a JOIN or eager loading, and watch dbCalls.calls drop to 2.

*Want a deep dive on N+1 detection?* Read our complete N+1 query guide.

Track Error Rates

Filter your logs by status >= 400 to see all errors. Group by route to find which endpoints fail most.

{
  "route": "/api/payments",
  "status": 500,
  "latency": 45,
  "error": "Connection refused"
}

Distributed Tracing Across Services

Every request gets a unique traceId. If your frontend calls Service A, which calls Service B, the same trace ID follows the entire chain:

Client → Service A (traceId: abc-123)
           → Service B (reads x-trace-id header, reuses abc-123)
              → Service C (same ID — full chain visible)

Access it in your handler with req.traceId. No Jaeger setup required.


Add a Cloud Dashboard (Optional)

Structured logs are powerful. But if you want charts, alerting, and a team-accessible UI — add your API key:

app.use(observe({
  apiKey: process.env.APILENS_KEY,  // free at apilens.rest
}));

Now you get a full dashboard at apilens.rest:

- Overview — request volume, error rate, P95 latency charts

- Routes — per-route breakdown (avg latency, errors, slow count)

- Database — N+1 detection, slow queries, query source distribution

- Errors — every 4xx/5xx with timeline and filters

- Live Tail — real-time SSE stream of requests as they happen

- Alerts — email/Slack when error rate or latency spikes

Free during beta. No credit card.


Customize When You Need To

The defaults work for most apps. But you can configure everything:

app.use(observe({
  slowThreshold: 500,           // flag requests over 500ms (default: 1000ms)
  skipRoutes: ['/health', '/metrics'],  // skip health checks
  sampleRate: 0.5,              // log 50% of requests (for high traffic)
  maxRoutes: 500,               // cap distinct routes in memory metrics
  logger: false,                // silence console output (use with apiKey only)
  autoInstrument: true,         // auto-patch DB libraries (default: true)
}));

Add Custom Fields

Attach business context to any request:

const { addField } = require('auto-api-observe');

app.get('/api/orders', async (req, res) => {
  addField('userId', req.user.id);
  addField('plan', req.user.plan);
  const orders = await getOrders(req.user.id);
  addField('orderCount', orders.length);
  res.json(orders);
});

Get Aggregated Metrics

const { getMetrics } = require('auto-api-observe');

app.get('/metrics', (req, res) => res.json(getMetrics()));

Returns per-route aggregates: request count, avg/min/max latency, error count, slow request count, and status code distribution.


How It Compares

Featureauto-api-observeDatadogNew RelicPrometheus + Grafana
Setup time60 seconds30+ minutes30+ minutes2-4 hours
Lines of code120+15+100+
Dependencies050+40+5+ packages
Config files0Agent YAML + app configConfig file + licenseprometheus.yml + grafana dashboards
Auto DB tracking8 librariesCustom setup per libCustom setupManual instrumentation
N+1 detectionBuilt-inManual query analysisManualManual
Distributed tracingAutomaticRequires agent + configRequires agentRequires Jaeger/Zipkin
CostFree (beta)$23/host/month$25+/hostFree (self-hosted infra cost)
Vendor lock-inNone (MIT open-source)YesYesNo

Works With Fastify Too

const fastify = require('fastify')();
const { fastifyObservability } = require('auto-api-observe');

await fastify.register(fastifyObservability);

fastify.get('/api/users', async () => ({ users: [] }));
await fastify.listen({ port: 3000 });

Same structured output. Same auto DB tracking. Same zero config.


Summary

1. Installnpm install auto-api-observe

2. Add one lineapp.use(observe())

3. Get instant visibility — latency, errors, DB queries, traces, slow endpoint detection

No Prometheus. No Grafana. No agents. No YAML. No credit card.

Every request becomes a structured JSON log. Every database query is tracked automatically. Every slow endpoint gets flagged. And if you want charts and alerting, add an API key for the free cloud dashboard.

Try it now

npm install auto-api-observe

- Dashboard: apilens.rest

- GitHub: github.com/rahhuul/auto-api-observe

- npm: auto-api-observe

Zero dependencies. 44 tests. MIT licensed. Free during beta.


*What API monitoring setup do you use for Express apps? I'd love to hear what works for you.*