As APIs become more pervasive within our solutions we see the arrival of not just design and cataloging tools such as Apiary, Apigee and others but also the arrival of gateways. The gateways provide execution of operations including validation, accounting (moneytization), routing, and other controls such as throttled checks that would often not occur until the first contact with a service bus. For example initial routing based on the API call, fine grained authentication and authorisation (differing from your firewalls who will just perhaps authorise).
In the more traditional integration middleware of Oracle Service Bus and SOA (regardless of cloud, on-premises) you can trace the execution through the middleware end to end. This tracing can be achieved because the platform creates and assigns the a UUID (aka eCID) and ensures that it is carried through the middleware. It is this very behaviour that allows Oracle to provide Business Activity Monitoring without any need to be invasive. Burt not only that in a highly distyributed environment you can track the processing of a transaction from end to end.
The challenge now is that the first point of middleware style behaviour can be at the gateway. So we actually need to move forward the UUID or equivalent forward the the first point of contact. Not only that we need to think about the fact we will see non Oracle integration middleware involved. Within Spring, Kabana and other established frameworks and tools which are getting signficiant traction with the rise of Microservices, the Ids being used are not the same as the UUIDs used by Oracle. For example Spring Cloud Slueth uses the same HTTP header Ids that Zipkin and Kabana support:
- X-B3-TraceId
- X-B3-SpanId
- X-B3-ParentSpanId
More information can be found here and here.
For the new Oracle API Platform Cloud Service we can check for the existance of the header attributes as a policy and apply actions such as:
- Apply a header with a TraceId or spanId,
- If a SpanId exists then we may wish to nest our call as a child span by moving the SpandId to the ParentSpanId and creating a new SpanId.
Ultimately it would be more attractive to apply the logic using the API Platform’s SDK but to get things rolling applying the IDs with the API Groovy policy is sufficient (more here).
Next question that begs, is where to put the ID and want to call it? Put the value in the body, and you’re invading the business aspect of an API with execution specific details, not to mention potentially changing the API definition. Whilst stuffing HTTP(s) headers with custom attributes is often discouraged as the values aren’t to immediately visible. In my opinion at least the answer largely has been set by president for us. If you weren’t using HTTPS but JMS then you would use the header, but also a number of frameworks already exist that do make use of this strategy such as those mentioned above.
Using the header defined by Kabana etc means that the very process will mean that a number of Support tools out of the box will understand and be able to help visualise your logs with no additional effort.
The following is a Groovy script that could ber used for the purposes of applying an Id appropriately into the HTTP header in the API Platform:
if (!context.getApiRequest().getHeaders().containsKey ("baggage-UUID ")) { // use current time to seed random generator def now = java.time.Instant.now() def random = new java.util.Random(now.getEpochSecond()) // create an array of 16 bytes to hold the random value byte[] uid = new byte[16] random.nextBytes(uid) // convert the random string from Hex to an ASCII string Writable uidInHex= uid.encodeHex() String uidStr= uidInHex.toString() // set the outbound header context.getServiceRequest().setHeader("baggage-UUID", uidStr) }