Introduction

One of the most important things when it comes to your application's health is logging information. Whether that is external dependencies, performance metrics or errors, logging is one of the fundamental things that your application should have.

I have too much information and I don't want more. - No one, ever

One of the most requested features in my workplace when I was showcasing Cosmonaut was logging. Initially I didn't have logging in place and that's because I thought that the only way to add logging is to add external packages which is something I really didn't want to do, mainly because I don't wanna needlessly increase the minimum .NET Standard requirements.

Turns out, Microsoft has my back.

Reminder: Everything you are about to read, is already included in Cosmonaut. If you are already using it you don't need to worry about adding this but it's still good to read this blog to learn how it works behind the scenes.

EventSource

System.Diagnostics is part of the .NET Standard and it contains everything you need in order to create an Event Source. That event source can then be used with your CosmosDB calls in order to offer the basic logging solution.

Here is what my event source for Cosmonaut looks like:

As you can see, I am extending the EventSource class to create DependencyEvents and DependencyEventErrors.

Once I do that I can call the Singleton CosmosEventSource from wherever I want and use the CosmosEventSource.EventSource.TrackSuccess or CosmosEventSource.EventSource.TrackError methods to track successful or failed CosmosDB calls.

An example of how to invoke a CosmosDB dependency call with logging looks something like this:

As we can see we have all the data we need including time metrics for the action.

I created some extension methods for my needs, which you can find here.

This is how CosmonautClient calls CosmosDB.

You can find the complete Diagnostics solution that I use for Cosmonaut here.

It contains some handy extension methods and examples on how to use it.

You can also add more custom data by adding more entries in the EventMetadata.Properties dictionary, which is translated to customDimensions later.

This however doesn't mean that our data is logged in a place that's useful for us yet. Let's see what we can do to log this data somewhere.

Application Insights

My APM of choice is Application Insights because Azure, that's why.
In all seriousness, Application Insights gets better and better every day and with it's querying and visualisation power makes retrieving data really easy. It's also really cheap and it has kick ass integration with Visual Studio and .NET.

What we need to do is to create an EventListener that implements ITelemetryModule in order to capture those Event Source events and add them in Application Insights.

The module's code is pretty simple. First we need to override the OnEventSourceCreated method in order to Enable the events for our EventSource. The next method we need to override is the OnEventWritten which is the method called every time we write an event in the event source.
Simply converting the event into a dependency and calling our telemetry client's TrackDependency method will do the trick.

 var dependencyTelemetry = CreateDependency(eventData);
_telemetryClient.TrackDependency(dependencyTelemetry);  

Note: Due to how the Application Insights SDK internal buffer logic works, the event won't be flushed to App Insights instantly but rather when one of the three things happen: 1) You manually call the Flush method of the client. 2) 30 seconds (or whatever the interval is) goes by. 3) The event buffer is full.

Here is the full code of Cosmonaut.ApplicationInsights telemetry module.

In order to activate it you either need to register it in your IoC or simply call the AppInsightsTelemetryModule.Instance.Initialize method.

Keep in mind however that if you already have an ApplicationInsights TelemetryClient registered you should NOT instantiate a new TelemetryConfiguration object but rather use the TelemetryConfiguration.Active one.

If however you don't have an active one simply create one like this: AppInsightsTelemetryModule.Instance.Initialize(new TelemetryConfiguration("InstrumentationKey")).

Here is an example of how the end-to-end transaction for a simple GET request on a web api with 3 cosmosdb calls looks like:

As you can see, all the important information is logged such as time taken for each request, which class and method was called, request charge, activity id, how many documents where returned and also the query that was executed.

You can also do flexible querying in the analytics region of Application Insights.

or visualise things like your average request charge every n seconds

Hope this helps you learn more about your services.