How to dynamically set log file using App.config and System.Diagnostics?

Simpleton picture Simpleton · Oct 10, 2012 · Viewed 20.4k times · Source

I was looking for a solution to provide logging to my latest project when I came across an article ( http://www.daveoncsharp.com/2009/09/create-a-logger-using-the-trace-listener-in-csharp/ ) that talked about using System.Diagnostics and App.config to log via the Trace method. I was able to successfully implement both the class and the App.config but I'd really like to be able to dynamically assign the value/location (inside initializeData) of the log file and I don't have a clue how to do it. If you have any suggestions, please feel free to post!

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="myListener" 
             type="System.Diagnostics.TextWriterTraceListener" 
             initializeData="fileSizeThreshold=512, fileSizeUnit=kilobytes, 
             fileAgeThreshold=1, fileAgeUnit=months, fileNameTemplate='{0}\MyApp-{1:MMM-yy}.log'"/>
        <remove name="Default" />
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

Logger Class:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;


namespace MyCurrentProject
{
    class Logger
    {
        public void Error(string module, string message)
        {
            WriteEntry(message, "ERROR:", module);
        }

        public void Error(Exception ex, string module)
        {
            WriteEntry(ex.Message, "ERROR:", module);
        }

        public void Warning(string module, string message)
        {
            WriteEntry(message, "WARNING:", module);
        }

        public void Info(string module, string message)
        {
            WriteEntry(message, "INFO:", module);
        }

        private void WriteEntry(string message, string type, string module)
        {
            Trace.WriteLine(
                    string.Format("{0} {1} [{2}] {3}",
                                  DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                  type,
                                  module,
                                  message));
        }
    }
}

RE: Sorry for not being clear... just to be clear, I need the file path that the log file output is save to to be dynamically set. I'd like the path to save to a location in %AppData%. The problem I had with the config was that once I set the value for 'initializeData' I couldn't find a way to change or dynamically set/reset that value. Truthfully... at this point I just want a solution that works and allows me to manage the location of the log file.

Answer

MatthewMartin picture MatthewMartin · Oct 11, 2012

Here is a worked example using Systems.Diagnostics, which has two advantages over non-base class libraries. It is always allowed (in large organizations), always available, and to the extent that developers are familiar with the base class library, the next batch of maintenance developers will have heard of it.

using System.Diagnostics;

namespace DynamicTraceLog
{
    class Program
    {
        static void Main(string[] args)
        {
            //Use TraceSource, not Trace, they are easier to turn off
            TraceSource trace = new TraceSource("app");
            //SourceSwitches allow you to turn the tracing on and off.
            SourceSwitch level =new SourceSwitch("app");
            //I assume you want to be dynamic, so probalby some user input would be here:
            if(args.Length>0 && args[0]=="Off")
                level.Level= SourceLevels.Off;
            else
                level.Level = SourceLevels.Verbose;
            trace.Switch = level;
            //remove default listner to improve performance
            trace.Listeners.Clear();
            //Listeners implement IDisposable
            using (TextWriterTraceListener file = new TextWriterTraceListener("log.txt"))
            using (ConsoleTraceListener console = new ConsoleTraceListener())
            {
                //The file will likely be in /bin/Debug/log.txt
                trace.Listeners.Add(file);
                //So you can see the results in screen
                trace.Listeners.Add(console);
                //Now trace, the console trace appears immediately.
                trace.TraceInformation("Hello world");
                //File buffers, it flushes on Dispose or when you say so.
                file.Flush();
            }
            System.Console.ReadKey();
        }
    }
}

Re: how to format the output Try either of these two for trace listeners that implement templated trace formating/output using Systems.Diagnostics classes: http://essentialdiagnostics.codeplex.com or http://ukadcdiagnostics.codeplex.com/ Systems.Diagnostics doesn't provide for any particular formating or outputing of standard tokens.