none
Optimizing Logging RRS feed

  • Question

  • I hope this is the correct forum.

    We've discovered that logging takes a significant amount of CPU time even if it is turned off:

    Log("Foo " + x.SomeExpensiveConvertToString());


    We don't want to insert conditions before every logging opertaion, as this will uglify the code. A google search uncovers Just4log, that does this for java.

    Is there something similar for .NET ? How do you do your own logging?

    Thanks,
    Ron
    Wednesday, April 16, 2008 11:36 AM

Answers

  • To summarize, this statement is slow because the time consuming expression x.SomeExpensiveConvertToString() is called regardless of whether or not logging is actually enabled.

     

    This is a tricky (but not uncommon) issue when logging.

     

    Method 1:

     

    > We don't want to insert conditions before every logging opertaion, as this will uglify the code.


    This is often a solid, practical solution.  You could centralize the code that checks if logging is enabled so that you can keep the code as simple as possible.  For example, you could make it so that your logging looks like the following one-liner:

     

    Code Snippet
    if (Util.LoggingEnabled) Log("Foo " + x.SomeExpensiveConvertToString());

     

    Method 2:

     

    An alternative to consider is ConditionalAttribute (http://msdn2.microsoft.com/en-us/library/system.diagnostics.conditionalattribute.aspx).  This attribute will cause the compiler to omit entire calls to a method, including evaluation of arguments, if a conditional compilation symbol is not defined.  For example, here is a wrapper method that will be called only in debug builds.  The main drawback of this is that you have to make the decision whether logging is enabled or not at compile time.

     

    Code Snippet
    [ConditionalAttribute("DEBUG")]
    public static void MyLog(string s)
    {  
      Log(s);
    }

     

    Nit-picking detail:  The documentation says that "CLS-compliant compilers are permitted to ignore ConditionalAttribute".  This is not an issue when calling the method from C#/J#/VB.NET.  But, to implement properly you should make sure that somewhere in the implementation surrounded by ConditionalAttribute is a "double check" that logging is really enabled in case the compiler failed to observe the ConditionalAttribute and included the method call anyways.

     

    Method 3:

     

    Since it looks like you are saying that a ToString() method is slow, you might consider making a logging wrapper using String.Format.  Notice that String.Format will be responsible for calling ToString(), so you won't need to do it within the argument (which was the reason for the slowness)  An example call would be Util.LogFormatted("Foo {0}", x).

     

    Code Snippet

    public static void LogFormatted(string format, params object[] args)

    {

    if (Util.LoggingEnabled)

    Log(String.Format(format, args));

    }

     

     

    Thursday, April 17, 2008 12:13 AM
  • The Trace class was designed to solve this problem.  If it doesn't fit your bill, use the ConditionalAttribute on your custom logging class methods.
    Thursday, April 17, 2008 1:15 AM
    Moderator

All replies

  • Try log4net at: http://logging.apache.org/log4net/index.html
    It is very fast.

    Wednesday, April 16, 2008 2:53 PM
  • To summarize, this statement is slow because the time consuming expression x.SomeExpensiveConvertToString() is called regardless of whether or not logging is actually enabled.

     

    This is a tricky (but not uncommon) issue when logging.

     

    Method 1:

     

    > We don't want to insert conditions before every logging opertaion, as this will uglify the code.


    This is often a solid, practical solution.  You could centralize the code that checks if logging is enabled so that you can keep the code as simple as possible.  For example, you could make it so that your logging looks like the following one-liner:

     

    Code Snippet
    if (Util.LoggingEnabled) Log("Foo " + x.SomeExpensiveConvertToString());

     

    Method 2:

     

    An alternative to consider is ConditionalAttribute (http://msdn2.microsoft.com/en-us/library/system.diagnostics.conditionalattribute.aspx).  This attribute will cause the compiler to omit entire calls to a method, including evaluation of arguments, if a conditional compilation symbol is not defined.  For example, here is a wrapper method that will be called only in debug builds.  The main drawback of this is that you have to make the decision whether logging is enabled or not at compile time.

     

    Code Snippet
    [ConditionalAttribute("DEBUG")]
    public static void MyLog(string s)
    {  
      Log(s);
    }

     

    Nit-picking detail:  The documentation says that "CLS-compliant compilers are permitted to ignore ConditionalAttribute".  This is not an issue when calling the method from C#/J#/VB.NET.  But, to implement properly you should make sure that somewhere in the implementation surrounded by ConditionalAttribute is a "double check" that logging is really enabled in case the compiler failed to observe the ConditionalAttribute and included the method call anyways.

     

    Method 3:

     

    Since it looks like you are saying that a ToString() method is slow, you might consider making a logging wrapper using String.Format.  Notice that String.Format will be responsible for calling ToString(), so you won't need to do it within the argument (which was the reason for the slowness)  An example call would be Util.LogFormatted("Foo {0}", x).

     

    Code Snippet

    public static void LogFormatted(string format, params object[] args)

    {

    if (Util.LoggingEnabled)

    Log(String.Format(format, args));

    }

     

     

    Thursday, April 17, 2008 12:13 AM
  • The Trace class was designed to solve this problem.  If it doesn't fit your bill, use the ConditionalAttribute on your custom logging class methods.
    Thursday, April 17, 2008 1:15 AM
    Moderator
  • A friend came up with this idea - use Lambdas to defer calculation of the string:

    Log(x => "Some log messages" + foo.ToString());

    Thursday, April 17, 2008 8:56 AM