Thursday, June 4, 2009

Avoid verbose log formatting in .NET TraceListeners

The problem is:

when you use any of default TraceListeners (for example, I need ConsoleTraceListener), and when you call Trace.LogInfo , Trace.LogError or Trace.LogWarning, you wil have something like

Your application name: Information : : And here is a text of your message
Your application name: Warning : : And here is a text of your warning
....

Well, I don't need application name and I want to exactly control how the log is formatted. Setting traceOutputOptions in app.config will not change the situation, because with traceOutputOptions you can add date, timestamp or even full stack to the log, but there is no way to remove something out from there. Damn, now I understand why we have been used Log4Net for logging instead of System.Diagnostics.Trace! But in the current project I can't use Log4Net

Ok, to solve the problem I try to understand how the MS code works, when going from the point where you call LogInfo (message) to the point where it outputs to the stream.
I noticed that

When I call Trace.LogInfo(message), the following happens

1) TraceListener.Write is called with parameter like "application_name: message_type: 0 "
2) TraceListener.WriteLine is called with my message

So actually they write a log message in 2 turns, OK, sound great for me, as far as we can handle it now in the following way:

1) I created a simple class LaconicTraceListener, and the code you will find below. You need to override just one function there
2) And I added new cutom listener to the app.config file to the section.



And it works!


///
/// Class overrides one function of standard ConsoleTraceListener
/// to make output less verbose
///

public class LaconicConsoleTraceListener: System.Diagnostics.ConsoleTraceListener
{

public LaconicConsoleTraceListener(): base()

{
}

public LaconicConsoleTraceListener(bool useErrorStream)
: base(useErrorStream)
{
}

public override void Write(string message)
{
/*
A trick to avoid verbose logging.
LogInformation function works in following way -
For each call of LogInformation(Message) it actually calls:
1) Write("AssemblyName: MessageType: MessageIndent");
2) WriteLine(message)

We don't want to have an assembly name in each trace line, so we will exclude it
*/
if (!message.StartsWith(this.GetType().Assembly.GetName().Name,
StringComparison.InvariantCultureIgnoreCase))

{
base.Write(message);
}
}
}