Skip to content

feat: SAP performance statistics on HTTP client spans - #547

Merged
sjvans merged 5 commits into
cap-js:developfrom
kulliax:sap-statistics
Oct 27, 2026
Merged

sjvans merged 5 commits into
cap-js:developfrom
kulliax:sap-statistics

Conversation

@kulliax

@kulliax kulliax commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Enriches outgoing HTTP client spans with SAP performance statistics parsed from the response headers sap-statistics (Gateway/ICM/Web Dispatcher), sap-statistics-scc (Cloud Connector) and sap-statistics-hciodp (OData provisioning on BTP), which SAP systems return when a request asks for them (e.g. sap-statistics: true).

Original contribution by @kulliax; taken over and reworked by the maintainers (rebased onto develop, see notes below).

Configuration — opt-in, off by default

cds.requires.telemetry.tracing.sap_statistics:

  • unset / false — off (default)
  • true — on with the default mode (fields)
  • { "mode": "fields" } — one numeric attribute per field, e.g. sap.statistics.total = 42
  • { "mode": "raw" } — one string attribute per header, e.g. sap.statistics = "total=42,..."
  • { "mode": "both" } — raw and parsed

Coverage

Hooked into both @opentelemetry/instrumentation-http (http/https, e.g. the SAP Cloud SDK) and @opentelemetry/instrumentation-undici (fetch/undici). undici delivers headers as a raw Buffer[], so they are normalized to the shared object shape before parsing. A project-configured responseHook still runs afterwards.

Changes from the original PR

@kulliax
kulliax requested a review from a team as a code owner October 20, 2026 13:46
@sjvans
sjvans changed the base branch from main to develop October 20, 2026 13:58
@sjvans sjvans changed the title Sap statistics feat: SAP performance statistics on HTTP client spans Oct 26, 2026
sjvans and others added 3 commits October 27, 2026 23:21
Enrich outgoing HTTP client spans with SAP performance statistics parsed from
the sap-statistics, sap-statistics-scc and sap-statistics-hciodp response
headers. Hooked into both the http/https and undici instrumentations
(undici's raw Buffer[] headers are normalized to the shared object shape).

Opt-in and off by default: cds.requires.telemetry.tracing.sap_statistics
accepts `true` (enables the default `fields` mode) or `{ mode: 'fields' |
'raw' | 'both' }`.

Co-authored-by: ankul <116072312+kulliax@users.noreply.github.com>
…abled

- restrict recognized headers to an exact allowlist (sap-statistics,
  -scc, -hciodp) instead of a `sap-statistics` prefix match, so an
  untrusted server can't inject arbitrary high-cardinality attributes
- gate both the http and undici responseHooks on isSapStatisticsEnabled()
  so the disabled default path does no per-request work (notably the
  undici header-normalization allocation)
- document that the feature is unavailable under the SAP Cloud ALM agent,
  which owns the OTel SDK and its instrumentations
@sjvans
sjvans merged commit a8cdf6c into cap-js:develop Oct 27, 2026
5 checks passed
sjvans added a commit that referenced this pull request Oct 29, 2026
…568)

## What

Hoists the `isSapStatisticsEnabled()` gate out of the per-request
`responseHook` and up to instrumentation registration time in
`_getInstrumentations()`. Also promotes the `./tracing/sap_statistics`
import from a lazy in-loop `require` to a module-level one.

## Why

The `sap_statistics` config is static: `_getConfig()` reads
`cds.env.requires.telemetry?.tracing?.sap_statistics` once and memoizes
it, and `cds.env` doesn't change at runtime. So evaluating the gate once
while building the instrumentations is equivalent to the former
per-request check — registration already runs after env resolution (the
same function reads `cds.env.requires.telemetry.logging`
unconditionally).

Net effect:
- **Feature off (default):** the `responseHook` wrappers are no longer
installed at all — previously a wrapper ran on every HTTP client
response just to call the gate and return.
- **Feature on:** the per-request gate call is gone from the hot path;
the hook does its real work directly.

No behavior change for users — the feature already couldn't be toggled
after setup (memoized config), so taking the snapshot at registration
rather than first request is not a regression. Pure internal cleanup of
the beta feature added in #547, so no changelog entry.

## Test plan
- [ ] Existing `sap_statistics` tests pass (both `http` and `undici`
paths, all modes)
sjvans added a commit that referenced this pull request Oct 29, 2026
# Release: `v2.2.0`

Standing release PR — accumulates everything merged into `develop`.
Review and merge with a team member to satisfy the `main` review
requirement. Description kept current as PRs land on `develop`.

> Note: both `develop` and `main` are **squash-only** per repository
ruleset, so this PR is squash-merged at release time (a merge commit is
not permitted). `develop` therefore reads "behind `main`" by one squash
commit per prior release; the content diff is empty, so this divergence
is structural and benign.

> The OpenTelemetry 2/3 work (#564 parallel vs #567 3-only) is a
**separate strategic decision** and is **not** part of this 2.2.0
release — whichever is chosen ships in its own release (3.0.0 if #567).

### Changes so far

* **feat:** service bindings are now also read from the file referenced
by `VCAP_SERVICES_FILE_PATH` when set, taking precedence over
`VCAP_SERVICES` (Cloud Foundry file-based service bindings) (#538)
* **feat (beta):** opt-in enrichment of outgoing HTTP client spans with
SAP performance statistics from the `sap-statistics`,
`sap-statistics-scc` and `sap-statistics-hciodp` response headers, via
`cds.requires.telemetry.tracing.sap_statistics` (#547)
* **fix:** the per-tenant queue-stats poller is now self-healing — it
stops itself (and drops its metrics) when the tenant's database is gone,
and tolerates transient errors, instead of polling a deprovisioned
tenant forever; works regardless of multitenancy topology (#565)
* **fix(test):** pin vitest `--silent=true` so single-suite runs work
(#559)
* **chore(deps):** combined non-OpenTelemetry dependabot updates —
vitest, oxfmt, and security transitives (#557)
* `package.json` / `package-lock.json` / `CHANGELOG.md`: version →
`2.2.0`; `## Version 2.2.0` changelog skeleton opened (#548)

closes #545

---

compiled of:
- #548
- #557
- #538
- #559
- #547
- #565

> The queue-metrics fix originally landed as #561, was reverted (#566)
as incomplete, and re-landed as #565 (self-healing). #561/#566 cancel
out and are omitted above.

---------

Co-authored-by: I548646 <paul.erlenwein@sap.com>
Co-authored-by: Paul <paul.erlenwein@gmail.com>
Co-authored-by: ankul <116072312+kulliax@users.noreply.github.com>
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.

2 participants