Skip to content

Issue #480 - Extend the way of how to create the logger #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,40 @@ package io.github.oshai.kotlinlogging

import io.github.oshai.kotlinlogging.internal.KLoggerFactory
import io.github.oshai.kotlinlogging.internal.KLoggerNameResolver
import kotlin.js.JsName

/**
* Since this library is intended to be multiplatform, there are several ways to create a logger
* depending on your programming language.
*
* Please note, that creating a logger by reference involves reflection or, in some cases, stack
* trace analysis. Therefore, if performance is a priority, avoid creating loggers in frequently
* executed code sections.
*
* A logger created by reference will take the name of the class of the reference. If the reference
* is a "companion object," the name of its enclosing class will be used instead.
*
* ```kotlin
* val topLevelNamedLogger = KotlinLogging.logger("TopLevelNamedLogger")
* val topLevelLambdaLogger = KotlinLogging.logger {}
*
* class MyClass {
* val classNamedLogger = KotlinLogging.logger("MyClass")
* val classLambdaLogger = KotlinLogging.logger {}
* val classRefLogger = KotlinLogging.logger(this)
*
* companion object {
* val companionNamedLogger = KotlinLogging.logger("MyClassCompanion")
* val companionLambdaLogger = KotlinLogging.logger {}
* val companionRefLogger = KotlinLogging.logger(this)
* }
* }
* ```
*/
public object KotlinLogging {
/**
* This method allow defining the logger in a file in the following way:
* ```
* private val logger = KotlinLogging.logger {}
* ```
*/
public fun logger(func: () -> Unit): KLogger = logger(KLoggerNameResolver.name(func))
@JsName("kotlinLoggerByRef")
public fun logger(ref: Any): KLogger = logger(KLoggerNameResolver.name(ref))

/**
* This method allow defining the logger in a file in the following way:
* ```
* private val logger = KotlinLogging.logger("io.github.oshai.kotlinlogging.MyLogger")
* ```
*
* In most cases the name represents the package notation of the file that the logger is defined
* in.
*/
@JsName("kotlinLoggerByName")
public fun logger(name: String): KLogger = KLoggerFactory.logger(name)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package io.github.oshai.kotlinlogging.internal

internal expect object KLoggerNameResolver {

internal fun name(func: () -> Unit): String
internal fun name(ref: Any): String
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package io.github.oshai.kotlinlogging.internal

internal actual object KLoggerNameResolver {

internal actual fun name(func: () -> Unit): String = func::class.qualifiedName ?: ""
internal actual fun name(ref: Any): String = ref::class.qualifiedName ?: ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import kotlin.reflect.KClass
internal actual object KLoggerNameResolver {

/** get class name for function by the package of the function */
internal actual fun name(func: () -> Unit): String {
return name(func::class)
internal actual fun name(ref: Any): String {
return name(ref::class)
}

internal fun name(clazz: KClass<*>): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.oshai.kotlinlogging.slf4j

import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import io.github.oshai.kotlinlogging.Level
import io.github.oshai.kotlinlogging.Marker
import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jLoggerFactory
Expand All @@ -27,8 +26,4 @@ public fun Level.toSlf4j(): org.slf4j.event.Level =
Level.OFF -> throw IllegalArgumentException("OFF level is not supported")
}

@Suppress("UnusedReceiverParameter")
public fun KotlinLogging.logger(underlyingLogger: Logger): KLogger =
Slf4jLoggerFactory.wrapJLogger(underlyingLogger)

public fun Logger.toKLogger(): KLogger = KotlinLogging.logger(this)
public fun Logger.toKLogger(): KLogger = Slf4jLoggerFactory.wrapJLogger(this)
29 changes: 0 additions & 29 deletions src/jsMain/kotlin/io/github/oshai/kotlinlogging/KotlinLogging.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
package io.github.oshai.kotlinlogging.internal

internal actual object KLoggerNameResolver {
private const val DEFAULT_LOGGER_NAME = "root-logger"
private const val LOGGER_FUNCTION_NAME = "kotlinLoggerByRef"
private const val COMPANION_GET_INSTANCE_SUFFIX = "_getInstance"
private val TOP_LEVEL_INIT_PROPERTIES_REGEX = Regex("_init_properties_(\\S+)_kt_")
private val CLASS_LEVEL_INIT_PROPERTIES_REGEX = Regex("new (\\S+)")

internal actual fun name(func: () -> Unit): String {
var found = false
val exception = Exception()
for (line in exception.stackTraceToString().split("\n")) {
if (found) {
return line.substringBefore(".kt").substringAfterLast(".").substringAfterLast("/")
}
if (line.contains("at KotlinLogging")) {
found = true
}
internal actual fun name(ref: Any): String {
return findLoggerCallerClassName() ?: DEFAULT_LOGGER_NAME
}

private fun findLoggerCallerClassName(): String? {
val stackTrace = Throwable().stackTraceToString().split('\n')
val invokeLoggerLine = stackTrace.indexOfFirst { it.contains(LOGGER_FUNCTION_NAME) }
if (invokeLoggerLine == -1 || invokeLoggerLine + 1 >= stackTrace.size) return null
val callerLine = invokeLoggerLine + 1
return resolveAsTopLevelProperty(stackTrace, callerLine)
?: resolveAsClassLevelProperty(stackTrace, callerLine)
}

private fun resolveAsTopLevelProperty(stackTrace: List<String>, callerLine: Int): String? {
val found = TOP_LEVEL_INIT_PROPERTIES_REGEX.find(stackTrace[callerLine]) ?: return null
return found.groupValues[1]
}

private fun resolveAsClassLevelProperty(stackTrace: List<String>, callerLine: Int): String? {
val found = CLASS_LEVEL_INIT_PROPERTIES_REGEX.find(stackTrace[callerLine]) ?: return null
val className = found.groupValues[1]
// find enclosing class in case of Companion object:
// new MyCompanion() <- found class name
// MyCompanion_getInstance()
// new MyClass() <- enclosing class
if (
callerLine + 2 >= stackTrace.size ||
!stackTrace[callerLine + 1].contains("$className$COMPANION_GET_INSTANCE_SUFFIX")
) {
return className
}
return ""
val enclosingFound =
CLASS_LEVEL_INIT_PROPERTIES_REGEX.find(stackTrace[callerLine + 2]) ?: return className
return enclosingFound.groupValues[1]
}
}
Loading
Loading