Skip to content

fix(python): support public tracer providers - #859

Open
telyai wants to merge 1 commit into
langwatch:mainfrom
telyai:fix/public-span-processor-provider
Open

fix(python): support public tracer providers#859
telyai wants to merge 1 commit into
langwatch:mainfrom
telyai:fix/public-span-processor-provider

Conversation

@telyai

@telyai telyai commented Jul 29, 2026

Copy link
Copy Markdown

Scenario currently recognizes only the SDK TracerProvider (or one delegated SDK provider). OpenTelemetry’s public provider API allows other implementations to expose add_span_processor; Temporal 1.30 uses that shape for its replay-safe provider. Detect the public processor hook before proxy unwrapping so Scenario attaches its collector/exporters to the existing provider instead of attempting to replace the global provider. Includes a focused regression test.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Tracing setup now accepts any provider exposing add_span_processor, routes compatible existing providers through attachment, and instruments them when instrumentors are supplied. Tests cover provider detection and instrumentation through _do_setup.

Changes

Tracing provider compatibility

Layer / File(s) Summary
Detect span-processor-capable providers
python/scenario/_tracing/setup.py, python/tests/test_tracing_setup.py
Defines a span-processor provider protocol, broadens provider detection, and tests returning a compatible public provider unchanged.
Instrument existing providers
python/scenario/_tracing/setup.py, python/tests/test_tracing_setup.py
Passes instrumentors through existing-provider setup, invokes them with the provider, and verifies the behavior through _do_setup.

Poem

A rabbit hops through traces bright,
Finding providers just right.
Span processors join the flow,
Instrumentors softly go.
“Hop!” says Bun, “the setup’s spry!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: supporting public tracer providers.
Description check ✅ Passed The description matches the changeset by explaining public provider detection and the regression test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@telyai
telyai force-pushed the fix/public-span-processor-provider branch from 302c4c3 to 5ca69c7 Compare July 29, 2026 19:51

@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: 2

🧹 Nitpick comments (1)
python/tests/test_tracing_setup.py (1)

144-157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert processor attachment in this regression test.

The test passes only instrumentors, so it does not verify the PR’s collector/exporter attachment behavior. Pass a spy processor/exporter and assert provider.add_span_processor(...) is called, while also confirming the global provider is not replaced.

Based on the PR objective, this path must attach collectors/exporters to the existing provider.

🤖 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 `@python/tests/test_tracing_setup.py` around lines 144 - 157, Update
test_instruments_an_existing_public_provider to provide a spy processor/exporter
through the _do_setup configuration, then assert the existing provider’s
add_span_processor method receives it and trace.set_tracer_provider is not
called. Preserve the existing assertion that the instrumentor receives the
original provider.
🤖 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 `@python/scenario/_tracing/setup.py`:
- Line 95: Complete the explicit Python annotations: annotate the provider
parameter in _get_concrete_provider, parameterize the Sequence return or
parameter annotation with the instrumentor type in setup.py, and annotate both
span_processor parameters in the affected test functions. Apply the changes at
python/scenario/_tracing/setup.py lines 95 and 140-145, and
python/tests/test_tracing_setup.py lines 98-99 and 146-147.
- Around line 104-109: Require providers to expose both get_tracer and
add_span_processor before treating them as _SpanProcessorProvider instances:
update _SpanProcessorProvider, _get_concrete_provider, and all provider test
doubles in python/scenario/_tracing/setup.py:28-31,
python/scenario/_tracing/setup.py:104-109,
python/tests/test_tracing_setup.py:96-106, and
python/tests/test_tracing_setup.py:144-157. Ensure only providers satisfying the
full contract are passed to instrumentation.

---

Nitpick comments:
In `@python/tests/test_tracing_setup.py`:
- Around line 144-157: Update test_instruments_an_existing_public_provider to
provide a spy processor/exporter through the _do_setup configuration, then
assert the existing provider’s add_span_processor method receives it and
trace.set_tracer_provider is not called. Preserve the existing assertion that
the instrumentor receives the original provider.
🪄 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 Plus

Run ID: fb3eee0e-16dd-4d31-9275-aa9c610b4b7b

📥 Commits

Reviewing files that changed from the base of the PR and between 80d2b1c and 5ca69c7.

📒 Files selected for processing (2)
  • python/scenario/_tracing/setup.py
  • python/tests/test_tracing_setup.py



def _get_concrete_provider(provider) -> Optional[TracerProvider]:
def _get_concrete_provider(provider) -> Optional[_SpanProcessorProvider]:

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 | 🟠 Major | ⚡ Quick win

Complete the new Python annotations.

  • python/scenario/_tracing/setup.py#L95-L95: annotate provider.
  • python/scenario/_tracing/setup.py#L140-L145: parameterize Sequence with the instrumentor type.
  • python/tests/test_tracing_setup.py#L98-L99: annotate the first span_processor parameter.
  • python/tests/test_tracing_setup.py#L146-L147: annotate the second span_processor parameter.

As per coding guidelines, Python functions under python/**/*.py must use explicit, specific type annotations.

📍 Affects 2 files
  • python/scenario/_tracing/setup.py#L95-L95 (this comment)
  • python/scenario/_tracing/setup.py#L140-L145
  • python/tests/test_tracing_setup.py#L98-L99
  • python/tests/test_tracing_setup.py#L146-L147
🤖 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 `@python/scenario/_tracing/setup.py` at line 95, Complete the explicit Python
annotations: annotate the provider parameter in _get_concrete_provider,
parameterize the Sequence return or parameter annotation with the instrumentor
type in setup.py, and annotate both span_processor parameters in the affected
test functions. Apply the changes at python/scenario/_tracing/setup.py lines 95
and 140-145, and python/tests/test_tracing_setup.py lines 98-99 and 146-147.

Source: Coding guidelines

Comment on lines +104 to +109
# OpenTelemetry's public provider interface does not require an SDK
# TracerProvider subclass. Providers such as Temporal's replay-safe wrapper
# expose the processor hook directly and are safe to configure in place.
if callable(getattr(provider, "add_span_processor", None)):
return cast(_SpanProcessorProvider, provider)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate files =="
git ls-files | rg 'python/scenario/_tracing/setup\.py|python/tests/test_tracing_setup\.py|pyproject\.toml|requirements|poetry.lock|uv.lock' || true

echo "== setup relevant lines =="
wc -l python/scenario/_tracing/setup.py python/tests/test_tracing_setup.py
sed -n '1,170p' python/scenario/_tracing/setup.py
sed -n '80,170p' python/tests/test_tracing_setup.py

echo "== package opentelemetry deps =="
rg -n "opentelemetry|otel" python pyproject.toml Pipfile requirements.txt uv.lock poetry.lock 2>/dev/null || true

echo "== source references for get_tracers/add_span_processor =="
rg -n "get_tracer|_get_concrete_provider|add_span_processor|_do_setup|tracer_provider" python/scenario/_tracing/setup.py python/tests/test_tracing_setup.py

Repository: langwatch/scenario

Length of output: 39749


🌐 Web query:

OpenTelemetry Python TracerProvider defines get_tracer tracer_provider argument instrumentation source

💡 Result:

In the OpenTelemetry Python SDK, the TracerProvider.get_tracer method is used to acquire a Tracer instance [1][2]. The argument often referred to as the "instrumentation source" is the instrumenting_module_name [1][3][2]. The get_tracer method signature is as follows [1][4]: get_tracer(instrumenting_module_name, instrumenting_library_version=None, schema_url=None, attributes=None) Key details regarding this argument include: 1. Identification: The instrumenting_module_name acts as a unique identifier for the instrumentation scope [1][2]. It should represent the library, package, module, or class that is performing the instrumentation [1][3]. 2. Naming Convention: It is explicitly recommended to use a fixed string—such as the full name of the instrumentation package—rather than using the dynamic name variable, as name can vary depending on which file the tracer is initialized in [1][4][2]. 3. Instrumentation vs. Instrumented: A critical distinction is that this name should identify the code doing the instrumentation, not the library being instrumented [1][2][5]. For example, when instrumenting the "requests" library, one should use "opentelemetry.instrumentation.requests" rather than just "requests" [1][3][2]. 4. Convenience Wrapper: The opentelemetry.trace.get_tracer function serves as a convenience wrapper for the TracerProvider.get_tracer method [1][2]. If a TracerProvider is not explicitly provided, it defaults to the currently configured global TracerProvider [1][4][2]. These identifiers (name and version) are crucial for telemetry processing, allowing users to understand the source of the data, filter signals, and debug instrumentation issues [6][5][7].

Citations:


🌐 Web query:

opentelemetry-python instrument.py inject tracer_provider get_tracer provider.tracer_provider

💡 Result:

In OpenTelemetry Python, the tracer_provider and the get_tracer function are core components used to manage and create tracers for instrumentation [1][2][3]. TracerProvider The TracerProvider acts as the factory for tracers [2][4]. You typically initialize a TracerProvider, configure it with span processors and exporters, and then set it as the global default provider [1][3]. Global Configuration To set the global TracerProvider, you use: from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider provider = TracerProvider trace.set_tracer_provider(provider) This allows other parts of your application to access the same provider via trace.get_tracer_provider [5][2]. get_tracer The get_tracer function is a convenience wrapper provided by the opentelemetry.trace API to create a tracer [5][2]. Its signature is: get_tracer(instrumenting_module_name, instrumenting_library_version=None, tracer_provider=None, schema_url=None, attributes=None) Usage Patterns: 1. Using the Global Provider (Default): If you omit the tracer_provider argument, the function automatically uses the currently configured global tracer provider [5][2]. tracer = trace.get_tracer("my.instrumentation.name") 2. Providing a Specific Provider: If you need to use a specific, non-global provider (e.g., in advanced scenarios requiring different resource configurations), you can pass it explicitly [6]: tracer = trace.get_tracer("my.instrumentation.name", tracer_provider=my_custom_provider) Regarding your query about instrument.py, note that automatic instrumentation tools like the opentelemetry-instrument CLI automatically handle the configuration of the global tracer provider based on environment variables [7]. Manual instrumentation requires explicitly initializing these components in your code as shown above [8][3].

Citations:


🌐 Web query:

site:github.com/open-telemetry/opentelemetry-python-contrib tracer_provider.tracer_provider get_tracer tracer_provider

💡 Result:

In OpenTelemetry Python, the expression tracer_provider.get_tracer refers to the method used to retrieve a tracer instance from a specific TracerProvider object [1]. While users often access the global tracer provider via trace.get_tracer_provider [2][3], libraries and instrumentations frequently accept an optional tracer_provider argument [4][5]. When this argument is provided, the instrumentation uses that specific TracerProvider instance to create its tracer via the get_tracer method, falling back to the global provider only if one is not explicitly provided [4][5][6]. The standard signature for this method is typically: tracer = tracer_provider.get_tracer( instrumenting_module_name, instrumenting_library_version=None, schema_url=None) This mechanism ensures that instrumented code can be configured with a specific provider (which may have unique resource attributes or span processors) rather than relying solely on the global state [4][5].

Citations:


🌐 Web query:

opentelemetry-instrumentation-requests get_tracer tracer_provider Instrumentor._instrument tracer_provider

💡 Result:

In the OpenTelemetry Python instrumentation for the requests library, the components you mentioned—get_tracer, tracer_provider, and Instrumentor._instrument—are part of the internal implementation used to set up and manage telemetry collection [1][2]. 1. tracer_provider: This is an optional argument passed to the instrumentation methods [3][4]. It allows you to specify a custom TracerProvider if you do not wish to use the global default provider [3][4]. 2. get_tracer: Inside the instrumentation package, this function is called to retrieve a tracer instance [1][2]. It typically uses the provided tracer_provider (or the global default) along with library-specific information (like name and version) to initialize a tracer that records spans for outgoing HTTP requests [1][2]. 3. Instrumentor._instrument: The RequestsInstrumentor class inherits from BaseInstrumentor [3][4]. The _instrument method is an internal implementation method that you generally do not call directly [5]. When you call.instrument on the RequestsInstrumentor instance, it internally calls this _instrument method, passing along configuration options like the tracer_provider [4][5]. This method then proceeds to perform the actual monkey-patching of the requests library to enable tracing [4][6]. In typical usage, you do not need to interact with these internal methods. Instead, you use the public API: from opentelemetry.instrumentation.requests import RequestsInstrumentor # Automatically instruments 'requests' using global providers RequestsInstrumentor.instrument # Or, optionally pass a custom TracerProvider RequestsInstrumentor.instrument(tracer_provider=my_custom_tracer_provider)

Citations:


🌐 Web query:

github.com/open-telemetry/opentelemetry-instrumentation BaseInstrumentor tracer_provider get_tracer tracer_provider

💡 Result:

In OpenTelemetry Python instrumentation, the BaseInstrumentor class serves as an abstract base class for creating instrumentation libraries [1][2]. While BaseInstrumentor itself provides methods for instrumenting and uninstrumenting libraries [2], the acquisition of a tracer is handled by the OpenTelemetry API's tracer provider mechanisms [3][4]. To acquire a tracer within an instrumentation, you use the TracerProvider's get_tracer method [3][4]. The recommended approach involves the following steps: 1. Tracer Acquisition: Use opentelemetry.trace.get_tracer. This is a convenience wrapper that delegates to the configured TracerProvider [3][4]. 2. Tracer Provider Handling: While you can call trace.get_tracer directly (which defaults to the global tracer provider), many custom instrumentors are designed to accept an optional tracer_provider as a keyword argument (e.g., in their init or instrument method) [5][6]. If a tracer_provider is provided, it should be used to create the tracer; otherwise, the global tracer provider is used [3][7][4]. 3. Scope Identification: When calling get_tracer, you must provide a unique identifier for the instrumentation scope (instrumenting_module_name), typically the name of the package or module performing the instrumentation [3][4]. It is best practice to use a fixed string rather than name, as the latter can result in inconsistent tracer names if the instrumentation spans multiple files [4][8]. Example usage pattern: from opentelemetry import trace # Inside your instrumentor tracer = trace.get_tracer( instrumenting_module_name="my.instrumentation.package", instrumenting_library_version="1.0.0", tracer_provider=self.tracer_provider # If optional provider was passed to the instrumentor) This pattern ensures that your instrumentation can be easily integrated into different environments, including those that require custom tracer providers rather than the global default [7][5][6].

Citations:


🌐 Web query:

site:github.com/open-telemetry/opentelemetry-python-contrib "tracer_provider.tracer_provider" "tracer_provider.get_tracer" "instrumentor.py"

💡 Result:

In the context of the OpenTelemetry Python instrumentation libraries, tracer_provider and get_tracer are used to manage how spans are created and reported [1][2]. The standard pattern for OpenTelemetry instrumentations involves using a tracer provider to create tracer instances, which are then used to instrument library code [1][2][3]. Key aspects of this pattern include: 1. Tracer Provider Usage: Instrumentations are designed to accept an optional tracer_provider argument [1][2][3]. If a tracer provider is provided, the instrumentation uses it to create its tracer; if it is not provided, the instrumentation falls back to the global tracer provider [1][2][3]. This is important because different tracer providers can have different configurations, such as distinct Resource attributes [1][2]. 2. Implementation in instrumentor.py: The instrumentor.py file, located in the opentelemetry-instrumentation package, defines the BaseInstrumentor class [4]. While the base class provides the structure for instrumentation lifecycle management (such as instrument and uninstrument methods) [5][4], the actual tracer initialization typically occurs within the specific instrumentation packages (e.g., opentelemetry-instrumentation-fastapi or opentelemetry-instrumentation-aws-lambda) [6][3]. 3. Creating the Tracer: The get_tracer function from the opentelemetry.trace API is used to instantiate the tracer [3]. It is commonly called as follows: tracer = get_tracer(name, version, tracer_provider=tracer_provider, schema_url=...) [3] This ensures that the instrumentation is properly associated with the correct tracer provider and semantic convention schema [3].

Citations:


🌐 Web query:

github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py tracer_provider

💡 Result:

In the OpenTelemetry Python Requests instrumentation library, the tracer_provider is an optional keyword argument that can be passed to the instrument method of the RequestsInstrumentor class [1][2]. When invoking RequestsInstrumentor.instrument, you can provide a custom TracerProvider instance to control where spans are sent [1][3]. If no tracer_provider is specified, the instrumentation defaults to using the global TracerProvider (configured via trace.set_tracer_provider) [4][2]. Example usage: from opentelemetry.instrumentation.requests import RequestsInstrumentor from opentelemetry.sdk.trace import TracerProvider # Create a custom tracer provider provider = TracerProvider # Pass the provider to the instrumentor RequestsInstrumentor.instrument(tracer_provider=provider) The tracer_provider argument allows developers to use specific, isolated tracing configurations for their requests, rather than relying on the globally registered provider [4][2]. Internal implementations of the instrumentation use this provider when initializing the tracer via get_tracer [5][2].

Citations:


Require the full tracer-provider contract before instrumenting.

instrumentor.instrument(tracer_provider=provider) may pass this object into OpenTelemetry instrumentation code, where it is expected to support get_tracer(...); only add_span_processor leaves the contract incomplete. Require both methods in _SpanProcessorProvider, _get_concrete_provider, and the provider test doubles.

📍 Affects 2 files
  • python/scenario/_tracing/setup.py#L104-L109 (this comment)
  • python/scenario/_tracing/setup.py#L28-L31
  • python/tests/test_tracing_setup.py#L96-L106
  • python/tests/test_tracing_setup.py#L144-L157
🤖 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 `@python/scenario/_tracing/setup.py` around lines 104 - 109, Require providers
to expose both get_tracer and add_span_processor before treating them as
_SpanProcessorProvider instances: update _SpanProcessorProvider,
_get_concrete_provider, and all provider test doubles in
python/scenario/_tracing/setup.py:28-31,
python/scenario/_tracing/setup.py:104-109,
python/tests/test_tracing_setup.py:96-106, and
python/tests/test_tracing_setup.py:144-157. Ensure only providers satisfying the
full contract are passed to instrumentation.

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

Static review found no actionable correctness, security, or tracing-ownership issue in the current fork change. The public-provider capability check remains restricted to attaching a span processor and instrumentors receive the selected provider. I did not execute the untrusted head or its scripts.

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

Static review of external contribution at 5ca69c7dd9c445e87b6d4ab299320f11c7aad3bc (no PR-branch code or dependencies executed). No merge-blocking issue found. The structural provider check accepts public tracer providers only when they expose the needed processor-registration method, preserves the no-provider path, and passes the selected provider through to available instrumentors. CI evidence was considered but not rerun under the external-contribution trust boundary.

@langwatch-agent langwatch-agent added hound-checked Triaged by the pr-hound agent at the current head SHA ci-green Latest run of every check is passing (checks API, not the legacy commit-status index) labels Aug 5, 2026

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

Clean static review. The duck-typed provider boundary is constrained to the processor operation used here, and the added instrumentation path is covered. Residual risk: the fork is stale and has no current full CI result.\n\nLangWatch-Review: verdict=clean sha=5ca69c7dd9c445e87b6d4ab299320f11c7aad3bc p0=0 p1=0 p2=0 p3=0

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

External static review: no blocking concern found in the current diff. I did not execute branch code, install dependencies, or run contributor-provided scripts. Residual risk: runtime behavior remains covered by the repository CI.

LangWatch-Review: verdict=clean sha=5ca69c7dd9c445e87b6d4ab299320f11c7aad3bc p0=0 p1=0 p2=0 p3=0

@langwatch-agent langwatch-agent added the review: targeted PR Hound review mode label Aug 20, 2026
@langwatch-agent

Copy link
Copy Markdown
Contributor

Human Review Brief

Caution

This attaches Scenario's exporter to a provider Scenario does not own and cannot flush.

The new _get_concrete_provider returns any object with a callable add_span_processor, and the setup then adds Scenario's processors to it. That is the right idea and it hands control of the span lifecycle to someone else's provider. Whether the run report ever reaches LangWatch now depends on that provider being shut down or force-flushed at exit, which Scenario no longer does and cannot check.

The motivating case makes this concrete rather than theoretical. Temporal's replay-safe provider is replay-safe precisely because it suppresses span emission during replay. Attaching to it is correct, and it means a scenario run inside a replay produces no spans, silently and by design. Someone will hit that and read it as Scenario being broken.

The other thing to check is ordering. The duck-type check runs before proxy unwrapping, and an SDK TracerProvider also has add_span_processor, so it now matches on the first branch and whatever unwrapping or delegation logic came after is skipped for every existing user. That is very likely fine, since attaching in place is what the old path was trying to reach anyway, and it is a behaviour change for everybody rather than only for the new case.

Mode Targeted Review. Two small functions and a test file. Read the detection order and the lifecycle question.
Issue No linked issue. The motivating case is named in the description: Temporal 1.30's replay-safe provider.
State +45 / -4 across 2 files. CI green, mergeable. Requested reviewer rogeriochaves. Open since 29 July. Outside contributor.
Evidence A focused regression test with a hand-rolled PublicProvider exposing only add_span_processor, covering both the detection and the instrumentor wiring. It does not cover an SDK provider going down the new branch, which is the case that changed for everyone.
Where to look _get_concrete_provider and its ordering against the old proxy path · whether anything flushes on exit · what an instrumentor does when handed a non-SDK provider
What is being fixed

Scenario needs somewhere to send its spans. Previously it recognised only the OpenTelemetry SDK TracerProvider, or one delegated SDK provider behind a proxy. Anything else and it would try to replace the global provider, which stomps on whatever the host application had set up.

But OpenTelemetry's public provider API does not require an SDK subclass. Other implementations expose add_span_processor and are perfectly safe to configure in place. Temporal's is one. So the fix duck-types on the hook instead of the type, and attaches rather than replaces.

That is the right instinct: attaching to what is there beats replacing what someone else configured.

Worth asking the author

Who flushes at the end of a run? Scenario's report is only useful if the spans arrive. With an SDK provider there is a known shutdown path. With a foreign provider there is not, and a run that ends by exiting the process may lose everything buffered. If Scenario keeps a handle on its own BatchSpanProcessor, force-flushing that at the end of a run is cheap and closes it regardless of whose provider it lives on.

Does an instrumentor accept a non-SDK provider? instrumentor.instrument(tracer_provider=provider) is called with whatever came back. Instrumentors vary in how much they assume about the object they are given.

Should the SDK check come first? Putting the isinstance check ahead of the duck-type check would keep the existing path byte-for-byte identical for existing users and confine the change to the case it is for. If the new ordering is deliberate because attaching in place is better even for SDK providers, that is worth saying, since it is the part of the change that touches everybody.

Is the Temporal replay case documented anywhere? No spans during replay is correct behaviour that will read as a bug. One line in the docs saves someone a day.

Note

Attaching to an existing provider is the right move; owning nothing about its lifecycle is the cost. The review question is what guarantees the spans get out.

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

Labels

ci-green Latest run of every check is passing (checks API, not the legacy commit-status index) hound-checked Triaged by the pr-hound agent at the current head SHA review: targeted PR Hound review mode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants