Trace OpenStack API Calls Across Services with X-Openstack-Global-Request-ID
Trace one OpenStack API call across Nova, Neutron and Cinder using x-openstack-global-request-id: generate a req- UUID, pass --os-global-request-id, and grep it across service logs.
- #openstack
- #logging
- #tracing
- #troubleshooting
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
The Problem: One Action, Many Services
A single OpenStack action fans out across services. Booting a server calls Nova, which calls Neutron for ports and Cinder for volumes, each with its own API workers and log files. When something fails halfway through, correlating the Nova log line with the Neutron and Cinder lines it triggered is painful — timestamps overlap and every service has its own request id. OpenStack solves this with two related headers, and understanding the difference between them is the key to end-to-end tracing.
X-Openstack-Request-Id vs X-Openstack-Global-Request-ID
Every OpenStack API response already returns a local request id:
X-Openstack-Request-Id: req-4f8c1a2b-9d3e-4a71-8c0f-2b1e6d5a9c44
That id is generated per service, per API call. Nova has one, the Neutron call it makes has a different one, Cinder yet another. On its own it only lets you trace within a single service.
The global request id is the glue:
X-Openstack-Global-Request-ID: req-1122aabb-ccdd-4eef-9911-223344556677
You supply it on the first request. Each service records it as global_request_id and, crucially, forwards it to the downstream services it calls. So Nova, Neutron, and Cinder all log the same global id even though each keeps its own local req- id. Grep for the one global id and you get every log line for the whole operation.
Both values use the same req-<uuid> format, and the global id must match the regex OpenStack expects (req- followed by a UUID) or services will reject or ignore it.
Generating a Global Request ID
Any RFC 4122 UUID with a req- prefix works. Generate one on the shell:
echo "req-$(uuidgen)"
req-1122aabb-ccdd-4eef-9911-223344556677
Reuse that single value for the whole operation you want to trace. Do not generate a new one per service — that defeats the purpose.
Passing the Global ID on a Request
The OpenStackClient (OSC) exposes it as a first-class flag. Set your id and pass it through:
GLOBAL_ID="req-1122aabb-ccdd-4eef-9911-223344556677"
openstack --os-global-request-id "$GLOBAL_ID" \
server create --image ubuntu-22.04 --flavor m1.small \
--network private --block-device-mapping vdb=my-vol:::0 \
trace-demo
If you are calling the REST API directly, set the header yourself:
curl -s -X POST "$NOVA_URL/servers" \
-H "X-Auth-Token: $TOKEN" \
-H "X-Openstack-Global-Request-ID: $GLOBAL_ID" \
-H "Content-Type: application/json" \
-d @server.json
Nova validates the header, stores it as the global request id for this operation, and passes it on when it talks to Neutron and Cinder.
How the ID Propagates Nova to Neutron to Cinder
OpenStack’s common libraries (oslo.context and oslo.middleware’s RequestId) carry the global id through the request context. When Nova’s compute or API layer builds a client to call another service, that client re-emits the value as an outbound X-Openstack-Global-Request-ID header. The chain for a boot-from-volume looks like this:
- Nova API receives your request with
global_request_id = req-1122.... - Nova calls Neutron to create/bind the port, sending the same header. Neutron logs
global_request_id req-1122...plus its own localreq-id. - Nova calls Cinder to attach the volume, again forwarding the header. Cinder logs the same global id.
- Each hop keeps its own
X-Openstack-Request-Idfor local tracing, but the global id is constant across all three.
Step-by-Step Resolution
- Mint one global id and export it:
export GLOBAL_ID="req-$(uuidgen)"
echo "$GLOBAL_ID"
- Issue the action with the id attached:
openstack --os-global-request-id "$GLOBAL_ID" \
server create --image ubuntu-22.04 --flavor m1.small \
--network private trace-demo
- Confirm the value came back on the response so you know it was accepted (add
--debugto OSC, or read the header from a raw curl):
openstack --debug --os-global-request-id "$GLOBAL_ID" \
server show trace-demo 2>&1 | grep -i global-request-id
- Grep the id across each service’s logs. On a packaged deployment the logs live under
/var/log/<service>/:
sudo grep -R "$GLOBAL_ID" \
/var/log/nova/ /var/log/neutron/ /var/log/cinder/
/var/log/nova/nova-api.log:... [req-4f8c... req-1122...] POST /servers
/var/log/neutron/server.log:... [req-77aa... req-1122...] create_port
/var/log/cinder/cinder-api.log:... [req-9c14... req-1122...] attach volume
- For containerized deployments (Kolla) or systemd journals, query the same string:
sudo journalctl -u devstack@n-api -u devstack@q-svc -u devstack@c-api \
| grep "$GLOBAL_ID"
- Order the matches by timestamp to reconstruct the exact sequence — Nova first, then the Neutron and Cinder calls it fanned out. The local
req-id in each line lets you then drill into that one service if needed. Turning this grep-and-correlate loop into a repeatable runbook is a natural fit for our DevOps AI prompt library.
Prevention and Best Practices
- Have your automation and CI generate a
req-<uuid>global id per user action and pass--os-global-request-idon every OSC call, so failures are traceable after the fact. - Log the global id you used alongside the ticket or alert; it is the single search key across all services.
- Keep the format strict (
req-+ a valid UUID). Malformed values are silently dropped and you lose correlation. - Centralize logs (rsyslog, Fluentd, Loki) so one search hits Nova, Neutron, and Cinder at once instead of grepping each host.
- Do not confuse the local
X-Openstack-Request-Idwith the global one — only the global id spans services.
Frequently Asked Questions
What is the difference between X-Openstack-Request-Id and X-Openstack-Global-Request-ID? The local X-Openstack-Request-Id is generated per service per call, while X-Openstack-Global-Request-ID is one id you supply that every service records and forwards downstream, letting you trace a single action across Nova, Neutron, and Cinder.
How do I generate a valid global request id? Use echo "req-$(uuidgen)". OpenStack expects the literal req- prefix followed by a UUID; malformed ids are ignored.
How do I pass the global request id with the OpenStack client? Add --os-global-request-id req-<uuid> to any openstack command, or set the X-Openstack-Global-Request-ID header directly when calling the REST API with curl.
How do I find every log line for one request across services? Grep the single global id across each service log, e.g. grep -R req-<uuid> /var/log/nova /var/log/neutron /var/log/cinder, then sort the hits by timestamp to reconstruct the flow. For more platform tracing tips, see the OpenStack guides.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.