Skip to main content

apm-integrations

Use when adding, debugging, fixing, or modifying instrumentation and plugins for third-party libraries in dd-trace-js. Triggers: "add a new integration", "instrument a library", any *Plugin base class (Tracing/Database/Cache/ Client/Server/Consumer/Producer/Composite), "addHook", "shimmer.wrap", "orchestrion", "bindStart"/"bindFinish", "diagnostic channel", "runStores", "subscriber cardinality", "channel.publish gate", "read upstream source", "reference plugin".

インストールへ移動

ソース情報

リポジトリ
DataDog/dd-trace-js
ソースの最終更新活動
2026年9月11日 17:03
検出された SKILL.md の言語
英語
スター
834
フォーク
407

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
6 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
apm-integrations
description
Use when adding, debugging, fixing, or modifying instrumentation and plugins for third-party libraries in dd-trace-js. Triggers: "add a new integration", "instrument a library", any *Plugin base class (Tracing/Database/Cache/ Client/Server/Consumer/Producer/Composite), "addHook", "shimmer.wrap", "orchestrion", "bindStart"/"bindFinish", "diagnostic channel", "runStores", "subscriber cardinality", "channel.publish gate", "read upstream source", "reference plugin".
# APM Integrations dd-trace-js provides automatic tracing for 100+ third-party libraries. Each integration consists of two decoupled layers communicating via Node.js diagnostic channels. ## Architecture ```text ┌──────────────────────────┐ diagnostic channels ┌─────────────────────────┐ │ Instrumentation │ ──────────────────────────▶ │ Plugin │ │ datadog-instrumentations │ apm:<name>:<op>:start │ datadog-plugin-<name> │ │ │ apm:<name>:<op>:finish │ │ │ Hooks into library │ apm:<name>:<op>:error │ Creates spans, sets │ │ methods, emits events │ │ tags, handles errors │ └──────────────────────────┘ └─────────────────────────┘ ``` `finish` above is the legacy manual-channel completion event. `tracingChannel` and Orchestrion use `end` / `asyncEnd`, as described below. **Instrumentation** (`packages/datadog-instrumentations/src/`): Hooks into a library's internals and publishes events with context data to named diagnostic channels. Has zero knowledge of tracing — only emits events. **Plugin** (`packages/datadog-plugin-<name>/src/`): Subscribes to diagnostic channel events and creates APM spans with service name, resource, tags, and error metadata. Extends a base class providing lifecycle management. Both layers are always needed for a new integration. ## Instrumentation: Orchestrion First **Orchestrion is the required default when the work exists as a source function.** It rewrites matched CJS/ESM source from JavaScript config, avoiding runtime monkey-patching and ESM's static-binding traps. Start there for top-level declarations, class/object methods, named expressions, and assignments to named receivers. Use shimmer only when the work is created entirely at runtime or the required argument/result mutation cannot happen from Orchestrion's subscriber lifecycle. Config lives in `packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/<name>.js`. See [Orchestrion Reference](references/orchestrion.md) for the full config format and examples. ### When Shimmer Is Necessary Instead Shimmer (`addHook` + `shimmer.wrap`) should **only** be used when orchestrion cannot handle the pattern. When using shimmer, **always include a code comment explaining why orchestrion is not viable.** Valid reasons: - **Dynamic method interception** — methods created at runtime or on prototype chains that orchestrion's static analysis cannot reach - **Factory results that cannot be substituted** — `end` can replace synchronous results and `asyncEnd` can replace native-Promise results; shimmer remains necessary for Promise subclasses, userland thenables, or APIs that require the original result's identity - **Pre-lifecycle argument modification** — arguments must be changed before Orchestrion's `bindStart` / subscribers can run If none of these apply, use orchestrion. For shimmer patterns, refer to existing shimmer-based instrumentations in the codebase (e.g., `packages/datadog-instrumentations/src/pg.js`). Always try to use Orchestrion when beginning a new integration! ## Plugin Base Classes Plugins extend a base class matching the library type. The base class provides automatic channel subscriptions, span lifecycle, and type-specific tags. ```text Plugin ├── CompositePlugin — Multiple sub-plugins (produce + consume) ├── LogPlugin — Log correlation injection (no spans) ├── WebPlugin — Base web plugin │ └── RouterPlugin — Web frameworks with middleware └── TracingPlugin — Base for all span-creating plugins ├── InboundPlugin — Inbound calls │ ├── ServerPlugin — HTTP servers │ └── ConsumerPlugin — Message consumers (DSM) └── OutboundPlugin — Outbound calls ├── ProducerPlugin — Message producers (DSM) └── ClientPlugin — HTTP/RPC clients └── StoragePlugin — Storage systems ├── DatabasePlugin — Database clients (DBM, db.* tags) └── CachePlugin — Key-value caches ``` **Wrong base class = complex workarounds.** Always match the library type to the base class. ## Read Upstream Source First Touching `packages/datadog-instrumentations/src/<lib>.js`, its plugin counterpart, or any orchestrion config — for any reason — read the upstream library's source first. Memory of an SDK's contract drifts faster than the SDK; comments in the wrap go stale every minor version; cross-version diffs surface contract changes guessing misses (lazy → eager attachment, mode-exclusive APIs, new error paths). Two ways to fetch the source locally: 1. **Shallow clone** the installed version: ```bash git clone --depth 1 --branch v<x.y.z> https://github.com/<org>/<repo>.git /tmp/<lib>-versions/v<x.y.z> ``` 1. **`npm pack`** when the published runtime artifact is what matters: ```bash cd /tmp/<lib>-versions && npm pack <lib>@<x.y.z> tar -xzf <lib>-<x.y.z>.tgz -C v<x.y.z> --strip-components=1 ``` Read the file the wrap hooks, the base classes the hooked methods inherit from, and files the wrap doesn't currently touch — a public method, an internal channel, or a metadata field the current instrumentation skipped often gives a cleaner hook (e.g., kafka `cluster.brokerPool.metadata.clusterId`, couchbase `tracingChannel`). ## Key Concepts ### The `ctx` Object Context flows from instrumentation to plugin: - **Orchestrion**: automatically provides `ctx.arguments` (method args) and `ctx.self` (instance) - **Shimmer**: instrumentation sets named properties (`ctx.sql`, `ctx.client`, etc.) - **Plugin sets**: `ctx.currentStore` (span), `ctx.parentStore` (parent span) - **On completion**: `ctx.result` or `ctx.error` ### Channel Event Lifecycle - `runStores()` for **start** events — establishes async context (always) - `publish()` for **completion/error** events — notification only - `hasSubscribers` guard — skip publish/subscriber work when no plugin listens; orchestrion still pays wrapper setup in current templates - When shimmer is necessary, prefer `tracingChannel` (from `dc-polyfill`) over manual channels — it provides `start/end/asyncStart/asyncEnd/error` events automatically ### Channel Prefix Patterns - **Orchestrion**: `tracing:orchestrion:<npm-package>:<channelName>` (set via `static prefix`) - **Shimmer + `tracingChannel`** (preferred): `tracing:apm:<name>:<operation>` (set via `static prefix`) - **Shimmer + manual channels** (legacy): `apm:{id}:{operation}` (default, no `static prefix` needed) ### `bindStart` and completion handlers Use `bindStart` to create the span and return its store. Finish in the event the instrumentation emits: usually `end` for synchronous work, `asyncEnd` for promises/callbacks, and `finish` only for legacy instrumentations that publish it. Orchestrion does not publish `finish`. ### Subscriber Cardinality (`channel.publish` position) When relocating a `channel.publish` call behind a dedupe gate, depth filter, cache-hit return, or any short-circuit, the question is not *"is the publish still there?"* but *"what cardinality does each downstream subscriber need?"*. Subscribers split into two camps that look identical from inside the publish site: - **Once per first occurrence** — tracing plugins that dedupe spans, distinct-path metrics. Safe behind a dedupe gate. - **Once per call** — IAST taint-tracking (mutates each call's `args` object by reference), AppSec WAF subscribers that block/log per invocation, anything walking payload identity. Drops data silently when cardinality falls below one-per-call. Before adding or moving a gate in front of a publish, grep the repo for the channel name, list its subscribers, decide per-subscriber whether the new position preserves the cardinality each needs. When cardinalities diverge, split the publish into a pre-gate (per-call) and a post-gate (per-first-occurrence) call. ## Reference Integrations **Always read 1-2 references of the same type before writing or modifying code.** | Library Type | Plugin | Instrumentation | Base Class | | --- | --- | --- | --- | | Database | `datadog-plugin-pg` | `src/pg.js` | `DatabasePlugin` | | Cache | `datadog-plugin-redis` | `src/redis.js` | `CachePlugin` | | HTTP client | `datadog-plugin-fetch` | `src/fetch.js` | `HttpClientPlugin` (extends `ClientPlugin`) | | Web framework | `datadog-plugin-express` | `src/express.js` | `RouterPlugin` | | Message queue | `datadog-plugin-kafkajs` | `src/kafkajs.js` | `Producer`/`ConsumerPlugin` | | Orchestrion | `datadog-plugin-langchain` | `rewriter/instrumentations/langchain.js` | `TracingPlugin` | For the complete list by base class, see [Reference Plugins](references/reference-plugins.md). ## Debugging - `DD_TRACE_DEBUG=true` to see channel activity - Log `Object.keys(ctx)` in `bindStart` to inspect available context - Spans missing → verify `hasSubscribers` guard; check channel names match between layers - Context lost → ensure `runStores()` (not `publish()`) for start events - ESM fails but CJS works → check `esmFirst: true` in hooks.js (or switch to orchestrion) ## Implementation Workflow Follow these steps when creating or modifying an integration: 1. **Investigate** — Read the upstream library's source (see [Read Upstream Source First](#read-upstream-source-first)). Read 1-2 reference integrations of the same type (see table above). Understand the instrumentation and plugin patterns before writing code. 2. **Implement instrumentation** — Create the instrumentation in `packages/datadog-instrumentations/src/`. Use orchestrion for instrumentation. 3. **Implement plugin** — Create the plugin in `packages/datadog-plugin-<name>/src/`. Extend the correct base class. 4. **Register** — Add entries in `packages/dd-trace/src/plugins/index.js`, every supported public TypeScript surface, `docs/test.ts`, `docs/API.md`, and `.github/workflows/apm-integrations.yml`. 5. **Write tests** — Add unit tests and ESM integration tests. See [Testing](references/testing.md) for templates. 6. **Run tests** — Validate with: ```bash # Run plugin tests (preferred CI command — handles yarn services automatically) PLUGINS="<name>" npm run test:plugins:ci # If the plugin needs external services (databases, message brokers, etc.), # check docker-compose.yml for available service names, then: docker compose up -d <service> SERVICES="<service>" PLUGINS="<name>" npm run test:plugins:ci ``` 7. **Verify** — Confirm all tests pass before marking work as complete. ## Reference Files - **[New Integration Guide](references/new-integration-guide.md)** — Step-by-step guide and checklist for creating a new integration end-to-end - **[Orchestrion Reference](references/orchestrion.md)** — JavaScript config format, channel naming, function kinds, plugin subscription - **[Plugin Patterns](references/plugin-patterns.md)** — `startSpan()` API, `ctx` object details, `CompositePlugin`, channel subscriptions, code style - **[Testing](references/testing.md)** — Unit test and ESM integration test templates - **[Reference Plugins](references/reference-plugins.md)** — All plugins organized by base class
GitHubで見る