Skip to content

Logs and metrics

The gateway gives you three sources of information: the gateway log, the access log and Prometheus metrics.

Source Content Where
Gateway log What the gateway itself is doing: startup, config loading, errors standard error
Access log One JSON line per request standard output
Prometheus metrics Counters, histograms and gauges /metrics on the support server

Written to standard error. Configure it with --gLogLevel (trace, debug, info, warn, error) and --gLogFormat (json for machines, console for people). See Command line.

One JSON line is written for every request the gateway handled, to standard output. Lines are written in batches, a request never waits for the log. If the log can’t keep up, events are dropped rather than slowing requests down, and counted in gw_access_log_dropped_total.

Use --gAccessLogSinks none to turn it off, --gAccessLogSinks stdout (the default) to keep it on. See Command line.

Example line (wrapped here for reading):

{"stream":"access","ts":"2026-10-20T15:04:05.123Z","request_path":"/a/limited/ping","request_method":"GET",
"response_status":429,"error_reason":"Too many requests","caller_ip":"203.0.113.7","caller_id":"",
"request_id":"","nocleye_request_id":"9f2c...","auth_method":"","request_size_bytes":0,
"response_size_bytes":17,"upstream_service":"svc-a","upstream_latency_ms":0,"latency_ms":0.21,
"user_agent":"curl/8.5.0","path_pattern":"/a/limited","route_matched":"a-limited","gateway_version":"1.0.0"}
Field Description
stream Always access.
ts Time the request was received, UTC, millisecond precision.
request_path, request_method Path and method of the request.
response_status Status code returned to the caller.
error_reason Why the gateway itself rejected the request: Too many requests, Unauthorized, API NOT FOUND, BAD REQUEST, API UNAVAILABLE, UPSTREAM ERROR or CLIENT CANCELED. Empty when the response came from the backend.
caller_ip IP of the caller. See --gTrustedProxies in Command line.
caller_id Identity from the token when the route is authenticated, otherwise empty.
request_id The X-Request-Id sent by the caller, if it is valid. Only recorded, never reused.
nocleye_request_id Request ID generated by the gateway. It is also sent to the backend as X-Nocleye-Request-Id, use it to correlate logs.
auth_method Name of the authentication method applied, empty if none.
request_size_bytes, response_size_bytes Body sizes.
upstream_service Name of the server the request was routed to.
upstream_latency_ms Time spent waiting for the backend.
latency_ms Total time spent in the gateway, including the backend.
user_agent User-Agent of the caller.
path_pattern, route_matched PathPattern and name of the matched route. Empty when no route matched.
gateway_version Version of the gateway that handled the request.

caller_ip and caller_id can be personal data. Keep that in mind when you ship or store the access log.

Requests that don’t match any route, or that are rejected as a bad request, are counted in the metrics but are not written to the access log.

An internal HTTP server, bound to --sHost:--sPort (default 127.0.0.1:8081). Do not expose it publicly. It also hosts the live config API, see Support server.

Endpoint Description
GET /healthz Liveness probe. Answers 200 whenever the process is up.
GET /readyz Readiness probe. Answers 200 with ok once the config is loaded, and 503 while starting and once shutdown has begun, so load balancers stop sending traffic before the gateway drains.
GET /metrics Prometheus metrics. Only available when --sPrometheusEnabled is true.

Turn Prometheus on with --sPrometheusEnabled, then choose what to expose with --sPrometheusMetrics, a comma separated list of metric families, or all. With an empty list /metrics has no series, and nocleye check warns about it.

Terminal window
nocleye gateway --gConfigPath ./gateway.yaml \
--sPrometheusEnabled \
--sPrometheusMetrics gw_requests_total,gw_request_duration_seconds,go,process

Scrape it with:

scrape_configs:
- job_name: gateway
static_configs:
- targets: ["gateway:8081"]
Metric Type Labels Description
gw_requests_total counter route, upstream, auth_method, method, code, source, reason Total requests handled.
gw_request_duration_seconds histogram route, upstream Request latency as seen by the gateway.
gw_upstream_duration_seconds histogram route, upstream Backend latency.
gw_request_size_bytes histogram route Request body size.
gw_response_size_bytes histogram route Response body size.
gw_in_flight_requests gauge upstream Requests currently being proxied to a backend.
gw_upstream_last_success_timestamp_seconds gauge upstream Unix time of the last successful response from a backend.

Requests that match no route are counted under route="__unmatched__".

The source label tells who produced the response, and reason tells why when the gateway or the caller ended the request:

source reason Meaning
upstream none The response came from the backend, whatever its status.
upstream upstream_error The backend could not be reached or failed mid request.
gateway rate_limited A usage control limit was exceeded.
gateway unauthorized Authentication failed.
gateway route_not_found No route matched.
gateway bad_request The request was rejected as malformed.
gateway upstream_unavailable The route’s server is not available.
client client_canceled The caller closed the connection.
Metric Type Labels Description
gw_ratelimit_key_utilization histogram rule Distribution of how much of the limit each caller has used.
gw_ratelimit_keys gauge rule Number of callers currently tracked by a rule.

These use approximate counting, so memory stays small no matter how many callers you have.

Metric Type Labels Description
gw_unique_callers gauge route, window Approximate distinct callers per route.
gw_unique_caller_ips gauge route, window Approximate distinct caller IPs per route.
gw_auth_failure_unique_ips gauge auth_method Approximate distinct IPs failing authentication.
gw_unmatched_unique_paths gauge none Approximate distinct paths that matched no route.
Metric Type Labels Description
gw_sink_events_total counter sink, result Access log events seen by a sink.
gw_sink_dropped_total counter sink, reason Access log events dropped by a sink.
gw_sink_queue_depth gauge sink Current queue depth of a sink.
gw_sink_queue_capacity gauge sink Queue capacity of a sink.
gw_sink_last_success_timestamp_seconds gauge sink Unix time of a sink’s last successful write.
gw_sink_last_write_seconds gauge sink Duration of a sink’s last write.
gw_access_log_dropped_total counter reason Access log events dropped before reaching any sink.
Metric Type Labels Description
gw_build_info gauge version, go_version Build information, always 1.
gw_config_info gauge hash The loaded config, always 1. hash changes whenever the config changes.
gw_config_reloads_total counter result Config loads, by result.
gw_routes gauge none Number of routes in the loaded config.
gw_metrics_series_overflow_total counter none Requests whose label combination was refused a new series because of --sPrometheusMaxSeries.

go (Go runtime metrics) and process (CPU, memory, file descriptors) can be listed in --sPrometheusMetrics like any other family.

gw_requests_total creates one series per label combination. --sPrometheusMaxSeries (default 20000) caps them. Once the cap is reached, new combinations are folded into a single route="__overflow__" series and counted in gw_metrics_series_overflow_total, so memory stays bounded.