Structured logging with the Semantic Logging Block

In another post I looked at Serilog and what structured logging capabilities can bring to an application, here I’m going to investigate the Patterns & Practices Semantic Logging Application Block.

So we’re looking at a means of logging more than just a “simple” string representing our state or failure (or whatever) from our application. Most likely we’re wanting to output log entries which can be analysed later in a more programmatic manner, i.e. querying or grouping log data.

Getting started

Let’s just get some simple code up and running to see how things fit together.

  • Create a console application
  • Using Nuget, add the following EnterpriseLibrary.SemanticLogging package
  • Add a new class named whatever you want, mine’s called MyEventSource

The MyEventSource class looks like this

[EventSource(Name = "MyEventSource")]
public class MyEventSource : EventSource
{
   public static MyEventSource Log { get; } = new MyEventSource();

   [Event(1, Message = "Application Failure: {0}", 
    Level = EventLevel.Informational,
    Keywords = EventKeywords.None)]
   public void Information(string message)
   {
      WriteEvent(1, message);
   }
}

Next up, let’s implement some simple logging code in our Main method

var eventSource = MyEventSource.Log;
var listener = ConsoleLog.CreateListener(
   new JsonEventTextFormatter(EventTextFormatting.Indented));

listener.EnableEvents(eventSource, 
   EventLevel.LogAlways, 
   EventKeywords.All);

eventSource.Information("Application Started");

// do something worthwhile 

eventSource.Information("Existing Application");

In the example code we’re logging to the console and using the JsonEventTextFormatter, so the output looks like this

{
"ProviderId": "8983a2e6-c5d2-5a1f-691f-db243cb1f681",
"EventId": 1,
"Keywords": 0,
"Level": 4,
"Message": "Application Failure: Application Started",
"Opcode": 0,
"Task": 65533,
"Version": 0,
"Payload": {
"message": "Application Started"
},
"EventName": "InformationInfo",
"Timestamp": "2016-07-08T10:19:22.8698814Z",
"ProcessId": 20136,
"ThreadId": 19128
},
{
"ProviderId": "8983a2e6-c5d2-5a1f-691f-db243cb1f681",
"EventId": 1,
"Keywords": 0,
"Level": 4,
"Message": "Application Failure: Existing Application",
"Opcode": 0,
"Task": 65533,
"Version": 0,
"Payload": {
"message": "Existing Application"
},
"EventName": "InformationInfo",
"Timestamp": "2016-07-08T10:19:22.9648909Z",
"ProcessId": 20136,
"ThreadId": 19128
},

Let’s now add a rolling file listener to our Main method

var rollingFileListener =
   RollingFlatFileLog.CreateListener(
      "logs\\semantic.txt", 1073741824,
      "yyyy.MM.dd",
      RollFileExistsBehavior.Increment, 
      RollInterval.Day,
      new JsonEventTextFormatter(EventTextFormatting.Indented));

rollingFileListener.EnableEvents(
   eventSource, 
   EventLevel.LogAlways, 
   EventKeywords.All);

So we simply attach another listener to our event source and now we are logging to both the console and a file (ofcourse in a non-sample application we would not be creating multiple JsoEventTextFormatters etc. but you get the idea).

That’s basically it – we’re up and running.