MartyIX
MartyIX

Reputation: 28648

Question about effective logging in C#

I've written a simple class for debugging and I call the method Debugger.WriteLine(...) in my code like this:

Debugger.WriteLine("[Draw]", "InProgress",
    "[x,y] = " + x.ToString("0.00") + 
    ", " + y.ToString("0.00") + 
    "; pos = " + lastPosX.ToString() + "x" + 
    lastPosY.ToString() + " -> " + posX.ToString() + 
    "x" + posY.ToString() + "; SS = " + 
    squareSize.ToString() + "; MST = " + 
    startTime.ToString("0.000") + "; Time = " + time.ToString() +
    phase.ToString(".0000") + "; progress = " + 
    progress.ToString("0.000") + "; step = " + 
    step.ToString() + "; TimeMovementEnd = " + 
    UI.MovementEndTime.ToString()
);

The body of the procedure Debugger.WriteLine is compiled only in Debug mode (directives #if, #endif). What makes me worry is that I often need ToString() in Debugger.WriteLine call which is costly because it creates still new strings (for changing number for example). How to solve this problem?

A few points/questions about debugging/tracing:

Which seems nice. Is it a solution for my problem with ToString()?

Upvotes: 4

Views: 776

Answers (5)

Kevin Won
Kevin Won

Reputation: 7186

The pattern I use is to define a logging interface (ILogger) that gets dependency injected into all the classes

public class MyClassThatLogs
{
    public MyClassThatLogs(ILogger logger)
    {
        try
        {
            logger.Write("bla bla bla");
        }
        catch(Exception ex)
        {
            logger.Write(ex); //overload of Write() that takes in an Exception
        }
    }
}

So when you new it up you can pass in a 'real' logger or a mock/fake one

var mc = new MyClassThatLogs(new FakeLogger());

Now you have abstracted away the need to know in the MyClassThatLogs class what's going on with logging. Basic SOLID stuff. So the 'top' (say main() method of a console) would have the IF DEBUG directive then pass in the correct implementation of the logger.

Upvotes: 1

Catalin DICU
Catalin DICU

Reputation: 4638

Using Reflector I found out that Debug.Writeline is declared this way :

[Conditional("DEBUG")]
public static void WriteLine(string message)

That means that in Release mode all calls to this method are eliminated from code.

For example this code :

public static void Test(int a)
{
    string b = Console.ReadLine();
    Debug.WriteLine(a + " " + b);
    Console.WriteLine(a + " " + b);
}

compiles in release mode to :

public static void Test(int a)
{
    Console.WriteLine(a + " " + Console.ReadLine());
}

Upvotes: 4

Paul Sasik
Paul Sasik

Reputation: 81429

Use StringBuilder to create your output strings instead of concatenating each and every value.

And you can create your own custom debugger (MyDbg) class that contains a WriteLine member the contents of which you can surround with compile directives. It wouldn't entirely compile out the debug code but would turn you MyDbg.WriteLine calls into no-ops.

Here's a quick sketch of the class:

using System;
using System.Text ;

public static class MyDbg
{
    public static void WriteLine(string str) // and some other params
    {
        #if DEBUG

        StringBuilder sb = new StringBuilder();
        sb.Append(str);
        // etc. appending other params as you see fit
        #endif
    }
}

OR

[Conditional("DEBUG")]
public static class MyDbg
{
    public static void WriteLine(string str) // and some other params
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(str);
        // etc. appending other params as you see fit
    }
}

You'd modify it to suit your own needs of course. And instead of creating a separate class, you could create a member method if #if DEBUG/#endif built-in for displaying its own state when in the debugger.

Upvotes: 3

Sascha
Sascha

Reputation: 10347

For Logging have a look at frameworks such as Log4net or the Enterprise library. They make logging configurable in many ways. Even if you want to log at all.

HTH

Upvotes: 2

Tomas Voracek
Tomas Voracek

Reputation: 5914

  1. You do not need to wrap every line. Just write helper method containing Debug.WriteLine and turn it on/off by flag (usually bool).

  2. Tracing will be in your code even in release mode. You can configure it, see http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx

  3. string.Format calls ToString() on arguments internally, so no benefit there.

Upvotes: 0

Related Questions