agentsclimarketplace

Kora aop logging

Skill kora-projects/kora-skills/plugins/kora-v1/skills/kora-aop-logging

Declarative method logging in Kora via the logging-common module — @Log (args + result), @Log.in / @Log.out / @Log.result, @Log.off to suppress a parameter or method, and @Mdc for Mapped Diagnostic Context (key/value, ${expr} interpolation, global thread scope). Covers the imperative ru.tinkoff.kora.logging.common.MDC API and the SLF4J-MDC import pitfall. Use when adding entry/exit logging to a service method, enriching logs with contextual keys, hiding sensitive arguments from log output, or wiring LoggingModule into a @KoraApp.From its SKILL.md

Install
npx -y skills add kora-projects/kora-skills --skill kora-aop-logging

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.7 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it

Kora AOP Logging — @Log and @Mdc

Declarative, compile-time method logging. The annotation processor generates a *Aspect class around your method; there is no reflection or runtime proxy. The aspect writes through SLF4J, so your Logback configuration controls the final format.

Use this skill when you need to:

  • log method entry/exit with arguments and return value (@Log),
  • enrich every log line of a call with contextual keys (@Mdc),
  • suppress credentials or large payloads from log output (@Log.off),
  • wire LoggingModule into a @KoraApp.

Quick Start

1. Dependencies

logging-common is usually pulled transitively by a logging backend (logging-logback). Add it explicitly only if it is missing. All Kora artifacts inherit their version from the kora-parent BOM — never pin an individual ru.tinkoff.kora:* version.

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")

    // Mandatory: without the annotation processor no aspect is generated
    annotationProcessor "ru.tinkoff.kora:annotation-processors"

    implementation "ru.tinkoff.kora:logging-logback" // pulls logging-common transitively
}

Kotlin replaces the processor with KSP:

ksp "ru.tinkoff.kora:symbol-processors"
implementation "ru.tinkoff.kora:logging-logback"

2. Enable in the application graph

@KoraApp
public interface Application extends LoggingModule { }

3. Log a method

The enclosing class must be non-final (Java) / open (Kotlin) so the aspect can subclass it.

@Component
public class UserService {          // NOT final

    @Log
    public User getUser(String id) {
        return userRepository.findById(id);
    }
}

4. Enrich with MDC

@Log
public User getUser(@Mdc(key = "userId") String id) {
    return userRepository.findById(id); // every log line in this call carries userId=<id>
}

@Log family

All annotations live in ru.tinkoff.kora.logging.common.annotation.

AnnotationEffect
@LogLog on entry and exit
@Log.inLog on method entry only
@Log.outLog on method exit only
@Log.resultLog the return value only
@Log.off on a parameterSuppress that one value in the log line
@Log.off on a methodSuppress all logging for the method

Choosing the level

@Log, @Log.in, and @Log.out accept the level as the annotation value — the attribute is value, not level, and the type is org.slf4j.event.Level.

import org.slf4j.event.Level;

@Log(Level.DEBUG)            // value attribute, not level =
public User getUser(String id) { ... }

Default level is INFO for @Log/@Log.in/@Log.out and DEBUG for @Log.result.

There is no Level.OFForg.slf4j.event.Level only has TRACE, DEBUG, INFO, WARN, ERROR. To disable logging for a method, use @Log.off (not a level).

Output by configured logger level

For @Log on methodWithArgs(String strParam, int numParam) returning "testResult", the actual output depends on the logger level configured in logback.xml for that class:

Logger levelOutput
TRACE / DEBUG> {data: {strParam: "s", numParam: "4"}} then < {data: {out: "testResult"}}
INFO> then < (boundary markers only, no argument or result data)
WARN+nothing

So @Log is safe on hot-path methods in production at INFO — you get execution traces with no PII or large payloads. Drop the logger to DEBUG to see argument/result data.


@Mdc — Mapped Diagnostic Context

@Mdc attaches key/value pairs to Kora's MDC for the duration of the method call (or, with global = true, for the rest of the thread's life). The annotation is @Repeatable, so multiple @Mdc on one method/parameter are allowed.

@Mdc attributeDefaultMeaning
keyannotated parameter / method nameMDC key
valueannotated parameter's runtime valueMDC value; supports ${expr} interpolation
globalfalseIf true, the value stays on the thread after the method returns

On a parameter

public Order create(@Mdc UUID orderId) { ... }            // key = "orderId", value = orderId.toString()
public Order create(@Mdc(key = "order_id") UUID id) { ... } // explicit key

On a method (with interpolation)

${expression} references method parameters by name and can call methods.

@Mdc(key = "tenant", value = "${tenantId}")
@Mdc(key = "requestId", value = "${java.util.UUID.randomUUID().toString()}")
public Order create(String tenantId, CreateOrderDto body) { ... }

Global MDC

@Mdc(key = "tenant", value = "${tenantId}", global = true)
public void enterTenantContext(String tenantId) { ... }

After the method returns, tenant remains in the MDC for the rest of the thread's life. Use sparingly — global keys leak into unrelated work on a pooled thread. Remove them imperatively with the static MDC.remove("tenant") when the unit of work ends.

Imperative API

Kora's imperative MDC is ru.tinkoff.kora.logging.common.MDC (static methods):

import ru.tinkoff.kora.logging.common.MDC;

MDC.put("userId", "42");   // also overloads for Integer, Long, Boolean, StructuredArgumentWriter
MDC.remove("userId");
MDC.get();                 // current MDC instance

Never import org.slf4j.MDC. SLF4J's stock MDC writes into a different thread-local that KoraAsyncAppender does not propagate and Kora's encoder does not render — values silently vanish. IDE auto-import picks the SLF4J one by default; verify the import on every MDC usage. There is no MDC.wrap(...) / MDC.clear() in Kora's API.


Combined example

@Component
public class OrderService {                       // NOT final

    @Log                                          // entry + exit
    @Mdc(key = "tenant", value = "${tenantId}")
    @Mdc(key = "operation", value = "create-order")
    public Order create(
        @Mdc String tenantId,                     // value lands in MDC as tenantId
        @Log.off CreateOrderDto body              // body never appears in log output
    ) {
        return repository.save(body.toEntity());
    }
}

MDC keys present during the call: tenant, operation, tenantId. The log line shows tenantId (and the boundary markers); body is suppressed.


Supported signatures

JavaKotlin
T myMethod()fun myMethod(): T (or T?, Unit)
Optional<T> myMethod()
CompletionStage<T> myMethod()suspend fun myMethod(): T
Mono<T> / Flux<T> (needs io.projectreactor:reactor-core)Flow<T> (needs kotlinx-coroutines-core)

Java class must be non-final; Kotlin class must be open.


Common pitfalls

SymptomFix
@Log compiles but nothing is loggedThe class is final (Java) / not open (Kotlin), or the annotation processor / KSP is missing
MDC values never appear in outputorg.slf4j.MDC imported instead of ru.tinkoff.kora.logging.common.MDC
@Log(level = ...) does not compileThe attribute is value, not level: write @Log(Level.DEBUG)
Looking for Level.OFFIt does not exist; use @Log.off to disable a method
Want full args but see only > / <The logger level for that class is INFO; set it to DEBUG in logback.xml
Sensitive argument leaks into logsAdd @Log.off to that parameter
Global MDC bleeds across requestsAvoid global = true, or remove the key with the static MDC.remove(key) at the end of the unit of work

References

Assets

  • assets/LoggedService.java.template, assets/LoggedService.kt.template — runnable @Log + @Mdc service templates. See assets/README.md.

What ships with it: 6 files

23.0 KB alongside SKILL.md

evals/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.