Skip to main content

apm-integrations

Write a new library instrumentation end-to-end. Use when the user ask to add a new APM integration or a library instrumentation.

설치로 이동

소스 정보

저장소
DataDog/dd-trace-java
최근 소스 활동
2026년 9월 1일 13:06
감지된 SKILL.md 언어
영어
스타
737
포크
359

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
8 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
apm-integrations
description
Write a new library instrumentation end-to-end. Use when the user ask to add a new APM integration or a library instrumentation.
context
fork
allowed-tools
["Bash","Read","Write","Edit","Glob","Grep"]
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: 1. [`docs/how_instrumentations_work.md`](docs/how_instrumentations_work.md) — full reference (types, methods, advice, helpers, context stores, decorators) 2. [`docs/add_new_instrumentation.md`](docs/add_new_instrumentation.md) — step-by-step walkthrough 3. [`docs/how_to_test.md`](docs/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 1. Create directory: `dd-java-agent/instrumentation/$framework/$framework-$minVersion/` 2. Under it, create the standard Maven source layout: - `src/main/java/` — instrumentation code - `src/test/groovy/` (default) or `src/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) 3. Create `build.gradle` with: - `compileOnly` dependencies for the target framework - `testImplementation` dependencies for tests - `muzzle { pass { } }` directives (see Step 9.2) 4. Register the new module in `settings.gradle.kts` in **alphabetical order** 5. Register all integration names in `metadata/supported-configurations.json` — **read [Supported Configurations](references/supported-configurations.md)** for the exact key shapes and CI checks involved. Declaring several names (`super("a", "b")`) means one entry each. **See [Naming Conventions](references/naming-conventions.md) — 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](references/context-tracking.md) 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](references/instrumenter-module.md).** 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 DECORATE` instance - Define `UTF8BytesString` constants 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"`. - `BaseDecorator` uses those names to resolve analytics settings (`DD_TRACE_<NAME>_ANALYTICS_ENABLED`, `DD_TRACE_<NAME>_ANALYTICS_SAMPLE_RATE`). Search `metadata/supported-configurations.json` for each returned name — if analytics keys are absent, add them (see [Supported Configurations](references/supported-configurations.md) for the JSON shape). ## Step 7 – Write the Advice class (highest-risk step) **Read [Writing the Advice Class](references/advice-class.md) — 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](references/context-tracking.md)'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](references/tests.md).** 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](references/supported-configurations.md). 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](references/muzzle.md)** — 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](references/tests.md)'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: ```bash ./gradlew :dd-java-agent:instrumentation:$framework:$framework-$version:latestDepTest ``` **`latestDepTestImplementation` version range must match the instrumented range.** If your module instruments version `2.x`, use `2.+` as the version constraint, not `3.+`: ```groovy // 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: ```bash ./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:updateAgentJarIntegrationsGoldenFile ``` After `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 `versions` in `build.gradle` doesn'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 `compileOnly` version or the muzzle range. **If `checkInstrumenterModuleConfigurations` fails:** an integration name from `super(...)` is missing (or mismatched) in `metadata/supported-configurations.json` — see [Supported Configurations](references/supported-configurations.md). **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](references/supported-configurations.md). **If tests fail:** verify span lifecycle order (start → activate → error → close → finish), helper registration, and `contextStore()` map entries match actual usage. ## Step 11 – Checklist before finishing Output this checklist and confirm each item is satisfied: - [ ] `settings.gradle.kts` entry added in alphabetical order - [ ] `metadata/supported-configurations.json` has a `DD_TRACE_<NAME>_ENABLED` entry (+ the two aliases) for every name passed to `super(...)` - [ ] `metadata/supported-configurations.json` has `DD_TRACE_<NAME>_ANALYTICS_ENABLED` and `DD_TRACE_<NAME>_ANALYTICS_SAMPLE_RATE` entries for every name returned by the decorator's `instrumentationNames()` - [ ] `build.gradle` has `compileOnly` deps and `muzzle` directives - [ ] Muzzle pattern is correct (see [Muzzle Directives](references/muzzle.md)) - [ ] `latestDepTestImplementation` version range matches the instrumented version range (e.g. `2+` not `3+` for a `2.x` module) - [ ] `@AutoService(InstrumenterModule.class)` annotation present on the module class - [ ] `helperClassNames()` lists ALL referenced helpers (including inner, anonymous, and enum synthetic classes) - [ ] Advice methods are `static` with `@Advice.OnMethodEnter` / `@Advice.OnMethodExit` annotations - [ ] `@Advice.OnMethodEnter(suppress = Throwable.class)` on enter; `@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)` on exit (omit `onThrowable` when 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=false` left in production code - [ ] No `java.util.logging.*` / `java.nio.file.*` / `javax.management.*` in bootstrap path - [ ] `metadata/agent-jar-checks.properties` updated via `./gradlew :dd-java-agent:updateAgentJarIntegrationsGoldenFile` and 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:** 1. **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) 2. **Docs vs. skill gaps** — did Step 1's sync miss anything? Did you consult the docs for something not captured here? 3. **Reference instrumentation insights** — did the reference integration use a pattern, API, or convention not reflected in any step of this skill? 4. **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.
GitHub에서 보기