Single Source Multiple RollingFlatFile Logs

Topics: Semantic Logging Application Block
Jul 4, 2013 at 8:13 AM
Hello,

I have an application that creates multiple "controllers" at run time based on the specific user requirements. These controllers receive alarm messages from various pieces of equipment at the customer site. I am required to log the incoming alarms to a separate log file for each controller. The formatting for each controller is identical and only the physical log file is different. To keep things simple I would like to use the Semantic Application Logging Block to achieve this with a single procedure in my EventSource to trigger the write. Because I don't know how many Controllers there will be at design time I can't use a Keyword to filter in the Listener.

I have created a custom TextFormatter with a property for the Controller Name. The WriteEvent procedure simply checks the payload to see if the Controller matches the Property. If it does then I write the event. If not then I simply do nothing.

So whilst I have a solution it seems a little inefficient as each listener gets triggered every time a message comes in. Is there a way to filter at the Listener level so only the Controller's Listener sees the Event?

Many thanks in advance.
Editor
Jul 6, 2013 at 8:29 AM
Edited Jul 8, 2013 at 4:40 AM
Here's a solution using a custom filter with Reactive Extensions. I think it's quite similar to what you are describing but I think would be a bit more efficient. This is for an in process scenario.

First Let's say I have a single EventSource with the same events for all controllers:
    [EventSource(Name = "MyEventSource")]
    public class MyEventSource : EventSource
    {
        [Event(1, Message = "Message: ", Level = EventLevel.Verbose)]
        public void Write(string controllerName, string message)
        {
            WriteEvent(1, controllerName, message);
        }

        public static readonly MyEventSource Log = new MyEventSource();
    }

Notice that the Write method accepts the controllerName as the first argument.

Next, I added Reactive Extensions via NuGet. Now I use the first payload argument (i.e. controllerName) to filter on EventEntry:
    ObservableEventListener listener1 = new ObservableEventListener();
    listener1.EnableEvents(MyEventSource.Log, EventLevel.LogAlways, Keywords.All);            
        listener1.Where(item => item.Payload[0].ToString() == "Controller1")
        .LogToFlatFile(@"C:\Logs\MyLogFile1.txt");

    MyEventSource.Log.Write("Controller1", "Test");

    ObservableEventListener listener2 = new ObservableEventListener();
    listener2.EnableEvents(MyEventSource.Log, EventLevel.LogAlways, Keywords.All);
    listener2.Where(item => item.Payload[0].ToString() == "Controller2")
        .LogToFlatFile(@"C:\Logs\MyLogFile2.txt");

    MyEventSource.Log.Write("Controller2", "Test");

Note that the lambda expression is a bit naive with no error checking (e.g. nulls, array length, etc.).

The EventSource Write method will still be called once for every call and the Func will be evaluated once for every listener but if the controller names do not match there should be no further processing for that EventEntry by that listener.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Marked as answer by randylevy on 10/7/2013 at 11:12 PM
Jul 10, 2013 at 2:37 AM
Hi Randy,

Thanks very much for this and for the prompt reply. I'll use this as part of the solution.

Kind regards,

Peter