Skip to content

[stash] switch to vitest#437

Draft
sjvans wants to merge 33 commits into
mainfrom
vitest
Draft

[stash] switch to vitest#437
sjvans wants to merge 33 commits into
mainfrom
vitest

Conversation

@sjvans

@sjvans sjvans commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Upgrade to OpenTelemetry SDK 2.0 and Switch to Vitest

Refactor

♻️ This PR upgrades all OpenTelemetry dependencies from SDK v1/v0.57 to SDK v2/v0.219, adapting the codebase to the breaking API changes introduced in OpenTelemetry SDK 2.0. The previously blocked warning about SDK 2.0 incompatibility has been removed now that the upgrade is complete.

Changes

  • package.json: Bumped all @opentelemetry/* dependencies to v2 (core, resources, sdk-metrics, sdk-trace-base, sdk-trace-node) and v0.219 (instrumentation packages), and updated exporter and host-metrics dev dependencies accordingly.
  • cds-plugin.js: Removed the version-check guard that blocked usage of OpenTelemetry SDK 2.0, along with the _version_of helper function.
  • README.md: Removed the warning about OpenTelemetry SDK 2.0 not being supported.
  • lib/utils.js: Replaced new Resource(attrs) with resourceFromAttributes(attrs) and switched from process.env.* to getStringFromEnv() for reading OTEL environment variables.
  • lib/tracing/index.js: Replaced deprecated getEnv/getEnvWithoutDefaults with getStringFromEnv, replaced new Resource({}) with resourceFromAttributes({}), and refactored NodeTracerProvider initialization to use the new spanProcessors constructor option instead of addSpanProcessor().
  • lib/tracing/trace.js: Updated span property access from instrumentationLibrary.name to instrumentationScope.name to match the SDK 2.0 API.
  • lib/metrics/index.js: Replaced deprecated APIs (new Resource, getEnv, getEnvWithoutDefaults, View, DropAggregation) with their SDK 2.0 equivalents (resourceFromAttributes, getStringFromEnv, object-based view config with AggregationType.DROP). Refactored MeterProvider initialization to use readers constructor option instead of addMetricReader().
  • lib/logging/index.js: Replaced getEnv/getEnvWithoutDefaults with getStringFromEnv, and refactored LoggerProvider initialization to use the processors constructor option.
  • lib/exporter/ConsoleSpanExporter.js: Updated span parent access from span.parentSpanId to span.parentSpanContext?.spanId to match the SDK 2.0 API.
  • lib/index.js: Added import of getStringFromEnv and diagLogLevelFromString from @opentelemetry/core.
  • .gitignore: Added .claude/ to the ignore list.
  • 🔄 Regenerate and Update Summary
PR Bot Information

Version: 1.26.5

  • File Content Strategy: Full file content
  • Output Template: Default Template
  • LLM: anthropic--claude-4.6-sonnet
  • Summary Prompt: Default Prompt
  • Event Trigger: pull_request.opened
  • Correlation ID: 0ff37167-2947-4247-8ed4-2d99b2aa4751

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

The PR correctly migrates to OpenTelemetry SDK 2.0 (updating APIs like ResourceresourceFromAttributes, parentSpanIdparentSpanContext?.spanId, instrumentationLibraryinstrumentationScope, and getEnv/getEnvWithoutDefaultsgetStringFromEnv), but introduces a few issues: a bug where spanProcessors: [undefined] is passed to NodeTracerProvider in the OneAgent path, misaligned indentation left over from the removed guard block in metrics, two typos, and an unguarded setGlobalLoggerProvider that could overwrite a provider set by another module.

PR Bot Information

Version: 1.26.5

  • Event Trigger: pull_request.opened
  • File Content Strategy: Full file content
  • LLM: anthropic--claude-4.6-sonnet
  • Correlation ID: 0ff37167-2947-4247-8ed4-2d99b2aa4751

Comment thread lib/tracing/index.js
// TODO: CALM may have initialized a global provider already

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, processor remains undefined, and spanProcessors: [processor] passes [undefined] to NodeTracerProvider. This would likely cause a runtime error or silent failure when the OneAgent path is taken.

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

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/metrics/index.js
Comment on lines +100 to +120
const dtmetadata = getDynatraceMetadata();
resource = resourceFromAttributes({}).merge(resource).merge(dtmetadata);
// unfortunately, we have to pass views to the MeterProvider constructor
// something like meterProvider.addView() would be a lot nicer for locality
let views = []
let views = [];
if (process.env.HOST_METRICS_RETAIN_SYSTEM) {
// nothing to do
} else {
views.push(
new View({
meterName: '@cap-js/telemetry:host-metrics',
instrumentName: 'system.*',
aggregation: new DropAggregation()
})
)
views.push({
meterName: "@cap-js/telemetry:host-metrics",
instrumentName: "system.*",
aggregation: {
type: AggregationType.DROP,
},
});
}
meterProvider = new MeterProvider({ resource, views })
metrics.setGlobalMeterProvider(meterProvider)
} else {
LOG._warn && LOG.warn('MeterProvider already initialized by a different module. It will be used as is.')
}

const metricsConfig = cds.env.requires.telemetry.metrics.config
const exporter = _getExporter()
// push vs. pull
if (typeof exporter.export === 'function') {
const metricReader = new PeriodicExportingMetricReader({ ...metricsConfig, exporter })
meterProvider.addMetricReader(metricReader)
} else {
meterProvider.addMetricReader(exporter)
}
// TODO: CALM may have initialized a global provider already

const meterProvider = new MeterProvider({ resource, readers: [exporter], views });
metrics.setGlobalMeterProvider(meterProvider);

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.

Logic Error: The indentation here is mismatched — lines 100–120 are indented as if inside a block, but they are actually at the top level of the module.exports function. While JS doesn't care about indentation, the metricsConfig variable (line 91) and exporter (line 92) are also at the outer level, making it clear the inner block was accidentally left indented. This is harmless but was likely a leftover from the removed if (meterProvider.constructor.name === 'NoopMeterProvider') block.

Suggested change
const dtmetadata = getDynatraceMetadata();
resource = resourceFromAttributes({}).merge(resource).merge(dtmetadata);
// unfortunately, we have to pass views to the MeterProvider constructor
// something like meterProvider.addView() would be a lot nicer for locality
let views = []
let views = [];
if (process.env.HOST_METRICS_RETAIN_SYSTEM) {
// nothing to do
} else {
views.push(
new View({
meterName: '@cap-js/telemetry:host-metrics',
instrumentName: 'system.*',
aggregation: new DropAggregation()
})
)
views.push({
meterName: "@cap-js/telemetry:host-metrics",
instrumentName: "system.*",
aggregation: {
type: AggregationType.DROP,
},
});
}
meterProvider = new MeterProvider({ resource, views })
metrics.setGlobalMeterProvider(meterProvider)
} else {
LOG._warn && LOG.warn('MeterProvider already initialized by a different module. It will be used as is.')
}
const metricsConfig = cds.env.requires.telemetry.metrics.config
const exporter = _getExporter()
// push vs. pull
if (typeof exporter.export === 'function') {
const metricReader = new PeriodicExportingMetricReader({ ...metricsConfig, exporter })
meterProvider.addMetricReader(metricReader)
} else {
meterProvider.addMetricReader(exporter)
}
// TODO: CALM may have initialized a global provider already
const meterProvider = new MeterProvider({ resource, readers: [exporter], views });
metrics.setGlobalMeterProvider(meterProvider);
const dtmetadata = getDynatraceMetadata()
resource = resourceFromAttributes({}).merge(resource).merge(dtmetadata)
// unfortunately, we have to pass views to the MeterProvider constructor
// something like meterProvider.addView() would be a lot nicer for locality
let views = []
if (process.env.HOST_METRICS_RETAIN_SYSTEM) {
// nothing to do
} else {
views.push({
meterName: "@cap-js/telemetry:host-metrics",
instrumentName: "system.*",
aggregation: {
type: AggregationType.DROP,
},
})
}
// TODO: CALM may have initialized a global provider already
const meterProvider = new MeterProvider({ resource, readers: [exporter], views })
metrics.setGlobalMeterProvider(meterProvider)

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/metrics/index.js
const config = { ...(metricsExporter.config || {}) }
config.temporalityPreference ??= AggregationTemporality.DELTA

// Augment configruation depending on 'kind' of telementry

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.

Typo: "configruation" → "configuration" and "telementry" → "telemetry".

Suggested change
// Augment configruation depending on 'kind' of telementry
// Augment configuration depending on 'kind' of telemetry

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/metrics/index.js

if (typeof exporter.export === 'function') {
// In case export is a function to be called by this runtime (push):
// > The exporter needs to be wrappeed thus, to set an export interval

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.

Typo: "wrappeed" → "wrapped".

Suggested change
// > The exporter needs to be wrappeed thus, to set an export interval
// > The exporter needs to be wrapped thus, to set an export interval

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/logging/index.js
// TODO: CALM may have initialized a global provider already

const loggerProvider = new LoggerProvider({ resource, processors: [logProcessor]})
logs.setGlobalLoggerProvider(loggerProvider)

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.

Logic Error: LoggerProvider was previously initialized only when no global provider existed. Now it unconditionally calls logs.setGlobalLoggerProvider(loggerProvider) without checking whether a provider has already been set. The TODO comment acknowledges this, but the removed guard was load-bearing — if CALM (or any other module) sets a global provider first, this will silently overwrite it.


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.

2 participants