Contents

Log File Intelligence - log4net meets Splunk

At DrDoctor we are slowly adopting Splunk as our central reporting repository. We already have most of our application specific events going into it and we are already seeing some great benefits.

In this post I’m going to show the various steps I went through to get our log4net files being ingested in a useful format. Monitoring a file is easy, extracting useful fields is sometimes a challenge especially with log files.

Setting the format string

The first step was to change the format string in the log4net.config file. The main aim here was to make my life easier for when the log files are going into Splunk. By prefixing all the log4net tokens with a name means that I can write some simple, but very reliable regexes in Splunk to turn these into fields.

1
%utcdate{ISO8601} Release:'!release!' Version:'!version!' Thread:'\[%thread\]' Level:'%-5level' Logger:'%logger' Message:'%message'%newlineException:'%exception'

Those who are familiar with the log4net configuration options with notice that there are two tokens that don’t exist in the format string above. They are !release! and !version!, these are two very useful values to capture alongside our error messages as we can then start to track when new types of errors are discovered or introduced.

I’m using a custom PowerShell script in our deployment system, Octopus Deploy to set these values during the deployment phase, the release number reflects the Octopus Deploy release and the version number reflects the build number from TeamCity. Arguably we probably don’t need both, but I’m not entirely sure what I’m going to need yet so I’m going to stick with both for now.

Setting up Splunk

In our environment and most others I would assume, we are using the Splunk universal forwarder to send data to Splunk. The first step then is to add a new entry to the inputs.conf file to keep an eye on our logs directory.

1
[monitor://d:\logs\*.log] sourcetype=log4net 

Well that was easy, now that the Universal Forwarder is tracking the log files directory we should start seeing log entries appearing in Splunk.

This is a good start, but it would be more useful if we could start seeing the breakdown of the various entries. This is the point where we need to extract the various fields from the raw events.

To do this we need to make use of the Splunk field extractions. To extract more fields scroll down and click the link “Extract New Fields”

/log4net-monitoring-with-splunk/images/1-extract-new-fields.png

Then click “I prefer to enter the regex myself”

/log4net-monitoring-with-splunk/images/2-write-myown-regex.png

All the extractions follow a similar pattern, here is the regex to extract the log level:

1
Level:'(?P(([A-Za-z]*)))'

Enter that into the regex input, then click the Preview button, in the sample events you will see all the different logging levels highlighted, you will also notice a new tab called Level appear.

https://kzhendev.files.wordpress.com/2015/05/3-preview.png?w=660

Here is the complete list:

1
2
3
4
Release:'(?P<Release>(([0-9|.]*)))'
Version:'(?P<Version>(([0-9|.]*)))'
Level:'(?P<Level>(([a-zA-Z]*)))'
Message:'(?P<Message>((.+)))'

Go through the steps above for each one.

Log Intelligence

Now we can start doing some fancy queries.

Example one: number of errors by Release and host

1
index=logs sourcetype=log4net | stats count by Release, host

https://kzhendev.files.wordpress.com/2015/05/4-count-by-release-host.png?w=660

Example two: number of errors over time

1
index=logs sourcetype=log4net | timechart count

https://kzhendev.files.wordpress.com/2015/05/5-timechart.png?w=660

Example three: number of errors by application

1
index=logs sourcetype=log4net | rex field=source "Error\\\(?<app>(\w|\s|\d)*)" | stats count by Release, host, app | sort -Release, -count

https://kzhendev.files.wordpress.com/2015/05/6-errors-by-application.png?w=660

Next steps

There are many possibilities, here are a couple of ideas:

  • Build a dashboard from the various queries above
  • Create some Splunk Alerts to trigger when a threshold of errors have been triggered