Zero-dependency HTTP monitoring, APM metrics, percentile latencies (p50/p90/p95/p99), threshold alert callbacks, Prometheus format exporter, slow request profiler, and real-time embedded web dashboard for Express.js applications.
- Native TypeScript: Written entirely in strict TypeScript with complete auto-generated type declarations (
.d.ts). - JSR & NPM Registry: Published to both NPM and JSR for Node.js, Deno, and Bun.
- Zero External Dependencies: Lightweight and fast, zero extra npm package footprint.
- Embedded Real-Time Dashboard: Built-in dark mode dashboard UI with Server-Sent Events (SSE) live streaming.
- True Percentile Latencies: Sliding window calculation of p50, p90, p95, and p99 response times globally and per-route.
- Threshold Alert Callbacks: Trigger custom
onAlertcallbacks when error rates crossX%, RSS memory exceedsY MB, or average latency spikes. - Slow Request Profiler: Automatically capture and profile requests exceeding
slowThresholdMs(e.g., 500ms). - Prometheus Exporter: Serves standard Prometheus Exposition format (
text/plain; version=0.0.4) at/metricsready for Grafana & Prometheus scrapers. - cURL Generator & Header Redaction: Auto-generate cURL commands for captured requests with automatic masking of sensitive credentials (
authorization,cookie,api-key). - HAR Export & Request Replay: Download HTTP Archive (HAR 1.2) JSON exports and replay captured HTTP requests.
| Feature | morgan |
pino-http |
@codebygarv/express-lens |
|---|---|---|---|
| Request Logging | Text line | JSON log | Colorized ANSI + In-Memory APM |
| Percentile Latencies (p50/p90/p95/p99) | β No | β No | β Built-in |
Threshold Alert Callbacks (onAlert) |
β No | β No | β Built-in |
Slow Request Profiler (slowThresholdMs) |
β No | β No | β Built-in |
Prometheus Exposition Exporter (/metrics) |
β No | β No | β Built-in |
| Embedded Web Dashboard (SSE Live Stream) | β No | β No | β Built-in |
| cURL Command Generation | β No | β No | β Built-in |
| HAR 1.2 Export & Request Replay | β No | β No | β Built-in |
| Sensitive Header Redaction | β No | β Automatic | |
| Memory Overhead | Low | Low | Bounded Ring Buffer |
NPM / Yarn / pnpm:
npm install @codebygarv/express-lens
yarn add @codebygarv/express-lens
pnpm add @codebygarv/express-lensDeno / JSR:
deno add jsr:@codebygarv/express-lens
npx jsr add @codebygarv/express-lensimport express from 'express';
import monitor, {
metricsHandler,
prometheusHandler,
dashboardHandler,
} from '@codebygarv/express-lens';
const app = express();
// 1. Attach Express Lens Middleware
app.use(
monitor({
slowThresholdMs: 500, // Profile requests slower than 500ms
alerts: {
errorRateThreshold: 5, // Alert if error rate >= 5%
memoryThresholdMb: 500, // Alert if RSS memory >= 500MB
onAlert: (alert) => {
console.warn('π¨ EXPRESS LENS ALERT:', alert.message);
},
},
})
);
// 2. Mount Prometheus /metrics endpoint (for Grafana/Prometheus)
app.get('/metrics', prometheusHandler());
// 3. Mount Real-Time Web Dashboard
app.use('/express-lens', dashboardHandler());
// 4. Mount JSON metrics API endpoint
app.get('/express-lens/json', metricsHandler());
// Sample Routes
app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: 'Alice' }]);
});
app.get('/api/slow', async (req, res) => {
await new Promise((resolve) => setTimeout(resolve, 600)); // Triggers Slow Profiler
res.json({ status: 'done' });
});
app.listen(3000, () => {
console.log('π Server running on http://localhost:3000');
console.log('π Dashboard live at http://localhost:3000/express-lens');
console.log('π Prometheus metrics at http://localhost:3000/metrics');
});@codebygarv/express-lens ships with dedicated framework adapters:
import Fastify from 'fastify';
import { fastifyExpressLens } from '@codebygarv/express-lens/fastify';
const fastify = Fastify();
await fastify.register(fastifyExpressLens({ slowThresholdMs: 500 }));import { Hono } from 'hono';
import { honoExpressLens } from '@codebygarv/express-lens/hono';
const app = new Hono();
app.use('*', honoExpressLens({ slowThresholdMs: 500 }));// app/api/users/route.ts
import { withExpressLens } from '@codebygarv/express-lens/next';
async function handler(req: Request) {
return Response.json({ users: [] });
}
export const GET = withExpressLens(handler);
// app/api/express-lens/[[...route]]/route.ts
import { dashboardRoute } from '@codebygarv/express-lens/next';
export const GET = dashboardRoute();Access the embedded live dashboard by mounting app.use('/express-lens', dashboardHandler()).
Features included in the dashboard:
- Live Stream Feed: Server-Sent Events (SSE) push new requests instantly.
- Percentile Gauges: Real-time display of p50, p90, p95, and p99 latencies.
- Slow Requests Profiler Tab: Dedicated view of slow HTTP operations exceeding
slowThresholdMs. - Search & Filter Toolbar: Search traffic by method (
GET,POST), URL regex, or HTTP status (2xx,4xx,5xx). - cURL Copy & HAR Export: Copy exact cURL strings for any request or download full HAR 1.2 JSON files.
Express Lens exports standard Prometheus Exposition text (v0.0.4):
# HELP http_requests_total Total number of HTTP requests processed
# TYPE http_requests_total counter
http_requests_total 142
# HELP http_request_duration_seconds Summary of HTTP request durations in seconds
# TYPE http_request_duration_seconds summary
http_request_duration_seconds{quantile="0.5"} 0.012500
http_request_duration_seconds{quantile="0.9"} 0.045000
http_request_duration_seconds{quantile="0.95"} 0.088000
http_request_duration_seconds{quantile="0.99"} 0.120000
# HELP express_lens_memory_rss_bytes Process RSS memory in bytes
# TYPE express_lens_memory_rss_bytes gauge
express_lens_memory_rss_bytes 48200000
Add to your prometheus.yml scraper configuration:
scrape_configs:
- job_name: 'express-app'
metrics_path: '/metrics'
static_configs:
- targets: ['localhost:3000']app.use(
monitor({
logAnalytics: true, // Default: true. Console log request metrics
logInterval: 0, // Default: 0 (log each request). > 0 sets batched summary logging (ms)
colorize: true, // Colorize status codes and latency in terminal
ignoreRoutes: ['/health', '/metrics'], // Skip tracking for matched paths or regex
slowThresholdMs: 500, // Profile requests exceeding duration threshold (ms)
maxBodySize: 1024, // Maximum body bytes to capture per request (default: 1024 bytes)
maxDepth: 4, // Maximum JSON depth before collapsing inner objects
maxArrayItems: 10, // Maximum array items to show before truncating
redactHeaders: ['x-custom-token'], // Additional header names to mask as [REDACTED]
alerts: {
errorRateThreshold: 5, // Alert when error rate >= 5%
memoryThresholdMb: 500, // Alert when RSS memory >= 500MB
avgDurationThresholdMs: 1000, // Alert when average latency >= 1000ms
onAlert: (alert) => {
// Callback function triggered on breach
console.log(alert.type, alert.message, alert.timestamp);
},
},
})
);Returns a complete JSON snapshot of all tracked metrics:
import { getMetrics } from '@codebygarv/express-lens';
console.log(getMetrics());Returns exact percentiles (p50, p90, p95, p99) for an array of latency numbers.
Returns standard HTTP Archive (HAR 1.2) compliant JSON object of recent traffic.
Replays a recorded request by its unique request ID.
Generates copy-pasteable cURL string for a request object with redacted sensitive headers.
MIT License β Created with β€οΈ by Garv Thakral.