Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 18, 2025

Vitest now automatically propagates OpenTelemetry trace context from parent processes via TRACEPARENT and TRACESTATE environment variables. This follows standard and enables integrating trace with some known instrumented CI/CD pipelines (e.g., Dagger).

Example

Tested with https://github.com/dagger/dagger

cd examples/opentelemetry
dagger run pnpm test run --experimental.openTelemetry.enabled
image
Original prompt

support TRACEPARENT and TRACESTATE environment variable as discussed in

Inject traceparent when using Vitest with OTEL
Vasek - Tom C.
OP
— 1:50 AM
Hello!

I saw that you guys have a Opentelemetry integration on Vitest.
Do you guys have a way to inject value directly in the Vitest OTEL test? Or maybe you are already injecting the trace parent if the env var exist?

The tests are running as part of a bigger process and I need to inject a trace parent fetched from an environment variable inside the context to get the correct order on the UI.

Essentially this require the usage of context.with, but I would like to do it before the test run, not inside.

(sorry for the double post, I noticed the help section after sending my first message)
Vasek - Tom C.
changed the post title: Injest traceparent when using Vitest with OTEL — 1:51 AM
Vasek - Tom C.
changed the post title: Inject traceparent when using Vitest with OTEL — 1:51 AM
Vladimir

— 3:06 AM
Vitest OTEL context just inherits the parent context
Vasek - Tom C.
OP
— 6:10 AM
Yeah but is there a way to inject context directly from the configuration?
So I don't have to wrap the whole command inside a script to inject context the context.

I'm using dagger to call vitest and essentially dagger already sets a bunch of OTEL environment variable and a TRACEPARENT variable that must be set as parent context.

But from vite, inside my init script, I cannot set that variable in the context.

Here's my script otel.js script that I load inside the vitest.config.js file:

import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";

/**

  • Live span processor implementation.
  • It's a BatchSpanProcessor whose on_start calls on_end on the underlying
  • SpanProcessor in order to send live telemetry.
    */
    class LiveProcessor extends BatchSpanProcessor {
    onStart(_span, _parentContext) {
    this.onEnd(_span);
    }
    }

/**

  • Batch span processor scheduler delays.
  • We set to 100ms so it's almost live.
    */
    const NEARLY_IMMEDIATE = 100;
    const OTEL_TEST_RUNNER_SERVICE_NAME = "otel-typescript-test-runner";

const exporter = new OTLPTraceExporter();
const processor = new LiveProcessor(exporter, {
scheduledDelayMillis: NEARLY_IMMEDIATE,
});

const otelSDK = new NodeSDK({
serviceName: OTEL_TEST_RUNNER_SERVICE_NAME,
spanProcessors: [processor],
});

// how to set it as inside the parent context ?
// context.extract(context.active(), { traceparent: process.env.TRACEPARENT })
// process.env.TRACEPARENT

otelSDK.start();

export default otelSDK;

My work around would be to override the vitest API to propagate the context with the TRACEPARENT but that feels wrong
Hiroshi Ogawa — 9:44 AM
Do you have some doc about dagger? Maybe it explain how downstream tools should make use of TRACEPARENT (even by default?).
Hiroshi Ogawa — 6:45 PM
Untested but I'm thinking something like this might work:
import { NodeSDK, AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'
import { ROOT_CONTEXT, propagation } from "@opentelemetry/api"

const myRootContext = propagation.extract(
ROOT_CONTEXT,
{ traceparent: process.env.TRACEPARENT }
)

class MyContextManager extends AsyncLocalStorageContextManager {
active() {
const context = super.active()
if (context === ROOT_CONTEXT) {
return myRootContext
}
return context
}
}

const sdk = new NodeSDK({
serviceName: 'vitest',
contextManager: new MyContextManager(),

which seems fairly verbose, so it might be also reasonable to support TRACEPARENT out of the box if it's semi standard of some kind. Vitest probably just need to swap the root context for the first vitest.start span

return this._traces.$('vitest.start', async (startSpan) => {

Oh well, it looks like TRACEPARENT and TRACESTATE are indeed standardized https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/env-carriers.md
GitHub
opentelemetry-specification/specification/context/env-carriers.md a...
Specifications for OpenTelemetry. Contribute to open-telemetry/opentelemetry-specification development by creating an account on GitHub.
opentelemetry-specification/specification/context/env-carriers.md a...


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@netlify
Copy link

netlify bot commented Dec 18, 2025

Deploy Preview for vitest-dev ready!

Name Link
🔨 Latest commit 0a96b13
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/6944b166ccf3f8000876da61
😎 Deploy Preview https://deploy-preview-9295--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI changed the title [WIP] Support TRACEPARENT and TRACESTATE environment variable feat: support TRACEPARENT and TRACESTATE environment variables for OpenTelemetry context propagation Dec 18, 2025
Copilot AI requested a review from hi-ogawa December 18, 2025 10:16
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 19, 2025

@vitest/browser

npm i https://pkg.pr.new/@vitest/browser@9295

@vitest/browser-playwright

npm i https://pkg.pr.new/@vitest/browser-playwright@9295

@vitest/browser-preview

npm i https://pkg.pr.new/@vitest/browser-preview@9295

@vitest/browser-webdriverio

npm i https://pkg.pr.new/@vitest/browser-webdriverio@9295

@vitest/coverage-istanbul

npm i https://pkg.pr.new/@vitest/coverage-istanbul@9295

@vitest/coverage-v8

npm i https://pkg.pr.new/@vitest/coverage-v8@9295

@vitest/expect

npm i https://pkg.pr.new/@vitest/expect@9295

@vitest/mocker

npm i https://pkg.pr.new/@vitest/mocker@9295

@vitest/pretty-format

npm i https://pkg.pr.new/@vitest/pretty-format@9295

@vitest/runner

npm i https://pkg.pr.new/@vitest/runner@9295

@vitest/snapshot

npm i https://pkg.pr.new/@vitest/snapshot@9295

@vitest/spy

npm i https://pkg.pr.new/@vitest/spy@9295

@vitest/ui

npm i https://pkg.pr.new/@vitest/ui@9295

@vitest/utils

npm i https://pkg.pr.new/@vitest/utils@9295

vitest

npm i https://pkg.pr.new/vitest@9295

@vitest/web-worker

npm i https://pkg.pr.new/@vitest/web-worker@9295

@vitest/ws-client

npm i https://pkg.pr.new/@vitest/ws-client@9295

commit: 047f9f6

@hi-ogawa hi-ogawa marked this pull request as ready for review December 19, 2025 02:18
@TomChv
Copy link

TomChv commented Dec 19, 2025

💡 It's just a proposal, I think this shouldn't be done as part of the PR but maybe as a follow up or maybe I could help you with that?

Just a matter of visualisation but I think it could be quite neat to only trace by default the test suites/test and whatever span are created inside it.
The current traces produced by vitest looks more like something I would put behind a debug flag if I need to see the whole execution flow.

However, having access to a simple view of the tests traces by default would be quite nice in my opinion.

For example:

test("hello world", () => {
  expect(1 + 1).toBe(2);
});

describe("hello suite", () => {
  test("my cool test", () => {
    expect(1 + 1).toBe(2);
  });

  test("my amazing 2nd test", async () => {
    await tracer.startActiveSpan("embeded", async (span) => {
      expect(1 + 1).toBe(2);
      span.end();
    });
  });
});

Would produce traces like this:

- hello world
- hello suite
- --- my cool test
- --- my amazing 2nd test
- --- ---embeded

Right now, we have to navigate in a long list of span to access the tests and they are not named directly sadly

Screenshot 2025-12-19 at 12 06 41

@hi-ogawa
Copy link
Contributor

The current traces produced by vitest looks more like something I would put behind a debug flag if I need to see the whole execution flow.

Thanks for feedback. We might explore further, but at the moment, this is indeed targeted as performance debugging feature to visualize Vitest's inner working https://vitest.dev/guide/open-telemetry.html. Your use case would be more closer to reporter feature https://vitest.dev/guide/reporters.html and I don't think we'll adjust in that way from our side.

@sheremet-va
Copy link
Member

When I wrote the implementation, I wasn't sure how deep it should be. It was even more debuggier at one stage. Does dagger support filtering traces by name? I would expect the tool to control that, not Vitest.

@sheremet-va sheremet-va merged commit 876cb84 into main Dec 22, 2025
16 of 17 checks passed
@sheremet-va sheremet-va deleted the copilot/support-traceparent-tracestate-env branch December 22, 2025 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants