Skip to content

[stash] improve tracing#450

Draft
sjvans wants to merge 19 commits into
mainfrom
tracing-and-exporting
Draft

[stash] improve tracing#450
sjvans wants to merge 19 commits into
mainfrom
tracing-and-exporting

Conversation

@sjvans

@sjvans sjvans commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Upgrade to OpenTelemetry SDK 2.0 and @sap/cds^10 (v2.0.0)

New Feature / Refactor

✨ This is a major version bump (1.x → 2.0.0) of @cap-js/telemetry, bringing full support for OpenTelemetry SDK 2.0, @sap/cds^10, and significantly improved tracing coverage — especially for CAP's persistent outbox/queue worker path and CALM (@sap/xotel-agent-ext-js) integration.

Key highlights:

  • OTel SDK 2.0 support: Updated all @opentelemetry/* dependencies to ^2.x / latest ^0.219 instrumentation packages. Removed the previous SDK 2.0 compatibility check/block.
  • @opentelemetry/instrumentation-undici added as a default instrumentation.
  • @opentelemetry/instrumentation-host-metrics replaces deprecated @opentelemetry/host-metrics. Host metric collection now uses the metricGroups config option to limit to ['process.cpu', 'process.memory'] by default.
  • CALM support: Tracing, metrics, and logging now detect @sap/xotel-agent-ext-js and add processors/readers/log processors as delegates to the CALM composite providers instead of initializing standalone providers.
  • cds.tx(fn) wrapping: The telemetry plugin now wraps cds.Service.prototype.tx so that transactional units of work (queue worker transactions) appear as proper root spans under a single cds.spawn - run task root, instead of each top-level call becoming an orphan root.
  • Improved ConsoleSpanExporter: Indent state is no longer mutated on ReadableSpan instances; it is threaded through the recursive _list2tree traversal. Span parent lookup now uses parentSpanContext?.spanId (OTel SDK 2.0 API). Time formatting now uses toFixed(2) (rounds) instead of string truncation.
  • Clearer error messages: Credential-not-found errors for Dynatrace and SAP Cloud Logging now hint at the required service tag.
  • SAP Passport clearing for HANA moved to earlier in the tracing setup flow.
  • getEnvWithoutDefaults/getEnv replaced throughout with getStringFromEnv (SDK 2.0 API).
  • new Resource() replaced with resourceFromAttributes() (SDK 2.0 API).
  • Drop of @sap/cds^8 peer dependency support.

Changes

  • package.json / CHANGELOG.md: Bump to v2.0.0; update all OTel dependencies to SDK 2.0 versions; add undici instrumentation; update peer dependency to @sap/cds^10; expand vcap binding config to match both label and tag for Dynatrace and Cloud Logging.
  • cds-plugin.js: Added workaround for cds build command triggering telemetry; removed the SDK 2.0 compatibility version check (now supported).
  • lib/index.js: Split into setup_standalone and setup_with_calm paths; added automatic detection and configuration of @opentelemetry/instrumentation-host-metrics via metricGroups.
  • lib/tracing/index.js: Refactored to support CALM delegate pattern; moved SAP Passport clearing; updated to resourceFromAttributes and getStringFromEnv; improved error messages.
  • lib/tracing/cds.js: Added cds.Service.prototype.tx wrapping to properly scope queue-worker transactions as child spans under the cds.spawn - run task root.
  • lib/tracing/trace.js: Updated instrumentationScope.name check (was instrumentationLibrary.name).
  • lib/metrics/index.js: Refactored to support CALM delegate pattern; removed View/DropAggregation (superseded by metricGroups); updated to resourceFromAttributes.
  • lib/metrics/host.js: Removed (host metrics now handled via instrumentation-host-metrics config in lib/index.js).
  • lib/logging/index.js: Refactored provider initialization order (log interception registered before provider setup); added CALM delegate support; updated to getStringFromEnv.
  • lib/exporter/ConsoleSpanExporter.js: Fixed span mutation (indent carried in traversal, not on span object); fixed parentSpanContext?.spanId usage; improved time formatting; updated parent detection for root spans.
  • lib/exporter/ConsoleMetricExporter.js: Updated scope name match for @opentelemetry/instrumentation-host-metrics.
  • lib/utils.js: Updated to resourceFromAttributes, getStringFromEnv; improved legacy compatibility comments for Dynatrace and Cloud Logging UPS bindings.
  • README.md: Removed SDK 2.0 warning banner; updated host metrics docs; added undici instrumentation to defaults; added Cloud Logging UPS tag guidance.
  • Tests: Replaced all console-spy / regex-on-log-output patterns with a new MyInMemorySpanExporter that collects ReadableSpan objects directly. Added new test files for persistent outbox, scheduled tasks, outboxed batch fan-out, inbox/outbox combinations, and a ConsoleSpanExporter unit test. Replaced fixed wait(N) sleeps in metrics tests with expectEventually() polling helpers. Moved profile configs from inline process.env overrides to .cdsrc.json profiles.
  • 🔄 Regenerate and Update Summary
PR Bot Information

Version: 1.26.14

  • Output Template: Default Template
  • Event Trigger: pull_request.opened
  • LLM: anthropic--claude-4.6-sonnet
  • Correlation ID: d1ff2bc0-76e7-11f1-96e3-e8ee43c0a9a4
  • File Content Strategy: Full file content
  • Summary Prompt: Default Prompt

sjvans and others added 19 commits June 25, 2026 21:08
Adds HTTP semantic convention attributes to remote service spans by
wrapping `fetchClient.executeHttpRequest`.

Alternative considered: Using `@opentelemetry/instrumentation-undici`
response hooks to propagate attributes from HTTP child spans. This
approach was rejected as it requires an additional dependency and
creates duplicate spans.

---------

Co-authored-by: D050513 <sebastian.van.syckel@sap.com>
Co-authored-by: sjvans <30337871+sjvans@users.noreply.github.com>
- [x] traces
- [x] metrics
- [x] logs
- [x] #442

---------

Co-authored-by: I548646 <paul.erlenwein@sap.com>
Co-authored-by: Paul <paul.erlenwein@gmail.com>
)

# Improve `VCAP_SERVICES` Service Binding Resolution with Greedy
Matchers

### Chore

🔧 Updated service instance matching for SAP Cloud Logging and Dynatrace
to use greedy (array-based) VCAP matchers, extending the default
matching without breaking existing behavior. Error messages and
documentation have been updated to guide users toward the correct
configuration.

### Changes

* `package.json`: Updated `vcap` matching for `telemetry-to-dynatrace`
and `telemetry-to-cloud-logging` from a single object to an array of
matchers. Dynatrace now matches by `label: "dynatrace"` or `tag:
"dynatrace"`; Cloud Logging matches by `label: "cloud-logging"` or `tag:
"Cloud Logging"`.

* `lib/utils.js`: Improved inline comments to clearly document the
legacy compatibility behavior for `getCredsForDTAsUPS()` and
`getCredsForCLSAsUPS()`. Updated the warning message for Cloud Logging
user-provided services to recommend only the `"Cloud Logging"` tag
(dropped `"cloud-logging"` from the recommendation).

* `lib/logging/index.js`, `lib/metrics/index.js`,
`lib/tracing/index.js`: Improved error messages when credentials are not
found — now explicitly instruct users to ensure the bound service
instance uses the correct tag (`"Cloud Logging"` or `"dynatrace"`).

* `README.md`: Clarified that user-provided service instances for SAP
Cloud Logging must use the tag `"Cloud Logging"` (removed reference to
the legacy `cloud-logging` tag). Added a tip with the `cf
update-user-provided-service` command and a link to CAP's service
binding documentation.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.5`

- Correlation ID: `81bbd7c7-2290-4812-89e9-d178ac318c25`
- Event Trigger: `issue_comment.edited`
</details>

---------

Co-authored-by: sjvans <30337871+sjvans@users.noreply.github.com>
# Fix: Workaround for `cds.cli.command` Bug with `build` Command

### Bug Fix

🐛 Added a workaround to prevent the telemetry plugin from loading when
the `cds build` command is invoked. Due to a bug in `cds.cli.command`,
the `build` command incorrectly resolves to an empty string (`''`),
causing the plugin initialization check to pass unintentionally.

### Changes

* `cds-plugin.js`: Added an early return guard that checks if `build` is
present in `process.argv`. This ensures the plugin exits before
proceeding with initialization when the `cds build` command is used,
mirroring the existing workaround for `cds add`.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.5`

- Correlation ID: `4743ca7e-193a-4675-a529-8872b09ede9e`
- Summary Prompt: [Default
Prompt](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_instructions_prompt.md)
- LLM: `anthropic--claude-4.6-sonnet`
- Output Template: [Default
Template](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_default_output_template.md)
- Event Trigger: `pull_request.ready_for_review`
- File Content Strategy: Full file content
</details>

---------

Co-authored-by: hyperspace-insights[bot] <209611008+hyperspace-insights[bot]@users.noreply.github.com>
# Chore: Upgrade to `cds^10` — Migrate Test Config to `.cdsrc.json` and
CDS Profiles

### Refactor

♻️ Migrates test configuration from inline `process.env` overrides to a
dedicated `.cdsrc.json` file and CDS CLI profiles, aligning with the
`cds^10` approach for environment/profile-based configuration. Also
includes test timing optimizations and minor bug fixes.

### Changes

* `.github/workflows/ci.yml`: Commented out the `cds@8` downgrade step;
updated comment to reference `cds@9`.
* `.github/workflows/release.yml`: Added a `REVISIT` comment to remove
the `better-sqlite3` install workaround with `cds^10`.
* `.gitignore`: Removed `test/bookshop/.cdsrc.json` from the ignore list
so it can be tracked in version control.
* `test/bookshop/.cdsrc.json`: New file defining CDS profiles
(`logging`, `metrics`, `metrics-outbox`, `metrics-outbox-disabled`,
`tracing-attributes`, `persistent-outbox`, `without-outbox`)
consolidating telemetry, messaging, and metrics settings previously
scattered across test files.
* `test/bookshop/package.json`: Removed `_outbox` and profile-specific
`[metrics-outbox]`/`[metrics-outbox-disabled]` blocks (now in
`.cdsrc.json`); added `_scheduling: true`.
* `test/logging.test.js`: Removed inline `process.env` overrides for
telemetry/log format; switched to `cds.test(..., '--profile',
'logging')` with a minimal remaining env override for
`cls_custom_fields`.
* `test/metrics.test.js`: Removed `exportIntervalMillis` env override;
switched to `cds.test(..., '--profile', 'metrics')`.
* `test/metrics-outbox.test.js` /
`test/metrics-outbox-multitenant.test.js`: Reduced metric collection
wait times from `300ms` to `150ms`; fixed retry loop bug where both
loops checked `E1` instead of `E1`/`E2` respectively.
* `test/tracing-attributes.test.js`: Removed inline exporter env var;
switched to `cds.test(..., '--profile', 'tracing-attributes')`.
* `test/tracing-messaging-persistent-outbox.test.js`: Renamed `CASE` to
`persistent-outbox`; simplified env setup; marked `describe` block as
`skip` pending vitest migration.
* `test/tracing-messaging-without-outbox.test.js`: Renamed `CASE` to
`without-outbox`; simplified env setup using `outboxed: false`.
* `test/tracing-messaging-with-in-memory-outbox.test.js`: Removed this
test file entirely.
* `test/tracing-messaging.js`: Switched from `cds.test().in(...)` to
`cds.test(..., '--profile', CASE)`.
* `test/tracing.test.js`: Switched from `cds.test().in(...)` to
`cds.test(...)`.

- [ ] 🔄 Regenerate and Update Summary



<details>
<summary>PR Bot Information</summary>

**Version:** `1.26.11`

- Summary Prompt: [Default
Prompt](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_instructions_prompt.md)
- Correlation ID: `14c5ae4d-4c97-4eff-a004-330c9fdcf2fe`
- Event Trigger: `pull_request.edited`
- File Content Strategy: Full file content
- Output Template: [Default
Template](https://github.tools.sap/intelligent-insights/i2-pull-request/blob/main/src/services/llm/prompts/summary_default_output_template.md)
- LLM: `anthropic--claude-4.6-sonnet`
</details>

@hyperspace-insights hyperspace-insights Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is a significant major version bump (1.x → 2.0) that upgrades the entire OpenTelemetry stack to SDK 2.0, adds CALM integration, refactors span/metric/log provider initialization, and substantially improves test quality. The core logic changes are well-structured, but there are a few concrete bugs to address: the via_one_agent path passes undefined as a span processor (in both standalone and CALM branches), the CALM setup path silently skips instrumentation registration, and the CI workflow references a non-existent actions/checkout@v6.0.3 version that will break CI.

PR Bot Information

Version: 1.26.14

  • Event Trigger: pull_request.opened
  • File Content Strategy: Full file content
  • Correlation ID: d1ff2bc0-76e7-11f1-96e3-e8ee43c0a9a4
  • LLM: anthropic--claude-4.6-sonnet

Comment thread lib/tracing/index.js
Comment on lines +176 to +180
if (!resource) {
LOG.warn("@sap/xotel-agent-ext-js found, adding @cap-js/telemetry's span processor as delegate")
try {
const { getCompositeSpanProcessor } = require('@sap/xotel-agent-ext-js')
getCompositeSpanProcessor().addDelegate(processor)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: When via_one_agent is true, processor remains undefined and is passed to getCompositeSpanProcessor().addDelegate(undefined) in the CALM path — this will likely throw or silently register a broken delegate.

Suggested change
if (!resource) {
LOG.warn("@sap/xotel-agent-ext-js found, adding @cap-js/telemetry's span processor as delegate")
try {
const { getCompositeSpanProcessor } = require('@sap/xotel-agent-ext-js')
getCompositeSpanProcessor().addDelegate(processor)
if (!resource) {
if (processor) {
LOG.warn("@sap/xotel-agent-ext-js found, adding @cap-js/telemetry's span processor as delegate")
try {
const { getCompositeSpanProcessor } = require('@sap/xotel-agent-ext-js')
getCompositeSpanProcessor().addDelegate(processor)
} catch (error) {
LOG.error('Failed to add span processor as delegate:', error)
throw error
}
}
return
}

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Comment thread lib/tracing/index.js
require('./cloud_sdk')()

resource = resourceFromAttributes({}).merge(resource).merge(getDynatraceMetadata())
const tracerProvider = new NodeTracerProvider({ resource, spanProcessors: [processor], sampler: _getSampler() })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: When via_one_agent is true in the standalone path, processor is undefined and passing it to new NodeTracerProvider({ spanProcessors: [undefined] }) will likely cause a runtime error or silently register a no-op processor.

Suggested change
const tracerProvider = new NodeTracerProvider({ resource, spanProcessors: [processor], sampler: _getSampler() })
resource = resourceFromAttributes({}).merge(resource).merge(getDynatraceMetadata())
const spanProcessors = processor ? [processor] : []
const tracerProvider = new NodeTracerProvider({ resource, spanProcessors, sampler: _getSampler() })
tracerProvider.register({ propagator: _getPropagator() })
return tracerProvider

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Comment thread lib/index.js
Comment on lines +113 to +118
function setup_with_calm() {
// setup tracing, metrics, and logging
tracing()
metrics()
if (cds.env.requires.telemetry.logging) logging()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: setup_with_calm calls tracing(), metrics(), and logging() without registering instrumentations via registerInstrumentations. In setup_standalone, instrumentations are explicitly registered after the providers are set up. The CALM path silently skips all instrumentations (e.g., HttpInstrumentation, UndiciInstrumentation).


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Comment thread lib/metrics/index.js
const {
AggregationTemporality,
DropAggregation,
AggregationType,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: AggregationType is imported from @opentelemetry/sdk-metrics but never used anywhere in the file after the removal of DropAggregation — this is a stale import that should be removed.

Suggested change
AggregationType,
AggregationTemporality,
MeterProvider,
PeriodicExportingMetricReader

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Comment thread .github/workflows/ci.yml
# cds-version: [10, 9]
cds-version: [9]
steps:
- uses: actions/checkout@v6.0.3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The actions/checkout@v6.0.3 reference is invalid — the latest major release is v4. This will cause the workflow to fail with a "not found" error.

Suggested change
- uses: actions/checkout@v6.0.3
- uses: actions/checkout@v4

Double-check suggestion before committing. Edit this comment for amendments.


Please provide feedback on the review comment by checking the appropriate box:

  • 🌟 Awesome comment, a human might have missed that.
  • ✅ Helpful comment
  • 🤷 Neutral
  • ❌ This comment is not helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants