Get Control Of Your Enterprise Library Logging Application Block Logs

Enterprise Library’s Logger is powerful and convenient.  It’s default TextFormatter provides a suitable human readable format, and it also allows you to implement custom formatters to suite your needs.  I think that being able to work with log data without having to manually parse strings, can really simplify the development of tools for mining logs.   To this end, I whipped up a small WinForms app that demonstrates how to take log entries originating from a text spool, convert them into objects, and query them with Linq.  The primary goal was to provide simple UI that enables log search, filter, and find, with sorting, grouping, etc.

First off, the heavy lifting in this sample is provided by the EntLib Contrib LogParser.  Their FilteredLogReader class drives a tokenizer, which creates and populates LogEntry objects out of log text.   The tokenizer will use any formatting template, in our case, I’ve used the built in “Text Formatter”.   When it executes, it generates a RegularExpression capable of matching and trapping the values involved in populating our collection of LogEntry objects.  Ultimately, we are provided with a simple API for driving all of this.  Here’s a brief sample:

string configFile = "abc.config";

            string traceLog = "trace.log";

 

            FilteredLogFileReader reader =

new FilteredLogFileReader(traceLog, configFile,

                        new TimeStampParser(CultureInfo.CurrentCulture));

 

            Filter filter = new Filter

            {

                StartTime = DateTime.Now.AddHours(-1),

                StopTime = DateTime.Now

            };

 

            IEnumerable<LogEntry> entries = reader.ParseLogFile(filter);

The basic idiom here is:

1.       Get a FilteredLogFileReader

2.       Setup a Filter

3.       Feed the filter to the reader’s ParseLogFile

To facilitate a flexible set of filtering concepts at the UI, I decided to use a simple FilterExpression class to represent a set of keys, values, and match operators.  Here’s a quick way to get the intersection result set from applying a set of filters with a single pass through the logs.

       

        private IList<LogEntry> FilterLogEntries(List<LogEntry> lst,

                                                 List<FilterExpression> exprs)

        {

            var matchAllExprs = new List<LogEntry>();

                       List<PropertyInfo> props = typeof(LogEntry).GetProperties().ToList();

            lst.ForEach(entry =>

                {

                    int matchCount = 0;

                    exprs.ForEach(expr =>

                    {

                        string value = props.Find(prop => prop.Name.Equals(expr.Key))

                                                      .GetValue(entry, null).ToString();

                        switch (expr.Operator.ToLower())

                        {

                            case "contains":

                                if (value.Contains(expr.Value))

                                    matchCount++;

                                break;

                            case "!contains":

                                if (!value.Contains(expr.Value))

                                    matchCount++;

                                break;

                            case "regex match":

                                if (new Regex(expr.Value).IsMatch(value))

                                    matchCount++;

                                break;

                            case "==":

                                if (expr.Value.Equals(value))

                                    matchCount++;

                                break;

                            case "!=":

                                if (!expr.Value.Equals(value))

                                    matchCount++;

                                break;

                            default:

                                throw new Exception("operator not found");

                        }

                    });

                    if (exprs.Count == matchCount)

                        matchAllExprs.Add(entry);

                });

            return matchAllExprs;

        }

 

If any of the LogEntries match all of the expressions, then those are returned to the caller.  Now we can place the log data onto our screen for users.

this.dataGridView1.DataSource = 

    new BindingList<LogEntry>(FilterLogEntries(lst,

        lbxFilterExpressions.Items.Cast<FilterExpression>().ToList()));

The sample app that I’ve included, gives users the ability to create, configure, and apply FilterExpressions on the fly.  Here’s a screenshot.

You can get the source for this sample here.  Enjoy..   

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 )

Google+ photo

You are commenting using your Google+ 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