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.

Quick Start
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/metrics

Prometheus 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.

Configuration
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}));
Exposed Metrics
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 1548
Prometheus Scrape Config
1# 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.

Lambda Setup
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();
What Gets Emitted
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}
Custom Output Sink
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.

typescript
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.

Custom Stats Endpoint
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});

Next Steps