Support/improve interface-based logger mixin
diff --git a/log4j-api-kotlin-sample/src/main/kotlin/org/apache/logging/log4j/kotlin/sample/LoggingAppMixin.kt b/log4j-api-kotlin-sample/src/main/kotlin/org/apache/logging/log4j/kotlin/sample/LoggingAppMixin.kt
new file mode 100644
index 0000000..da3de0a
--- /dev/null
+++ b/log4j-api-kotlin-sample/src/main/kotlin/org/apache/logging/log4j/kotlin/sample/LoggingAppMixin.kt
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kotlin.sample
+
+import org.apache.logging.log4j.Level
+import org.apache.logging.log4j.kotlin.Logging
+import org.apache.logging.log4j.kotlin.logger
+import java.util.*
+
+object LoggingAppMixin: Logging {
+  @JvmStatic
+  fun main(args: Array<String>) {
+    val s1 = "foo"
+    val s2 = "bar"
+    val t = RuntimeException("error")
+
+    logger.info { "Hello, world: $s1 $s2" }
+
+    logger.trace("Regular trace")
+
+    logger.trace {
+      logger.info("Inside trace extension!")
+    }
+
+    logger.trace({ "Trace extension with entry message." }) {
+      logger.info("Inside trace extension with supplier!")
+    }
+
+    fun getKey(): Int = logger.trace {
+      Random().nextInt(10)
+    }
+
+    fun getKeyError(): Int = logger.trace {
+      throw Exception("Oops!")
+    }
+
+    logger.info { "Key was ${getKey()}" }
+    try {
+      logger.info { "Key was ${getKeyError()}" }
+    } catch(e: Exception) {
+      Unit
+    }
+
+    logger.throwing(t)
+    logger.throwing(Level.INFO, t)
+
+    logger.catching(t)
+  }
+}
diff --git a/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logger.kt b/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logger.kt
index 627d1fa..6ed453e 100644
--- a/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logger.kt
+++ b/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logger.kt
@@ -208,11 +208,14 @@
 }
 
 /**
- * Logger instantiation. Use: `val log = logger()`.
+ * Logger instantiation by function. Use: `val log = logger()`.
  */
 @Suppress("unused")
-inline fun <reified T : Any> T.logger(): FunctionalLogger =
-  FunctionalLogger(LogManager.getContext(T::class.java.classLoader, false).getLogger(unwrapCompanionClass(T::class.java).name))
+inline fun <reified T : Any> T.logger() = loggerOf(T::class.java)
+
+fun loggerOf(ofClass: Class<*>): FunctionalLogger {
+  return FunctionalLogger(LogManager.getContext(ofClass.classLoader, false).getLogger(unwrapCompanionClass(ofClass).name))
+}
 
 // unwrap companion class to enclosing class given a Java Class
 fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> {
diff --git a/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logging.kt b/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logging.kt
index 28229e5..8bd11cd 100644
--- a/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logging.kt
+++ b/log4j-api-kotlin/src/main/kotlin/org/apache/logging/log4j/kotlin/Logging.kt
@@ -1,7 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
 package org.apache.logging.log4j.kotlin
 
-import org.apache.logging.log4j.Logger
-
 /**
  * An interface-based "mixin" to easily add a log val to a class, named by the enclosing class. This allows
  * code like this:
@@ -10,24 +24,26 @@
  * import org.apache.logging.log4j.kotlin.Logging
  *
  * class MyClass: Logging {
- *   override val log: Logger = logger()
+ *   // use `logger` as necessary
  * }
  *
  * ```
  *
- * A simpler mechanism is to use the class extension directly, like:
+ * Or declaring the interface on a companion object works just as well:
  *
  * ```
  * import org.apache.logging.log4j.kotlin.logger
  *
  * class MyClass {
- *   val log = logger()
+ *   companion object: Logging
+ *
+ *   // use `logger` as necessary
  * }
  *
  * ```
  */
 interface Logging {
-  val log: Logger
-
-  fun logger(): Logger = this.javaClass.logger()
+  @Suppress("unused")
+  val logger
+    get() = loggerOf(this.javaClass)
 }
diff --git a/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerCompanionTest.kt b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerCompanionTest.kt
index a661533..1d78b0b 100644
--- a/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerCompanionTest.kt
+++ b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerCompanionTest.kt
@@ -24,7 +24,8 @@
   }
 
   @Test
-  fun `Logging from companion logger works!`() {
+  fun `Logging from a function instantiation via companion logs the correct class name`() {
+    // this should log from class LoggerCompanionTest
     log.error("This is an error log.")
   }
 }
diff --git a/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinCompanionExtendsTest.kt b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinCompanionExtendsTest.kt
new file mode 100644
index 0000000..223a0b6
--- /dev/null
+++ b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinCompanionExtendsTest.kt
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kotlin
+
+import org.junit.Test
+
+class LoggerMixinCompanionExtendsTest {
+
+  companion object : Logging
+
+  @Test
+  fun `Logging from an interface mix-in via companion logs the correct class name`() {
+    // this should log from class LoggerMixinCompanionExtendsTest
+    logger.error("This is an error log.")
+  }
+}
diff --git a/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinExtendsTest.kt b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinExtendsTest.kt
new file mode 100644
index 0000000..2939833
--- /dev/null
+++ b/log4j-api-kotlin/src/test/kotlin/org.apache.logging.log4j.kotlin/LoggerMixinExtendsTest.kt
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.kotlin
+
+import org.junit.Test
+
+class LoggerMixinExtendsTest : Logging {
+
+  @Test
+  fun `Logging using an interface mix-in logs the correct class name`() {
+    // this should log from class LoggerMixinExtendsTest
+    logger.error("This is an error log.")
+  }
+}