Function Tracing with Annotations
For Kotlin projects, Tracy provides the @Trace annotation, which allows you to
automatically trace any function. The Kotlin compiler plugin instruments annotated functions to capture execution details
such as start and end time, duration, inputs, and outputs.
Technical Implementation
Tracy uses a Kotlin Compiler Plugin to transform annotated functions at compile time. For details on the IR transformation process, see the Compiler Plugin section.
Usage
To use annotation-based tracing, you must:
- Apply the
org.jetbrains.ai.tracyplugin in yourbuild.gradle.kts. - Annotate your functions with
@Trace.
Preserving Parameter Names
By default, the Kotlin compiler may not preserve parameter names in the generated bytecode, resulting in generic names like arg0, arg1, etc., in your traces. To ensure that Tracy can capture the actual parameter names, add the -java-parameters compiler option to your build.gradle.kts:
Basic Example
@Trace(name = "GreetUser")
fun greetUser(name: String): String {
println("Hello, $name!")
return "Greeting sent to $name"
}
Nested Spans
When one traced function calls another, Tracy automatically creates a hierarchical trace structure. The outer call is recorded as a parent span, and the inner call as its child span.
See the full example: NestedSpansExample.kt
Advanced Usage
Inheritance and Propagation
The @Trace annotation
is automatically propagated through interfaces and class hierarchies. If you annotate a method in an interface, all
implementations of that method will be traced automatically.
See the full example: TracingPropagationExample.kt
Customizing Span Metadata
You can customize how spans are named and how inputs/outputs are serialized by providing an implementation of the SpanMetadataCustomizer interface.
Must be a Kotlin object
SpanMetadataCustomizer implementations must be declared as Kotlin objects. Passing a class will throw a runtime error.
object MyCustomizer : SpanMetadataCustomizer {
override fun formatInputAttributes(
method: PlatformMethod,
args: Array<Any?>
): String = "${method.name}(${args.joinToString { it.toString() }})"
// Implement other methods as needed
}
@Trace(metadataCustomizer = MyCustomizer::class)
fun myCustomFunction(input: String) {
// ...
}
See the full example: MetadataCustomizerExample.kt
Limitations
Annotation-based tracing has some limitations (local functions, Java interoperability). See the Limitations page for details.