why logging code need hold file handle

Topics: Logging Application Block
Jul 16, 2013 at 7:27 AM
As EL Loggging replacement for more flexiable category managing, I am trying implement my own logging codes. And I have one concern that i don't understand why EL holds log file handler till application ends. Is it to solve some issue or to get better write performance?
Jul 17, 2013 at 1:09 AM
Can someone help me out?
Editor
Jul 17, 2013 at 5:38 AM
Enterprise Library itself doesn't explicitly lock the file. The locking is done by the System.Diagnostics.TextWriterTraceListener which Enterprise Library extends. TextWriterTraceListener opens the file as FileShare.Read. Some reasons to do this would be for performance (avoid opening and closing the file constantly) and to avoid multiple processes writing interleaved output to the file.

This may be presumptuous since I have no idea about your specific scenario but, in general, I would recommend not writing your own logging framework in lieu of using one of the established logging frameworks.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 17, 2013 at 3:00 PM
Edited Jul 17, 2013 at 3:02 PM
Thanks for the explanation, Randy.

I want to dispatch log with category dynamically. For example, i only have category 1 logs at first, and i would write all logs to "1.log" file. Then i have category 2 logs, i need all category 2 logs to "2.log" file while category 1 logs still write to "1.log" file. When more categories come, the program should be able to dispatch logs by category without changing any code or config. Because, after product goes online, it is inconvenient to do either.

In my understanding, the logging blocking is not flexible enough to do so. Am i right?
Editor
Jul 18, 2013 at 7:32 AM
Edited Jul 18, 2013 at 7:46 AM
You can definitely do what you want using programmatic configuration. Here's an example with Enterprise Library 6 that uses a dictionary to store a separate LogWriter associated with each category:
    public class MyLogWriter
    {
        private static ConcurrentDictionary<string, LogWriter> logWriters = 
            new ConcurrentDictionary<string, LogWriter>();

        public void Write(string message, string category)
        {
            LogWriter logger = logWriters.GetOrAdd(category,
                (c) =>
                {
                    LoggingConfiguration config = new LoggingConfiguration();
                    config.AddLogSource(category,
                        SourceLevels.All,
                        true,
                        new FlatFileTraceListener(string.Format(@"c:\Logs\{0}.txt", category)));
                    return new LogWriter(config);
                });

            logger.Write(message);
        }
    }

The use of ConcurrentDictionary should make the above thread safe. The above seems like the best approach if thread safety is a concern (there are many other ways I can think of but locking could get messy).

Or instead of creating your own Write method you could create your own factory using a similar approach:
    public static class MyLogWriterFactory
    {
        private static ConcurrentDictionary<string, LogWriter> logWriters =
            new ConcurrentDictionary<string, LogWriter>();

        public static LogWriter Create(string category)
        {
            return logWriters.GetOrAdd(category,
                (c) =>
                {
                    LoggingConfiguration config = new LoggingConfiguration();
                    config.AddLogSource(category,
                        SourceLevels.All,
                        true,
                        new FlatFileTraceListener(string.Format(@"c:\Logs\{0}.txt", category)));
                    config.DefaultSource = category;
                    return new LogWriter(config);
                });
        }
    }


    MyLogWriterFactory.Create("category1").Write("Category 1 message");
    MyLogWriterFactory.Create("category2").Write("Category 2  message");

I made the factory class static but you could make it a singleton.

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

I tried ur example, and it works great. Thanks very much!

Ballian