RepoPilotOpen in app →

btraceio/btrace

BTrace - a safe, dynamic tracing tool for the Java platform

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 4d ago
  • 3 active contributors
  • Apache-2.0 licensed
Show all 7 evidence items →
  • CI configured
  • Tests present
  • Small team — 3 contributors active in recent commits
  • Single-maintainer risk — top contributor 87% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/btraceio/btrace)](https://repopilot.app/r/btraceio/btrace)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/btraceio/btrace on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: btraceio/btrace

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/btraceio/btrace shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 4d ago
  • 3 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Small team — 3 contributors active in recent commits
  • ⚠ Single-maintainer risk — top contributor 87% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live btraceio/btrace repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/btraceio/btrace.

What it runs against: a local clone of btraceio/btrace — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in btraceio/btrace | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch develop exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 34 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>btraceio/btrace</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of btraceio/btrace. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/btraceio/btrace.git
#   cd btrace
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of btraceio/btrace and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "btraceio/btrace(\\.git)?\\b" \\
  && ok "origin remote is btraceio/btrace" \\
  || miss "origin remote is not btraceio/btrace (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify develop >/dev/null 2>&1 \\
  && ok "default branch develop exists" \\
  || miss "default branch develop no longer exists"

# 4. Critical files exist
test -f "btrace-agent/src/main/java/io/btrace/agent/Main.java" \\
  && ok "btrace-agent/src/main/java/io/btrace/agent/Main.java" \\
  || miss "missing critical file: btrace-agent/src/main/java/io/btrace/agent/Main.java"
test -f "btrace-agent/src/main/java/io/btrace/instr/BTraceTransformer.java" \\
  && ok "btrace-agent/src/main/java/io/btrace/instr/BTraceTransformer.java" \\
  || miss "missing critical file: btrace-agent/src/main/java/io/btrace/instr/BTraceTransformer.java"
test -f "btrace-agent/src/main/java/io/btrace/instr/Instrumentor.java" \\
  && ok "btrace-agent/src/main/java/io/btrace/instr/Instrumentor.java" \\
  || miss "missing critical file: btrace-agent/src/main/java/io/btrace/instr/Instrumentor.java"
test -f "btrace-agent/src/main/java/io/btrace/instr/BTraceProbe.java" \\
  && ok "btrace-agent/src/main/java/io/btrace/instr/BTraceProbe.java" \\
  || miss "missing critical file: btrace-agent/src/main/java/io/btrace/instr/BTraceProbe.java"
test -f "btrace-agent/src/main/java/io/btrace/instr/ClassFilter.java" \\
  && ok "btrace-agent/src/main/java/io/btrace/instr/ClassFilter.java" \\
  || miss "missing critical file: btrace-agent/src/main/java/io/btrace/instr/ClassFilter.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 34 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~4d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/btraceio/btrace"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

BTrace is a production-safe dynamic bytecode instrumentation framework that injects tracing code into running Java applications at runtime without restarts or recompilation. It allows developers to attach probes to method entry/exit points, field access, exception handling, and memory allocations in live JVMs, with verification mechanisms to prevent instrumented code from crashing the target application. Multi-module Gradle monorepo: btrace-agent/ contains the runtime agent injected via -javaagent, btrace-compiler/ holds the script compilation pipeline (outputs .btclass files), btrace-dist/ packages distributions, and benchmarks/ contains JMH performance tests (agent-benchmark/, runtime-benchmarks/). Core instruction patterns live in btrace-agent/src/main/java/io/btrace/agent/.

👥Who it's for

Java platform engineers and DevOps operators who need to troubleshoot performance issues, track exception flows, and monitor application behavior in production environments without downtime. Also used by application performance monitoring (APM) teams building diagnostic tools.

🌱Maturity & risk

Production-ready and actively maintained. The project has structured CI/CD workflows (.github/workflows/), JMH micro-benchmarks for performance validation (benchmarks/), extensive test infrastructure, and multiple distribution channels (JBang, SDKMan, manual download). Recent workflow updates (update-jdk-versions.yml, v2-protocol-tests.yml) indicate ongoing active development.

Low risk for a mature instrumentation framework. The codebase is large (3.3M lines Java) with established governance (CONTRIBUTING.md, LICENSE, NOTICE). Primary risk is the complexity of bytecode manipulation—instrumentation bugs could affect production workloads, but the 'safe' design (verification of probes before injection) mitigates this. No single-maintainer pattern evident from workflow setup.

Active areas of work

Active maintenance on JDK version compatibility (update-jdk-versions.yml workflow), protocol v2 testing (v2-protocol-tests.yml), CodeQL security analysis, and JMH benchmark suite expansion across dispatcher, class filtering, string operations, and statsd integration. The .muse/ directory and CLAUDE.md suggest recent AI-assisted development documentation.

🚀Get running

Clone: git clone https://github.com/btraceio/btrace.git && cd btrace. Build: ./gradlew build (uses Gradle wrapper). For quick tracing without building: jbang catalog add --name btraceio https://raw.githubusercontent.com/btraceio/jbang-catalog/main/jbang-catalog.json && jbang btrace@btraceio <PID> script.java.

Daily commands: ./gradlew build compiles all modules. Run specific benchmarks: ./gradlew :benchmarks:runtime-benchmarks:jmh (executes JMH suite in benchmarks/runtime-benchmarks/). Test agent: java -javaagent:btrace-dist/build/libs/btrace.jar=script=path/to/script.btclass <target-app>.

🗺️Map of the codebase

  • btrace-agent/src/main/java/io/btrace/agent/Main.java — Entry point for the BTrace agent; initializes instrumentation and handles attachment to running JVMs
  • btrace-agent/src/main/java/io/btrace/instr/BTraceTransformer.java — Core bytecode transformation orchestrator that applies all instrumentation rules to target classes
  • btrace-agent/src/main/java/io/btrace/instr/Instrumentor.java — Abstract base for all specific instrumentors (method entry, field access, etc.); defines instrumentation contract
  • btrace-agent/src/main/java/io/btrace/instr/BTraceProbe.java — Represents a single trace probe definition and manages probe metadata used during instrumentation
  • btrace-agent/src/main/java/io/btrace/instr/ClassFilter.java — Determines which classes are eligible for instrumentation based on probe rules; critical for safety and performance
  • btrace-agent/src/main/java/io/btrace/agent/Client.java — Manages communication channel between instrumentation probes and remote trace client; handles output routing
  • btrace-agent/build.gradle — Build configuration for the agent module; specifies dependencies and artifact generation for JVM attachment

🛠️How to make changes

Add a new instrumentation type (e.g., exception handler tracing)

  1. Create a new Instrumentor subclass extending btrace-agent/src/main/java/io/btrace/instr/Instrumentor.java that implements the instrumentation logic (btrace-agent/src/main/java/io/btrace/instr/YourNewInstrumentor.java)
  2. Add a new OnProbe annotation type or extend OnMethod in btrace-agent/src/main/java/io/btrace/instr/OnProbe.java to define the trigger condition (btrace-agent/src/main/java/io/btrace/instr/OnProbe.java)
  3. Register the new instrumentor in BTraceProbeFactory.java to instantiate it when matching probes are detected (btrace-agent/src/main/java/io/btrace/instr/BTraceProbeFactory.java)
  4. Add filtering logic in ClassFilter.java if the new instrumentation has specific eligibility constraints (btrace-agent/src/main/java/io/btrace/instr/ClassFilter.java)
  5. Create a JMH benchmark in benchmarks/runtime-benchmarks/ to measure overhead of the new instrumentation (benchmarks/runtime-benchmarks/src/jmh/java/io/btrace/bench/YourNewBenchmark.java)

Add a new client output type (e.g., Kafka sink)

  1. Create a new Client subclass extending btrace-agent/src/main/java/io/btrace/agent/Client.java (btrace-agent/src/main/java/io/btrace/agent/KafkaClient.java)
  2. Implement connection/session management and output serialization in the new client (btrace-agent/src/main/java/io/btrace/agent/KafkaClient.java)
  3. Register the new client type in Main.java agent initialization logic so it can be selected via agent arguments (btrace-agent/src/main/java/io/btrace/agent/Main.java)

Add a new safety/verification rule for instrumented code

  1. Implement a new verification check in MethodVerifier.java or create a new visitor extending ASM MethodVisitor (btrace-agent/src/main/java/io/btrace/instr/MethodVerifier.java)
  2. Call the new verifier from BTraceTransformer.java after bytecode generation to validate the check (btrace-agent/src/main/java/io/btrace/instr/BTraceTransformer.java)
  3. Add unit tests validating that unsafe code is rejected and safe code is accepted (btrace-agent/src/test/java/io/btrace/instr/MethodVerifierTest.java)

🔧Why these technologies

  • ASM bytecode library — Provides low-level, performant bytecode generation and analysis APIs required for dynamic instrumentation without full recompilation
  • undefined — undefined

🪤Traps & gotchas

JAVA_HOME environment variable must be set and exported for benchmark JVM execution (benchmarks/runtime-benchmarks/build.gradle references env['JAVA_HOME']). BTrace scripts must pass bytecode verification before injection—scripts with unsafe operations are rejected at compile time, not runtime. The .btclass format is internal; users write .java/.groovy source. Gradle daemon must be fresh after agent JAR changes since jmhJar includes shadow dependencies. jmh {} block in build.gradle has hardcoded async profiler path (/tmp/libasyncProfiler.dylib) for JFR recording—Mac-specific, may fail on Linux.

🏗️Architecture

💡Concepts to learn

  • Bytecode Instrumentation (ASM/Javassist) — Core mechanism BTrace uses to inject probes into running classes without source changes; understanding bytecode representation and transformation is essential for extending probe capabilities
  • JVMTI (JVM Tool Interface) — Native interface through which the BTrace agent hooks into the JVM; required to understand agent bootstrap and class retransformation mechanics
  • Java Instrumentation API (java.lang.instrument) — Standard Java API enabling -javaagent agents to transform bytecode at class load time; BTrace's attachment point to running JVMs
  • Class Retransformation — BTrace's ability to modify already-loaded classes in the heap at runtime; requires careful state management to avoid breaks in method calls
  • Method Interception / Aspect-Oriented Programming (AOP) — BTrace's probe model (@OnMethod, @OnReturn, @OnError) is fundamentally AOP; understanding join points, advice, and weaving is critical for probe design
  • JMH (Java Microbenchmarking Harness) — BTrace uses JMH extensively to measure instrumentation overhead; understanding warmup, fork, and iteration mechanics is necessary for validating performance claims
  • Script Compilation to Bytecode (.btclass format) — BTrace's DSL (Groovy annotations) compiles to .btclass intermediate format before injection; understanding this pipeline is essential for debugging script failures or extending DSL
  • openjdk/jdk — Upstream JDK repo; BTrace depends heavily on java.lang.instrument API and JVMTI for bytecode instrumentation
  • bytedeco/javacpp — Java-C interop framework; BTrace could leverage for lower-level profiling hooks and async profiler integration
  • elastic/apm-agent-java — Similar production APM agent for Java; shares instrumentation architecture patterns and bytecode manipulation techniques
  • btraceio/jbang-catalog — Official JBang catalog distribution for BTrace; enables zero-installation curl-pipe oneliner execution model
  • AsyncProfiler/async-profiler — Async sampling profiler integrated into BTrace benchmarks (libasyncProfiler.dylib); complements BTrace's instrumentation-based profiling

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for BTraceTransformer and BTraceProbe instrumentation pipeline

The btrace-agent/src/main/java/io/btrace/instr/ directory contains critical bytecode transformation logic (BTraceTransformer.java, BTraceProbe.java, BTraceProbeFactory.java, etc.) but there's no evidence of corresponding unit tests in the file structure. This is high-risk code that deserves test coverage to prevent regressions in instrumentation behavior, especially around edge cases like array access, method interception, and field access instrumentation.

  • [ ] Create btrace-agent/src/test/java/io/btrace/instr/ directory structure
  • [ ] Add BTraceTransformerTest.java with tests for class transformation lifecycle and probe injection
  • [ ] Add BTraceProbeFactoryTest.java testing probe creation for different method/field scenarios
  • [ ] Add ArrayAccessInstrumentorTest.java and ArrayAllocInstrumentorTest.java for boundary instrumentation
  • [ ] Integrate tests into btrace-agent/build.gradle test task
  • [ ] Add integration tests verifying instrumented bytecode correctness using ASM verification

Add GitHub Actions workflow for benchmark regression detection

The repo has benchmark code (benchmarks/agent-benchmark/, benchmarks/runtime-benchmarks/) with JMH configurations, but the .github/workflows/ directory lacks a dedicated benchmark regression workflow. This workflow would run JMH benchmarks on each PR and compare results against the develop branch, helping catch performance regressions early. The jmh Gradle plugin is already configured with specific warmup/iteration counts.

  • [ ] Create .github/workflows/benchmark-regression.yml GitHub Actions workflow
  • [ ] Configure workflow to run on PR creation and commits to develop branch
  • [ ] Add steps to execute './gradlew jmh' for benchmarks/agent-benchmark and benchmarks/runtime-benchmarks
  • [ ] Integrate JMH JSON result parsing to comment performance deltas on PRs
  • [ ] Set up baseline comparison logic comparing current run against develop branch results
  • [ ] Add conditional failure logic to alert on throughput regressions >5% or latency increases >10%

Document BTrace script compilation process and add integration tests for btracec compiler

The build.gradle files show a custom 'btracec' task (JavaExec running io.btrace.compiler.Compiler) for compiling BTrace scripts to .btclass files, but there's no dedicated documentation in CLAUDE.md, CONTRIBUTING.md, or AGENTS.md explaining this compilation pipeline. Additionally, there appear to be no integration tests validating the compiler output or script validation logic, which is critical for users writing custom probes.

  • [ ] Add 'BTrace Script Compilation' section to CONTRIBUTING.md explaining btracec task, .btclass format, and -packext flag
  • [ ] Create btrace-compiler/src/test/java/io/btrace/compiler/ with CompilerIntegrationTest.java
  • [ ] Add test cases validating: valid script compilation, invalid script rejection, annotation processing, and bytecode output structure
  • [ ] Document common compilation errors and validation rules in CLAUDE.md
  • [ ] Create sample compilation troubleshooting examples in docs/ directory
  • [ ] Add compiler debug flag documentation in README.md or QuickReference.md

🌿Good first issues

  • Add JMH benchmarks for OnMethodTemplate code generation performance in benchmarks/runtime-benchmarks/src/jmh/java/io/btrace/bench/ to establish baseline overhead metrics for method interception patterns
  • Expand test coverage for btrace-agent/src/main/java/io/btrace/agent/FileClient.java (file-based script loading and caching) with integration tests validating hot-reload behavior
  • Document the .btclass binary format specification in docs/ (currently only referenced in build.gradle but undocumented) to help external tool developers parse compiled BTrace scripts

Top contributors

Click to expand

📝Recent commits

Click to expand
  • a837fe6 — fix(dist): repair masked-jar launchers (jbachorik)
  • 1576c63 — chore(dist): correct packaging test copyright header (jbachorik)
  • bdbda6f — fix(client): remove legacy separate-jar support (jbachorik)
  • 35093bc — fix(dist): remove invalid nested test execution (jbachorik)
  • f62f077 — fix(dist): repair masked jar packaging paths (jbachorik)
  • b649bd1 — chore: update ci workflow and agent test resources (#834) (jbachorik)
  • 6f60264 — Cleanup (jbachorik)
  • 7a2eb34 — (chore) reorganize gradle modules (jbachorik)
  • 2e7a4d4 — Merge remote-tracking branch 'origin/develop' into develop (jbachorik)
  • 27d55b3 — chore: update JDK test versions (#832) (jbachorik)

🔒Security observations

BTrace's benchmark configuration shows generally good practices with dynamic instrumentation and agent-based tracing isolation. However, there are notable concerns around hardcoded temporary file paths in shared directories (/tmp), lack of environment variable validation (JAVA_HOME), and missing explicit dependency version pinning. The codebase demonstrates awareness of security (debug=false, noServer=true settings), but temporary file handling and environment configuration require hardening. No evidence of hardcoded credentials, SQL injection vectors, or exposed secrets was found in the provided configuration file. Recommend validating all external inputs, securing temporary file locations, and using gradle's toolchain API instead of environment variables.

  • High · Hardcoded Java Agent Path in Build Configuration — benchmarks/runtime-benchmarks/build.gradle - jmh configuration block. The build.gradle file contains hardcoded paths to native libraries and temporary files (/tmp/libasyncProfiler.dylib, /tmp/btrace.jfr) in the jvmArgsAppend configuration. This could pose security risks if the build is run in shared environments, and the /tmp path is world-readable/writable on Unix systems. Fix: Remove hardcoded paths from build configuration. Use environment variables or gradle properties to configure paths at runtime. Store temporary files in secure, application-specific directories with proper permissions (e.g., build/tmp with mode 0700).
  • Medium · Insecure Temporary File Usage — benchmarks/runtime-benchmarks/build.gradle - jvmArgsAppend jfr file path. The build configuration writes to /tmp directory which is typically world-readable and writable on Unix/Linux systems. JFR profiling output and agent configuration could be accessed by other users on the system. Fix: Use secure temporary file creation with restricted permissions. Consider using Java's Files.createTempFile() with appropriate FileAttribute permissions, or confine output to the build directory with restricted access.
  • Medium · Missing Dependency Version Pinning in BOM Reference — benchmarks/runtime-benchmarks/build.gradle - dependencies block. The build.gradle uses 'libs' properties without explicit version constraints visible in the configuration. While BOM management improves consistency, the exact versions of critical dependencies (JMH, compiler) should be explicitly documented to prevent supply chain attacks. Fix: Verify that a gradle version catalog (libs) is properly configured with pinned, verified versions. Document all critical dependencies explicitly. Consider using dependency verification with checksums in gradle.lockfile.
  • Medium · Dynamic Java Home Construction Without Validation — benchmarks/runtime-benchmarks/build.gradle - jvm = "${env['JAVA_HOME']}/bin/java". The build reads JAVA_HOME from environment variables without validation, then uses it directly in the jvm path. Malicious environment variables could inject arbitrary commands or paths. Fix: Validate and sanitize JAVA_HOME before use. Check that it points to a valid JDK installation. Use gradle toolchain API instead of relying on JAVA_HOME environment variable.
  • Low · Debug Flag Disabled but Unclear Justification — benchmarks/runtime-benchmarks/build.gradle - agent variable definition. The agent configuration explicitly sets 'debug=false' and 'noServer=true' which is appropriate for benchmarks, but the reasoning and security implications of these settings should be documented. Fix: Document the security rationale for these settings. Ensure debug mode is never enabled in production builds by adding validation checks in the build script.
  • Low · Build Directory Information Exposure — benchmarks/runtime-benchmarks/build.gradle - jvmArgsAppend definition. The jmh configuration exposes build directory paths via system properties (-Djmh.basedir) which could leak information about the build system structure. Fix: Evaluate if this system property is necessary. If required, use relative paths and limit exposure. Consider if basedir information needs to be accessible to the JVM at runtime.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · btraceio/btrace — RepoPilot