Alex
Alex

Reputation: 4473

Convenient way for conditional logging

Logging is taking resources. Especially to create log messages. To save runtime resources I do this:

if (logFile!=null) Log(logFile, "Some Message "+someMethod());

It eliminates calling someMethod when logging is not required.

Is there more convenient way to code it? Like

Logger.logger?.Log("Some Message "+someMethod());

Logger is static class and logger is delegate... Unfortunately it doesn't work in my VS2012.

Update: Main purpose of this question is how to simplify code look and feel and reduce runtime spending. In my original approach method someMethod() is not called if logging is not necessary, but code stays the same. Checking for null is only suggested approach to avoid calling extra methods.

Update2: Some example:

    public class Example {      
        public class Logger 
            {
                public static void Log(string message)
                {
                    Console.WriteLine(message);
                }
            }

            public static Logger logger;

            public static void Test()
            {
                // has compilation error "Invalid expression term '.'
                logger?.Log("This "+"should "+"be "+"not invoked"); 
                logger = new Logger();
                logger?.Log("This should "+"be logged");
            }
}

Upvotes: 2

Views: 2276

Answers (1)

user310988
user310988

Reputation:

Could you wrap the null check inside the static class? You don't have to call the delegate directly.

e.g.

public class Logger
{
    public Action<string> LogAction { get;set; }

    public void Log(string message)
    {
        var logAction = LogAction;

        if(logAction != null)
            logAction(message);
    }
}

Which would then be simply called as:

Logger.Log("Something happened");

Another option is using the Conditional attribute.

https://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute(v=vs.110).aspx

Methods marked with that attribute will not be called in the compiled IL unless a compilation symbol is provided during the build.

public static class Logger
{
    public static Action<string> LogAction { get;set; }

    [Conditional("LoggingEnabled")]
    public static void LogConditional(string message)
    {
        var logAction = LogAction;

        if(logAction != null)
            logAction(message);
    }

    public static void Log(string message)
    {
        var logAction = LogAction;

        if(logAction != null)
            logAction(message);
    }
}

The Log method doesn't have the conditional attribute so the following code produces the following IL:

var foo = "foo";
var bar = "bar";

Logger.Log(foo + bar);

IL_0000:  nop         
IL_0001:  ldstr       "foo"
IL_0006:  stloc.0     // foo
IL_0007:  ldstr       "bar"
IL_000C:  stloc.1     // bar
IL_000D:  ldloc.0     // foo
IL_000E:  ldloc.1     // bar
IL_000F:  call        System.String.Concat
IL_0014:  call        UserQuery+Logger.Log
IL_0019:  nop         
IL_001A:  ret  

The LogConditional method does have the conditional attribute, and the compiler symbol has not been set so the following code produces the following IL:

var foo = "foo";
var bar = "bar";

Logger.LogConditional(foo + bar);

IL_0000:  nop         
IL_0001:  ldstr       "foo"
IL_0006:  stloc.0     // foo
IL_0007:  ldstr       "bar"
IL_000C:  stloc.1     // bar
IL_000D:  ret 

As you can see the string concatination is never performed because the method call isn't generated.

Upvotes: 3

Related Questions