14
\$\begingroup\$

I have a rather large class that needs to provide a reasonable amount of output for debugging purposes. I've done this with the following:

#if DEBUG
Console.WriteLine("Source Site Set to: {0}", archiveQueueEntity.SourceSite);
Console.WriteLine("Source List Set to: {0}", archiveQueueEntity.SourceUrl);
Console.WriteLine("Destination Site Set to {0}", archiveQueueEntity.DestinationSite);
Console.WriteLine("Destination List Set to: {0}", archiveQueueEntity.DestinationUrl);
#endif

Is there a better way to do this though?

After googling this I tried using Debug.WriteLine but it appears that this will only output to the 'output' window in Visual Studio, and not the console.

Am I missing something?

\$\endgroup\$
17
\$\begingroup\$

I think it would be much cleaner to utilize partial methods to create your logging statements. That way you can log wherever you need it and can disable the code my omitting it the logging function definition. By using partial methods, if the definition is omitted, no IL is generated for the method and calls to the partial method are ignored as if it was never there.

Just mark the class partial, define the signature of the partial method and call it like normal. Then wrap the actual implementation in the conditional compilation blocks.

partial class MyClass
{
    // declare the partial method
    static partial void Log(string format, params object[] arguments);

    static void SomeMethod()
    {
        // call the log method like usual
        Log("Source Site Set to: {0}", archiveQueueEntity.SourceSite);
        Log("Source List Set to: {0}", archiveQueueEntity.SourceUrl);
        Log("Destination Site Set to {0}", archiveQueueEntity.DestinationSite);
        Log("Destination List Set to: {0}", archiveQueueEntity.DestinationUrl);
    }

#if DEBUG
    static partial void Log(string format, params object[] arguments)
    {
        Console.WriteLine(format, arguments);
    }
#endif
}

Otherwise if you're not able to change it, you should still create a separate logging method and disable to actual printing in the method there. That way your method is called but does nothing.

static void Log(string format, params object[] arguments)
{
#if DEBUG
    Console.WriteLine(format, arguments);
#endif
}

Or alternatively, use the Trace class to do your logging. As long as you have no listeners registered, you will not see any of the logging messages. When debugging, add a ConsoleTraceListener to the Listeners collection.

#if DEBUG
    Trace.Listeners.Add(new ConsoleTraceListener());
#endif

Trace.WriteLine("Source Site Set to: {0}", archiveQueueEntity.SourceSite);
Trace.WriteLine("Source List Set to: {0}", archiveQueueEntity.SourceUrl);
Trace.WriteLine("Destination Site Set to {0}", archiveQueueEntity.DestinationSite);
Trace.WriteLine("Destination List Set to: {0}", archiveQueueEntity.DestinationUrl);

Something that eluded me until now, use the ConditionalAttribute attribute on the log function for both cases to achieve the same effect.

[Conditional("DEBUG")]
static void Log(string format, params object[] arguments)
{
    Console.WriteLine(format, arguments);
}
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Even better, use [Conditional("DEBUG")] on the Log method and you don't even need to have a partial class and a partial method. \$\endgroup\$ – svick Aug 29 '12 at 11:44
  • \$\begingroup\$ svick: Well, I think that Jeff Mercado thought about using partial to have the debugging-stuff in a different file. So you don't mix up "real code" with "test code". \$\endgroup\$ – basti Aug 29 '12 at 13:16
  • 1
    \$\begingroup\$ @svick: Ah, I keep forgetting about that one. Definitely nicer. \$\endgroup\$ – Jeff Mercado Aug 29 '12 at 13:54
  • 1
    \$\begingroup\$ @chiffre: That would still be possible whether it was a partial method or not, the class could still be made partial and the log function could be placed there regardless. I guess I'm just looking for excuses to use partial methods, there's not very many everyday uses for them. \$\endgroup\$ – Jeff Mercado Aug 29 '12 at 14:11
4
\$\begingroup\$

Also take a look at a proper logging framework like NLog (my favorite, for these reasons and more) or log4net.

If you really want to get esoteric but automated with logging (and other cross-cutting concerns), read up on aspect-oriented programming (AOP). PostSharp is the leading product in that area for .NET (at least as far as I know).

\$\endgroup\$
1
\$\begingroup\$

I would suggest something similar to the Trace option Jeff provided, with some differences:

  1. Use TraceSource instead. It is the suggested replacement for the Trace class.
  2. I would not use a compiler directive to switch the logging on and off. Omit the .Listeners.Add line (which also exists for TraceSource) entirely.
  3. Utilize app.config files to control whether or not the logging occurs and how it is output.

This saves you from swapping out binaries to troubleshoot an issue, which can in rare cases impact whether a bug is reproduced. Instead, you drop a modified app.config file in and restart the program/service.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.