Skip to content

Commit 3356abc

Browse files
docs(configuration): pair threads.preload with preloadRequire for dd-trace (#644)
* docs(configuration): pair threads.preload with preloadRequire for dd-trace `dd-trace/register.js` only installs the ESM loader hooks; it never calls `init()`. Configuring `threads.preload: dd-trace/register.js` alone therefore leaves the tracer uninitialized - spans are created and carry plausible trace ids, but they are no-ops and nothing is exported, so the failure is silent. `dd-trace/init` (`threads.preloadRequire`) is the entry that starts the tracer. Replace the claim that `dd-trace/init` "only covers the main thread", show both keys together in the dd-trace example, and cross-reference the two bullets. Behavior is scoped to dd-trace 6.x, since a future major could change `register.js`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(configuration): make every dd-trace preload example viable The multi-module `threads.preload` example still listed `dd-trace/register.js` under `preload` alone, which reproduces the exact inert-tracer footgun the single-module example was corrected for: anyone copying it gets a worker whose tracer is never initialized and which exports no traces. Add `preloadRequire: dd-trace/init` to that example too. Also record why `dd-trace/initialize.mjs` is not the simpler single-entry alternative it looks like. On dd-trace 6.x it gates both its `init()` call and its `Module.register()` of the loader hook behind `isMainThread`, and its exported `load`/`resolve` hooks only take effect under `--loader`. Harper preloads via `--import` in a worker's `execArgv`, so on a worker thread that entry starts nothing and registers nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(configuration): make threads.preload guidance agent-neutral The preload/preloadRequire bullets described a specific dd-trace pairing as if it were a Harper-validated recipe. Reading dd-trace's entry points establishes what those entries do; it does not establish that Harper's worker execArgv composition exports spans with usable trace context and clean shutdown. Rather than build a Harper end-to-end validation for this, the guidance is now agent-neutral and dd-trace is described as unverified: - Both bullets explain the general mechanism - preload uses --import (ESM, loader hooks), preloadRequire uses --require (CommonJS, runs the module body) - and note that which entry point does which is agent-specific. - dd-trace stays as an illustration of the split-entry case, behind an explicit warning that the values are not a Harper-validated APM configuration and that the specifics are only what dd-trace's own entries do as observed in 6.x. Readers are told to confirm spans arrive at their own collector. - The register.js-does-not-call-init() pairing detail is kept, scoped as a dd-trace observation. - Harper facts are unchanged: bare-specifier resolution against installed components' node_modules, absolute paths accepted, worker threads only, not under Bun. Both dd-trace examples on the page carry the same framing and comments. Closes #625 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(configuration): split the preload guidance into short bullets plus prose The preload and preloadRequire bullets had grown to a paragraph each, sitting in a list whose other entries are one-liners. Trim both to a sentence and move the mechanism -- --import for loader hooks, --require for initialization, and why an agent may need both -- into prose under a new heading. Drop the warning framing around the dd-trace example. The observed 6.x behavior is stated as what dd-trace does, with a closing reminder to check the agent's own docs and confirm spans reach the collector, rather than a block declaring the values unvalidated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent d895f42 commit 3356abc

1 file changed

Lines changed: 25 additions & 9 deletions

File tree

reference/configuration/options.md

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,28 +65,44 @@ threads:
6565
- `maxHeapMemory` — Heap limit per thread (MB)
6666
- `heapSnapshotNearLimit` — Write a `.heapsnapshot` file when a thread nears its heap limit (loadable in Chrome DevTools Memory tab); _Default_: `false`. See [Worker Thread Debugging](./debugging.md#heap-snapshots-near-the-limit)
6767
- `debug` — Enable Node.js inspector; sub-options: `port`, `startingPort`, `host`, `waitForDebugger`. See [Worker Thread Debugging](./debugging.md)
68-
- `preload` <VersionBadge version="v5.2.0" /> — Module, or list of modules, to load (via Node's `--import`) before any Harper or application module on each worker thread. Intended for instrumentation/APM agents that must load first to instrument subsequent module loads. Use the agent's ESM/register entry — e.g. `dd-trace/register.js`, which registers the loader hooks that instrument worker threads (where Harper runs its work); the plain `dd-trace/init` (`--require`) entry only covers the main thread. Bare specifiers resolve against the `node_modules` of your installed [components](../components/overview.md) — so the agent can be shipped as a dependency of a deployed component — and absolute paths are also accepted. Applies to worker threads only (not under Bun).
68+
- `preload` <VersionBadge version="v5.2.0" /> — Module, or list of modules, to load via Node's `--import` before any Harper or application module on each worker thread. Intended for instrumentation and APM agents. Worker threads only (not under Bun).
69+
- `preloadRequire` <VersionBadge version="v5.2.0" /> — The same, but via Node's `--require` (CommonJS). Worker threads only (not under Bun).
70+
71+
### Preloading an instrumentation agent
72+
73+
An APM or instrumentation agent has to load before the code it instruments. These two keys put a module on each worker thread's startup, ahead of Harper's own modules and your application's.
74+
75+
The two keys differ in how the module is loaded, and that determines what it can do. `--import` evaluates the module as ESM, which is how an agent installs Node's module loader hooks so modules loaded later by `import` can be instrumented. `--require` runs the module's body, which is how an agent's initialization entry starts it.
76+
77+
Installing loader hooks and starting an agent are separate jobs, and which of an agent's entry points does which is specific to that agent. Some ship a single entry that does both; others split them across an `--import` entry and a `--require` entry. When they are split, set both keys.
78+
79+
Bare specifiers resolve against the `node_modules` of your installed [components](../components/overview.md), so an agent can ship as a dependency of a deployed component. Absolute paths also work.
80+
81+
Follow your agent's own documentation for worker-thread setup, and confirm the telemetry you expect actually reaches your collector.
82+
83+
#### Example: a split-entry agent
84+
85+
dd-trace is a split-entry agent, which makes it a useful illustration. On dd-trace 6.x, `dd-trace/register.js` installs the ESM loader hooks but never calls `init()`, so `preload` on its own leaves the tracer uninitialized — it still hands out spans with plausible trace ids, but they are no-ops and nothing is exported. `dd-trace/init` is the entry that calls `init()`. Setting both keys covers both jobs:
6986

7087
```yaml
7188
threads:
72-
preload: dd-trace/register.js
89+
preloadRequire: dd-trace/init # the entry that calls init()
90+
preload: dd-trace/register.js # ESM loader hooks for automatic instrumentation
7391
```
7492

75-
Or several modules:
93+
`dd-trace/initialize.mjs` looks like a single-entry shortcut around that pairing, but it is not one on a worker thread: it gates both its `init()` call and its loader-hook registration behind `isMainThread`, so under `--import` on a worker it starts nothing and registers nothing.
94+
95+
An agent that is one of several preloaded modules still needs its own pairing:
7696

7797
```yaml
7898
threads:
99+
preloadRequire: dd-trace/init # the entry that calls init()
79100
preload:
80101
- dd-trace/register.js
81102
- /opt/instrumentation/agent.mjs
82103
```
83104

84-
- `preloadRequire` <VersionBadge version="v5.2.0" /> — Same as `preload`, but loads modules via Node's `--require` (CommonJS) instead of `--import`. Use this for agents that document the `--require` path and do not need ESM loader hooks (e.g. `dd-trace/init`, Dynatrace OneAgent). Same resolution rules as `preload`.
85-
86-
```yaml
87-
threads:
88-
preloadRequire: dd-trace/init
89-
```
105+
The dd-trace behavior described here was observed on 6.x. Check your agent's current documentation, and confirm your spans arrive at your collector.
90106

91107
---
92108

0 commit comments

Comments
 (0)