flamegraph-middleware
v1.0.0
Published
HTTP middleware for CPU and heap profiling with flamegraph visualization
Maintainers
Readme
flamegraph-middleware
Node.js HTTP middleware for on-demand CPU and heap profiling with interactive flamegraph visualization.
Features
- 🔥 On-demand profiling - Start CPU and heap profiling via HTTP request
- 📊 Interactive flamegraphs - Visualize profiles with WebGL-powered flamegraphs
- 🎯 Dual profiling - Collect both CPU and heap profiles simultaneously
- 🌐 Framework agnostic - Works with native
http, Express, Fastify, and other frameworks - ⚡ Non-blocking - Profiling runs in the background without blocking requests
- 💾 In-memory storage - Profiles stored temporarily with automatic expiration
- 🎨 Customizable - Configure colors, durations, and storage limits
Installation
npm install Qard/flamegraph-middlewareQuick Start
With Native HTTP Server
import http from 'http'
import { createFlamegraphMiddleware } from 'flamegraph-middleware'
const flamegraph = createFlamegraphMiddleware()
const server = http.createServer((req, res) => {
flamegraph(req, res, () => {
res.writeHead(200)
res.end('Hello World')
})
})
server.listen(3000)
console.log('Server running at http://localhost:3000')
console.log('Profile at http://localhost:3000/flamegraph?duration=5000')With Express
import express from 'express'
import { createFlamegraphMiddleware } from 'flamegraph-middleware'
const app = express()
app.use(createFlamegraphMiddleware({
basePath: '/flamegraph',
defaultDuration: 10000
}))
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000)With Fastify
import Fastify from 'fastify'
import middie from '@fastify/middie'
import { createFlamegraphMiddleware } from 'flamegraph-middleware'
const fastify = Fastify({ logger: true })
await fastify.register(middie)
fastify.use(createFlamegraphMiddleware({
logger: fastify.log // Use Fastify's pino logger
}))
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})
await fastify.listen({ port: 3000 })Usage
Starting a Profile
Navigate to /flamegraph?duration=10000 to start a 10-second profile:
curl http://localhost:3000/flamegraph?duration=10000The page will show a "Profiling in Progress" message and automatically refresh when complete.
Viewing Results
After profiling completes, you'll see two interactive flamegraphs:
- CPU Profile - Shows where CPU time is being spent
- Heap Profile - Shows memory allocation patterns
Each flamegraph is interactive:
- Click frames to zoom in
- Hover for details
- View stack traces
- Navigate hottest frames
Configuration
createFlamegraphMiddleware({
basePath: '/flamegraph', // Route prefix (default: '/flamegraph')
maxDuration: 60000, // Maximum profile duration in ms (default: 60000)
defaultDuration: 10000, // Default duration when not specified (default: 10000)
heapSamplingInterval: 524288, // Heap sampling interval in bytes (default: 512*1024)
maxProfiles: 10, // Max profiles to keep in memory (default: 10)
profileTTL: 300000, // Profile expiration time in ms (default: 300000)
colors: {
primary: '#ff4444', // Primary flamegraph color (default: '#ff4444')
secondary: '#ffcc66' // Secondary flamegraph color (default: '#ffcc66')
},
logger: pinoLogger // Pino logger instance (optional, no logging if not provided)
})Logging
The middleware supports pino for structured logging. By default, if no logger is provided, the middleware will not log. You can pass your own pino logger instance to enable logging and integrate with your application's logging:
import pino from 'pino'
import { createFlamegraphMiddleware } from 'flamegraph-middleware'
// Custom logger configuration
const logger = pino({
level: 'debug',
transport: {
target: 'pino-pretty'
}
})
const flamegraph = createFlamegraphMiddleware({ logger })Log Levels
The middleware logs at different levels:
- debug - Detailed operation logs (profile ID generation, encoding steps, retrieval attempts)
- info - Lifecycle events (profile requests, collection complete, storage operations)
- warn - Warnings (profile evictions, timing issues)
- error - Errors (profiling failures, encoding errors, storage issues)
All logs include structured data with relevant context like profileId, duration, component, etc.
API
createFlamegraphMiddleware(options)
Creates a middleware function for profiling.
Parameters:
options(Object) - Configuration optionsbasePath(string) - Base URL path for the middlewaremaxDuration(number) - Maximum allowed profile duration in millisecondsdefaultDuration(number) - Default profile duration when not specifiedheapSamplingInterval(number) - Heap profiling sampling interval in bytesmaxProfiles(number) - Maximum number of profiles to store in memoryprofileTTL(number) - Time in milliseconds before profiles expirecolors(Object) - Color customizationprimary(string) - Primary color for flamegraphs (hex format)secondary(string) - Secondary color for flamegraphs (hex format)
logger(Object) - Pino logger instance (optional, no logging if not provided)
Returns: Function - Middleware function with signature (req, res, next)
Routes
GET /flamegraph?duration=<ms>
Start a new profiling session.
Query Parameters:
duration(optional) - Profile duration in milliseconds (must be ≤ maxDuration)
Response: HTML page showing "Profiling in Progress" with auto-refresh
GET /flamegraph/result/<id>
View profiling results for a specific session.
Response: HTML page with interactive CPU and heap flamegraphs
How It Works
- Request - User navigates to
/flamegraph?duration=10000 - Initialize - Middleware starts CPU and heap profiling
- Progress - Returns a progress page that auto-refreshes
- Collect - After duration, both profiles are collected and stored
- Display - Results page shows interactive flamegraphs side-by-side
Security Considerations
⚠️ Important: This middleware exposes profiling capabilities that can:
- Impact application performance during profiling
- Expose internal code structure and behavior
- Consume memory to store profile data
Recommendations:
- Do not expose in production without authentication/authorization
- Use rate limiting to prevent abuse
- Monitor resource usage when profiling is active
- Set appropriate maxDuration to prevent excessive profiling
- Consider IP whitelisting for production deployments
Example with Authentication
import { createFlamegraphMiddleware } from 'flamegraph-middleware'
const flamegraph = createFlamegraphMiddleware()
function requireAuth (req, res, next) {
// Your authentication logic here
if (!isAuthorized(req)) {
res.writeHead(401)
res.end('Unauthorized')
return
}
next()
}
app.use('/flamegraph', requireAuth, flamegraph)Performance Impact
Profiling has minimal overhead on your application:
- CPU profiling: Sampling-based, ~1-2% overhead
- Heap profiling: Sampling-based with configurable interval
- No impact when not actively profiling
- Background collection doesn't block request handling
Example Application
A complete TODO CRUD application example is available in the example/ directory:
cd example
npm install
npm startVisit http://localhost:3000 to:
- Create, update, and delete TODO items
- Try flamegraph profiling with a working application
- See the middleware integrated with Fastify
See example/README.md for more details.
Examples
Generate a 30-second profile
curl http://localhost:3000/flamegraph?duration=30000Use default duration
curl http://localhost:3000/flamegraphCustom colors
createFlamegraphMiddleware({
colors: {
primary: '#2563eb', // Blue
secondary: '#7dd3fc' // Light blue
}
})Dependencies
- @datadog/pprof - CPU and heap profiling
- react-pprof - Flamegraph visualization
- pino - Fast structured logging
Requirements
- Node.js 18 or higher
- Supported platforms: Linux, macOS, Windows (x64/arm64)
License
Apache-2.0
