Performance Middleware
Monitoring & Metrics
Built-in observability with zero dependencies: Prometheus metrics with a scrape endpoint, CloudWatch metrics via Embedded Metric Format, request logging, and live framework statistics.
Overview
MoroJS ships dependency-free monitoring middleware. Pick the style that matches your infrastructure: pull-based Prometheus scraping for servers, push-via-logs CloudWatch EMF for AWS Lambda, or plain request logging anywhere.
1import { createApp, middleware } from '@morojs/moro';
2
3const app = await createApp();
4
5// Prometheus: records request metrics and serves GET /metrics
6app.use(middleware.prometheus({ endpoint: '/metrics' }));
7
8app.get('/api/hello', () => ({ ok: true }));
9
10app.listen(3000);
11// curl http://localhost:3000/metricsPrometheus Metrics
The Prometheus middleware records request counters and duration histograms — labeled by method and status only, so label cardinality stays bounded — and serves the standard text exposition format at the configured endpoint. No client library required.
1app.use(middleware.prometheus({
2 endpoint: '/metrics', // scrape path (default '/metrics')
3 includeProcessMetrics: true, // memory / heap / uptime gauges (default true)
4 includePoolMetrics: true, // object pool + route cache metrics (default true)
5 buckets: [0.005, 0.01, 0.05, 0.1, 0.5, 1, 5] // histogram bounds in seconds
6}));1# Request metrics
2http_requests_total{method="GET",status="200"} 1027
3http_request_duration_seconds_bucket{method="GET",status="200",le="0.01"} 998
4http_request_duration_seconds_sum{method="GET",status="200"} 3.2
5http_request_duration_seconds_count{method="GET",status="200"} 1027
6
7# Process metrics
8process_resident_memory_bytes 104857600
9nodejs_heap_size_used_bytes 52428800
10process_uptime_seconds 86400
11
12# Framework internals: object pools and route cache
13moro_pool_size{pool="params"} 42
14moro_pool_max_size{pool="params"} 180
15moro_route_cache_hits_total 98452
16moro_route_cache_misses_total 15481# prometheus.yml
2scrape_configs:
3 - job_name: 'moro-api'
4 scrape_interval: 15s
5 static_configs:
6 - targets: ['localhost:3000']CloudWatch (Embedded Metric Format)
The CloudWatch middleware emits one Embedded Metric Format JSON line per request to stdout. On AWS Lambda (and any environment shipping stdout to CloudWatch Logs), CloudWatch extracts these as real metrics automatically — no AWS SDK, credentials, or network calls.
1import { createAppLambda, middleware } from '@morojs/moro';
2
3const app = await createAppLambda();
4
5app.use(middleware.cloudWatch({
6 namespace: 'MoroAPI', // CloudWatch namespace (default 'MoroJS')
7 dimensions: { Service: 'orders' } // extra static dimensions
8}));
9
10app.get('/api/orders/:id', (req) => getOrder(req.params.id));
11
12export const handler = app.getHandler();1// One EMF record per completed request (stdout):
2{
3 "_aws": {
4 "Timestamp": 1753747200000,
5 "CloudWatchMetrics": [{
6 "Namespace": "MoroAPI",
7 "Dimensions": [["Method", "Status", "Service"]],
8 "Metrics": [
9 { "Name": "RequestCount", "Unit": "Count" },
10 { "Name": "RequestDuration", "Unit": "Milliseconds" }
11 ]
12 }]
13 },
14 "Method": "GET",
15 "Status": "200",
16 "Service": "orders",
17 "RequestCount": 1,
18 "RequestDuration": 12,
19 "Path": "/api/orders/42"
20}1// Redirect EMF lines anywhere (useful outside Lambda or in tests)
2app.use(middleware.cloudWatch({
3 namespace: 'MoroAPI',
4 emit: line => myLogPipeline.write(line)
5}));Request Logging
For plain request logging and slow-request warnings, use the built-in observability middleware — zero-config factories like every other entry in the middleware namespace.
1// Log each request and its completion time
2app.use(middleware.requestLogger());
3
4// Warn on requests slower than 1s
5app.use(middleware.performanceMonitor());Framework Statistics
Beyond middleware, the framework exposes live internal statistics you can surface on your own health or metrics endpoints.
1import { ObjectPoolManager } from '@morojs/moro';
2
3app.get('/api/stats', async () => {
4 const pools = ObjectPoolManager.getInstance().getPerformanceSummary();
5 const workers = await app.getWorkerStats(); // null if workers unused
6
7 return {
8 pools, // { routeCacheHitRate, responseCacheHitRate, paramPoolUtilization, totalMemoryKB }
9 workers, // { workerCount, activeTasks, queuedTasks, isShuttingDown }
10 uptime: process.uptime()
11 };
12});