# Monitoring & Performance

**Page:** api/exec/monitoring

[Download Raw Markdown](./api/exec/monitoring.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The exec service provides endpoints for runtime health checks, performance monitoring, active request inspection, Prometheus metrics export, and graceful server restarts. Use these endpoints from your dashboards, alerting pipelines, and control-plane tooling to observe and manage a running exec instance.

## Health

### `GET /api/v1/exec/health`

Returns process-level health and metadata for the exec service, including build timestamp, process start time, resident memory, file descriptor count, process ID, peer IP, and the incoming `User-Agent` header.

This endpoint takes no parameters.




```bash
curl -X GET "https://exec.example.com/api/v1/exec/health"
```




```typescript
await client.exec.health.check();
```




**Response**




```json
{
  "status": "ok",
  "service": "hoody-exec",
  "built": "2026-01-10T08:00:00.000Z",
  "started": "2026-01-15T00:00:00.000Z",
  "memory": {
    "rss": 178257920,
    "heap": 134217728
  },
  "fds": 42,
  "pid": 1234,
  "ip": "203.0.113.42",
  "userAgent": "curl/8.5.0"
}
```




```json
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "header",
    "reason": "missing or invalid header value"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "reason": "health probe failed"
  }
}
```





The `ip` field reflects the socket peer IP (TPROXY), **not** the `X-Forwarded-For` header. The `fds` field is `null` on non-Linux platforms because it is read from `/proc/self/fd`.


## Performance Monitoring

### `GET /api/v1/exec/monitor/stats`

Returns process-wide counters: uptime, memory usage, cache sizes, request totals, WebSocket lifecycle counters, cron fire counts, and the count of dropped per-script metrics entries.

This endpoint takes no parameters.




```bash
curl -X GET "https://exec.example.com/api/v1/exec/monitor/stats"
```




```typescript
await client.exec.monitor.getStats();
```




**Response**




```json
{
  "uptime": 86400,
  "memory": {
    "used": 134217728,
    "total": 268435456,
    "percentage": 50.0,
    "rss": 178257920,
    "external": 4194304
  },
  "cache": {
    "scripts": 12,
    "vms": 8,
    "sharedStates": 3,
    "activeWsHostnames": 2
  },
  "requests": {
    "total": 12453,
    "success": 12380,
    "errors": 73,
    "activeHttp": 2,
    "perSecond": 0.144,
    "per1m": 0.5,
    "per5m": 0.3,
    "per15m": 0.25
  },
  "websocket": {
    "opened": 87,
    "closed": 85,
    "active": 2,
    "normalCloses": 84,
    "abnormalCloses": 1
  },
  "cron": {
    "fires": 120,
    "errors": 2,
    "active": 0,
    "wrapperActive": 0
  },
  "droppedScripts": 0,
  "sinceMs": 1736899200000
}
```




```json
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "query",
    "reason": "unexpected parameter"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```





The `perSecond` field is the **lifetime** average req/s, not a windowed value. Use `per1m`, `per5m`, or `per15m` for rolling averages. A non-zero `droppedScripts` indicates the per-script LRU map is full and entries are being discarded.


### `GET /api/v1/exec/monitor/scripts`

Lists all scripts tracked by the in-memory metrics registry, including HTTP/WS aggregate stats, recent errors, and lifecycle timestamps. Supports pagination via `limit` and ordering via `sort`.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `limit` | query | integer | No | Max number of scripts to return. Clamped to `[1, 500]`. Default: `100`. |
| `sort` | query | string | No | Sort key. `lastActivity` (default) sorts by most recent activity; other keys sort descending by the matching metric. Accepted values: `lastActivity`, `requests`, `errors`, `p95`, `ws_active`. Default: `"lastActivity"`. |




```bash
curl -X GET "https://exec.example.com/api/v1/exec/monitor/scripts?limit=50&sort=p95"
```




```typescript
await client.exec.monitor.listMonitorScripts({
  limit: 50,
  sort: "p95"
});
```




**Response**




```json
{
  "count": 1,
  "total": 1,
  "scripts": [
    {
      "scriptPath": "/api/hello",
      "hostname": "host-1",
      "vmCached": true,
      "sharedStateBytes": 1024,
      "activeHttp": 0,
      "activeWs": 2,
      "concurrentRunning": 1,
      "http": {
        "total": 1523,
        "success": 1510,
        "errors": 13,
        "meanDurationMs": 12.4,
        "p50DurationMs": 8.1,
        "p95DurationMs": 45.2,
        "maxDurationMs": 312.7
      },
      "ws": {
        "opened": 87,
        "closed": 85,
        "normalCloses": 84,
        "abnormalCloses": 1,
        "meanSessionMs": 12345,
        "maxSessionMs": 67890
      },
      "recentErrors": [
        {
          "timestamp": "2026-01-15T10:25:00.000Z",
          "statusCode": 500,
          "message": "Unhandled exception in handler",
          "executionId": "exec_01HABCDEF1234567890ABCDEF"
        }
      ],
      "firstSeenAt": "2026-01-10T08:00:00.000Z",
      "lastActivityAt": "2026-01-15T10:30:00.000Z"
    }
  ]
}
```




```json
{
  "error": "Invalid query parameter",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "limit",
    "reason": "must be between 1 and 500"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```





`recentErrors[].message` may contain user-controlled content. The server sanitizes each entry to a single line capped at 256 code points, but downstream UIs should still treat the field as untrusted.


### `POST /api/v1/exec/monitor/script-performance`

Returns detailed lifetime metrics for a single tracked script, including per-script HTTP and WebSocket aggregates and a recent-duration sample array. The endpoint accepts an optional JSON body and returns an empty `metrics` object when no `scriptPath` is provided or the script is not tracked.

This endpoint takes no parameters.

**Request Body**

The request body is optional. The schema is empty `{}`; pass a payload to refine the response (the exact fields are not part of the public schema).




```bash
curl -X POST "https://exec.example.com/api/v1/exec/monitor/script-performance" \
  -H "Content-Type: application/json" \
  -d '{}'
```




```typescript
await client.exec.monitor.getScriptPerformance({});
```




**Response**




```json
{
  "metrics": {
    "scriptPath": "/api/hello",
    "period": "lifetime",
    "http": {
      "total": 1523,
      "success": 1510,
      "errors": 13,
      "meanDurationMs": 12.4,
      "p50DurationMs": 8.1,
      "p95DurationMs": 45.2,
      "maxDurationMs": 312.7,
      "recentDurationsMs": [10, 12, 8, 45, 312, 9, 11, 7]
    },
    "ws": {
      "opened": 87,
      "closed": 85,
      "normalCloses": 84,
      "abnormalCloses": 1,
      "meanSessionMs": 12345,
      "maxSessionMs": 67890
    },
    "activeHttp": 0,
    "activeWs": 2,
    "firstSeenAt": "2026-01-10T08:00:00.000Z",
    "lastActivityAt": "2026-01-15T10:30:00.000Z"
  }
}
```




```json
{
  "error": "Invalid request body",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "body",
    "reason": "malformed JSON"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```




### `GET /api/v1/exec/monitor/metrics`

Exposes runtime metrics in Prometheus 0.0.4 text exposition format, including per-script and global HTTP histograms, WebSocket connection gauges, error counters, and `process_start_time_seconds`.

This endpoint takes no parameters.




```bash
curl -X GET "https://exec.example.com/api/v1/exec/monitor/metrics"
```




```typescript
await client.exec.monitor.prometheusExport();
```




**Response**




```
# HELP hoody_exec_http_requests_total Total HTTP requests served by scripts
# TYPE hoody_exec_http_requests_total counter
hoody_exec_http_requests_total{script="/api/hello",method="GET"} 1523
hoody_exec_http_requests_total{script="/api/echo",method="POST"} 421

# HELP hoody_exec_http_errors_total Total HTTP errors served by scripts
# TYPE hoody_exec_http_errors_total counter
hoody_exec_http_errors_total{script="/api/hello",status="500"} 13

# HELP hoody_exec_http_duration_ms HTTP request duration in milliseconds (per-script histogram)
# TYPE hoody_exec_http_duration_ms histogram
hoody_exec_http_duration_ms_bucket{script="/api/hello",le="50"} 1480
hoody_exec_http_duration_ms_bucket{script="/api/hello",le="100"} 1510
hoody_exec_http_duration_ms_bucket{script="/api/hello",le="+Inf"} 1523
hoody_exec_http_duration_ms_count{script="/api/hello"} 1523
hoody_exec_http_duration_ms_sum{script="/api/hello"} 18855.2

# HELP hoody_exec_ws_connections_active Currently open WebSocket connections
# TYPE hoody_exec_ws_connections_active gauge
hoody_exec_ws_connections_active{script="/api/ws"} 2

# HELP process_start_time_seconds Start time of the process since unix epoch in seconds
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1736899200
```




```json
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "header",
    "reason": "invalid Accept header"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```
# Prometheus exporter disabled (--prometheus off)
```




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```





A 404 indicates the Prometheus exporter is disabled. Start the exec server **without** `--prometheus off` (the flag's default is on) to re-enable the `/api/v1/exec/monitor/metrics` endpoint.


## Active Requests

### `GET /api/v1/exec/monitor/active-requests`

Returns the list of in-flight script HTTP requests currently being handled, including execution ID, script path, method, URL (with tokens redacted), start time, and elapsed duration in milliseconds.

This endpoint takes no parameters.




```bash
curl -X GET "https://exec.example.com/api/v1/exec/monitor/active-requests"
```




```typescript
await client.exec.monitor.getActiveRequests();
```




**Response**




```json
{
  "count": 2,
  "active": [
    {
      "executionId": "exec_01HABCDEF1234567890ABCDEF",
      "scriptPath": "/api/hello",
      "hostname": "host-1",
      "clientIp": "203.0.113.42",
      "method": "GET",
      "url": "/api/hello?token=***",
      "startedAt": "2026-01-15T10:30:00.000Z",
      "duration": 125
    },
    {
      "executionId": "exec_01HIJKLMN1234567890ABCDEF",
      "scriptPath": "/api/echo",
      "hostname": "host-1",
      "clientIp": "198.51.100.7",
      "method": "POST",
      "url": "/api/echo",
      "startedAt": "2026-01-15T10:30:02.000Z",
      "duration": 42
    }
  ]
}
```




```json
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "query",
    "reason": "unexpected parameter"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```





Tokens inside the request URL are redacted server-side; never rely on the client to scrub them before reaching the exec service.


## System Management

### `GET /api/v1/exec/system/restart-status`

Reports whether the server can be safely restarted right now. Returns current uptime, the count of in-flight script requests, and a `restartReady` flag derived from those inputs.

This endpoint takes no parameters.




```bash
curl -X GET "https://exec.example.com/api/v1/exec/system/restart-status"
```




```typescript
await client.exec.system.getRestartStatus();
```




**Response**




```json
{
  "canRestart": true,
  "uptime": 86400,
  "uptimeFormatted": "1d 0h 0m",
  "activeRequests": 0,
  "active": [],
  "restartReady": true
}
```




```json
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "query",
    "reason": "unexpected parameter"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z"
}
```




### `POST /api/v1/exec/system/restart`

Triggers a server restart. In graceful mode the server drains in-flight requests up to `drainTimeoutMs` before exiting; the non-graceful path performs an immediate restart.

This endpoint takes no parameters.

**Request Body**

| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `graceful` | boolean | No | `true` | Drain in-flight requests before restarting. |
| `drainTimeoutMs` | integer | No | `5000` | Maximum time in milliseconds to wait for in-flight requests to complete during a graceful restart. |
| `reason` | string | No | `"API restart request"` | Free-form reason recorded in server logs. |




```bash
curl -X POST "https://exec.example.com/api/v1/exec/system/restart" \
  -H "Content-Type: application/json" \
  -d '{
    "graceful": true,
    "drainTimeoutMs": 10000,
    "reason": "deploying v1.2.3"
  }'
```




```typescript
await client.exec.system.restartServer({
  graceful: true,
  drainTimeoutMs: 10000,
  reason: "deploying v1.2.3"
});
```




**Response**




```json
{
  "error": "Invalid restart options",
  "code": "VALIDATION_ERROR",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "field": "drainTimeoutMs",
    "reason": "must be a positive integer"
  }
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input | Request parameters failed validation | Check parameter format and requirements |




```json
{
  "error": "Internal server error",
  "code": "ERROR_500",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "details": {
    "reason": "restart handler unavailable"
  }
}
```





Call `GET /api/v1/exec/system/restart-status` first to confirm `restartReady` is `true`. Issuing a graceful restart while active requests are still in flight will block on the drain until `drainTimeoutMs` elapses.