Conditional logging with minimal cyclomatic complexity

前端 未结 12 1908
情歌与酒
情歌与酒 2020-11-27 10:58

After reading \"What’s your/a good limit for cyclomatic complexity?\", I realize many of my colleagues were quite annoyed with this new QA policy on our project: no more 10

12条回答
  •  独厮守ぢ
    2020-11-27 11:32

    In Python you pass the formatted values as parameters to the logging function. String formatting is only applied if logging is enabled. There's still the overhead of a function call, but that's minuscule compared to formatting.

    log.info ("a = %s, b = %s", a, b)
    

    You can do something like this for any language with variadic arguments (C/C++, C#/Java, etc).


    This isn't really intended for when the arguments are difficult to retrieve, but for when formatting them to strings is expensive. For example, if your code already has a list of numbers in it, you might want to log that list for debugging. Executing mylist.toString() will take a while to no benefit, as the result will be thrown away. So you pass mylist as a parameter to the logging function, and let it handle string formatting. That way, formatting will only be performed if needed.


    Since the OP's question specifically mentions Java, here's how the above can be used:

    I must insist that the problem is not 'formatting' related, but 'argument evaluation' related (evaluation that can be very costly to do, just before calling a method which will do nothing)

    The trick is to have objects that will not perform expensive computations until absolutely needed. This is easy in languages like Smalltalk or Python that support lambdas and closures, but is still doable in Java with a bit of imagination.

    Say you have a function get_everything(). It will retrieve every object from your database into a list. You don't want to call this if the result will be discarded, obviously. So instead of using a call to that function directly, you define an inner class called LazyGetEverything:

    public class MainClass {
        private class LazyGetEverything { 
            @Override
            public String toString() { 
                return getEverything().toString(); 
            }
        }
    
        private Object getEverything() {
            /* returns what you want to .toString() in the inner class */
        }
    
        public void logEverything() {
            log.info(new LazyGetEverything());
        }
    }
    

    In this code, the call to getEverything() is wrapped so that it won't actually be executed until it's needed. The logging function will execute toString() on its parameters only if debugging is enabled. That way, your code will suffer only the overhead of a function call instead of the full getEverything() call.

提交回复
热议问题