|
1 | | -# Repository Guidelines |
| 1 | +# Repository Guide for Coding Agents |
2 | 2 |
|
3 | | -## Project Structure & Modules |
4 | | -- Root uses Gradle with multiple modules named `btrace-*`. |
5 | | -- Core code lives in module directories (for example, `btrace-core`, `btrace-agent`, `btrace-runtime`, `btrace-client`, `btrace-instr`). |
6 | | -- Distributions are built from `btrace-dist`. |
7 | | -- Integration tests live in `integration-tests`; benchmarks in `benchmarks/*`; docs in `docs/`. |
| 3 | +## Start here |
8 | 4 |
|
9 | | -## Architecture Overview |
10 | | -- btrace-agent: Attachable Java agent that installs a class transformer and manages script lifecycle (load/unload), output routing, and optional JFR hooks. |
11 | | -- btrace-compiler: Verifies and compiles BTrace scripts to bytecode. |
12 | | -- btrace-instr: ASM-based instrumentation and weaving utilities used by the agent/compiler. |
13 | | -- btrace-runtime: APIs exposed to scripts; provides safe helpers for printing, timers, and data collection. |
14 | | -- btrace-client: CLI/attach tooling that sends compiled scripts to the target JVM and streams results. |
15 | | -- extensions: API + implementations packaged as BTrace extensions (for example, statsd and metrics under `btrace-extensions/*`). |
16 | | -- Flow: client attaches → compiles/sends script → agent loads and instruments target classes → runtime emits events → client displays/exports. |
| 5 | +BTrace is a Java tracing tool: the client compiles and sends a script, the agent instruments the target JVM, and the runtime emits results. The root project is a multi-module Gradle build. |
17 | 6 |
|
18 | | -### High-Level Flow |
19 | | -``` |
20 | | - +--------------+ attach/send +-------------+ transform +------------------+ |
21 | | - | btrace-client| -----------------> | btrace-agent| --------------> | instrumented JVM | |
22 | | - +--------------+ +-------------+ +------------------+ |
23 | | - ^ | ^ | |
24 | | - | events/logs/stdout | | load/unload scripts | |
25 | | - | <------------------------------------+ +-------------------------------+ |
26 | | - | |
27 | | - +--------- optional exporters via services (eg. statsd) --------------------> |
28 | | -``` |
29 | | - |
30 | | -### Modules (at a glance) |
31 | | -``` |
32 | | - btrace-client -> btrace-agent -> btrace-instr |
33 | | - | | |
34 | | - v v |
35 | | - btrace-runtime extensions (e.g., statsd, utils, metrics) |
36 | | -
|
37 | | - btrace-compiler (validates/compiles scripts) |
38 | | - btrace-dist (packages binaries) |
39 | | -``` |
40 | | - |
41 | | -## Distribution Architecture: Masked JAR |
42 | | - |
43 | | -BTrace uses a **single masked JAR** (`btrace.jar`) as its distribution artifact. This JAR contains: |
44 | | - |
45 | | -### Structure |
46 | | -``` |
47 | | -btrace.jar |
48 | | -├── META-INF/ |
49 | | -│ ├── MANIFEST.MF (Main-Class, Premain-Class, Agent-Class → io.btrace.boot.Loader) |
50 | | -│ ├── btrace/ |
51 | | -│ │ ├── agent/*.classdata (agent classes - loaded in agent mode) |
52 | | -│ │ ├── client/*.classdata (client classes - loaded in client mode) |
53 | | -│ │ └── shared/*.classdata (shared classes - loaded in both modes) |
54 | | -├── org/openjdk/btrace/boot/ (bootstrap classes - visible to JVM) |
55 | | -└── org/openjdk/btrace/core/ (core/runtime classes from bootstrap module) |
56 | | -``` |
57 | | - |
58 | | -### Class Loading Strategy |
59 | | - |
60 | | -1. **Bootstrap Classes** (`.class` files in root): |
61 | | - - Loaded by bootstrap classloader |
62 | | - - Visible to JVM and all code |
63 | | - - Includes: Loader, MaskedClassLoader, MaskedJarUtils |
64 | | - - These classes initialize the masked jar system |
65 | | - |
66 | | -2. **Agent Classes** (`.classdata` in `META-INF/btrace/agent/`): |
67 | | - - Loaded via MaskedClassLoader in agent mode |
68 | | - - Isolated from application classes |
69 | | - - Includes: btrace-agent, btrace-instr, btrace-runtime, relocated jctools |
70 | | - |
71 | | -3. **Client Classes** (`.classdata` in `META-INF/btrace/client/`): |
72 | | - - Loaded via MaskedClassLoader in client mode |
73 | | - - Includes: btrace-client, btrace-compiler, lanterna UI |
74 | | - |
75 | | -4. **Shared Classes** (`.classdata` in `META-INF/btrace/shared/`): |
76 | | - - Loaded in both agent and client modes |
77 | | - - Includes: communication protocol, annotations, ASM core |
78 | | - - Critical for agent-client communication |
| 7 | +- `btrace-agent` — attachable agent and script lifecycle |
| 8 | +- `btrace-compiler` — script verification and compilation |
| 9 | +- `btrace-instr` — instrumentation and weaving |
| 10 | +- `btrace-runtime` / `btrace-core` — script APIs, runtime support, and protocol |
| 11 | +- `btrace-client` — CLI and attachment client |
| 12 | +- `btrace-dist` — distribution assembly; `integration-tests` — end-to-end tests |
| 13 | +- `btrace-extensions/*` — extension API and implementations |
79 | 14 |
|
80 | | -### Why Masked JAR? |
| 15 | +For the developer command reference and code-navigation pointers, see [CLAUDE.md](CLAUDE.md). For user and contributor documentation, start at [docs/README.md](docs/README.md). |
81 | 16 |
|
82 | | -- **Single Source of Truth**: One JAR for all use cases (agent, client, standalone) |
83 | | -- **Bootstrap Isolation**: Agent/client classes hidden from JVM, preventing conflicts |
84 | | -- **No Embedded JARs**: Eliminates nested JAR extraction overhead |
85 | | -- **Simplified Build**: Removed redundant uber jar - masked jar handles everything |
| 17 | +## Non-negotiable rules |
86 | 18 |
|
87 | | -### Build Process |
| 19 | +- Do not commit unless the changes are fully tested or the user explicitly requests a commit. |
| 20 | +- Preserve unrelated working-tree changes. |
| 21 | +- In Java code, import types and use simple names; do not introduce fully qualified type names in source. |
| 22 | +- Main code targets Java 8 and uses the Java 11 toolchain. Follow Spotless/Google Java Format. |
| 23 | +- Unit tests live in `src/test/java` and use `*Test`; integration tests live in `integration-tests/src/test/java`. |
88 | 24 |
|
89 | | -The masked JAR is built in `btrace-dist/build.gradle`: |
90 | | -1. `allClassesShadow` - Creates intermediate shadow jar with all dependencies and relocations |
91 | | -2. `prepareAgentClassdata` - Extracts agent classes, renames `.class` → `.classdata` |
92 | | -3. `prepareClientClassdata` - Extracts client classes, renames `.class` → `.classdata` |
93 | | -4. `prepareSharedClassdata` - Extracts shared classes, renames `.class` → `.classdata` |
94 | | -5. `btraceJar` - Combines bootstrap classes (as `.class`) + masked classes (as `.classdata`) |
| 25 | +## Build and verification |
95 | 26 |
|
96 | | -### Debugging Tips |
| 27 | +Run Gradle with a workspace-local cache in restricted environments: |
97 | 28 |
|
98 | | -- **ClassNotFoundException in agent mode**: Check if class is in `META-INF/btrace/agent/` (or shared if needed) |
99 | | -- **ClassNotFoundException in client mode**: Check if class is in `META-INF/btrace/client/` (or shared if needed) |
100 | | -- **NoClassDefFoundError between modes**: Class may need to be in shared section |
101 | | -- **Inspect masked JAR**: `unzip -l btrace.jar | grep -E "(\.class|\.classdata)"` |
102 | | -- **Check manifest**: `unzip -p btrace.jar META-INF/MANIFEST.MF` |
103 | | - |
104 | | -## Launch Modes |
105 | | -``` |
106 | | -Launch-time (agent mode): |
107 | | - java -javaagent:$BTRACE_HOME/libs/btrace.jar=script=MyTrace.java -jar app.jar |
108 | | - |-> Loader.premain() -> loads agent classes from .classdata -> installs transformer |
109 | | -
|
110 | | -Attach-time (client mode): |
111 | | - btrace <PID> MyTrace.java |
112 | | - |-> Loader as Main-Class -> loads client classes from .classdata -> attaches to target JVM |
113 | | - |-> Target JVM: Loader.agentmain() -> loads agent classes from .classdata -> instruments |
114 | | -
|
115 | | -Standalone (client mode): |
116 | | - java -jar btrace.jar <args> |
117 | | - |-> Same as attach-time, Loader delegates to client |
| 29 | +```bash |
| 30 | +GRADLE_USER_HOME=$(pwd)/.gradle-user ./gradlew :module:test |
118 | 31 | ``` |
119 | 32 |
|
120 | | -## Troubleshooting |
121 | | -- Attach disabled: if JVM was started with `-XX:+DisableAttachMechanism`, remove it or relaunch without it. |
122 | | -- Permission errors: attach requires same OS user as target JVM; on Linux/macOS avoid sudo mixing; check container/JDK permissions. |
123 | | -- Toolchains: ensure `JAVA_HOME` and optional `TEST_JAVA_HOME` point to valid JDKs; for integration tests, build `btrace-dist` first so client/libs exist. |
| 33 | +Do not consume Gradle output directly. Redirect it to a file, filter it to relevant lines, then read that file. Use `spotlessCheck` for validation and `spotlessApply` only when formatting changes are intended. Build `:btrace-dist:build` before integration tests. |
124 | 34 |
|
125 | | -### Masked JAR Troubleshooting |
126 | | -- **ClassNotFoundException with .classdata**: MaskedClassLoader can't find class in masked sections. Check: |
127 | | - 1. Is the class in the correct section? (agent/client/shared) |
128 | | - 2. Was the class relocated? Check package name matches relocated path |
129 | | - 3. Did the build complete successfully? Rebuild with `./gradlew clean :btrace-dist:btraceJar` |
130 | | -- **Shared classes**: If a class is used by BOTH agent and client (e.g., comm protocol, annotations), it MUST be in the shared section |
131 | | -- **Bootstrap vs Masked**: Bootstrap classes (.class) are visible everywhere; masked classes (.classdata) are isolated per-mode |
132 | | -- **Build order matters**: `allClassesShadow` must complete before prepare*Classdata tasks run |
| 35 | +If a restricted network environment causes address-selection failures, add: |
133 | 36 |
|
134 | | -## Example Script |
135 | | -```java |
136 | | -package helloworld; |
137 | | -import static io.btrace.core.BTraceUtils.*; |
138 | | -import io.btrace.core.annotations.*; |
139 | | -import io.btrace.core.types.AnyType; |
140 | | - |
141 | | -@BTrace |
142 | | -public class MyTrace { |
143 | | - @OnMethod(clazz="extra.HelloWorld", method="/.*/") |
144 | | - public static void onAny(@ProbeMethodName String pmn) { |
145 | | - println("entered: " + pmn); |
146 | | - } |
147 | | -} |
| 37 | +```bash |
| 38 | +JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false" |
148 | 39 | ``` |
149 | | -Run with: `btrace <PID> MyTrace.java` (see docs/BTraceTutorial.md for steps). |
150 | | - |
151 | | -```java |
152 | | -// Args capture |
153 | | -package helloworld; |
154 | | -import static io.btrace.core.BTraceUtils.*; |
155 | | -import io.btrace.core.annotations.*; |
156 | | -import io.btrace.core.types.AnyType; |
157 | 40 |
|
158 | | -@BTrace |
159 | | -public class ArgsTrace { |
160 | | - @OnMethod(clazz="extra.HelloWorld", method="/call.*/") |
161 | | - public static void onCall(@ProbeMethodName String pmn, AnyType[] args) { |
162 | | - println("args for " + pmn); |
163 | | - printArray(args); |
164 | | - } |
165 | | -} |
166 | | -``` |
| 41 | +## Distribution changes |
167 | 42 |
|
168 | | -```java |
169 | | -// Return value and duration |
170 | | -package helloworld; |
171 | | -import static io.btrace.core.BTraceUtils.*; |
172 | | -import io.btrace.core.annotations.*; |
173 | | -import io.btrace.core.types.AnyType; |
| 43 | +`btrace.jar` is a masked single-JAR distribution. Classes must be assigned to bootstrap, agent, client, or shared sections deliberately. Any masked-JAR structure change requires: |
174 | 44 |
|
175 | | -@BTrace |
176 | | -public class ReturnTrace { |
177 | | - @OnMethod(clazz="extra.HelloWorld", method="callC", location=@Location(Kind.RETURN)) |
178 | | - public static void onReturn(@Duration long dur, @Return AnyType ret) { |
179 | | - println("callC ret=" + str(ret) + ", dur(ns)=" + dur); |
180 | | - } |
181 | | -} |
| 45 | +```bash |
| 46 | +./gradlew clean :btrace-dist:btraceJar |
182 | 47 | ``` |
183 | 48 |
|
184 | | -## Build, Test, and Development |
185 | | -! Do not consume the gradle task logs directly. ! |
186 | | -! Write the output to a file, running through grep to include only relevant information and then read the log file. ! |
187 | | - |
188 | | -- Full build: `./gradlew build` — compiles all modules and runs unit tests. |
189 | | -- Distribution: `./gradlew :btrace-dist:build` — creates ZIP/TGZ/RPM/DEB and an exploded layout under `btrace-dist/build/resources/main`. |
190 | | -- Unit tests: `./gradlew test` — JUnit 5, runs per-module tests. |
191 | | -- Integration tests: first build dist, then `./gradlew -Pintegration test`. |
192 | | - - Requires `JAVA_HOME` and typically `TEST_JAVA_HOME` (e.g., JDK 11). Example: `TEST_JAVA_HOME=$JAVA_11_HOME ./gradlew -Pintegration test`. |
193 | | -- Formatting: `./gradlew spotlessApply` (check with `spotlessCheck`). |
194 | | -- Coverage: `./gradlew jacocoTestReport` (CI publishes to Codecov). |
195 | | - |
196 | | -## Coding Style & Naming |
197 | | -- Language: Java. Source/target set to 8; toolchains compile with JDK 11. |
198 | | -- Format: Google Java Format via Spotless. Import order enforced; unused imports removed. |
199 | | -- Packages under `io.btrace.*`. |
200 | | -- Module names follow `btrace-<component>` (e.g., `btrace-extensions:btrace-utils`). |
201 | | - |
202 | | -## Testing Guidelines |
203 | | -- Framework: JUnit Jupiter (JUnit 5). |
204 | | -- Unit tests reside under `src/test/java`; name classes with `*Test`. |
205 | | -- Integration tests in `integration-tests/src/test/java`; BTrace scripts under `integration-tests/src/test/btrace`. |
206 | | -- For integration runs, ensure `btrace-dist/build/resources/main/v<version>/libs/btrace.jar` exists (created by the dist build). |
207 | | -- The masked JAR is used for all integration tests - both agent and client modes use the same artifact. |
208 | | - |
209 | | -## Commit & Pull Request Guidelines |
210 | | -- Commit style: Conventional Commits (e.g., `feat(core): add probe`, `fix(instr): handle null arg`). |
211 | | -- PRs must be from signers of the Oracle Contributor Agreement (OCA) — see README. |
212 | | -- PR checklist: |
213 | | - - Clear description and rationale; link related issues. |
214 | | - - Tests updated/added; CI green across unit and integration suites. |
215 | | - - Formatting passes (`spotlessCheck`); no unrelated changes. |
216 | | - - For behavior changes, include before/after notes or relevant logs. |
217 | | - |
218 | | -## Tips & Environment |
219 | | -- Useful env vars: `JAVA_HOME`, `TEST_JAVA_HOME`, `BTRACE_TEST_DEBUG=true` (verbose integration tests), optional `BTRACE_HOME` when using the exploded dist. |
220 | | -- Example exploded dist path: `btrace-dist/build/resources/main/v2.2.6/`. |
221 | | - |
222 | | -### Restricted/CI Environments |
223 | | -- Prefer a workspace-local Gradle cache to avoid permission issues: set `GRADLE_USER_HOME=$(pwd)/.gradle-user`. |
224 | | -- If network interfaces are restricted, force IPv4 to avoid wildcard IP detection errors: set `JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false"`. |
225 | | -- Example: `GRADLE_USER_HOME=$(pwd)/.gradle-user JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false" ./gradlew :btrace-dist:buildZip -x test` |
226 | | - |
227 | | -## Common Patterns & Lessons Learned |
228 | | - |
229 | | -### Adding New Classes |
230 | | -1. **Determine the section**: Is the class used by agent, client, or both? |
231 | | - - Agent only → prepareAgentClassdata include pattern |
232 | | - - Client only → prepareClientClassdata include pattern |
233 | | - - Both → prepareSharedClassdata include pattern |
234 | | -2. **Update build.gradle**: Add include pattern in the appropriate task |
235 | | -3. **Rebuild and test**: `./gradlew clean :btrace-dist:btraceJar && ./gradlew -Pintegration test` |
| 49 | +Read [Masked JAR Architecture](docs/architecture/MaskedJarArchitecture.md) before modifying its class layout or loader behavior. |
236 | 50 |
|
237 | | -### Dependency Relocation |
238 | | -- All third-party dependencies are relocated to `io.btrace.libs.*` |
239 | | -- Relocations happen in `allClassesShadow` task using Shadow plugin |
240 | | -- Common relocations: ASM, SLF4J, JCTools |
241 | | -- After relocation, classes are extracted and masked in prepare*Classdata tasks |
| 51 | +## Documentation placement |
242 | 52 |
|
243 | | -### Build Simplification Wins |
244 | | -- **Before**: Separate agent.jar, client.jar, boot.jar, uber.jar (4 artifacts) |
245 | | -- **After**: Single btrace.jar with masked sections (1 artifact) |
246 | | -- **Result**: Simpler build, smaller distribution, easier maintenance |
| 53 | +- User-facing and contributor documentation belongs in `docs/`; keep [docs/README.md](docs/README.md) current when adding a guide. |
| 54 | +- Plans and session notes belong in `internal/plans/` (or `internal/superpowers/plans/`). |
| 55 | +- Design/requirement specs belong in `internal/specs/` (or `internal/superpowers/specs/`); libretto/muse files belong in `internal/libretti/`. |
| 56 | +- Never create or write to a singular `doc/` directory, or add plans, agent notes, or internal material below `docs/`. |
247 | 57 |
|
248 | | -### ClassLoader Isolation |
249 | | -- Bootstrap classes can see everything (including masked sections via MaskedClassLoader) |
250 | | -- Application classes cannot see masked sections (isolation prevents conflicts) |
251 | | -- Masked classes in agent mode cannot see masked classes in client mode (intentional isolation) |
252 | | -- Shared section solves cross-mode visibility when needed (e.g., command serialization) |
| 58 | +## Reference map |
253 | 59 |
|
254 | | -## Hard rules |
255 | | -- Never commit changes unless they are fully tested or you are explicitly asked to commit |
256 | | -- Do not use FQNs directly! Always import types and use simple type names in the code! |
257 | | -- When adding classes to masked jar, always consider: agent-only, client-only, or shared? |
258 | | -- Rebuild the distribution after any changes to masked jar structure: `./gradlew clean :btrace-dist:btraceJar` |
| 60 | +- [Contribution workflow](CONTRIBUTING.md) |
| 61 | +- [Instrumentation analysis](docs/architecture/BTraceInstrAnalysis.md) and [backend selection](docs/architecture/InstrumentationBackends.md) |
| 62 | +- [v2 wire protocol](docs/architecture/Version2ProtocolArchitecture.md) |
| 63 | +- [Extension development](docs/BTraceExtensionDevelopmentGuide.md) and [interface rules](docs/ExtensionInterfaceRules.md) |
| 64 | +- [Troubleshooting](docs/Troubleshooting.md) |
0 commit comments