Skip to content

georgeolson/serilog-sinks-applicationinsights

 
 

Repository files navigation

Serilog.Sinks.ApplicationInsights

A sink for Serilog that writes events to Microsoft Application Insights.

Build status NuGet Version

This Sink comes with two main helper extensions that send Serilog LogEvent messages to Application Insights as either EventTelemetry:

var log = new LoggerConfiguration()
    .WriteTo
	.ApplicationInsightsEvents("<MyApplicationInsightsInstrumentationKey>")
    .CreateLogger();

.. or as TraceTelemetry:

var log = new LoggerConfiguration()
    .WriteTo
	.ApplicationInsightsTraces("<MyApplicationInsightsInstrumentationKey>")
    .CreateLogger();

For those two LogEvent instances that have Exceptions are always sent as Exceptions to AI though... well, by default.

Additionally, you can also customize whether to send the LogEvents at all, if so which type(s) of Telemetry to send and also what to send (all or no LogEvent properties at all), via a bit more bare-metal set of overloads that take a Func<LogEvent, IFormatProvider, ITelemetry> logEventToTelemetryConverter parameter, i.e. like this to send over MetricTelemetries:

var log = new LoggerConfiguration()
    .WriteTo
	.ApplicationInsights("<MyApplicationInsightsInstrumentationKey>", LogEventsToMetricTelemetryConverter)
    .CreateLogger();

// ....

private static ITelemetry LogEventsToMetricTelemetryConverter(LogEvent serilogLogEvent, IFormatProvider formatProvider)
{
    var metricTelemetry = new MetricTelemetry(/* ...*/);
    // forward properties from logEvent or ignore them altogether...
    return metricTelemetry;
}

.. or alternatively by using the built-in, default TraceTelemetry generation logic, but adapt the Telemetry's Context to include a UserId:

public static void Main()
{
    var log = new LoggerConfiguration()
        .WriteTo
        .ApplicationInsights("<MyApplicationInsightsInstrumentationKey>", ConvertLogEventsToCustomTraceTelemetry)
        .CreateLogger();
}

private static ITelemetry ConvertLogEventsToCustomTraceTelemetry(LogEvent logEvent, IFormatProvider formatProvider)
{
    // first create a default TraceTelemetry using the sink's default logic
    // .. but without the log level, and (rendered) message (template) included in the Properties
    var telemetry = logEvent.ToDefaultTraceTelemetry(
        formatProvider,
        includeLogLevelAsProperty: false,
        includeRenderedMessageAsProperty: false,
        includeMessageTemplateAsProperty: false);

    // then go ahead and post-process the telemetry's context to contain the user id as desired
    if (logEvent.Properties.ContainsKey("UserId"))
    {
        telemetry.Context.User.Id = logEvent.Properties["UserId"].ToString();
    }

    // and remove the UserId from the Telemetry .Properties (we don't need redundancies)
    if (telemetry.Properties.ContainsKey("UserId"))
    {
        telemetry.Properties.Remove("UserId");
    }
	
    return telemetry;
}

If you want to skip sending a particular LogEvent, just return null from your own converter method.

How, When and Why to Flush Messages Manually

Or: Where did my Messages go?

As explained by the Application Insights documentation, the default behaviour of the AI client is to buffer messages and send them to AI in batches whenever the client seems fit. However, this may lead to lost messages when your application terminates while there are still unsent messages in said buffer.

You can either use Persistent Channels (see below) or control when AI shall flush its messages, for example when your application closes:

1.) Create a custom TelemetryClient and hold on to it in a field or property:

// private TelemetryClient _telemetryClient;

// ...
_telemetryClient = new TelemetryClient()
            {
                InstrumentationKey = "<My AI Instrumentation Key>"
            };

2.) Use that custom TelemetryClient to initialize the Sink:

var log = new LoggerConfiguration()
    .WriteTo
	.ApplicationInsightsEvents(telemetryClient)
    .CreateLogger();

3.) Call .Flush() on the TelemetryClient whenever you deem necessary, i.e. Application Shutdown:

_telemetryClient.Flush();

// The AI Documentation mentions that calling .Flush() *can* be asynchronous and non-blocking so
// depending on the underlying Channel to AI you might want to wait some time
// specific to your application and its connectivity constraints for the flush to finish.

await Task.Delay(1000);

// or 

System.Threading.Thread.Sleep(1000);

Using AI Persistent Channels

By default the Application Insights client and therefore also this Sink use an in-memory buffer of messages which are sent out periodically whenever the AI client deems necessary. This may lead to unexpected behaviour upon process termination, particularly not all of your logged messages may have been sent and therefore be lost.

Besides flushing the messages manually (see above), you can also use a custom ITelemetryChannel such as the Persistent Channel(s) one with this Sink and thereby not lose messages, i.e. like this:

1.) Add the Microsoft.ApplicationInsights.PersistenceChannel to your project

2.) Create a TelemetryConfiguration using the Persistence Channel:

var configuration = new TelemetryConfiguration()
            {
                InstrumentationKey = "<My AI Instrumentation Key>",
                TelemetryChannel = new PersistenceChannel()
            };

3.) Use that custom TelemetryConfiguration to initialize the Sink:

var log = new LoggerConfiguration()
    .WriteTo
	.ApplicationInsightsEvents(configuration)
    .CreateLogger();

Copyright © 2016 Serilog Contributors - Provided under the Apache License, Version 2.0.

See also: Serilog Documentation

About

A Serilog sink that writes events to Microsoft Azure Application Insights

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 98.6%
  • PowerShell 1.4%