Skip to content

feat(scope)!: scoped mode for setupOtel; remove OTEL_INSTRUMENT_FETCH - #11

Merged
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/fix-auto-instrument
Jun 30, 2026
Merged

feat(scope)!: scoped mode for setupOtel; remove OTEL_INSTRUMENT_FETCH#11
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/fix-auto-instrument

Conversation

@underthestars-zhy

@underthestars-zhy Ryan Zhu (underthestars-zhy) commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

  • Scoped / embeddable mode. A new register: false option on setupOtel() lets a library ship its own OpenTelemetry without taking over the host application's global providers. In scoped mode setupOtel() builds and holds its own tracer/logger providers (new internal src/scope.ts) instead of calling trace.setGlobalTracerProvider / logs.setGlobalLoggerProvider, and the top-level helpers (withSpan, createLogger, createInstrumentedFetch) resolve through the held providers — falling back to the global API when no scoped setup is active.
  • Host OTel is left untouched. The shared context manager and W3C propagator are still installed if absent (needed for span nesting and traceparent propagation), so spans nest across the library/host boundary and the host's setup is shared when it already installed one. Auto fetch instrumentation defaults off in scoped mode — wrapping globalThis.fetch is process-wide and native undici can only read the global provider — so trace a specific client with createInstrumentedFetch() instead.
  • The handle exposes the providers. OtelHandle now returns { shutdown(), tracerProvider, loggerProvider }, so embedders can build extra tracers or attach processors against the library's own providers.
  • 💥 BREAKING — OTEL_INSTRUMENT_FETCH removed. The env var introduced in 2.1.0 (feat(setup): add OTEL_INSTRUMENT_FETCH env var to toggle fetch tracing #10) is removed. It only toggled the process-global fetch wrap on/off and never addressed the provider-takeover problem that scoped mode now solves. Fetch instrumentation is still controlled by the setupOtel({ instrumentFetch }) option; per-client tracing via createInstrumentedFetch().

Usage

import { setupOtel, withSpan } from "@photon-ai/otel";

// A library embeds telemetry WITHOUT taking over the host app's global OTel:
const otel = setupOtel({ serviceName: "my-lib", register: false });

await withSpan("work", async () => {
  /* emits into the library's own providers; host globals untouched */
});

// Build extra tracers against the library's own provider if needed:
otel.tracerProvider.getTracer("my-lib.sub");

await otel.shutdown();

Changes

File Change
src/scope.ts New. Provider holder: setActiveProviders / clearActiveProviders, plus resolveTracer / resolveLogger that prefer the held provider and fall back to the global API. Resolved per call — no stale cache across setup/shutdown cycles.
src/setup.ts Add register?: boolean (default true). register: false skips setGlobalTracerProvider / setGlobalLoggerProvider, calls setActiveProviders, and defaults auto fetch off. OtelHandle now exposes tracerProvider / loggerProvider; shutdown() clears the holder. Removed parseBooleanEnv + the OTEL_INSTRUMENT_FETCH handling.
src/with-span.ts, src/logger.ts, src/instrument-fetch.ts Resolve the tracer/logger through resolveTracer / resolveLogger instead of a module-local memoized trace.getTracer() / logs.getLogger(), so scoped mode routes emissions to the held providers.
tests/scope.test.ts New (5). Holder routing, fallback-to-global after clear, no-stale-cache on provider swap, and withSpan nesting + createLogger correlation through the held providers.
tests/setup.scoped.test.ts New (4). register: false leaves the global tracer/logger untouched; default mode registers globally; scoped fetch defaults off even with an endpoint; explicit instrumentFetch in scoped mode uses the global wrap, never native undici.
tests/setup.test.ts Remove the OTEL_INSTRUMENT_FETCH env-var tests (feature removed); keep the both-strategies fetchInstrumentationActive helper.
README.md Add a Scoped mode section, update the setupOtel API row (handle shape + register: false), and remove the OTEL_INSTRUMENT_FETCH rows.
docs/*, .github/workflows/integration.yml, tests/integration/* Revert the OTEL_INSTRUMENT_FETCH docs, the CI build step, and the integration child/case added in #10.

Test plan

  • bun run test77 unit tests pass (9 new: scope.test.ts ×5, setup.scoped.test.ts ×4)
  • bun run build — tsdown ESM (24.07 kB) + DTS (9.88 kB) build succeeds
  • bun x ultracite check src tests — clean
  • bun run test:integration — real OTLP/HTTP round-trip; requires Docker, runs in CI

Notes

  • Rebased onto origin/main (2.1.0) so this is a single clean commit with no version downgrade. Removing the released OTEL_INSTRUMENT_FETCH env var is the breaking change; the commit carries a BREAKING CHANGE: footer so the release picks a major bump.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features

    • Added a new scoped mode for embedding the library without taking over global OpenTelemetry settings.
    • The returned setup handle now exposes tracer and logger providers in addition to shutdown.
  • Bug Fixes

    • Improved fetch and logging behavior so telemetry continues to work correctly in scoped and default setups.
    • Preserved span nesting and context propagation while avoiding duplicate or self-generated fetch tracing.

Add a scoped/embeddable mode to `setupOtel()` via a new `register: false`
option, backed by an internal provider holder (`src/scope.ts`). In scoped mode
the library builds and holds its own tracer/logger providers and routes
`withSpan` / `createLogger` / `createInstrumentedFetch` through them, leaving the
host app's global OpenTelemetry untouched. The shared context manager and W3C
propagator are still installed if absent (needed for span nesting and trace
propagation), and auto fetch instrumentation defaults off in scoped mode (it
wraps the process-global `fetch`). `OtelHandle` now also exposes
`tracerProvider` / `loggerProvider` so embedders can build extra tracers or
attach processors.

Remove the `OTEL_INSTRUMENT_FETCH` environment variable (shipped in 2.1.0). It
only toggled the process-global fetch wrap on/off and never addressed the
underlying provider-takeover problem that scoped mode now solves. Fetch
instrumentation is still controlled by the `setupOtel({ instrumentFetch })`
option, and individual clients can be traced with `createInstrumentedFetch()`.

BREAKING CHANGE: the OTEL_INSTRUMENT_FETCH environment variable is removed. Use
the `instrumentFetch` option to toggle fetch instrumentation, or `register:
false` for scoped mode.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new src/scope.ts module that holds TracerProvider/LoggerProvider instances and exposes resolveTracer/resolveLogger helpers with global fallback. setupOtel gains a register: false scoped mode that skips global OTel registration, routes library helpers through the held providers, and defaults fetch auto-instrumentation off. OTEL_INSTRUMENT_FETCH env-var support is removed throughout.

Changes

Scoped OTel provider mode and OTEL_INSTRUMENT_FETCH removal

Layer / File(s) Summary
New scope.ts provider holder
src/scope.ts
New module exporting setActiveProviders, clearActiveProviders, resolveTracer, and resolveLogger with fallback to OTel globals when no provider is held.
OtelHandle interface and setupOtel scoped mode wiring
src/setup.ts
OtelHandle gains loggerProvider; SetupOtelOptions gains register; parseBooleanEnv/OTEL_INSTRUMENT_FETCH removed; global tracer/logger registration and fetch auto-instrumentation are now conditional on register; setActiveProviders/clearActiveProviders called on setup/shutdown.
withSpan, instrument-fetch, logger use resolveTracer/resolveLogger
src/with-span.ts, src/instrument-fetch.ts, src/logger.ts
Module-level cached tracer/logger getters removed; each file now calls resolveTracer or resolveLogger at invocation time instead.
scope.ts and scoped-mode unit tests
tests/scope.test.ts, tests/setup.scoped.test.ts, tests/setup.test.ts
New suites verify provider routing, swap, clear/fallback, span-log correlation, register: false globals isolation, default global registration, and fetch instrumentation behavior in scoped mode; OTEL_INSTRUMENT_FETCH tests removed.
Integration tests and CI cleanup
tests/integration/otel-collector.test.ts, tests/integration/disabled-fetch.child.mjs, tests/integration/README.md, .github/workflows/integration.yml
Removes disabled-fetch child-process scenario, simplifies readSpans, removes CI build step, and updates integration README.
Docs and README updates
README.md, docs/configuration.mdx, docs/guides/fetch-instrumentation.mdx
Documents new OtelHandle shape and scoped mode; removes OTEL_INSTRUMENT_FETCH from env-var tables and fetch-instrumentation guide.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant setupOtel
  participant scope.ts
  participant withSpan/logger/fetch

  App->>setupOtel: setupOtel({ register: false, ... })
  setupOtel->>scope.ts: setActiveProviders({ tracerProvider, loggerProvider })
  Note over setupOtel: Skips trace.setGlobalTracerProvider()<br/>Skips logs.setGlobalLoggerProvider()<br/>Still installs context manager + W3C propagator

  App->>withSpan/logger/fetch: withSpan() / emit() / fetch()
  withSpan/logger/fetch->>scope.ts: resolveTracer() / resolveLogger()
  scope.ts-->>withSpan/logger/fetch: held provider's tracer/logger

  App->>setupOtel: handle.shutdown()
  setupOtel->>scope.ts: clearActiveProviders()
  Note over scope.ts: Future resolveTracer/resolveLogger<br/>fall back to OTel globals
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • photon-hq/otel#5: Directly overlaps — modifies setupOtel fetch auto-enable semantics and the end-to-end collector tests that this PR also rewrites.
  • photon-hq/otel#10: Added OTEL_INSTRUMENT_FETCH env-var support and disabled-fetch child test that this PR removes entirely.
  • photon-hq/otel#8: Modified the Node undici vs globalThis.fetch selection logic in src/setup.ts that this PR further conditions on the register flag.

Suggested labels

release

🐇 No more env-var to flip,
The scope now holds each provider's grip.
register: false—globals untouched,
Library helpers scoped, not clutched.
Hop hop, the rabbit ships clean code! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: scoped setupOtel mode and removal of OTEL_INSTRUMENT_FETCH.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ryan/fix-auto-instrument

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the release Fight on! label Jun 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/scope.ts (1)

22-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the exported scope mutators.

setActiveProviders and clearActiveProviders are part of the new exported surface, but only the resolver functions have contract comments right now. A short JSDoc block here would make the scoped-provider lifecycle much easier to use correctly. As per coding guidelines, "Include JSDoc comments for exported functions and classes".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scope.ts` around lines 22 - 33, Add JSDoc comments for the exported scope
mutators in scope.ts: document setActiveProviders and clearActiveProviders
alongside the existing resolver functions. Describe that setActiveProviders
stores the current TracerProvider and LoggerProvider for later retrieval, and
that clearActiveProviders resets that held state so the scope is empty again.
Keep the comments short and consistent with the contract style used by the other
exported functions.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 138-139: The README description for fetch instrumentation default
behavior is now misleading because it implies auto-on whenever a traces endpoint
is configured, but startFetchInstrumentation() only auto-enables that path when
register is true. Update the wording around the fetch instrumentation option to
explicitly distinguish scoped mode (register: false), which stays off by default
unless instrumentFetch is set, and keep the description consistent with the
behavior in startFetchInstrumentation().

In `@src/setup.ts`:
- Around line 89-97: The OtelHandle contract currently exposes loggerProvider
and tracerProvider as API interfaces even though the surrounding docs say
embedders should be able to attach processors; update the OtelHandle type in
setup.ts to either use the SDK provider types for these fields or adjust the
documentation to remove the processor-attachment guarantee. Use the existing
OtelHandle, loggerProvider, and tracerProvider symbols to locate the interface
and keep the public types aligned with the intended capabilities.

In `@tests/scope.test.ts`:
- Around line 1-20: Reset the global OpenTelemetry API state in this suite’s
teardown, not just the stored providers. Update the existing afterEach in
tests/scope.test.ts to mirror the cleanup used in tests/setup.scoped.test.ts by
unregistering/restoring the global context and tracer/logging registries
alongside clearActiveProviders, so resolveTracer, resolveLogger, and the
fallback case stay isolated across tests. Ensure the
AsyncLocalStorageContextManager installed for the suite is fully removed after
each test to prevent order-dependent behavior.

---

Nitpick comments:
In `@src/scope.ts`:
- Around line 22-33: Add JSDoc comments for the exported scope mutators in
scope.ts: document setActiveProviders and clearActiveProviders alongside the
existing resolver functions. Describe that setActiveProviders stores the current
TracerProvider and LoggerProvider for later retrieval, and that
clearActiveProviders resets that held state so the scope is empty again. Keep
the comments short and consistent with the contract style used by the other
exported functions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d2a6bd6-cc34-4a73-bf9f-ee77d04f5781

📥 Commits

Reviewing files that changed from the base of the PR and between 74ed619 and 1f66aee.

📒 Files selected for processing (15)
  • .github/workflows/integration.yml
  • README.md
  • docs/configuration.mdx
  • docs/guides/fetch-instrumentation.mdx
  • src/instrument-fetch.ts
  • src/logger.ts
  • src/scope.ts
  • src/setup.ts
  • src/with-span.ts
  • tests/integration/README.md
  • tests/integration/disabled-fetch.child.mjs
  • tests/integration/otel-collector.test.ts
  • tests/scope.test.ts
  • tests/setup.scoped.test.ts
  • tests/setup.test.ts
💤 Files with no reviewable changes (5)
  • tests/integration/disabled-fetch.child.mjs
  • .github/workflows/integration.yml
  • docs/guides/fetch-instrumentation.mdx
  • docs/configuration.mdx
  • tests/setup.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)

Prefer interface for defining object shapes in TypeScript rather than type aliases

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when the type is genuinely unknown
Use as const const assertions for immutable values and literal types
Leverage TypeScript type narrowing instead of type assertions
Use meaningful variable names instead of magic numbers; extract descriptive constants
Use arrow functions for callbacks and short functions
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, and never use var
Always await promises in async functions and use the return value
Use async/await syntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors

Files:

  • src/scope.ts
  • tests/setup.scoped.test.ts
  • tests/scope.test.ts
  • src/logger.ts
  • src/with-span.ts
  • src/instrument-fetch.ts
  • tests/integration/otel-collector.test.ts
  • src/setup.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variable and function names in JavaScript/TypeScript
Use PascalCase for class and component names in JavaScript/TypeScript
Always use async/await for promise handling instead of .then() chains
Include JSDoc comments for exported functions and classes
Use meaningful variable names that clearly describe their purpose
Avoid deeply nested conditionals; use early returns or guard clauses instead
Use const by default, let when reassignment is needed, avoid var

**/*.{js,jsx,ts,tsx}: Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks meaningfully; don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Keep functions focused and under reasonable cognitive complexity limits
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Group related code together and separate concerns
Add rel="noopener" when using target="_blank" on links
Avoid dangerouslySetInnerHTML unless absolutely necessary
Don't use eval() or assign directly to document.cookie
Validate and sanitize user input
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Avoid barrel files (index files that re-export everything)
Use proper image components (for example, Next.js <Image>) over <img> tags
Use next/head or the App Router metadata API for head elements
Use Server Components for async data fetching instead of async Client Components

Files:

  • src/scope.ts
  • tests/setup.scoped.test.ts
  • tests/scope.test.ts
  • src/logger.ts
  • src/with-span.ts
  • src/instrument-fetch.ts
  • tests/integration/otel-collector.test.ts
  • src/setup.ts
**/*.test.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)

Write unit tests for all public functions and components

Files:

  • tests/setup.scoped.test.ts
  • tests/scope.test.ts
  • tests/integration/otel-collector.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,jsx,ts,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests; use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat; avoid excessive describe nesting

Files:

  • tests/setup.scoped.test.ts
  • tests/scope.test.ts
  • tests/integration/otel-collector.test.ts
🪛 LanguageTool
README.md

[grammar] ~219-~219: Use a hyphen to join words.
Context: ...pans nest across the boundary). - Auto fetch instrumentation defaults off (wr...

(QB_NEW_EN_HYPHEN)

🔇 Additional comments (8)
tests/integration/otel-collector.test.ts (1)

157-185: LGTM!

tests/integration/README.md (1)

24-26: LGTM!

Also applies to: 48-52

README.md (1)

50-50: LGTM!

Also applies to: 115-116, 194-223

src/scope.ts (1)

35-53: LGTM!

src/with-span.ts (1)

1-4: LGTM!

Also applies to: 34-62

src/instrument-fetch.ts (1)

17-17: LGTM!

Also applies to: 194-230

src/logger.ts (1)

2-3: LGTM!

Also applies to: 124-124

src/setup.ts (1)

297-299: 🗄️ Data Integrity & Integration

No issue: keep setActiveProviders(...) unconditional. Scoped mode relies on the held providers so withSpan / createLogger / fetch instrumentation use the library-owned pipeline while host globals stay untouched; register: false is the coexistence path.

			> Likely an incorrect or invalid review comment.

Comment thread README.md
Comment on lines 138 to +139
- **`true` / `false`:** force on (even without an endpoint) / off. Defaults to on when a traces
endpoint is configured. The `OTEL_INSTRUMENT_FETCH` env var overrides this (`true`/`1` to force on,
`false`/`0` to disable) — toggle fetch tracing in production without a code change.
endpoint is configured.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the scoped-mode default here too.

Line 138 says fetch instrumentation defaults on whenever a traces endpoint is configured, but startFetchInstrumentation() only auto-enables that path when register is true; scoped mode (register: false) defaults off unless instrumentFetch is set explicitly. This line currently contradicts the new scoped-mode behavior described later in the README.

Suggested doc tweak
-- **`true` / `false`:** force on (even without an endpoint) / off. Defaults to on when a traces
-  endpoint is configured.
+- **`true` / `false`:** force on (even without an endpoint) / off. Defaults to on when a traces
+  endpoint is configured in the default app-level mode; scoped mode (`register: false`) defaults off.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **`true` / `false`:** force on (even without an endpoint) / off. Defaults to on when a traces
endpoint is configured. The `OTEL_INSTRUMENT_FETCH` env var overrides this (`true`/`1` to force on,
`false`/`0` to disable) — toggle fetch tracing in production without a code change.
endpoint is configured.
- **`true` / `false`:** force on (even without an endpoint) / off. Defaults to on when a traces
endpoint is configured in the default app-level mode; scoped mode (`register: false`) defaults off.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 138 - 139, The README description for fetch
instrumentation default behavior is now misleading because it implies auto-on
whenever a traces endpoint is configured, but startFetchInstrumentation() only
auto-enables that path when register is true. Update the wording around the
fetch instrumentation option to explicitly distinguish scoped mode (register:
false), which stays off by default unless instrumentFetch is set, and keep the
description consistent with the behavior in startFetchInstrumentation().

Comment thread src/setup.ts
Comment on lines +89 to +97
/** The logger provider this setup built (private in scoped mode). */
loggerProvider: LoggerProvider;
shutdown(): Promise<void>;
/**
* The tracer provider this setup built. In scoped mode it is the library's
* private provider (not the global one), so embedders can build extra tracers
* or attach processors against it.
*/
tracerProvider: TracerProvider;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the reviewed file around the reported lines.
wc -l src/setup.ts
sed -n '1,220p' src/setup.ts

# Find where OtelHandle is declared and how the provider types are imported.
rg -n "interface OtelHandle|type OtelHandle|loggerProvider|tracerProvider|setActiveProviders|register\\?" src/setup.ts

Repository: photon-hq/otel

Length of output: 8970


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the setup flow around provider creation and the public docs that describe OtelHandle.
sed -n '240,350p' src/setup.ts

printf '\n--- README / docs references ---\n'
rg -n "attach processors|extra tracers|OtelHandle|tracerProvider|loggerProvider|scoped mode|register: false" -S README.md src docs . || true

Repository: photon-hq/otel

Length of output: 12112


Expose the SDK provider types on OtelHandle
OtelHandle.tracerProvider / loggerProvider are typed as the API interfaces, but the docs promise embedders can attach processors. That capability isn’t available through these types without casting, so the public contract should either surface the SDK provider types here or narrow the docs to tracer/logger creation only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/setup.ts` around lines 89 - 97, The OtelHandle contract currently exposes
loggerProvider and tracerProvider as API interfaces even though the surrounding
docs say embedders should be able to attach processors; update the OtelHandle
type in setup.ts to either use the SDK provider types for these fields or adjust
the documentation to remove the processor-attachment guarantee. Use the existing
OtelHandle, loggerProvider, and tracerProvider symbols to locate the interface
and keep the public types aligned with the intended capabilities.

Comment thread tests/scope.test.ts
Comment on lines +1 to +20
import { context } from "@opentelemetry/api";
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
import {
InMemoryLogRecordExporter,
LoggerProvider,
SimpleLogRecordProcessor,
} from "@opentelemetry/sdk-logs";
import {
BasicTracerProvider,
InMemorySpanExporter,
SimpleSpanProcessor,
} from "@opentelemetry/sdk-trace-base";
import { afterEach, describe, expect, it } from "vitest";
import { createLogger } from "../src/logger";
import {
clearActiveProviders,
resolveLogger,
resolveTracer,
setActiveProviders,
} from "../src/scope";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Reset the global OTel APIs in this suite's teardown.

This file installs process-global state at Line 102 but only clears the held providers in afterEach(). That makes the fallback test at Lines 68-78 order-dependent and lets a failed assertion leave the AsyncLocalStorageContextManager behind for later tests. Mirror the teardown already used in tests/setup.scoped.test.ts so each case starts from a known OTel registry state.

Suggested fix
-import { context } from "`@opentelemetry/api`";
+import { context, propagation, trace } from "`@opentelemetry/api`";
+import { logs } from "`@opentelemetry/api-logs`";
 import { AsyncLocalStorageContextManager } from "`@opentelemetry/context-async-hooks`";
@@
   afterEach(() => {
     clearActiveProviders();
+    trace.disable();
+    logs.disable();
+    context.disable();
+    propagation.disable();
   });

Also applies to: 40-42

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/scope.test.ts` around lines 1 - 20, Reset the global OpenTelemetry API
state in this suite’s teardown, not just the stored providers. Update the
existing afterEach in tests/scope.test.ts to mirror the cleanup used in
tests/setup.scoped.test.ts by unregistering/restoring the global context and
tracer/logging registries alongside clearActiveProviders, so resolveTracer,
resolveLogger, and the fallback case stay isolated across tests. Ensure the
AsyncLocalStorageContextManager installed for the suite is fully removed after
each test to prevent order-dependent behavior.

@underthestars-zhy
Ryan Zhu (underthestars-zhy) merged commit 5b1ade4 into main Jun 30, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Fight on!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant