apm-integrations
Skill739 starsChanged 6 days agoApache-2.0View on GitHub
Write a new library instrumentation end-to-end. Use when the user ask to add a new APM integration or a library instrumentation.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- DataDog/dd-trace-pytheir own version, first seen Nov 1, 2026
- DataDog/dd-trace-gotheir own version, first seen Oct 8, 2026
- DataDog/dd-trace-jstheir own version, first seen Oct 8, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- DataDog/dd-trace-go★ 863same name
- DataDog/dd-trace-js★ 840same name
- DataDog/dd-trace-py★ 653same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository17 other files it gives its agents.
- AGENTS.mdAGENTS.md
- build-logic/AGENTS.mdAGENTS.md
- buildSrc/AGENTS.mdAGENTS.md
- build-logic/CLAUDE.mdCLAUDE.md
- buildSrc/CLAUDE.mdCLAUDE.md
- .claude/CLAUDE.mdCLAUDE.md
- clarify-java-commentsSkill
- fix-continuation-leakageSkill
- java-lintSkill
- migrate-groovy-to-javaSkill
- migrate-junit-source-to-tabletestSkill
- perf-reviewSkill
- reproduce-ci-flakinessSkill
- resolve-muzzle-ciSkill
- review-groovy-migrationSkill
- techdebtSkill
- fix-continuation-leakageSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. 0 are common, 6 are distinctive, and 11 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
6
Distinctive
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 14
Write a new APM end-to-end integration for dd-trace-java, based on library instrumentations, following all project conventions.
- Distinctive: line 18
Before writing any code, read all three files in full:
- Distinctive: line 28
If the user has not already provided all of the following, ask before proceeding:
- Very specific: line 37
Search dd-java-agent/instrumentation/ for a structurally similar integration:
- Very specific: line 41
Read the reference integration's InstrumenterModule, Advice, Decorator, and test files to understand the established pattern before writing …
- Very specific: line 61
Read Context-Tracking Instrumentation and decide whether the library needs InstrumenterModule.Tracing (I/O operations that create spans) or …
- Very specific: line 75
Keep all tag/naming/error logic here — not in the Advice class
- Very specific: line 88
Place them in the helpers package, declare them in helperClassNames().
- Very specific: line 104
If the library's API surface changes across minor versions (deprecated/removed methods, changed signatures), see Writing Tests's …
- Very specific: line 106
Use latestDepTestImplementation in build.gradle to pin the latest available version.
- Very specific: line 125
Add a smoke test in dd-smoke-tests/ only if the framework warrants a full end-to-end demo-app test.
- Distinctive: line 129
Run these commands in order and fix any failures before proceeding:
- Very specific: line 141
After updateAgentJarIntegrationsGoldenFile runs, commit the updated metadata/agent-jar-checks.properties file alongside your …
- Very specific: line 153
If tests fail: verify span lifecycle order (start → activate → error → close → finish), helper registration, and contextStore() map entries …
- Distinctive: line 183
After the instrumentation is complete (or abandoned), review the full session and improve this skill for future use.
- Distinctive: line 201
Keep each change minimal and targeted.
- Distinctive: line 202
After editing, confirm to the user which improvements were made to the skill.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Write a new APM end-to-end integration for dd-trace-java, based on library instrumentations, following all project conventions.
Step 1 – Read the authoritative docs and sync this skill (mandatory, always first)
Before writing any code, read all three files in full:
docs/how_instrumentations_work.md— full reference (types, methods, advice, helpers, context stores, decorators)docs/add_new_instrumentation.md— step-by-step walkthroughdocs/how_to_test.md— test types and how to run them
These files are the single source of truth. Reference them while implementing.
Step 2 – Clarify the task
If the user has not already provided all of the following, ask before proceeding:
- Framework name and minimum supported version (e.g.
okhttp-3.0) - Target class(es) and method(s) to instrument (fully qualified class names preferred)
- Target system: one of
Tracing,Profiling,AppSec,Iast,CiVisibility,Usm,ContextTracking - Whether this is a bootstrap instrumentation (affects allowed imports)
Step 3 – Find a reference instrumentation
Search dd-java-agent/instrumentation/ for a structurally similar integration:
- Same target system
- Comparable type-matching strategy (single type, hierarchy, known types)
Read the reference integration's InstrumenterModule, Advice, Decorator, and test files to understand the established
pattern before writing new code. Use it as a template.
Step 4 – Set up the module
- Create directory:
dd-java-agent/instrumentation/$framework/$framework-$minVersion/ - Under it, create the standard Maven source layout:
src/main/java/— instrumentation codesrc/test/groovy/(default) orsrc/test/java/if the module's master version and version-siblings are already on the Java/JUnit DSL — check them before creating this directory (see Step 9.1)
- Create
build.gradlewith:compileOnlydependencies for the target frameworktestImplementationdependencies for testsmuzzle { pass { } }directives (see Step 9.2)
- Register the new module in
settings.gradle.ktsin alphabetical order - Register all integration names in
metadata/supported-configurations.json— read Supported Configurations for the exact key shapes and CI checks involved. Declaring several names (super("a", "b")) means one entry each.
See Naming Conventions — module directory name must end with a version or an allowed suffix (-common, -stubs, -iast). Java filename and public class name MUST match character-for-character including acronym casing (CRITICAL — see § "Java naming consistency").
Step 4.1 – Span-creating vs context-tracking instrumentation
Read Context-Tracking Instrumentation and decide whether the library needs InstrumenterModule.Tracing (I/O operations that create spans) or InstrumenterModule.ContextTracking (async-boundary bridging, no spans).
If you picked ContextTracking: the same file's "Library-native context maps" section tells you whether the library needs a *ContextBridge-style helper (Reactor is the canonical example) in addition to the subscriber-wrapping pattern — read it before moving to Step 5. Its "Wrap placement" section covers where to allocate wrappers and context-store entries to avoid per-operator overhead on hot reactive paths.
Step 5 – Write the InstrumenterModule
Read InstrumenterModule Guidance. If you're editing an existing module rather than writing a new one, its "Editing an existing module" note applies — read the current file first and change only what the task requires.
Step 6 – Write the Decorator
- Extend the most specific available base decorator:
HttpClientDecorator,DatabaseClientDecorator,ServerDecorator,MessagingClientDecorator, etc.
- One
public static final DECORATEinstance - Define
UTF8BytesStringconstants for the component name and operation name - Keep all tag/naming/error logic here — not in the Advice class
- Override
spanType(),component(),spanKind()as appropriate - Override
instrumentationNames()to return the primary integration name without a version suffix:return new String[] {"jedis"};not"jedis-3.0". BaseDecoratoruses those names to resolve analytics settings (DD_TRACE_<NAME>_ANALYTICS_ENABLED,DD_TRACE_<NAME>_ANALYTICS_SAMPLE_RATE). Searchmetadata/supported-configurations.jsonfor each returned name — if analytics keys are absent, add them (see Supported Configurations for the JSON shape).
Step 7 – Write the Advice class (highest-risk step)
Read Writing the Advice Class — the highest-risk step. Pay particular attention to: @Advice.OnMethodEnter/Exit annotations; CallDepthThreadLocalMap reentrancy guarding; span lifecycle order; and the "Must NOT do" list. If the target wraps or delegates to another async client, its "Do not double-span async HTTP clients" section covers whether to open a second span or rely on context-propagation-only advice. If a returned CompletableFuture/CompletionStage needs a completion callback, see Context-Tracking Instrumentation's "Preserving cancellation" section for the read-only-return + named-callback pattern — do not reassign the future with future = future.whenComplete(...).
Step 8 – Add SETTER/GETTER adapters (if applicable)
For context propagation to and from upstream services, like HTTP headers,
implement AgentPropagation.Setter / AgentPropagation.Getter adapters that wrap the framework's specific header API.
Place them in the helpers package, declare them in helperClassNames().
Step 9 – Write tests
Cover all mandatory test types:
1. Instrumentation test (mandatory)
Read Writing Tests. Groovy/Spock (src/test/groovy/) is the default for instrumentation tests — add the tag: override groovy enforcement label to suppress the Enforce Groovy Migration CI check (which blocks new .groovy files by default). Match the sibling module's test DSL is the deciding factor: write your tests in src/test/groovy/ to match the master module and its version-siblings, UNLESS that family is already on the Java/JUnit DSL — do NOT introduce a src/test/java/** JUnit suite into a Groovy family, and do NOT copy the Java AbstractInstrumentationTest examples in references/tests.md (they illustrate style rules for modules already on the Java DSL, they are not a license to migrate a Groovy family to Java). Must cover error/exception scenarios. When adding new integration names, register them per Supported Configurations. When compileOnly and testImplementation use different versions, comment the specific class that requires the higher version. Include sibling version modules as testImplementation dependencies for mutual-exclusion tests.
2. Muzzle directives (mandatory)
Read Muzzle Directives — it covers all three valid patterns and their assertInverse rules. Search adjacent module build.gradle files for skipVersions before declaring a new version-bounded module's muzzle directives. If a prior-major-version sibling module already exists in the repo (e.g. you're writing rxjava-3.0 and rxjava-2.0 exists), add the "Namespace-isolation fail block" that section describes — it's not optional, it's how CI catches accidental cross-version advice matching.
3. Latest dependency test (mandatory)
If the library's API surface changes across minor versions (deprecated/removed methods, changed signatures), see Writing Tests's "Version-sensitive tests belong in a separate latestDepTest source set" section for which tests belong in src/test/ vs src/latestDepTest/.
Use latestDepTestImplementation in build.gradle to pin the latest available version. Run with:
./gradlew :dd-java-agent:instrumentation:$framework:$framework-$version:latestDepTestlatestDepTestImplementation version range must match the instrumented range. If your module instruments version 2.x, use 2.+ as the version constraint, not 3.+:
// WRONG — latestDep tests against 3.x but the module only instruments 2.x
latestDepTestImplementation group: 'commons-httpclient', name: 'commons-httpclient', version: '3.+'
// CORRECT — latestDep tests against the highest 2.x release
latestDepTestImplementation group: 'commons-httpclient', name: 'commons-httpclient', version: '2.+'Using 3.+ for a 2.x instrumentation means latestDepTest runs against an incompatible API version and will either fail or silently test nothing.
4. Smoke test (optional)
Add a smoke test in dd-smoke-tests/ only if the framework warrants a full end-to-end demo-app test.
Step 10 – Build and verify
Run these commands in order and fix any failures before proceeding:
./gradlew :dd-java-agent:instrumentation:$framework:$framework-$version:muzzle
./gradlew :dd-java-agent:instrumentation:$framework:$framework-$version:test
./gradlew :dd-java-agent:instrumentation:$framework:$framework-$version:latestDepTest
./gradlew checkInstrumenterModuleConfigurations
./gradlew checkDecoratorAnalyticsConfigurations
./gradlew spotlessApply
./gradlew :dd-java-agent:updateAgentJarIntegrationsGoldenFileAfter updateAgentJarIntegrationsGoldenFile runs, commit the updated metadata/agent-jar-checks.properties file alongside your instrumentation changes. The verifyAgentJarIntegrations check runs automatically in CI and fails if this file is out of date.
If muzzle fails:
- Missing helper class names in
helperClassNames()— the most common cause; add any missing inner, anonymous, or enum synthetic classes. - Wrong version range — the declared
versionsinbuild.gradledoesn't cover the versions actually used by tests; adjust the bounds. - API mismatch — the instrumented class or method doesn't exist in the declared version; check the library's changelog and narrow the
compileOnlyversion or the muzzle range.
If checkInstrumenterModuleConfigurations fails: an integration name from super(...) is missing
(or mismatched) in metadata/supported-configurations.json — see Supported Configurations.
If checkDecoratorAnalyticsConfigurations fails: a name returned by the decorator's instrumentationNames() is missing DD_TRACE_<NAME>_ANALYTICS_ENABLED / DD_TRACE_<NAME>_ANALYTICS_SAMPLE_RATE entries in metadata/supported-configurations.json — add them per Supported Configurations.
If tests fail: verify span lifecycle order (start → activate → error → close → finish), helper
registration, and contextStore() map entries match actual usage. If the output contains
Scope/continuation timeline, read and follow
.agents/skills/fix-continuation-leakage/SKILL.md; fix the broken ownership edge rather than
adding strictTraceWrites(false) or disabling the diagnostic.
Step 11 – Checklist before finishing
Output this checklist and confirm each item is satisfied:
settings.gradle.ktsentry added in alphabetical ordermetadata/supported-configurations.jsonhas aDD_TRACE_<NAME>_ENABLEDentry (+ the two aliases) for every name passed tosuper(...)metadata/supported-configurations.jsonhasDD_TRACE_<NAME>_ANALYTICS_ENABLEDandDD_TRACE_<NAME>_ANALYTICS_SAMPLE_RATEentries for every name returned by the decorator'sinstrumentationNames()build.gradlehascompileOnlydeps andmuzzledirectives- Muzzle pattern is correct (see Muzzle Directives)
latestDepTestImplementationversion range matches the instrumented version range (e.g.2+not3+for a2.xmodule)@AutoService(InstrumenterModule.class)annotation present on the module classhelperClassNames()lists ALL referenced helpers (including inner, anonymous, and enum synthetic classes)- Advice methods are
staticwith@Advice.OnMethodEnter/@Advice.OnMethodExitannotations @Advice.OnMethodEnter(suppress = Throwable.class)on enter;@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)on exit (omitonThrowablewhen hooking a constructor)- No static constants holding return values of one-shot instrumenter methods (
triggerClasses(),contextStore(), etc.) - No logger field in the Advice class or InstrumenterModule class
- No
inline=falseleft in production code - No
java.util.logging.*/java.nio.file.*/javax.management.*in bootstrap path metadata/agent-jar-checks.propertiesupdated via./gradlew :dd-java-agent:updateAgentJarIntegrationsGoldenFileand committed- Span lifecycle order is correct: startSpan → afterStart → activateSpan (enter); onError → beforeFinish → close → finish (exit)
- All Step 10 verification commands passed with no failures
Step 12 – Retrospective: update this skill with what was learned
After the instrumentation is complete (or abandoned), review the full session and improve this skill for future use.
Collect lessons from four sources:
- Build/test failures — did any Gradle task fail with an error that this skill did not anticipate or gave wrong guidance for? (e.g. a muzzle failure that wasn't caused by missing helpers, a test pattern that didn't work)
- Docs vs. skill gaps — did Step 1's sync miss anything? Did you consult the docs for something not captured here?
- Reference instrumentation insights — did the reference integration use a pattern, API, or convention not reflected in any step of this skill?
- User corrections — did the user correct an output, override a decision, or point out a mistake?
For each lesson identified, edit this file (.agents/skills/apm-integrations/SKILL.md) or its referenced files
using the Edit tool:
- Wrong rule → fix it in place
- Missing rule → add it to the most relevant step
- Wrong failure guidance → update the relevant "If X fails" section in Step 10
- Misleading or obsolete content → remove it
Keep each change minimal and targeted. Do not rewrite sections that worked correctly. After editing, confirm to the user which improvements were made to the skill.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

