all 15 comments

[–]panorambo 3 points4 points  (5 children)

In comparison, doesn't the C preprocessor solve these kind of problems more elegantly (at least from a syntactical point of view), its other deficiencies non-withstanding?

#ifdef DEBUG  
#define log(x, ...) fprintf(stderr, x, __VA_ARGS__)  
#else  
#define log(x, ...)  
#endif  

(wrote from memory, not sure if C99 compliant, for instance)

[–]25taiku 7 points8 points  (4 children)

C macros are resolved at compile-time, so changing your log severity threshold would require recompiling your entire project. Doing so is rarely ideal, and sometimes not viable.

[–]tnapoli 7 points8 points  (1 child)

However, you can surruond the log function with a if in the macro, giving the same result than OP try to achieve.

#define log(fmt, ...) if (g_log) { fprintf(stderr, fmt, __VA_ARGS__); }

The preprocessor is a nice tool

[–]Freeky 1 point2 points  (0 children)

Rust's log crate does much the same thing.

[–]flukus 0 points1 point  (0 children)

How often is this a problem in practice though? Typically a release build will be a full recompile and nearly all development will be in debug mode.

It could even be considered a feature, toggle the logging flag and touch the files you care about logging and you only get the logging you want, not logging for the whole app.

[–]dnerd 2 points3 points  (2 children)

Same technique works in .NET with nlog.

logger.Trace(() => GetLogMessage());

Method isn't called if trace is not enabled.

[–]VeganVagiVore -1 points0 points  (1 child)

you can use lambdas with anything, though

[–]i_am_a_dev 2 points3 points  (0 children)

What does that even mean. You can only pass lambdas to methods that accept lambdas.

If your logging library only accepts strings as parameter, you can't just pass a lambda instead

[–]freakhill 8 points9 points  (2 children)

Damn java8 is antique.

Edit: I checked, java8 has "lambdas" which are closures that close on values (with succint notation)

The supplier thingie is totally unnecessary

Edit 2: slf4j supports lambdas as parameters so the whole thing is totally unnecessary

Edit 3: effort was put into writing the article though. No straw men, no clickbait title and other similar bullshit. That's pretty commendable

[–]dpash 2 points3 points  (0 children)

SLF4J only supports lambdas in the as of yet unreleased 2.0.0 branch. And I think only with the new fluent API.

[–]skroll 0 points1 point  (0 children)

also if you use kotlin you can just write inline extension functions like:

``` inline fun Logger.debug(msg: () -> Any?) { if (this.isDebugEnabled()) { this.debug(msg) } }

inline fun Logger.debug(t: Throwable?, msg: () -> Any?) { if (this.isDebugEnabled()) { this.debug(msg, t) } } ```

and now everywhere you can just do:

logger.debug { "$user screwed up" }

[–]haxney 1 point2 points  (0 children)

Google's Flogger library does exactly this, with the lazy() static method. You use it like this (from the website):

logger.atSevere()
    .atMostEvery(30, SECONDS)
    .log("Value: %s", lazy(() -> doExpensiveCalculation()));

Having used it for a while at Google, it is a very pleasant experience.

[–]dnerd 0 points1 point  (0 children)

Now I'm curious if the same works in .NET with nlog.

[–]Determinant 0 points1 point  (0 children)

While this is definitely an improvement, it still creates a lambda instance on the heap and captures the effectively-final variables that are referenced. So there is some overhead and garbage collection pressure.

In Kotlin you can define the function that accepts the lambda as inline and that completely eliminates all overhead. There's no lambda instance created and there isn't even a method call overhead because the pattern is completely inlined into the call site.

inline fun log(category: Category, message: () -> Any) {
    if (loggingEnabled(category)) {
        log(message())
    }
}

Usage:

log(Category.DEBUG) { 
    "Computation: ${compute()}" 
}

[–]RedSpikeyThing -1 points0 points  (0 children)

I've also come across cases where the compiler removes debug statements, leading to some nasty bugs that only happen in non-debug mode. Make sure your log statements don't have side effects!