LoggedIrTransformer
Rewrites the body of every function annotated with io.github.smyrgeorge.log4k.annotation.Logged so that it is executed with entry/exit logging.
Given:
class UserService {
private val log = Logger.of(this::class)
@Logged
fun compute(x: Int): Int { /* body */}
}the body is replaced with (conceptually):
fun compute(x: Int): Int =
log.logged(Level.INFO, span = null, tags = emptyMap(), "UserService.compute", "x=$x",
SourceLocation("UserService.kt", 6, "UserService.compute")) {
/* body */
}The SourceLocation describes the instrumented function's declaration (its file, line, and ClassName.functionName) — also when the annotation sits on the class — so every emitted line is attributed to the annotated function.
@Logged(tags = [Tag(k, v), …]) is materialized as the tags map argument (class-level tags are added first, so a function's own tag with the same key wins).
A parameter annotated with io.github.smyrgeorge.log4k.annotation.Masked is rendered in the entry line as the literal paramName=<MASKED> instead of its value.
Logger.logged is inline, so both regular and suspend functions work: the moved body is placed in an inline lambda and therefore keeps its original suspension context. The Logger is resolved by OfThisClassField: a log4k log: Logger member is reused, else the class's single Logger-typed property (whatever its name); otherwise (e.g. log is a foreign type such as org.slf4j.Logger and no other log4k Logger is declared) private val _log_ = Logger.of(this::class) is synthesized. A span is attached to the log lines when one is in scope: a TracingContext parameter/receiver (its currentOrNull()), else a TracingEvent.Span parameter/receiver directly, else none.