A sink for Serilog that writes events to Microsoft Application Insights.
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.
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);
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