3

I am trying to add debug log to my C#.net code. But it messes up my code, it looks like a hell. Is there anything that log every code with its values automatically ? Now it looks like this

    #if DEBUG 
        debuglogger("The functionstarted");
    #endif
    someCode1(); 
    #if DEBUG 
        debuglogger("SomeCode1 Finished");
    #endif
    someCode2(); 
    #if DEBUG 
        debuglogger("SomeCode2 Finished");
    #endif
    someCode3(); 
    #if DEBUG 
        debuglogger("SomeCode3 Finished");
    #endif
    #if DEBUG 
        debuglogger("Function End");
    #endif
Magnus Johansson
  • 28,010
  • 19
  • 106
  • 164
Yesudass Moses
  • 1,841
  • 3
  • 27
  • 63

5 Answers5

6

You should use the ConditionalAttribute. It allows you to define conditional methods that will be removed at build time if the condition doesn't match:

[Conditional("DEBUG")]
void DebugLog(string message)
{
    // Do some logging...
}

calls to this method will be stripped out in builds without DEBUG defined. Just like

#if DEBUG
DebugLog("Testing...");
#endif

This has the added benefit of not cluttering up the stack traces as opposed to moving the #if inside the method.

khellang
  • 17,550
  • 6
  • 64
  • 84
3

Pretty late answer but I leave for future reference. In my opinion you should consider Aspect Oriented Programming for tasks like this. That said if you don't need to add such complexity for a small task you may move preprocessor conditions to your log method:

public static void Log(string message)
{
#if DEBUG
    // Do logging
#endif
}

Do not worry to leave an empty method, JIT will optimize it away and it won't even be called. It's almost equivalent to:

[Condition("DEBUG")]
public static void Log(string message)

Warning: I say almost because with a method with [Condition] attribute arguments won't even be evaluated then given this code in release:

Log(String.Format("Index: {0}", index++));

index variable won't ever be incremented, because JIT compiler won't emit call to Log and even its arguments won't be evaluated. This is not true if you keep your method body empty with #if directive inside it. Call won't be emitted (because of empty body) but its arguments will be evaluated.

Problem of this solution is that it'll clutter your normal program flow. With log calls, parameters dumping and stuff like that. What can you do?

Refactor your log

If you call SomeCode1() method many times you shouldn't log at each call site, much better is to move logging inside called method. Log only at beginning and end of each function, log will still be in your code but it'll be spanned across multiple functions.

void SomeCode1() {
    Log("Starting SomeCode1");
    // Do something
    Log("SomeCode1 completed");
}

Your calling site will then be clean:

SomeCode1();
SomeCode2();
SomeCode3();

Expressions

If performance aren't an issue (measure, don't guess) you may use Expressions to do the trick for you. You can log parameters too (or fields, object status, diagnostic informations, invariants and whatever else you may need), everything controlled by diagnostic switches (to enable them only when required). No logging code in your LOB classes but price to pay is execution speed (and LoggedOperation function complexity).

This code is (to be polite with myself) very naive, a decent implementation will be much more complex so just think about it as an idea more than an implementation.

static void LoggedOperation(Expression<Action> expression)
{
    MethodCallExpression methodCall = expression.Body as MethodCallExpression;
    if (methodCall != null)
    Log("Calling {0}", methodCall.Method.Name);

    expression.Compile()();

    if (methodCall != null)
        Log("{0} completed", methodCall.Method.Name);
}

It'll be then used like this:

LoggedOperation(() => SomeCode1());
LoggedOperation(() => SomeCode2());
LoggedOperation(() => SomeCode3());

You'll get:

Calling SomeCode1
SomeCode1 completed
Calling SomeCode2
SomeCode2 completed
Calling SomeCode3
SomeCode3 completed

AOP will give you a much cleaner code but this may be enough in many situations.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
0

You can either move the preprocessor directives to the debuglogger function, or use a configurable logging framework that lets you configure when to log rather than relying on preprocessor statements at build time. That way you can "turn on" logging without having to rebuild the application.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
0

You can use AOP for this, although I've not tried it myself.

Alternatively there are a number of things you can do to help improve the readability of your code such as using the Conditional attribute

Marking the debuglogger method with the Conditional attribute removes the need for the #if DEBUG code

[Conditional("DEBUG")]
public void debuglogger(string message)
{
    // Logging code goes here
}

debuglogger("The functionstarted");
someCode1(); 
debuglogger("SomeCode1 Finished");
someCode2(); 
debuglogger("SomeCode2 Finished");
someCode3();
debuglogger("SomeCode3 Finished");
debuglogger("Function End");

Personally I would also have the someCodeN methods log the "SomeCodeN Finished" messages, which further simplifies your code

debuglogger("The functionstarted");
someCode1(); 
someCode2(); 
someCode3();
debuglogger("Function End");

public void someCode1()
{
    // Do something
    debuglogger("someCode1 Finished");
}
Community
  • 1
  • 1
Justin
  • 84,773
  • 49
  • 224
  • 367
0

Mark Gravell recently posted an interesting idea utilizing partial classes. Link to his plog post

Project structure:

-Foo.cs
-Foo.debug.cs

And here the classes:

// Foo.debug.cs
    #if DEBUG
        partial class Foo
        {
            partial void Trace(string value)
            {
                Console.WriteLine("The value is: {0}", value);
            }
        }
    #endif

// Foo.cs
partial class Foo
{
    partial void Trace(string value);
    public void MethodWithTracing()
    {
        Trace("This is traced");
    }
}

Debug / Trace logic is separated from the normal code and when changing build options, it won't be compiled.

Alex
  • 7,901
  • 1
  • 41
  • 56