Skip to content

Inline all logging functions #34

@kosiakk

Description

@kosiakk

It seems that the whole fuzz around logging is to not create "expensive" String object, if logging level is not enabled. That totally makes sense.

And that's why we library offers a nice function:

    fun unknownElementType(elementType: Int) {

        // Lazy evaluation of the log message
        log.warn  { "Unknown element: $elementType" }

    }

So, what gets generated for this line?

this.log.warn((Function0)(new Function0() {
         // $FF: synthetic method
         // $FF: bridge method
         public Object invoke() {
            return this.invoke();
         }

         @NotNull
         public final String invoke() {
            return "Unknown element: " + elementType;
         }
      }));

Hm... instead of a String, we create:

  1. An anonymous inner class
  2. Instance of this class, which gets the closure reference to all required outer variables like elementType

That doesn't look very cheap to me.

On the other hand, in Kotlin StdLib pretty much all map or forEach functions are inline. So, we might write it like this:

inline fun KLogger.warnInline(message: () -> String) {
    if (underlyingLogger.isWarnEnabled) 
        underlyingLogger.warn(message())
}

And this gets compiled to the simplest possible, desired lazy evaluation of String:

   void unknownElementType(int elementType) {

      KLogger $receiver$iv = this.log;
      Logger logger$iv = $receiver$iv.getUnderlyingLogger();
      if (logger$iv.isWarnEnabled()) {
         // Lazy evaluation of the log message
         String var7 = "Unknown element: " + elementType;
         logger$iv.warn(var7);
      }

   }

Just like we wanted in the first place.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions