When using Application Insights to monitor your Microservices environment, it would be nice to track calls over process boundaries. Application Insights has a preview for Multi-Role Application Maps. This enables you to visualize the dependencies over multiple processes and name the different processes. In this blog posts I will explain how to use Multi Role Application Maps, give you different process names and add dependency tracking into your application.
Naming processes/applications/microserives in Application Insights
Naming process can be done by filling the Cloud Role in the ITelemetry Context. The CloudRole is a property of the Cloud context. Setting it can be done by adding a TelemetryInitializer to the active initialize on start up. This will run each time a new Telemetry item is created.
private void ConfigureAppInsights(IServiceCollection services) { services.AddApplicationInsightsTelemetry(Configuration); TelemetryConfiguration.Active.TelemetryInitializers .Add(new ServiceNameInitializer()); }
The implementation of ServiceNameInitializer to set the Cloud RoleName:
public class ServiceNameInitializer : ITelemetryInitializer { public void Initialize(ITelemetry telemetry) { telemetry.Context.Cloud.RoleName = "MyProcessName"; } }
Now you have set the name of the Application, you are ready to create the dependency tracking.
Add dependency tracking to your application
DependencyTelemetry allows you to track dependencies over process boundaries in one Application Insights instance, or within one process in case of async process with queues. This works by creating a DependencyTelemetry before calling or triggering you external process. In you external process you first create an other DependencyTelemetry with the same OperationId and OperationParentId. Around the actial processing of the request you create a RequestTelemetry for Application Insights.
protected override async Task PublishImpl(string message) { var queuename = "MessageBus"; using (var operation = _telemetryClient.StartOperation($"Enqueue {queuename}")) { operation.Telemetry.Type = "Service Bus Queue"; operation.Telemetry.Data = $"Enqueue publisher {queuename}"; var brokeredMessage = new Message(System.Text.Encoding.Unicode.GetBytes(message)); brokeredMessage.UserProperties["RootId"] = operation.Telemetry.Context.Operation.Id; brokeredMessage.UserProperties["ParentId"] = operation.Telemetry.Id; try { await _topicClient.SendAsync(brokeredMessage).ConfigureAwait(false) ; operation.Telemetry.Success = true; } catch { operation.Telemetry.Success = false; throw; } } }
In this case a ServiceBus message is created. The correlation between the processes is done with the Operation.Id and Operation.ParentId. Thay are saved in the UserProperties of the queue message.
private async Task ProcessMessagesAsync(Message message, CancellationToken token) { var operationId = message.UserProperties["RootId"].ToString(); var parentOperationId = message.UserProperties["ParentId"].ToString(); var queuename = "MessageBus"; var telemetry = new DependencyTelemetry { Type = "Service Bus Queue", Name = $"Dequeue subscriber {queuename}" }; telemetry.Start(); telemetry.Context.Operation.Id = operationId; telemetry.Context.Operation.ParentId = parentOperationId; try { string json = Encoding.Unicode.GetString(message.Body); EventData eventData = JsonConvert.DeserializeObject(json); // After the message is dequeued from the queue, create RequestTelemetry to track its processing. RequestTelemetry requestTelemetry = new { Name = $"Process {queuename}" }; requestTelemetry.Context.Operation.Id = operationId; requestTelemetry.Context.Operation.ParentId = parentOperationId; using (var requestOperation = _telemetryClient.StartOperation(requestTelemetry)) { try { await ProcessEvent(eventData).ConfigureAwait(false); } catch //Log error on higher level { requestOperation.Telemetry.Success = false; throw; } } await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken).ConfigureAwait(false); } catch (Exception ex) { telemetry.Success = false; //Log error } finally { telemetry.Stop(); _telemetryClient.Track(telemetry); } }
Now you are ready to run and track your dependencies over different applications or within your application when doing async processing with for example a queue.

Final thoughts
The drill down isn’t exactly working as I wanted. Within a process I want to create multiple dependency layers. We have high level commands that can have multiple events. It would be nice to have the events as leaves of the commands. This will probably be able in time. I’ll update the blog when I’m able to create such graph.
The Multi-role Application Map is really nice to monitor you application. This will enable you to quickly identify and solve problems with your application. If a dependency fails all parent nodes will show something is not correct. Besides the fast problem identification you are able to see all timings of the operations you are monitoring. This will give you great insights in the current timing and state of your application.
For extra reading:
Track custom operations with Application Insights .NET SDK
Thanks for the nice article. To use Multi-role Application Map, should I use single AI instance for multiple apps or AI instance per apps?
LikeLike
It really depends, I would say one Application Insights instance for DevOps team. If a team has multiple related applications, use Multi-Role Application Map. When you have multiple teams, use multiple Application Insights Instances.
LikeLiked by 1 person
Sounds reasonable. Thx. 🙂
LikeLike
Note that the Multi-role Application map feature is no longer in preview, so there’s no need to enable the preview in order to get the multi-role view in the map. It comes by default.
LikeLike
Thanks for the comment, I’ll update the blog post.
LikeLike