Traceability
For microservices architecture, a request sent from a client may pass through several services to the backend repository/Book of Record, and then a response is returned in the reverse path. If there is an error in the call tree, we need to identify where the problem is during runtime. Also, for some mission-critical applications, the entire call tree must be in the audit log to meet regulatory compliance requirements, for example, banking applications.
The framework has two tracing IDs built in and X-Traceability-Id is one that is handled by this middleware component. Another one is X-Correlation-Id which is documented in correlation.
X-Traceability-Id is generated by the original client and might not be unique across the API domain. It is unique for that particular client though. It is usually a sequence number generated from a database or an identifier in the application like transaction Id. The usage of this id is to debug broken transactions as every service will have this id logged once if the service is called and will return this id in response header to the caller.
Every API/Service is responsible for passing the X-Traceability-Id (from request header) to the next service (set the request header by Http2Client when calling another service).
Not all clients will supply traceabilityId, so this is an optional field in the request header. If it doesn’t exist, do nothing. If it does exist, the framework is responsible for passing it to the next API in the chain or passing to the Book of Record.
It is recommended that X-Traceability-Id should be persisted in Backend Repository/Book of Record. However, this might not be possible for some legacy applications, i.e., mainframe applications.
It should only be logged once in the audit log once your API processing is done and successful.
Configuration
The configuration for this handler is straightforward. It just controls if this handler is enabled or not. It will only be plugged into the request/response chain if enabled is true in the traceability.yml
enabled: true
Calling sequence
This handler will be loaded after the metric handler and before the correlation handler.
Dependencies
This handler sets the response header from request header. However, to make it work across services, it depends on the following middleware or component to work.
- Audit to log the traceabilityId to the audit log file.
- Client to pass the X-Traceability-Id to the next service through HttpRequest header.
Logging
Unlike correlationId which is put into the MDC of SLF4J so that it is included in every logging statement, the traceabilityId is not in the MDC because it is optional and the id is not enforced to be globally unique. Once it goes to the central logging like ElasticSearch, any duplication will cause problems. Since it is optional, it doesn’t make sense to put it into the MDC which subsequently goes to the log.
The idea is to associate this traceabilityId with the correlationId in the log so that users can search the traceabilityId and then find out the correlationId to link all the logs for the same traceabilityId.
String cId = exchange.getRequestHeaders().getFirst(HttpStringConstants.CORRELATION_ID);
if(cId == null) {
// if not set, check the autgen flag and generate if set to true
if(config.isAutogenCorrelationID()) {
// generate a UUID and put it into the request header
cId = Util.getUUID();
exchange.getRequestHeaders().put(HttpStringConstants.CORRELATION_ID, cId);
String tId = exchange.getRequestHeaders().getFirst(HttpStringConstants.TRACEABILITY_ID);
if(tId != null && logger.isInfoEnabled()) {
logger.info("Associate traceability Id " + tId + " with correlation Id " + cId);
}
}
}
// Add the cId into MDC so that all log statement will have cId as part of it.
MDC.put(CID, cId);