The Proxy Logs endpoints let you query, summarize, and stream the centralized logs that the Hoody proxy collects for every request, response, and event flowing through your services. Use them to audit traffic, debug routing issues, or pipe live activity into dashboards and alerting pipelines.
All endpoints on this page are served from a per-container logs subdomain of the form https://{projectId}-{containerId}-logs-1.{serverName}.containers.hoody.icu.
Querying logs
Section titled “Querying logs”GET /_logs
Section titled “GET /_logs”Search and filter through stored request, response, and event logs.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | No | Maximum number of entries to return. Default: 200 |
| offset | query | integer | No | Number of entries to skip. Default: 0 |
| projectId | query | string | No | Filter to a single project |
| containerId | query | string | No | Filter to a single container |
| serviceName | query | string | No | Filter to a single service name |
| level | query | string | No | Comma-separated levels (debug,info,warn,error) |
| includeRequestBody | query | boolean | No | Include the request body on entries. Default: false |
| includeResponseBody | query | boolean | No | Include the response body on entries. Default: false |
| last | query | integer | No | Return only the last N entries |
| afterId | query | integer | No | Return entries with SQLite row ID greater than this (ASC cursor) |
| cursor | query | string | No | Pagination cursor (signed opaque base64) |
| kind | query | string | No | One of request, response, event |
| method | query | string | No | Filter by HTTP method |
| source | query | string | No | One of backend, edge |
This endpoint accepts no request body.
Response
Section titled “Response”Log query results. Scoped reads (filtered by projectId and/or containerId) return a paginated JSON payload. Unscoped reads can request application/x-ndjson to stream the scan, with one compact entry per line and a final trailer carrying cursor, filesVisited, rowsEmitted, and stoppedReason.
{ "entries": [ { "id": 18234, "traceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "tsMs": 1719438215432, "tsIso": "2024-06-26T14:23:35.432Z", "kind": "request", "level": "info", "projectId": "proj_abc123", "containerId": "cont_xyz789", "serviceName": "auth-service", "method": "POST", "url": "/api/v1/login", "clientIp": "203.0.113.42", "status": 200, "data": {}, "source": "backend" }, { "id": 18235, "traceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "tsMs": 1719438215435, "tsIso": "2024-06-26T14:23:35.435Z", "kind": "response", "level": "info", "projectId": "proj_abc123", "containerId": "cont_xyz789", "serviceName": "auth-service", "method": "POST", "url": "/api/v1/login", "clientIp": "203.0.113.42", "status": 200, "data": {}, "source": "backend" } ], "total": 18432, "limit": 200, "offset": 0}{ "statusCode": 403, "error": "Forbidden", "message": "Logs token is missing or does not grant access to the requested scope"}The fanout snapshot has expired. The client must restart the scan without a cursor.
{"__trailer": true, "error": "snapshot_expired", "status": 410}Example request
Section titled “Example request”curl -X GET "https://proj_abc123-cont_xyz789-logs-1.us-east-1.containers.hoody.icu/_logs?limit=50&level=info&kind=request" \ -H "Authorization: Bearer <token>"await client.proxyLogs.logs.listIterator({ limit: 50, level: 'info', kind: 'request'})GET /_logs/stats
Section titled “GET /_logs/stats”Return aggregate counts of stored logs broken down by level, project, container, and service.
This endpoint takes no parameters.
Response
Section titled “Response”{ "total": 18432, "byLevel": { "debug": 8421, "info": 7102, "warn": 1923, "error": 986 }, "byProject": { "proj_abc123": 12300, "proj_def456": 6132 }, "byContainer": { "cont_xyz789": 12300, "cont_uvw012": 6132 }, "byService": { "auth-service": 8230, "billing-service": 5102, "notification-service": 5100 }}Example request
Section titled “Example request”curl -X GET "https://proj_abc123-cont_xyz789-logs-1.us-east-1.containers.hoody.icu/_logs/stats" \ -H "Authorization: Bearer <token>"await client.proxyLogs.logs.getStats()Streaming logs
Section titled “Streaming logs”GET /_logs/stream
Section titled “GET /_logs/stream”Opens a persistent Server-Sent Events connection that streams new log entries as they are recorded.
Framing — every frame carries an id: <ringSeq> line followed by data: .
Reconnect resume — clients may send Last-Event-ID: <ringSeq> on reconnect. The server skips any frame whose ringSeq is ≤ the supplied value from the ring buffer.
Named events (v8 contract):
event: scope-destroyed— the container was destroyed; the stream closes immediately. Clients should exit cleanly.event: reset— the server restarted and theringSeqcounter has been reset with a≥ 10000safety margin. Clients MUST discard theirlastSeenIdand reconnect fresh.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
| projectId | query | string | No | Filter to a single project |
| containerId | query | string | No | Filter to a single container |
| kind | query | string | No | One of request, response, event |
| level | query | string | No | One of debug, info, warn, error |
| Last-Event-ID | header | string | No | Numeric ringSeq of the last event received. Server skips entries ≤ this value from the ring buffer on reconnect |
This endpoint accepts no request body.
Response
Section titled “Response”Server-Sent Events stream of live log entries. Each data: line carries a JSON-serialized LogEntry.
id: 18235data: {"id":18235,"traceId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","tsMs":1719438216000,"tsIso":"2024-06-26T14:23:36.000Z","kind":"response","level":"info","projectId":"proj_abc123","containerId":"cont_xyz789","serviceName":"auth-service","method":"POST","url":"/api/v1/login","clientIp":"203.0.113.42","status":200,"data":{},"source":"backend"}
:The :\n\n line is a comment heartbeat emitted every 15 seconds.
The logs token is missing or invalid, or the gateway policy denied the request.
{ "statusCode": 403, "error": "Forbidden", "message": "Logs token missing or invalid"}The client was rate limited.
{ "statusCode": 429, "error": "Too Many Requests", "message": "Rate limit exceeded"}Example request
Section titled “Example request”curl -N -X GET "https://proj_abc123-cont_xyz789-logs-1.us-east-1.containers.hoody.icu/_logs/stream?projectId=proj_abc123&level=info" \ -H "Authorization: Bearer <token>"await client.proxyLogs.logs.streamLogs({ projectId: 'proj_abc123', level: 'info'})