Distributed Tracing with Application Insights with Java talking with Azure Functions
I’m writing a sample of the Distributed Tracing sample with Application Insights. NOTE: This blog is under experiment. I might change the contents in the near future.
Goal
My customer wants distributed tracing like this.
Http -> HttpTrigger(Azure Functions) -> Storage Queue-> Storage Queue Trigger (Azure Functions) -> Http -> Spring boot -> Service Bus Queue
I’m a beginner of Java Programming these days. I don’t know how to implement Java part.
In this article, I focus on Java and Http Correlation Protocol implementation.
Prerequisite
If you don’t familiar with the concept of the distributed tracing tracking with Application Insights, please refer this blog post.
Sending Request Telemetry
Sending Request Telemetry is very easy. Just follow the official document.
In short, all you need to do is
- Getting Instrument Key from Application Insights on Azure
- Adding dependency to your Gradle or Maven
- Add ApplicationInsights.xml
- Add an Http filter
The request telemetry is automatically send to the Application Insights.
Where the correlation Id reside?
In care of Http Request, it is sent by HTTP Header “Request-Id” You can refer which Request-Id is coming.
String parentRequestId = requestEntity.getHeaders().getFirst("Request-Id");
The filter receive the “Request-Id” and generate the new Id for correlation. You can see the source code in here.
Where is the Activity class in Java SDK
In C#, Activity class plays key role of the Correlation. It plays
- Generate a new Id from parent Id
- Has a Correlation properties(Id, RootId, ParentId)
- Share the Activity object using AsyncLocal with Activity.Current
In case of Java SDK, they have helper class instead.
For the Http Correlation protocol, you can refer the TelemetryCorrelationUtils,
FYI, For the W3C Trace Context, you can use TraceContextCorrelation
What the filter do?
The filter will do
- Generate new Id from the parent Id which is obtained from “Request-Id”
- Create RequestTelemetryContext and RequestTelemetry object
- Store the RequestTelemetryContext on the ThreadContext class
- Send the RequestTelemetry using TelemetryClient
How can I get the new RequestTelemetryId?
The filter automatically create a new Id and send a telemetry. It is fine. However, if you want to send dependency telemetry, you need the parent id which means RequestTelemetry.getId().
You can get the current RequestTelemetryId using ThreadContext class.
RequestTelemetryContext context = ThreadContext.getRequestTelemetryContext();RequestTelemetry requestTelemetry = context.getHttpRequestTelemetry();System.out.println(String.format(currentTemplate,requestTelemetry.getId(),requestTelemetry.getContext().getOperation().getId(), // RootIdrequestTelemetry.getContext().getOperation().getParentId() ));
As you can get the RequestTelemetryContext from the ThreadContext class. Inside of the class, they use ThreadLocal to share the context object. Then you can get RequestTelemetry object from the context.
The correalation telemetry has been set already.
- RequestTelemetry.Id : requestTelemetry.getId()
- RootId : requestTelemetry.getContext().getOperation().getId()
- ParentId: requestTelemetry.getContext().getOperation().getParentId()
If you want to manually send the telemetry, you can set the same parameter to that property.
Sending Dependency telemetry
Now you are ready to send dependency telemetry.
Generate Dependency Id
TelemetryCorrelationUtils class helps you out.
String dependencyId = TelemetryCorrelationUtils.generateChildDependencyId();
Inside of the generateChildDepndencyId
it is refer the current RequestTelemetry by the ThreadContext class then create a new ID from the parent id which is the requst id.
Create DependencyTelemetry
We have RemoteDependencyTelemetry for this purpose. Simply create the instance, pass the name of the telemetry and pass the correlation id from the request Id.
RemoteDependencyTelemetry dependencyTelemetry = new RemoteDependencyTelemetry("Send ServiceBus Queue");dependencyTelemetry.setId(dependencyId);dependencyTelemetry.getContext().getOperation().setId(requestTelemetry.getContext().getOperation().getId());dependencyTelemetry.getContext().getOperation().setParentId(requestTelemetry.getId());
For the Duration of the DependencyTelemetry, you can use com.microsoft.applicationinsights.telemetry.Duration class.
Duration duration = new Duration(0,0,0,0,10); // set the duration 10 millisec as an example.dependencyTelemetry.setDuration(duration);
Send Dependency Telemetry
Now ready to send the dependnecy telemetry.
TelemetryConfiguration configuration = TelemetryConfiguration.getActive();TelemetryClient telemetryClient = new TelemetryClient(configuration);telemetryClient.trackDependency(dependencyTelemetry);
If you send a message to this controller, you can find the request/dependency telemetry is sent to the Application Insights.
Application Insights support HTTP dependency telemetry. However, in this case, I need to send Service Bus queue. All I need to do is sending the dependencyTelemetry.getId() as the ParentId with the Queue metadata.
Whole Controller code is here.
You can find whole Azure Functions and Spring Boot sample in here.
Conclusion
I successfully sent the Request/Dependency telemetry by Spring Boot Java application. The next step will be
- Send Correlation information to the ServiceBus
- W3C TraceContext sample
- Create a following sample of the Azure Functions
I hope this article is helpful for someone.