ENTERPRISE

Microsoft Enterprise Library : Non-Formatted Trace Listeners (part 1) - Creating and Using Logentry Objects, Capturing Unprocessed Events and Logging Errors

9/12/2012 1:09:22 AM
While we are discussing output formatting, there is one other factor to consider. Some trace listeners do not use a text formatter to format the output they generate. This is generally because the output is in a binary or specific format. The WMI trace listener is a typical example that does not use a text formatter.

For such trace listeners, you can set the TraceOutputOptions property to one of a range of values to specify the values you want to include in the output. The Trace OutputOptions property accepts a value from the System.Diagnostics.TraceOptions enumeration. Valid values include CallStack, DateTime, ProcessId, LogicalOperation Stack, Timestamp, and ThreadId. The documentation installed with Enterprise Library, and the documentation for the System.Diagnostics namespace on MSDN®, provide more information.

1. Filtering by Severity in a Trace Listener

1.1. Filtering by Severity in a Trace Listener

The previous example generates a third disk file that we haven't looked at yet. We didn't forget this, but saved if for this section because it demonstrates another feature of the trace listeners that you will often find extremely useful. To see this, you need to view the file XmlLogFile.xml that was generated in the C:\Temp folder by the XML trace listener we used in the previous example. You should open it in Microsoft Internet Explorer® (or another Web browser or text editor) to see the structure.

You will see that the file contains only one event from the previous example, not the three that the code in the example generated. This is because the XML trace listener has the Filter property in its configuration set to Error. Therefore, it will log only events with a severity of Error or higher. If you look back at the example code, you will see that only the last of the three calls to the Write method specified a value for the severity (TraceEventType.Critical in this case), and so the default value Information was used for the other two events.


Note:

If you get an error indicating that the XML document created by the XML trace listener is invalid, it's probably because you have more than one log entry in the file. This means that it is not a valid XML document—it contains separate event log entries added to the file each time you ran this example. To view it as XML, you must open the file in a text editor and add an opening and closing element (such as <root> and </root>) around the content. Or, just delete it and run the example once more.


All of the trace listeners provided with Enterprise Library expose the Filter property, and you can use this to limit the log entries written to the logging target to only those that are important to you. If your code generates many information events that you use for monitoring and debugging only under specific circumstances, you can filter these to reduce the growth and size of the log when they are not required.

Alternatively, (as in the example) you can use the Filter property to differentiate the granularity of logging for different listeners in the same category. It may be that a flat file trace listener will log all entries to an audit log file for some particular event, but an Email trace listener in the same category will send e-mail messages to administrators only when an Error or Critical event occurs.

1.2. Filtering All Log Entries by Priority

As well as being able to filter log entries in individual trace listeners based on their severity, you can set the Logging block to filter all log entries sent to it based on their priority. Alongside the log-enabled filter and category filter in the Filters section of the configuration , you can add a filter named Priority Filter.

This filter has two properties that you can set: Minimum Priority and Maximum Priority. The default setting for the priority of a log entry is -1, which is the same as the default setting of the Minimum Priority property of the filter, and there is no maximum priority set. Therefore, this filter will not block any log entries. However, if you change the defaults for these properties, only log entries with a priority between the configured values (including the specified maximum and minimum values) will be logged. The exception is log entries that have the default priority of -1. These are never filtered.

2. Creating and Using Logentry Objects

So far we have used the Write method of the LogWriter class to generate log entries. An alternative approach that may be useful if you want to create log entries individually, perhaps to return them from methods or to pass them between processes, is to generate instances of the LogEntry class and then write them to the configured targets afterwards.

The example, Creating and writing log entries with a LogEntry object, demonstrates this approach. It creates two LogEntry instances. The code first calls the most complex constructor of the LogEntry class that accepts all of the possible values. This includes a Dictionary of objects with a string key (in this example, the single item Extra Information) that will be included in the output of the trace listener and formatter. Then it writes this log entry using an overload of the Write method of the LogWriter that accepts a LogEntry instance.

Next, the code creates a new empty LogEntry using the default constructor and populates this by setting individual properties, before writing it using the same Write method of the LogWriter.

// Check if logging is enabled before creating log entries.
if (defaultWriter.IsLoggingEnabled())
{
  // Create a Dictionary of extended properties
  Dictionary<string, object> exProperties = new Dictionary<string, object>();
  exProperties.Add("Extra Information", "Some Special Value");
  // Create a LogEntry using the constructor parameters.
  LogEntry entry1 = new LogEntry("LogEntry with category, priority, event ID, "
                                 + "severity, and title.", "General", 8, 9006,
                                 TraceEventType.Error, "Logging Block Examples",
                                 exProperties);
  defaultWriter.Write(entry1);
  // Create a LogEntry and populate the individual properties.
  LogEntry entry2 = new LogEntry();
  entry2.Categories = new string[] {"General"};
  entry2.EventId = 9007;
  entry2.Message = "LogEntry with individual properties specified.";
  entry2.Priority = 9;
  entry2.Severity = TraceEventType.Warning;
  entry2.Title = "Logging Block Examples";
  entry2.ExtendedProperties = exProperties;
  defaultWriter.Write(entry2);
}
else
{
  Console.WriteLine("Logging is disabled in the configuration.");
}

					  

This example writes the log entries to the Windows Application Event Log by using the General category. If you view the events this example generates, you will see the values set in the code above including (at the end of the list) the extended property we specified using a Dictionary. You can see this in Figure 1.

Figure 1. A log entry written to the General category


3. Capturing Unprocessed Events and Logging Errors

The capability to route log entries through different categories to a configured set of trace listener targets provides a very powerful mechanism for performing a wide range of logging activities. However, it prompts some questions. In particular, what happens if the categories specified in a log entry don't match any in the configuration? And what happens if there is an error when the trace listener attempts to write the log entry to the target?

3.1. About Special Sources

In fact, the Logging block includes three special sources that handle these situations. Each is effectively a category, and you can add references to configured trace listeners to each one so that events arriving in that category will be written to the target(s) you specify.

The All Events special source receives all events, irrespective of all other settings within the configuration of the block. You can use this to provide an audit trail of all events, if required. By default, it has no trace listeners configured.

The Unprocessed Category special source receives any log entry that has a category that does not match any configured categories. By default, this category has no trace listeners configured.

The Logging Errors & Warnings special source receives any log entry that causes an error in the logging process. By default, this category contains a reference to a trace listener that writes details of the error to the Windows Application Event Log, though you can reconfigure this if you wish.

3.2. An Example of Using Special Sources

The example, Using Special Sources to capture unprocessed events or errors, demonstrates how the Logging block reacts under these two circumstances. The code first writes a log entry to a category named InvalidCategory, which does not exist in the configuration. Next, it writes another log entry to a category named CauseLoggingError that is configured to use a Database trace listener. However, this trace listener specifies a connection string that is invalid; it points to a database that does not exist.

// Check if logging is enabled before creating log entries.
if (defaultWriter.IsLoggingEnabled())
{
  // Create log entry to be processed by the "Unprocessed" special source.
  defaultWriter.Write("Entry with category not defined in configuration.",
                      "InvalidCategory");
  // Create log entry to be processed by the "Errors & Warnings" special source.
  defaultWriter.Write("Entry that causes a logging error.", "CauseLoggingError");
}
else
{
  Console.WriteLine("Logging is disabled in the configuration.");
}

					  

You might expect that neither of these log entries would actually make it to their target. However, the example generates the following messages that indicate where to look for the log entries that are generated.

Created a Log Entry with a category name not defined in the configuration.
The Log Entry will appear in the Unprocessed.log file in the C:\Temp folder.
Created a Log Entry that causes a logging error.
The Log Entry will appear in the Windows Application Event Log.

					  

This occurs because we configured the Unprocessed Category in the Special Sources section with a reference to a flat file trace listener that writes log entries to a file named Unprocessed.log. If you open this file, you will see the log entry that was sent to the InvalidCategory category.

The example uses the default configuration for the Logging Errors & Warnings special source. This means that the log entry that caused a logging error will be sent to the formatted event log trace listener referenced in this category. If you open the application event log, you will see this log entry. The listing below shows some of the content.

Timestamp: 24/11/2009 15:14:30
Message: Tracing to LogSource 'CauseLoggingError' failed. Processing for other
sources will continue. See summary information below for more information. Should
this problem persist, stop the service and check the configuration file(s) for
possible error(s) in the configuration of the categories and sinks.
Summary for Enterprise Library Distributor Service:
======================================
-->
Message:
Timestamp: 24/11/2009 15:14:30
Message: Entry that causes a logging error.
Category: CauseLoggingError
...
...
Exception Information Details:
======================================
Exception Type: System.Data.SqlClient.SqlException
Errors: System.Data.SqlClient.SqlErrorCollection
Class: 11
LineNumber: 65536
Number: 4060
Procedure:
Server: (local)\SQLEXPRESS
State: 1
Source: .Net SqlClient Data Provider
ErrorCode: -2146232060
Message: Cannot open database "DoesNotExist" requested by the login. The login
failed.
Login failed for user 'xxxxxxx\xxx'.
...
...
StackTrace Information Details:
======================================
...
...

					 
In addition to the log entry itself, you can see that the event contains a wealth of information to help you to debug the error. It contains a message indicating that a logging error occurred, followed by the log entry itself. However, after that is a section containing details of the exception raised by the logging mechanism (you can see the error message generated by the SqlClient data access code), and after this is the full stack trace.
Other  
  •  Introducing Windows Presentation Foundation and XAML : Transforming Markup into a .NET Assembly
  •  Introducing Windows Presentation Foundation and XAML : Building a WPF Application using Only XAML
  •  Intel : We For One Welcome Our Apple Overlords
  •  Azure Table Storage (part 2) - Accessing Table Storage, Choosing a PartitionKey, Exception handling
  •  Azure Table Storage (part 1) - Table Storage versus database tables
  •  Cheetah3D 6 : Britain's next top modeler
  •  System Center Configuration Manager 2007 : Developing the Solution Architecture (part 5) - Site Design,Client Architecture,Multilanguage Scenarios
  •  System Center Configuration Manager 2007 : Developing the Solution Architecture (part 4) - Capacity Planning,Site Boundaries,Roaming
  •  System Center Configuration Manager 2007 : Developing the Solution Architecture (part 3) - Developing the Server Architecture
  •  System Center Configuration Manager 2007 : Developing the Solution Architecture (part 2) - Configuration Manager 2007 Roles
  •  System Center Configuration Manager 2007 : Developing the Solution Architecture (part 1) - Developing the Network Infrastructure
  •  System Center Configuration Manager 2007 : Operating System Deployment Planning, Out of Band Management Planning
  •  Visual Studio 2010 IDE : Customizing Visual Studio 2010
  •  Visual Studio 2010 IDE : Exporting Templates
  •  System Center Configuration Manager 2007 : Certificate Requirements Planning, Windows Server 2008 Planning
  •  System Center Configuration Manager 2007 : Planning for Internet-Based Clients
  •  Active Directory Domain Services 2008 : Automatically Populate a Migration Table from a Group Policy Object
  •  Active Directory Domain Services 2008 : Create a Migration Table
  •  Microsoft Content Management Server : Developing Custom Properties for the Web Part
  •  Microsoft Content Management Server : Building SharePoint Web Parts - Creating the Web Part, Defining Custom Properties for the Web Part
  •  
    Most View
    Sigma 35mm f1.4 EX HSM Lens Review (Part 1)
    Apple EarPods – An Innovation Or Another Thing For The Recycle Bin? (Part 1)
    Performing mySAP.com Component Installations : Leveraging Installation Documentation, Tools, and Approaches
    Windows Vista : Deploying Applications - Injecting in a Disk Image
    Generation I (For Insecure)?
    Canon SX50 HS Vs Panasonic FZ200 (Part 2)
    Lenovo Ideatab S2110 - A Transformer’s Strong Competitor Running Android 4.0 (Part 1)
    Samsung Galaxy Note 8.0 - Powerful Performance And Vivid Screen (Part 3)
    Sweet 660 Ti DrectCU II TCP
    What Can We Expect From The New Mac Pro (Part 2)
    Top 10
    Windows Management and Maintenance : The Windows 7 Control Panel (part 11) - Region and Language, System
    Windows Management and Maintenance : The Windows 7 Control Panel (part 10) - Programs and Features
    Windows Management and Maintenance : The Windows 7 Control Panel (part 9) - Notification Area Icons, Performance Information and Tools
    Windows Management and Maintenance : The Windows 7 Control Panel (part 8) - Fonts
    Windows Management and Maintenance : The Windows 7 Control Panel (part 7) - Ease of Access Center
    Windows Management and Maintenance : The Windows 7 Control Panel (part 6) - Devices and Printers
    Windows Management and Maintenance : The Windows 7 Control Panel (part 5) - AutoPlay
    Windows Management and Maintenance : The Windows 7 Control Panel (part 4) - AutoPlay
    Windows Management and Maintenance : The Windows 7 Control Panel (part 3) - Action Center
    Windows Management and Maintenance : The Windows 7 Control Panel (part 2)