Compiler Plugin
Tracy uses a Kotlin Compiler Plugin (KCP) to power its annotation-based tracing. This section explains how the plugin works and provides background on the Kotlin compiler architecture.
Related: Usage Guide
For documentation on using the @Trace annotation in your code, see Function Tracing with Annotations. This section covers the technical implementation details of the compiler plugin.
What is a Kotlin Compiler Plugin?
A Kotlin Compiler Plugin is a program that "hooks" into the Kotlin compiler pipeline to change or extend its behavior. Plugins typically work directly with Kotlin's Intermediate Representation (IR) to transform code at compile time.
Examples of Compiler Plugins
The Kotlin ecosystem includes several well-known compiler plugins:
noarg: Automatically generates a no-argument constructor for classesallopen: Automatically makes classes and their membersopenkotlin-serialization: Generates efficient serializers and deserializers for data classespower-assert: Provides detailed assertion failure messages
Tracy's compiler plugin automatically wraps functions annotated with @Trace with tracing logic — no boilerplate required.
Compiler Plugins vs Annotation Processors
Tracy uses a compiler plugin rather than annotation processors (kapt/KSP) due to the following differences:
| Annotation Processors | Compiler Plugins | |
|---|---|---|
| API stability | Public, documented | Private, undocumented |
| Code generation | Emits new source files | Modifies existing bytecode |
| Code modification | Cannot modify existing code | Can transform function bodies |
| Multiplatform | KSP only (kapt is JVM-only) | All targets (JVM, JS, Native) |
| Execution phase | Before compilation | During compilation (IR phase) |
Tracy must wrap existing functions with tracing logic. Annotation processors can only generate new files — they cannot modify the annotated function itself. Compiler plugins operate on IR and can transform any function body directly.
Plugin Architecture
A Kotlin compiler plugin consists of several components:
flowchart TB
gradle["<b>Gradle Plugin</b>"]
registrar["<b>Component<br/>Registrar</b>"]
ext1["<b>Extension</b>"]
ext2["<b>Extension</b>"]
gradle --> registrar
registrar --> ext1
registrar --> ext2
style gradle fill:#a3be8c,stroke:#4c566a,stroke-width:2px,rx:10,ry:10
style registrar fill:#ffffff,stroke:#4c566a,stroke-width:2px,rx:20,ry:20
style ext1 fill:#ffffff,stroke:#4c566a,stroke-width:2px,rx:20,ry:20
style ext2 fill:#ffffff,stroke:#4c566a,stroke-width:2px,rx:20,ry:20
Gradle Plugin
The Gradle plugin integrates with your build system and configures the compiler plugin. Tracy's Gradle plugin (org.jetbrains.ai.tracy) handles version compatibility automatically — since Kotlin compiler plugins must match the Kotlin compiler version, Tracy provides multiple plugin builds (for Kotlin 1.9.x, 2.0.x, 2.1.x, 2.2.x). The Gradle plugin detects your Kotlin version and selects the appropriate compiler plugin artifact.
Component Registrar
The Component Registrar is the entry point that registers extensions with the Kotlin compiler. Tracy's TracyPluginRegistrar implements CompilerPluginRegistrar and supports both K1 and K2 compilers.
Extensions
Extensions are where the actual work happens. Tracy uses IrGenerationExtension to transform Kotlin IR. The TracyGeneratorExtension visits all functions, finds those annotated with @Trace, and wraps their bodies with tracing calls.
Learn More
- How Tracy Transforms Code: Deep dive into Tracy's IR transformation logic