Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance Tricks for C# Logging

I am looking into C# logging and I do not want my log messages to spend any time processing if the message is below the logging threshold. The best I can see log4net does is a threshold check AFTER evaluating the log parameters.

Example:

_logger.Debug( "My complicated log message " + thisFunctionTakesALongTime() + " will take a long time" )

Even if the threshold is above Debug, thisFunctionTakesALongTime will still be evaluated.

In log4net you are supposed to use _logger.isDebugEnabled so you end up with

if( _logger.isDebugEnabled )
    _logger.Debug( "Much faster" )

I want to know if there is a better solution for .net logging that does not involve a check each time I want to log.

In C++ I am allowed to do

LOG_DEBUG( "My complicated log message " + thisFunctionTakesALongTime() + " will take no time" )

since my LOG_DEBUG macro does the log level check itself. This frees me to have a 1 line log message throughout my app which I greatly prefer. Anyone know of a way to replicate this behavior in C#?

like image 846
Charles Avatar asked Apr 12 '10 02:04

Charles


People also ask

How do I optimize my code?

Optimize Program Algorithm For any code, you should always allocate some time to think the right algorithm to use. So, the first task is to select and improve the algorithm which will be frequently used in the code. 2. Avoid Type Conversion Whenever possible, plan to use the same type of variables for processing.

Which is faster C or C+?

Performance: C++ is widely used when higher level languages are not efficient. C++ code is much faster than C# code, which makes it a better solution for applications where performance is important.

Is C sharp fast?

Still, my conclusion is that C# is not as fast as C++ in most cases by default. But I think it's not much slower and it usually doesn't matter. When you do have performance-sensitive code, you can optimize C# and achieve near-similar performance to C++.


3 Answers

If you can target .NET 3.5 (C# 3.0) you can use extension methods to wrap the if statements.

so you can do the equivalent "macro":

logger.Log_Debug("Much faster");

logger.Log_Debug(() => { "My complicated log message " + thisFunctionTakesALongTime() + " will take no time" });

by wrapping the check in this method:

public class Log4NetExtensionMethods {
    // simple string wrapper
    public void Log_Debug(this log4net.ILog logger, string logMessage) {
        if(logger.isDebugEnabled) {
             logger.Debug(logMessage);
        }
    }

    // this takes a delegate so you can delay execution
    // of a function call until you've determined it's necessary
    public void Log_Debug(this log4net.ILog logger, Func<string> logMessageDelegate) {
        if(logger.isDebugEnabled) {
             logger.Debug(logMessageDelegate());
        }
    }
}
like image 63
Jeff Meatball Yang Avatar answered Sep 19 '22 01:09

Jeff Meatball Yang


17.4.2 The Conditional attribute

The attribute Conditional enables the definition of conditional methods. The Conditional attribute indicates a condition by testing a conditional compilation symbol. Calls to a conditional method are either included or omitted depending on whether this symbol is defined at the point of the call. If the symbol is defined, the call is included; otherwise, the call (including evaluation of the parameters of the call) is omitted.

[ Conditional("DEBUG") ]
public static void LogLine(string msg,string detail)
{
    Console.WriteLine("Log: {0} = {1}",msg,detail);
}

public static void Main(string[] args)
{
    int Total = 0;
    for(int Lp = 1; Lp < 10; Lp++)
    {
        LogLine("Total",Total.ToString());
        Total = Total + Lp;
    }
}
like image 34
blammo Avatar answered Sep 20 '22 01:09

blammo


The problem here is that all method parameters must be evaluated before the method is invoked. There is no way around this, given the syntax you are using. Since C# does not have a real preprocessor or macros, you can't do anything like "LOG_DEBUG". The best you could do is use if (logger.isDebugEnable) as suggested.

The only thing I can think of is maybe using something like a lambda expression to delay evaluation. But I would warn you that this will almost certainly have more of a performance hit in the end.

internal class Sample
{
    private static void Main(string[] args)
    {
        DelayedEvaluationLogger.Debug(logger, () => "This is " + Expensive() + " to log.");
    }

    private static string Expensive()
    {
        // ...
    }
}

internal static class DelayedEvaluationLogger
{
    public static void Debug(ILog logger, Func<string> logString)
    {
        if (logger.isDebugEnabled)
        {
            logger.Debug(logString());
        }
    }
}
like image 44
bobbymcr Avatar answered Sep 18 '22 01:09

bobbymcr