Writing Sitecore Logs to Azure Application Insights in IAAS/On Prem

Sitecore’s installer for Azure app services installs a neat feature; a Log4Net appender that writes Sitecore log entries to Application Insights as TRACE messages. Nifty! However, for reasons I cannot comprehend, this is not included in the normal installer. That’s a terrible shame, as App Insights is still useful for Sitecore running on actual tin or in a VM.

As a result, I offer the following:

public class AppInsightsAppender : AppenderSkeleton
{
	private readonly TelemetryClient telemetryClient;

	public string Category
	{
		get;
		set;
	}

	public AppInsightsAppender()
	{
		this.telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
	}

	public override void OnClose()
	{
		this.telemetryClient.Flush();
		base.OnClose();
	}

	protected override void Append(LoggingEvent loggingEvent)
	{
		if (!string.IsNullOrEmpty(loggingEvent.RenderedMessage))
		{
			TraceTelemetry traceTelemetry = new TraceTelemetry(loggingEvent.RenderedMessage, AppInsightsAppender.GetSeverityLevel(loggingEvent.Level));
			this.AddCustomParameters(loggingEvent, traceTelemetry);
			this.telemetryClient.TrackTrace(traceTelemetry);
		}
	}

	private void AddCustomParameters(LoggingEvent loggingEvent, TraceTelemetry traceTelemetry)
	{
		traceTelemetry.Properties.Add("Domain", loggingEvent.Domain);
		traceTelemetry.Properties.Add("Identity", loggingEvent.Identity);
		traceTelemetry.Properties.Add("LoggerName", loggingEvent.LoggerName);
		traceTelemetry.Properties.Add("ThreadName", loggingEvent.ThreadName);
		traceTelemetry.Properties.Add("UserName", loggingEvent.UserName);
		traceTelemetry.Properties.Add("Category", this.Category);
		string[] keys = loggingEvent.Properties.GetKeys();
		foreach (string text in keys)
		{
			if (!traceTelemetry.Properties.ContainsKey(text) && text.StartsWith("log4net", StringComparison.InvariantCultureIgnoreCase))
			{
				traceTelemetry.Properties.Add(text, loggingEvent.Properties[text].ToString());
			}
		}
	}

	private static SeverityLevel GetSeverityLevel(Level loggingEventLevel)
	{
		if (!(loggingEventLevel == (Level)null) && loggingEventLevel.Value >= Level.INFO.Value)
		{
			if (loggingEventLevel.Value < Level.WARN.Value)
			{
				return SeverityLevel.Information;
			}
			if (loggingEventLevel.Value < Level.ERROR.Value)
			{
				return SeverityLevel.Warning;
			}
			if (loggingEventLevel.Value < Level.SEVERE.Value)
			{
				return SeverityLevel.Error;
			}
			return SeverityLevel.Critical;
		}
		return SeverityLevel.Verbose;
	}
}

It’s an appender to write Sitecore log entries to App Insights as a Trace. It does use classes found in the Sitecore.Logging nuget package, so you’ll need to reference it. It’s based around the Sitecore one for Azure App Services.

To add the configuration for it, you can use this patch file:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
	<sitecore>
		<log4net>	
			<root>
				<appender-ref ref="AppInsightsAppenderLog" desc="AppInsightsAppender" />
			</root>			
			<appender patch:after="root" name="AppInsightsAppenderLog" type="{full classname}, {assembly name}">
				<category value="Log" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>
			
			<logger name="Sitecore.Diagnostics.Publishing">
				<appender-ref ref="AppInsightsAppenderPublishing" desc="AppInsightsAppenderPublishing" />
			</logger>		
			<appender name="AppInsightsAppenderPublishing" type="{full classname}, {assembly name}">
				<category value="Publishing" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>
			
			<logger name="ClientRoot">
				<appender-ref ref="AppInsightsAppenderClient" desc="AppInsightsAppenderClient" />
			</logger>		
			<appender name="AppInsightsAppenderClient" type="{full classname}, {assembly name}">
				<category value="Client" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>
			
			<logger name="Sitecore.Diagnostics.Search">
				<appender-ref ref="AppInsightsAppenderSearch" desc="AppInsightsAppenderSearch" />
			</logger>		
			<appender name="AppInsightsAppenderSearch" type="{full classname}, {assembly name}">
				<category value="Search" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>			
			
			<logger name="Sitecore.Diagnostics.Crawling">
				<appender-ref ref="AppInsightsAppenderCrawl" desc="AppInsightsAppenderCrawl" />
			</logger>		
			<appender name="AppInsightsAppenderCrawl" type="{full classname}, {assembly name}">
				<category value="Crawl" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>
			
			<logger name="Sitecore.Owin.Diagnostics">
				<appender-ref ref="AppInsightsAppenderOwin" desc="AppInsightsAppenderOwin" />
			</logger>		
			<appender name="AppInsightsAppenderOwin" type="{full classname}, {assembly name}">
				<category value="OWIN" />
				<filter type="log4net.Filter.LevelRangeFilter">
					<levelMin value="WARN" />
				</filter>
			</appender>		
		</log4net>
	</sitecore>
</configuration>

Note that these entries set a “Category” attribute, so you can refine your searches in App Insights. Also, I’ve used a <filter> to only record WARN and more important messages, so even if your logger is recording at INFO detail, only WARN and more critical messages will be written to App Insights. That’s my way of thing to avoid having too many irrelevant messages recorded to App Insights.

Oh, and {full classname}, {assembly name} should be your full classname and assembly name – e.g. Sitecore.Foundation.AppInsights.Appenders.AppInsightsAppender, Sitecore.Foundation.AppInsights

Writing Sitecore Logs to Azure Application Insights in IAAS/On Prem

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.