Correlation, Causation, and Request Identity
Correlation ID, Causation ID, Request ID, Trace ID, and Business Keys
Standar identitas teknis dan bisnis untuk korelasi HTTP, messaging, workflow, background job, audit, dan production debugging.
Part 009 — Correlation ID, Causation ID, and Request ID
1. Core Idea
Production debugging becomes difficult when every service can only explain its own local execution. A customer-facing request in an enterprise system rarely stays inside one process. It enters through an edge layer, reaches a Java/JAX-RS endpoint, calls service logic, reads or writes PostgreSQL, touches Redis, publishes Kafka/RabbitMQ messages, triggers workflow execution, invokes downstream services, and may later continue through background jobs or human approval steps.
Without a consistent identity model, all those signals become disconnected fragments.
Correlation identity exists to answer:
"Which logs, metrics, traces, events, audit records, messages, workflow instances, and database changes belong to the same real-world operation?"
This part focuses on the identity vocabulary behind observability:
- request ID
- correlation ID
- causation ID
- trace ID
- span ID
- business transaction ID
- idempotency key
- message ID
- event ID
- process instance ID
- quote ID / order ID / customer-facing business key
These identifiers are related, but they are not interchangeable. A senior engineer must know which one answers which production question.
2. The Problem: Logs Without Identity Are Local Noise
Consider a customer reports:
"My quote was approved, but the order was not created."
You search logs and find:
INFO Quote approved
INFO Publishing order creation event
INFO Received order creation event
ERROR Failed to create order
This is not enough.
You still need to know:
- Which quote?
- Which order attempt?
- Which HTTP request started the change?
- Which user or system actor triggered it?
- Which Kafka/RabbitMQ message carried it?
- Which workflow/process instance handled it?
- Was it a retry or the first attempt?
- Did another service receive the same event?
- Was the failure related to the same trace?
- Was it caused by this request or by a later background reconciliation job?
A log line without identity only proves that something happened somewhere. A log line with correct identity becomes evidence.
3. Identifier Taxonomy
3.1 Request ID
A request ID identifies one inbound request handled by a service boundary.
Typical scope:
- one HTTP request
- one API gateway request
- one JAX-RS resource invocation
- one consumer handling attempt
- one job execution attempt
Common usage:
- find all logs emitted while processing one HTTP request
- diagnose one failed API call
- map edge access log to application log
- compare request start/end/error logs
Example:
request.id = req_01JABCD8S4M7Q2Z6R0P8K2T3N9
A request ID is usually short-lived. It should not be treated as the identity of an entire business transaction.
3.2 Correlation ID
A correlation ID groups multiple technical operations that belong to the same broader workflow or transaction.
Typical scope:
- one customer operation across multiple services
- one quote submission flow
- one order capture flow
- one asynchronous continuation after an API call
- one workflow/process chain
Common usage:
- correlate logs across services
- connect HTTP request to Kafka/RabbitMQ message
- connect producer and consumer processing
- connect background job continuation to original operation
- reconstruct incident timeline
Example:
correlation.id = corr_01JABCDKX7KCY04M7Q6H2P3Y5Z
The correlation ID often survives longer than one request ID.
3.3 Causation ID
A causation ID identifies the immediate parent event or command that caused the current operation.
It answers:
"Why did this operation happen? What directly triggered it?"
Typical usage:
- event-driven systems
- async workflows
- retry chains
- command processing
- saga/process orchestration
- audit reconstruction
Example:
event.id = evt_quote_approved_123
causation.id = evt_quote_submitted_987
Correlation groups a whole flow. Causation describes parent-child triggering.
3.4 Trace ID
A trace ID is part of distributed tracing. It identifies one distributed trace.
Typical scope:
- a single end-to-end execution path represented by spans
- one sampled or recorded distributed trace
- one HTTP request and its downstream calls
- sometimes extended across messaging boundaries if propagation is implemented
Example:
trace.id = 4bf92f3577b34da6a3ce929d0e0e4736
Trace ID is excellent for execution graph debugging. It is not always enough for business lifecycle debugging because traces may be sampled, truncated, expired, or broken at async boundaries.
3.5 Span ID
A span ID identifies one operation inside a trace.
Typical examples:
- inbound HTTP handler span
- PostgreSQL query span
- Redis command span
- Kafka produce span
- Kafka consume span
- RabbitMQ publish/consume span
- downstream HTTP call span
Example:
span.id = 00f067aa0ba902b7
Span ID is useful when you need to connect a log line to an exact span, especially for high-detail trace/log correlation.
3.6 Business Transaction ID
A business transaction ID identifies a domain-level transaction or lifecycle.
Examples:
business.transaction.id = bt_quote_to_order_20260115_000019
quote.id = Q-2026-000123
order.id = O-2026-000771
This is the identity business users care about. It is often more durable than request ID or trace ID.
3.7 Idempotency Key
An idempotency key identifies a client or system operation that must be safely repeatable.
It answers:
"Have we already processed this operation?"
Common use cases:
- create quote
- submit order
- accept payment-like command
- publish command once
- retry HTTP POST safely
- deduplicate message processing
Example:
idempotency.key = idem_01JABCE2V2AHTQ9V0Y7M2Y8R8B
Idempotency key is not the same as request ID. A retry should usually have a different request ID but the same idempotency key.
3.8 Message ID
A message ID identifies one message instance in a broker or event system.
Examples:
message.id = msg_01JABCEYBM0X5ZG54KME4PHX47
kafka.topic = quote.events
kafka.partition = 4
kafka.offset = 982734
rabbitmq.delivery.tag = 98344
Message ID helps diagnose:
- duplicate delivery
- retry loops
- DLQ movement
- replay
- poison message
- consumer lag
- redelivery
3.9 Event ID
An event ID identifies a domain event.
Example:
{
"eventId": "evt_01JABCF9F4S3RQ59W35J8ZJ7T0",
"eventType": "QuoteApproved",
"quoteId": "Q-2026-000123"
}
Message ID and event ID may differ. A single event may be republished, retried, copied to DLQ, or replayed in a new message envelope.
3.10 Process Instance ID
A process instance ID identifies a workflow execution.
Common in Camunda or workflow orchestration:
process.instance.id = 9d7d2f6a-4d5f-4e20-a818-4c02a8e4d4a1
process.definition.key = quoteToOrder
business.key = Q-2026-000123
The process instance ID helps connect:
- workflow incidents
- failed jobs
- human tasks
- timers
- message correlation
- business lifecycle states
4. Identity Is Multi-Layered
A common mistake is trying to use one identifier for everything. That usually fails.
A healthy observability model uses layered identifiers:
| Layer | Identifier | Primary Question |
|---|---|---|
| HTTP request | request.id | What happened during this inbound request? |
| Distributed execution | trace.id, span.id | What operations were executed and where was latency/error introduced? |
| Workflow/operation | correlation.id | Which technical signals belong to the same broader operation? |
| Causal chain | causation.id | What triggered this event/operation? |
| Domain lifecycle | quote.id, order.id, business.transaction.id | Which business entity or lifecycle is affected? |
| Messaging | message.id, event.id, topic/partition/offset | Which async message or domain event is involved? |
| Idempotency | idempotency.key | Is this retry/duplicate safe? |
| Workflow engine | process.instance.id, business.key | Which process execution is affected? |
| Audit | audit.event.id, actor, action, target | Who did what, when, where, and why? |
The goal is not to log every possible identifier everywhere. The goal is to ensure the right identifiers are available at the right boundary.
5. Request ID vs Correlation ID
Request ID
A request ID is usually generated per inbound request.
Example flow:
Client request A
-> API Gateway assigns request.id=req-001
-> Service A logs request.id=req-001
-> Service A calls Service B with request.id=req-001 or downstream-request-id=req-002 depending on convention
Request ID is ideal for request-scoped debugging.
Correlation ID
Correlation ID should survive across multiple requests or async steps.
Example flow:
POST /quotes/Q-123/submit
request.id=req-001
correlation.id=corr-quote-submit-777
Kafka QuoteSubmitted event
message.id=msg-222
event.id=evt-333
correlation.id=corr-quote-submit-777
causation.id=req-001 or evt-previous
Order service consumer
request.id=req-consume-444
correlation.id=corr-quote-submit-777
The consumer should not reuse the producer HTTP request ID as its own request ID. It should create its own local request/processing ID while preserving the correlation ID.
6. Correlation ID vs Trace ID
A trace ID is a tracing-specific execution identity. A correlation ID is a broader application/business correlation identity.
They may be the same in simple systems, but in enterprise systems it is often safer to keep them conceptually separate.
Why not rely only on trace ID?
Because:
- traces can be sampled
- traces may not be retained as long as logs/audit
- async trace continuity can break
- business operations may span hours or days
- workflow/human approval steps do not fit neatly into one trace
- not every system participates in distributed tracing
- external partners may not propagate trace headers
Trace ID is excellent for execution-level debugging. Correlation ID is better for long-lived operation reconstruction.
Recommended relationship
Use both:
{
"request.id": "req-001",
"correlation.id": "corr-777",
"trace.id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span.id": "00f067aa0ba902b7",
"quote.id": "Q-2026-000123"
}
This gives you:
- log search by correlation ID
- trace navigation by trace ID
- business lookup by quote/order ID
- exact span correlation by span ID
7. Correlation ID vs Causation ID
Correlation ID groups related work. Causation ID explains immediate trigger.
Example event chain:
Command: SubmitQuote
event.id = cmd-001
correlation.id = corr-777
causation.id = null
Event: QuoteSubmitted
event.id = evt-002
correlation.id = corr-777
causation.id = cmd-001
Event: QuoteApproved
event.id = evt-003
correlation.id = corr-777
causation.id = evt-002
Command: CreateOrder
event.id = cmd-004
correlation.id = corr-777
causation.id = evt-003
Event: OrderCreated
event.id = evt-005
correlation.id = corr-777
causation.id = cmd-004
All events share the same correlation ID. Each event has a different causation ID pointing to the immediate parent.
This is extremely useful when debugging:
- duplicate event emission
- unexpected workflow transition
- retry chains
- saga compensation
- delayed messages
- manual intervention
- reconciliation jobs
8. Business Keys Are Not Just Nice-to-Have
For CPQ/order management systems, business keys are operationally critical.
Examples:
quote.idquote.versionorder.idorder.line.idcustomer.idaccount.idtenant.idproduct.catalog.idprocess.instance.idbusiness.transaction.id
A trace tells you what code executed. A business key tells you which customer-facing entity was affected.
During incidents, engineers often start from business evidence:
- customer gave quote number
- support ticket references order ID
- workflow incident references process instance ID
- settlement/reconciliation report references external order number
- audit team asks who approved a change
If logs and traces do not contain business keys, production debugging becomes slow and indirect.
Business key rule
A business key should be included when:
- it is already known at that layer
- it is safe to log
- it has bounded cardinality impact for logs/traces
- it helps support or incident debugging
- it does not violate privacy/security policy
For metrics, business keys are dangerous as labels because they are high cardinality. For logs/traces, they are often acceptable if protected by access control and retention policy.
9. Recommended Context Fields
A practical baseline for structured logs:
{
"timestamp": "2026-01-15T10:15:30.123Z",
"level": "INFO",
"service.name": "quote-service",
"service.version": "1.42.0",
"environment": "prod",
"request.id": "req_01JABC...",
"correlation.id": "corr_01JABC...",
"trace.id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span.id": "00f067aa0ba902b7",
"tenant.id": "tenant_abc",
"actor.id": "user_123",
"quote.id": "Q-2026-000123",
"order.id": null,
"event.id": null,
"causation.id": null,
"message": "Quote submission accepted"
}
For async consumer logs:
{
"timestamp": "2026-01-15T10:15:34.550Z",
"level": "INFO",
"service.name": "order-service",
"request.id": "req_consumer_01JABC...",
"correlation.id": "corr_01JABC...",
"trace.id": "9f3e...",
"span.id": "a0b1...",
"message.id": "msg_01JABC...",
"event.id": "evt_quote_approved_01JABC...",
"causation.id": "evt_quote_submitted_01JABC...",
"kafka.topic": "quote.events",
"kafka.partition": 4,
"kafka.offset": 982734,
"quote.id": "Q-2026-000123",
"message": "Processing QuoteApproved event"
}
For workflow logs:
{
"service.name": "workflow-service",
"correlation.id": "corr_01JABC...",
"process.instance.id": "9d7d2f6a-4d5f-4e20-a818-4c02a8e4d4a1",
"process.definition.key": "quoteToOrder",
"business.key": "Q-2026-000123",
"activity.id": "approveQuoteTask",
"quote.id": "Q-2026-000123",
"message": "Workflow task completed"
}
10. Boundary Rules
10.1 Inbound HTTP Boundary
At HTTP ingress:
- accept trusted correlation/request headers only from trusted upstreams
- generate missing request ID
- generate missing correlation ID
- validate header length and allowed characters
- prevent spoofing from public clients
- attach context to MDC
- attach context to trace/span attributes where appropriate
- return request ID in response header if policy allows
Recommended inbound fields:
request.id
correlation.id
trace.id
span.id
http.method
http.route
http.status_code
tenant.id
actor.id
client.ip
user_agent.original
10.2 Outbound HTTP Boundary
For downstream calls:
- propagate trace context using standard propagator
- propagate correlation ID according to internal convention
- optionally generate downstream request ID if convention requires
- never propagate untrusted headers blindly
- include correlation ID in logs around call start/end/error
Recommended outbound fields:
correlation.id
trace.id
span.id
peer.service
http.method
http.url or http.route depending on privacy policy
http.status_code
network.peer.name
error.type
10.3 Kafka/RabbitMQ Producer Boundary
When publishing:
- include correlation ID in message headers
- include causation ID from current command/event/request
- include event ID in payload or envelope
- include trace context if tracing supports messaging propagation
- include business key if safe and useful
- log publish attempt and publish result
Recommended message headers:
correlation-id
causation-id
traceparent
tracestate
message-id
event-id
producer-service
schema-version
Actual header names must follow internal standards. Do not invent incompatible names if a team standard already exists.
10.4 Kafka/RabbitMQ Consumer Boundary
When consuming:
- extract correlation ID
- extract trace context
- create local processing/request ID
- attach event ID and message ID
- attach topic/queue metadata
- attach business key if available
- log start/end/failure of processing
- preserve causation when publishing follow-up events
Important:
The consumer processing attempt should usually have its own local request ID. The correlation ID should be preserved.
10.5 Background Job Boundary
For scheduled jobs:
- generate job execution ID
- generate or derive correlation ID per job run
- attach job name, schedule, shard, batch ID
- attach reconciliation target if applicable
- attach processed count, failed count, skipped count
- attach business keys only in detailed logs, not metric labels
10.6 Workflow Boundary
For Camunda/workflow:
- use process instance ID
- use business key
- preserve correlation ID when starting process
- preserve event/causation ID when correlating messages
- log activity/task transitions
- audit business-significant transitions
11. JAX-RS Context Propagation Sketch
A simplified JAX-RS request filter can normalize identifiers.
package com.example.observability;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.ext.Provider;
import org.slf4j.MDC;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
@Provider
@Priority(Priorities.AUTHENTICATION)
public class CorrelationContextFilter implements ContainerRequestFilter, ContainerResponseFilter {
public static final String REQUEST_ID_HEADER = "X-Request-ID";
public static final String CORRELATION_ID_HEADER = "X-Correlation-ID";
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String requestId = normalizeOrGenerate(requestContext.getHeaderString(REQUEST_ID_HEADER), "req");
String correlationId = normalizeOrGenerate(requestContext.getHeaderString(CORRELATION_ID_HEADER), "corr");
MDC.put("request.id", requestId);
MDC.put("correlation.id", correlationId);
requestContext.setProperty("request.id", requestId);
requestContext.setProperty("correlation.id", correlationId);
}
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
String requestId = Optional.ofNullable((String) requestContext.getProperty("request.id"))
.orElse(MDC.get("request.id"));
String correlationId = Optional.ofNullable((String) requestContext.getProperty("correlation.id"))
.orElse(MDC.get("correlation.id"));
if (requestId != null) {
responseContext.getHeaders().putSingle(REQUEST_ID_HEADER, requestId);
}
if (correlationId != null) {
responseContext.getHeaders().putSingle(CORRELATION_ID_HEADER, correlationId);
}
MDC.remove("request.id");
MDC.remove("correlation.id");
}
private String normalizeOrGenerate(String raw, String prefix) {
if (raw == null || raw.isBlank() || raw.length() > 128 || !raw.matches("[A-Za-z0-9._:-]+")) {
return prefix + "_" + UUID.randomUUID();
}
return raw;
}
}
This is intentionally simplified. Production systems should verify:
- trusted header boundary
- naming convention
- UUID/ULID strategy
- MDC cleanup on exception path
- async request lifecycle
- OpenTelemetry propagation integration
- privacy/security header policy
- response header policy
12. OpenTelemetry Relationship
OpenTelemetry already handles trace context propagation when configured correctly. However, application-level correlation may still be needed.
A common approach:
- OTel manages
trace.idandspan.id - application filter manages
request.idandcorrelation.id - structured logging includes both
- selected business keys are attached as log fields and span attributes
- message producers propagate both trace context and correlation context
Example span enrichment:
import io.opentelemetry.api.trace.Span;
public final class ObservabilityContext {
public static void enrichCurrentSpan(String correlationId, String tenantId, String quoteId) {
Span span = Span.current();
span.setAttribute("correlation.id", correlationId);
if (tenantId != null) {
span.setAttribute("tenant.id", tenantId);
}
if (quoteId != null) {
span.setAttribute("quote.id", quoteId);
}
}
}
Be careful with span attributes:
- avoid high-cardinality attributes if the tracing backend indexes them aggressively
- do not attach secrets or raw tokens
- avoid full SQL parameters
- avoid large payloads
- verify internal semantic conventions
13. Messaging Envelope Pattern
A robust event envelope separates business payload from observability metadata.
{
"metadata": {
"eventId": "evt_01JABCF9F4S3RQ59W35J8ZJ7T0",
"eventType": "QuoteApproved",
"eventVersion": "1.0",
"correlationId": "corr_01JABC...",
"causationId": "evt_quote_submitted_01JABC...",
"idempotencyKey": "idem_01JABC...",
"producerService": "quote-service",
"producedAt": "2026-01-15T10:15:31.000Z",
"tenantId": "tenant_abc",
"businessKey": "Q-2026-000123"
},
"payload": {
"quoteId": "Q-2026-000123",
"approvedBy": "user_123",
"approvedAt": "2026-01-15T10:15:30.900Z"
}
}
For Kafka/RabbitMQ, some metadata may live in headers instead of payload. The exact design should be consistent with schema governance, broker conventions, tracing propagation, and security policy.
14. Metric Label Warning
Identifiers are useful in logs and traces. They are dangerous in metric labels.
Avoid metric labels such as:
request_id
correlation_id
trace_id
span_id
message_id
event_id
quote_id
order_id
user_id
raw_path
error_message
These create high cardinality and may damage metric backend performance or cost.
Prefer bounded labels:
service
endpoint_template
http_method
status_code_class
dependency
operation_type
outcome
error_type
queue_name
topic
consumer_group
tenant_tier # if bounded and approved
Business IDs belong in logs, traces, audit events, or searchable event stores, not high-cardinality time-series labels.
15. Audit Relationship
Audit logs need identity too, but audit identity is not the same as request correlation.
A good audit event may include:
{
"audit.event.id": "aud_01JABC...",
"timestamp": "2026-01-15T10:15:30.123Z",
"actor.id": "user_123",
"actor.type": "human",
"action": "QUOTE_APPROVED",
"target.type": "quote",
"target.id": "Q-2026-000123",
"correlation.id": "corr_01JABC...",
"request.id": "req_01JABC...",
"trace.id": "4bf92f3577b34da6a3ce929d0e0e4736",
"source.ip": "203.0.113.10",
"reason": "approval workflow step completed"
}
Correlation fields help connect audit event to operational evidence. Audit event ID gives the compliance record its own identity.
16. Failure Modes
16.1 Missing Correlation ID
Symptoms:
- logs cannot be connected across services
- support ticket requires manual guesswork
- async consumer logs cannot be tied to producer logs
- incident timeline has gaps
Likely causes:
- ingress does not generate correlation ID
- downstream propagation missing
- message headers not populated
- background job starts without context
- MDC cleared too early
16.2 Reused Request ID Across Async Boundaries
Symptoms:
- multiple consumer attempts appear as one request
- retry attempts are hard to distinguish
- request duration becomes misleading
Fix:
- preserve correlation ID
- generate new local request/processing ID per attempt
- include message ID and event ID
16.3 Trace Break
Symptoms:
- trace stops at producer
- consumer starts a new unrelated trace
- logs have trace ID only in one service
Likely causes:
- missing propagation headers
- unsupported broker instrumentation
- custom producer/consumer wrapper drops headers
- async executor loses context
16.4 Context Spoofing
Symptoms:
- external client controls internal correlation headers
- malicious or accidental huge header value pollutes logs
- log search results are polluted by forged IDs
Controls:
- only trust headers from known gateways
- validate length/characters
- regenerate unsafe identifiers
- preserve external request ID separately if needed
16.5 Business Key Missing
Symptoms:
- logs show technical flow but cannot answer which quote/order was affected
- support engineer cannot search by customer-facing reference
- RCA cannot connect failure to business impact
Fix:
- attach business key once known
- include it in logs/traces/audit
- avoid metric labels for high-cardinality business IDs
16.6 Cardinality Explosion
Symptoms:
- metric backend becomes expensive or slow
- dashboard queries time out
- storage cost spikes
Likely causes:
- request ID, trace ID, order ID, user ID used as metric labels
- raw path instead of endpoint template
- exception message used as label
17. Debugging Playbook
When investigating a failed quote/order operation:
-
Start from the business key.
- quote ID
- order ID
- customer/account ID if allowed
- process instance ID
-
Search logs by business key.
-
Extract correlation ID.
-
Search logs across services by correlation ID.
-
Find request IDs for each local operation.
-
Find trace IDs attached to request logs.
-
Open distributed traces and inspect:
- failed spans
- slow spans
- downstream calls
- DB calls
- message publish/consume spans
-
For async processing, inspect:
- event ID
- message ID
- Kafka topic/partition/offset
- RabbitMQ exchange/queue/routing key
- retry/DLQ movement
- event age
-
For workflow, inspect:
- process instance ID
- activity ID
- failed jobs
- incidents
- timers
- human task aging
-
For audit, inspect:
- actor
- action
- target
- before/after
- timestamp
- request/correlation IDs
18. PR Review Checklist
When reviewing a PR that touches request handling, async messaging, workflow, or audit:
- Does the code preserve
correlation.id? - Does each local operation have a distinct
request.idor processing ID? - Are
trace.idandspan.idavailable in logs? - Are business keys logged once they are known?
- Are business keys avoided as metric labels?
- Does event publishing include
event.idandcausation.id? - Does consumer processing extract and restore context?
- Does retry/DLQ handling preserve original event identity?
- Does workflow start/correlation include business key and correlation ID?
- Does audit logging include actor, action, target, request ID, and correlation ID?
- Are untrusted inbound headers validated?
- Is context cleaned up after request/consumer/job completion?
- Are sensitive IDs protected according to privacy policy?
- Are context fields standardized with existing team conventions?
19. Internal Verification Checklist
Verify with the internal codebase, senior engineers, SRE/platform team, or security team:
Header and Field Standards
- What is the official request ID header?
- What is the official correlation ID header?
- Are W3C
traceparentandtracestateused? - Is baggage allowed?
- Are custom headers allowed through ingress/API gateway?
- Which headers are trusted from external clients?
Logging Context
- Which fields are included in JSON logs?
- Are
request.id,correlation.id,trace.id, andspan.idalways present? - Are
tenant.id,actor.id,quote.id, andorder.idlogged? - Is MDC cleanup implemented correctly?
- Is executor/thread pool context propagation implemented?
Messaging
- Are correlation and causation IDs included in Kafka/RabbitMQ headers or payload?
- Is
event.idmandatory? - Is
message.idgenerated by producer, broker, or both? - Are retry and DLQ flows preserving identity?
- Are event schemas versioned?
Workflow
- Is Camunda/process business key aligned with quote/order ID?
- Is process instance ID logged in application logs?
- Are message correlation failures observable?
- Are workflow incidents correlated to service logs?
Tracing
- Is OpenTelemetry enabled?
- Are logs correlated with trace/span IDs?
- Does tracing continue across Kafka/RabbitMQ?
- Are traces sampled?
- Are critical business flows sampled differently?
Metrics and Cost
- Are high-cardinality labels prohibited?
- Are raw paths normalized to route templates?
- Are business IDs excluded from metric labels?
- Is there a cardinality dashboard/report?
Security and Privacy
- Are actor/customer/tenant identifiers considered sensitive?
- Are tokens/cookies/auth headers stripped?
- Are IDs encrypted, hashed, masked, or raw?
- Who can query logs containing business identifiers?
- What is retention for operational logs vs audit logs?
20. Practical Mental Model
Use this rule:
Request ID tells you the local operation. Correlation ID tells you the wider story. Causation ID tells you why the next thing happened. Trace ID tells you the execution graph. Business key tells you who or what was affected.
A mature production system does not rely on one identifier. It carries a small, disciplined identity set across boundaries and uses each identifier for the question it is designed to answer.
21. Summary
In enterprise Java/JAX-RS observability, identity is not decorative metadata. It is the backbone of production evidence.
You should now be able to:
- distinguish request ID, correlation ID, causation ID, trace ID, span ID, event ID, message ID, idempotency key, process instance ID, and business key
- decide which identifier belongs in logs, traces, metrics, audit events, message headers, and workflow metadata
- avoid confusing trace ID with long-lived business correlation
- preserve correlation across HTTP, Kafka, RabbitMQ, background jobs, and workflow
- avoid high-cardinality metric labels
- review PRs for context propagation and production-debugging readiness
- identify what must be verified internally instead of assuming a team standard
The next part applies these identity concepts directly to JAX-RS request/response logging.
You just completed lesson 09 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.
Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.