Request IDs

Every request OxPHP processes gets a unique identifier for tracing and log correlation. The ID appears in response headers and access logs, so you have one value to follow a request across every layer of your stack.

How it works

OxPHP assigns an ID to each incoming request before anything else runs. If the client already sent an X-Request-ID header (say, from a load balancer or API gateway), OxPHP validates that value and keeps it. To pass validation the header must be 1–64 characters long and contain only alphanumerics, hyphens (-), underscores (_), or dots (.). Anything that fails is replaced with a freshly generated ID.

When no valid X-Request-ID arrives, OxPHP generates a 20-character lowercase hexadecimal ID such as 67890abc12341a2b0042. The value encodes a timestamp, a process-unique value, and a monotonic counter, so collisions across containers and restarts are extremely unlikely.

From there the ID travels with the request:

  • It goes out in the X-Request-ID response header on every response.
  • When access logging is enabled, it appears in the request_id field of every access log entry.
  • PHP scripts can read it via oxphp_request_id().

Response header

Every HTTP response from OxPHP includes the X-Request-ID header:

http
HTTP/1.1 200 OK X-Request-ID: 67890abc12341a2b0042 Content-Type: text/html; charset=utf-8

When an upstream load balancer or gateway provides an X-Request-ID on the incoming request, OxPHP echoes the same value back in the response, so traceability holds end to end across your infrastructure.

Reading the request ID from PHP

Read the current request ID with oxphp_request_id():

php
<?php $requestId = oxphp_request_id(); // Include in application logs for correlation $logger->info('Processing order', [ 'request_id' => $requestId, 'order_id' => $orderId, ]);

Forward the request ID to downstream services to keep traceability across API calls:

php
<?php $requestId = oxphp_request_id(); $ch = curl_init('https://api.example.com/users'); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Request-ID: $requestId", ]); $response = curl_exec($ch); curl_close($ch);

Access log entries

When access logging is enabled, every log entry includes the request_id field:

json
{ "timestamp": "2026-02-11T12:34:56.789Z", "level": "INFO", "fields": { "request_id": "67890abc12341a2b0042", "method": "GET", "path": "/api/users", "status": 200, "duration_us": 1234, "remote_ip": "10.0.0.1", "message": "request completed" } }

Filter your log aggregator by request_id to trace the full lifecycle of a single request, including any PHP errors or application log entries that reference the same ID.

Troubleshooting

The `X-Request-ID` header is missing from responses

This is unexpected. OxPHP adds the header to every response, so if it is missing, an intermediate proxy is probably stripping it.

Check: Test directly against OxPHP without any proxy in the path:

bash
curl -v http://localhost:8080/ 2>&1 | grep -i x-request-id
An upstream ID is not being preserved

The incoming X-Request-ID value may be failing validation. OxPHP rejects IDs that are empty, longer than 64 characters, or contain characters other than alphanumerics, hyphens, underscores, or dots.

Check: Inspect the value your upstream sends and verify it meets the character and length requirements. Common failures include values with slashes, spaces, or brace characters.

`oxphp_request_id()` returns an empty string

This function is only available within OxPHP. If you run the same PHP code under PHP-FPM or CLI, the function is not defined. Guard calls with a compatibility check:

php
<?php $requestId = function_exists('oxphp_request_id') ? oxphp_request_id() : ($_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid('', true));

See also

  • Access Logging — every log entry includes the request_id field
  • PHP Functions — full reference for oxphp_request_id() and other built-in functions