Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
815768d
chore(deps): bump the gh-actions-packages group across 2 directories …
dependabot[bot] Feb 18, 2026
3547497
chore: configure Datadog merge queue (#7561)
watson Feb 18, 2026
dc7383d
ci: fix Datadog merge queue config filename (#7561) (#7562)
watson Feb 18, 2026
f58fd3b
chore(cursor): add worktrees.json for worktree setup (#7563)
watson Feb 18, 2026
20b4d65
chore: add add-new-instrumentation agent skill (#7564)
watson Feb 18, 2026
5cc4de8
bump native appsec to 11.0.1 (#7566)
simon-id Feb 19, 2026
8d0159b
add packaging reminder to eslint conf (#7565)
simon-id Feb 19, 2026
5bdf1a3
test: enable --allow-uncaught in mocha runs (#7575)
watson Feb 19, 2026
0bee241
chore: clean up redundant co-owner entries in CODEOWNERS (#7574)
watson Feb 19, 2026
d8eab33
docs(cursor): clarify pr-body command instructions (#7552)
watson Feb 19, 2026
6eddbce
feat(dsm,dbm): add process tags support for enhanced trace correlatio…
tlhunter Feb 19, 2026
685fc1e
chore(test): Fix downstream request flaky test (#7578)
uurien Feb 20, 2026
000c409
jest: wrap outer hooks too (#7587)
juan-fernandez Feb 20, 2026
ed96545
chore(ci): enable workflows for merge queue (#7588)
watson Feb 20, 2026
e8202a2
chore: align editor config and simplify (#7551)
watson Feb 22, 2026
5a9e227
docs: remove redirect creation script (#7593)
tlhunter Feb 22, 2026
a12c68a
docs(debugger): correct captureTimeoutMs default to 15 (#7592)
watson Feb 22, 2026
75118d9
add integration skill (#7568)
wconti27 Feb 23, 2026
ffa90d1
chore(test): Fix cmd injection telemetry flaky tests (#7599)
uurien Feb 23, 2026
b17aaff
Update libdatadog-nodejs to 0.8.1 (#7525)
szegedi Feb 23, 2026
43b2ef8
fix(dsm): move dsm plugin init to start from bindStart (#7395)
robcarlan-datadog Feb 23, 2026
cd22239
[test optimization] Improve cypress - RUM integration (#7600)
juan-fernandez Feb 23, 2026
f42eb7d
v5.88.0
rochdev Feb 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions .agents/skills/apm-integrations/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
name: apm-integrations
description: |
This skill should be used when the user asks to "add a new integration",
"instrument a library", "add instrumentation for",
"create instrumentation", "new dd-trace integration",
"add tracing for", "TracingPlugin", "DatabasePlugin", "CachePlugin",
"ClientPlugin", "ServerPlugin", "CompositePlugin", "ConsumerPlugin",
"ProducerPlugin", "addHook", "shimmer.wrap", "orchestrion",
"bindStart", "bindFinish", "startSpan", "diagnostic channel",
"runStores", "reference plugin", "example plugin", "similar integration",
or needs to build, modify, or debug the instrumentation and plugin layers
for a third-party library in dd-trace-js.
---

# 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

```
┌──────────────────────────┐ 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 │
└──────────────────────────┘ └─────────────────────────┘
```

**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 for all new instrumentations.** It is an AST rewriter that automatically wraps methods via JSON configuration, with correct CJS and ESM handling built in. Orchestrion handles ESM code far more reliably than traditional shimmer-based wrapping, which struggles with ESM's static module structure.

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 patterns** — wrapping return values of factory functions
- **Argument modification** — instrumentations that need to mutate arguments before the original call

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.

```
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.

## 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 **finish/error** events — notification only
- `hasSubscribers` guard — skip instrumentation when no plugin listens (performance fast path)
- 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` / `bindFinish`
Primary plugin methods. Base classes handle most lifecycle; often only `bindStart` is needed to create the span and set tags.

## 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 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`, `index.d.ts`, `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>
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)** — JSON 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
Loading
Loading