Last active
March 5, 2022 06:59
-
-
Save sabirove/ff9f731c88a5910537f2728fdeacf49a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// dependencies: | |
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.7.30 | |
/** | |
* Wrapper over slf4j [Logger] providing Kotlin functional-style API with inline call optimization: | |
* lambda parameter is inlined by the Kotlin compiler while actual method invocations should | |
* eventually be removed by the branch predictor whenever corresponding logging level is not | |
* active so there's no performance hit from inactive logging statements whatsoever. | |
* | |
* Note: "Logg" because it's short and avoids all kinds of namespace conflicts. | |
*/ | |
class Logg(loggerName: String) { | |
@Suppress("PropertyName") | |
val _log: Logger = LoggerFactory.getLogger(loggerName) | |
/** Infers [Logg] name from the [klass]' FQDN */ | |
constructor(klass: KClass<*>) : this(klass.qualifiedName ?: error("can't get FQDN for $klass")) | |
/** | |
* Infers [Logg] name implicitly using a normalized class' FQDN obtained from | |
* the [capture] scope. Use for concise log declarations, e.g. `val log = Logg {}` | |
* | |
* Normalization rules: | |
* - Companion object declaration is "unwrapped" and inferred as a top-level class' FQDN | |
* - File-level declaration is inferred as a file name without the `Kt` postfix | |
* - Other declarations (including nested/inner classes) are inferred as a class' FQDN | |
* | |
* NB: if class inheritance is used and logger is declared on the base type instance level, | |
* it's name will be inferred from the base type' FQDN and NOT the actual inheritor. | |
* Use `val log = Logg(this::class)` instead to yield the inherited class' FQDN name instead. | |
*/ | |
constructor(capture: () -> Unit) : this( | |
loggerName = capture.javaClass.name.let { | |
when { | |
// companion declaration (might be nested class companion, so normalization is due) | |
it.contains("\$Companion") -> | |
it.substringBefore("\$Companion").replace('$', '.') | |
// file-level declaration | |
it.contains("Kt$") -> it.substringBefore("Kt$") | |
// other declaration (might be nested/inner class, so normalization is due) | |
else -> it.substringBeforeLast('$') | |
.substringBeforeLast('$') | |
.replace('$', '.') | |
} | |
} | |
) | |
inline fun trace(lazyMessage: () -> String) { | |
if (_log.isTraceEnabled) _log.trace(lazyMessage()) | |
} | |
inline fun trace(e: Throwable, lazyMessage: () -> String) { | |
if (_log.isTraceEnabled) _log.trace(lazyMessage(), e) | |
} | |
inline fun debug(lazyMessage: () -> String) { | |
if (_log.isDebugEnabled) _log.debug(lazyMessage()) | |
} | |
inline fun debug(e: Throwable, lazyMessage: () -> String) { | |
if (_log.isDebugEnabled) _log.debug(lazyMessage(), e) | |
} | |
inline fun info(lazyMessage: () -> String) { | |
if (_log.isInfoEnabled) _log.info(lazyMessage()) | |
} | |
inline fun info(e: Throwable, lazyMessage: () -> String) { | |
if (_log.isInfoEnabled) _log.info(lazyMessage(), e) | |
} | |
inline fun warn(lazyMessage: () -> String) { | |
if (_log.isWarnEnabled) _log.warn(lazyMessage()) | |
} | |
inline fun warn(e: Throwable, lazyMessage: () -> String) { | |
if (_log.isWarnEnabled) _log.warn(lazyMessage(), e) | |
} | |
inline fun error(lazyMessage: () -> String) { | |
if (_log.isErrorEnabled) _log.error(lazyMessage()) | |
} | |
inline fun error(e: Throwable, lazyMessage: () -> String) { | |
if (_log.isErrorEnabled) _log.error(lazyMessage(), e) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment