Skip to content

otel-thread-ctx: publish V8 + ObjectWrap layout constants for readers#375

Merged
szegedi merged 3 commits into
mainfrom
szegedi/otel-thread-ctx-nodejs-reader-attrs
Jul 17, 2026
Merged

otel-thread-ctx: publish V8 + ObjectWrap layout constants for readers#375
szegedi merged 3 commits into
mainfrom
szegedi/otel-thread-ctx-nodejs-reader-attrs

Conversation

@szegedi

@szegedi szegedi commented Jul 15, 2026

Copy link
Copy Markdown

Summary

Extends the OTEP-4719 process-context attributes published by getProcessContextAttributes with three new keys an out-of-process eBPF reader needs to walk from our TLS discovery struct all the way to the OTEP-4947 record:

  • threadlocal.native_wrap_fields_offsetsizeof(node::ObjectWrap). Given a CtxWrap* fetched via wrapped_object_offset, add this to reach CtxWrap::record_.
  • threadlocal.js_map_table_offset — offset within a V8 JSMap of the tagged pointer to its backing OrderedHashMap (0x18).
  • threadlocal.ordered_hash_map_header_size — size of the header preceding the element_count / deleted_element_count / n_buckets fields inside an OrderedHashMap (0x10).

Without these a reader would have to hardcode them and re-verify per V8 version. Keeping them in the addon puts one source of truth close to V8. The two V8 internal offsets aren't exposed in V8's public headers; the code comments cite the Node.js private V8 source paths (deps/v8/src/objects/{js-collection,ordered-hash-table}.h) so a future V8 layout change has a clear pointer to what to re-check.

Motivated by planning an eBPF Node.js schema reader on top of open-telemetry/opentelemetry-ebpf-profiler#1229; the parca-dev fork already has a similar walker that hardcodes these values in eBPF (native_custom_labels.h:304).

Test plan

  • Docker test suite (npm run test:docker) — 152 passing, no regressions.
  • The returns the expected shape test now asserts the three new keys are present with expected values and updates the sorted-keys list.

Extends the OTEP-4719 process-context attributes emitted by
getProcessContextAttributes with three new entries an out-of-process
eBPF reader needs to walk from our TLS discovery struct to the actual
OTEP-4947 record:

- threadlocal.native_wrap_fields_offset — sizeof(node::ObjectWrap).
  Given a pointer to a CtxWrap fetched via wrapped_object_offset, add
  this to reach CtxWrap::record_.

- threadlocal.js_map_table_offset — offset within a V8 JSMap object of
  the tagged pointer to its backing OrderedHashMap table
  (JSCollection::kTableOffset in V8, 0x18).

- threadlocal.ordered_hash_map_header_size — size of the header
  preceding the element_count / deleted_element_count / n_buckets
  fields inside an OrderedHashMap (0x10).

Without these, a reader implementing the Node.js schema would have to
hardcode them itself and re-verify them per V8 version. Keeping the
constants in the addon puts one source of truth close to V8. The two
V8 internal offsets are not exposed in V8's public headers
(v8-internal.h); they live in Node's private V8 tree
(deps/v8/src/objects/{js-collection,ordered-hash-table}.h) — we cite
those paths in the code comments so a future V8 layout change has a
clear pointer to what to re-check.

New non-Linux fallback values match the Linux ones (24 / 0x18 / 0x10);
the reader contract is Linux-only per the OTEP anyway, so this just
keeps the exported surface consistent in shape across platforms.
@github-actions

Copy link
Copy Markdown

Overall package size

Self size: 2.41 MB
Deduped: 3.11 MB
No deduping: 3.11 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | pprof-format | 2.2.2 | 500.53 kB | 500.53 kB | | source-map | 0.7.6 | 185.63 kB | 185.63 kB | | node-gyp-build | 4.8.4 | 13.86 kB | 13.86 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-datadog-us1-prod

This comment has been minimized.

nsavoire
nsavoire previously approved these changes Jul 16, 2026
@szegedi szegedi added the semver-minor Usually minor non-breaking improvements label Jul 16, 2026
The five layout-constant publications in OtelThreadCtx::Init were
each spelled out as an exports->Set(ctx, NewFromUtf8Literal(...),
Integer::New(...)).FromJust() block. Fold the shape into a
`publish_int` lambda and call it five times, sorted alphabetically by
exported name. NewFromUtf8 (with ToLocalChecked) replaces the
compile-time NewFromUtf8Literal since the lambda parameter can't be a
template-deduced string-literal reference; this runs at module init
only, so the runtime cost is negligible.
@szegedi
szegedi merged commit a692ed5 into main Jul 17, 2026
70 checks passed
@szegedi
szegedi deleted the szegedi/otel-thread-ctx-nodejs-reader-attrs branch July 17, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver-minor Usually minor non-breaking improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants