Design of the Semantic Logging Application Block

patterns & practices Developer Center

The Semantic Logging Application Block includes the following features:

  • A simple and consistent way of logging event information
  • Capability to process log messages either in-process or out-of-process
  • Distribution of log messages to multiple destinations
  • Simplified application block configuration
  • Extensibility through custom trace sinks, formatters, and out-of-process trace listener host applications

Design goals

The Semantic Logging Application Block was designed to achieve the following goals:

  • Enable users to take advantage of the EventSource class without having to learn the details of working directly with Event Tracing for Windows (ETW).
  • Help users embrace the need to author event source classes that define the structured events to log.
  • Help users to ensure that event sources have been properly authored to avoid errors at runtime.
  • Allow users to filter or manipulate events before sending them to a sink.
  • Take advantage of the capabilities provided by the .NET Framework System.Diagnostics.Tracing.EventSource class ETW.
  • Meet the performance requirements for the application block by ensuring that its code has minimal overhead compared to custom code that uses the System.Diagnostics.Tracing namespace classes directly.
  • Make message routing flexible by using a simple model for distributing log entries.
  • Encapsulate the logic that performs the most common application logging tasks, minimizing the need for custom logging-related code.
  • Minimize the risk of losing log messages if you chose to buffer messages
  • Make sure that the application block is easily and highly configurable.
  • Make sure that the application block is extensible.
  • Make sure that the sink implementations are thread-safe.

Design highlights

Figure 1 shows the design of the parts of the Semantic Logging Application Block that are relevant to the in-process scenario. In this scenario, as part of the client’s bootstrapping process, the client application uses the block within the client application’s process, typically creating instances of the ObservableEventListener, sink types, and IEventTextFormatter types to collect and process events that the client will create. The client uses the event methods in the custom EventSource class to create events.

The listeners receive the events because the sinks implement the IObserver interface and subscribe to the ObservableEventListener instance that implements the IObservable interface. Extension methods on the ObservableEventListener class create sinks and generate subscriptions.

Figure 1 - Design of the Semantic Logging Application Block for the in-process scenario

Figure 1 - Design of the Semantic Logging Application Block for the in-process scenario

Figure 2 shows the design of the parts of the Semantic Logging Application Block that are relevant to the out-of-process scenario. In this scenario, the client application does not use the block directly, it uses a custom EventSource implementation to define and send trace messages to the ETW infrastructure in Windows. A separate process hosts a TraceEventServiceHost instance that uses configuration data to build the necessary sink and formatter instances to receive and process the log messages delivered by the ETW infrastructure in the operating system. There is one TraceEventServiceWorker for each sink, and these workers receive events from the corresponding ETW session and deliver them to the sink.

Figure 2 - Design of the Semantic Logging Application Block for the out-of-process scenario

Figure 2 - Design of the Semantic Logging Application Block for the out-of-process scenario

Both scenarios share many of the same elements such as sinks and formatters. Both scenarios can also use the same client application event source implementations to define and raise custom events, which means that you can use the same EventSource classes in both in-process and out-of-process scenarios.

The EventSource class

This class is in the System.Diagnostics.Tracing namespace in the .NET Framework. Your custom EventSource implementation must extend this class to define the log messages you plan to use in your application.

The EventEntry class

This class is part of the Semantic Logging Application Block, and an instance is created to represent each event. In the in-process scenario, the EventSource class passes events to listeners as instances of the EventWrittenEventArgs class but, as a performance optimization, these instances are reused. The Semantic Logging Application Block needs a persisted copy of the event in order to execute asynchronous processing, buffering, and batching, and so it uses instances of the EventEntry class to hold the copies of each event as they are processed.

The ObservableEventListener class (in-process only)

This class extends the abstract EventListener class in the System.Diagnostics.Tracing namespace of the .NET framework and implements the IObservable<EventEntry> interface. It is used only in the in-process scenario for receiving event messages from an event source. Its task is to receive the notification of events from the EventSource, map the EventWrittenEventArgs to an EventEntry, and publish the EventEntry so that any IObserver<EventEntry> implementation (usually an event sink in the block) can consume it. It enables multiple sinks to subscribe to event messages it receives from the event source. It is possible for a sink to subscribe indirectly to an event source through an intermediary that can filter or manipulate the events before the sink receives them.

The TraceEventServiceHost class (out-of-process only)

In the out-of-process scenario, the TraceEventServiceHost class uses the TraceEventServiceConfiguration class to read the configuration information from the configuration file, and passes that configuration information to the TraceEventService instance. The TraceEventService class uses the TraceEvent API to create real-time consumers of ETW events produced by EventSource instances (as specified in the configuration). These consumers convert the event representations of the TraceEvent API into equivalent EventEntry representations suitable for consumption by the sinks provided in the block. Typically, you will not use this class directly unless you want to implement your own out-of-process service for use in place of the one supplied with the block.

The Sink classes

Each sink type represents a destination for the event messages from the event source. The sinks subscribe to the ObservableEventListener instance, which implements the IObservable<EventEntry> interface. The different sink types each have their own specific configuration settings that are relevant to the destination, such as the file name for the FlatFileSink or the database name for the SqlDatabaseSink. You can create the sinks and subscribe them to an event listener using the extension methods defined in the IObservable<EventEntry> interface that the ObservableEventListener class implements. These extension methods can also be used with any IObservable<EventEntry> instance, such as a reactive extensions (Rx) query.

Buffering sinks

Some sinks, such as the Azure Table Storage sink and the SQL Database sink, enable you to buffer log messages in order to improve message throughput. If you host these sinks in-process, you will lose any buffered messages if your application crashes. The out-of-process host application available for use with the Semantic Logging Application Block is designed to be robust in order to minimize the risk of losing log messages.

The IEventTextFormatter interface

The Semantic Logging Application Block includes implementations of this interface. These implementations are responsible for controlling the formatting of the log messages saved to flat files or written to the console. The formatters provided in the block include the TextEventTextFormatter, XmlEventTextFormatter, JsonEventTextFormatter, and CustomEventTextFormatter. The formatters each have different configuration options that enable you to refine the formatting of the messages to suit your own requirements.

The IConsoleColorMapper interface

The DefaultColorMapper class that implements the IConsoleColorMapper interface contains a set of rules that specify the colors to use to highlight the different severity level of the log messages when displayed in the console. You can provide your own implementation of this interface.

Previous Topic | Home | Community