Skip to content

fix(zipkin): tolerate invalid OTEL_EXPORTER_ZIPKIN_TIMEOUT env var - #5704

Open
RichardoMrMu wants to merge 7 commits into
open-telemetry:mainfrom
RichardoMrMu:fix/zipkin-timeout-env-fallback
Open

RichardoMrMu wants to merge 7 commits into
open-telemetry:mainfrom
RichardoMrMu:fix/zipkin-timeout-env-fallback

Conversation

@RichardoMrMu

Copy link
Copy Markdown
Contributor

Description

Both Zipkin span exporters construct their timeout with a bare int(environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT, 10)) in __init__ (opentelemetry-exporter-zipkin-json and opentelemetry-exporter-zipkin-proto-http). A malformed value such as OTEL_EXPORTER_ZIPKIN_TIMEOUT=10s raises ValueError: invalid literal for int() while the exporter is being built, which takes SDK/TracerProvider startup down before any telemetry can flow.

The OTLP exporters already tolerate this: the HTTP transport has _resolve_timeout() (#5389) and the gRPC transport now has _timeout_from_env() (#5448), both of which log a warning and fall back to the default. The Zipkin exporters were the remaining outlier parsing this env var with an unguarded conversion.

This change adds a private _timeout_from_env() in each Zipkin exporter that:

  • returns the default (10 seconds) silently when the variable is unset or empty/whitespace;
  • logs a warning and returns the default when the value is not an integer;
  • otherwise returns the parsed integer.

Precedence of an explicit timeout= constructor argument is unchanged (timeout or _timeout_from_env()).

Type of change

  • Bug fix (non-breaking change)

How Has This Been Tested?

Pure-Python, no collector or network needed. Added two tests to each exporter's test_zipkin_exporter.py:

  • test_constructor_invalid_timeout_env_var_falls_back: sets OTEL_EXPORTER_ZIPKIN_TIMEOUT=10s, asserts the exporter builds with timeout == 10 and emits a WARNING.
  • test_constructor_empty_timeout_env_var_falls_back: sets the variable to "", asserts timeout == 10.

Red (before the fix), run per package:

>       self.timeout = timeout or int(environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT, 10))
E       ValueError: invalid literal for int() with base 10: '10s'
====================== 2 failed, 15 deselected ======================

Green (after the fix):

opentelemetry-exporter-zipkin-json ........ 17 passed in 0.23s
opentelemetry-exporter-zipkin-proto-http ... 17 passed in 0.26s

The pre-existing constructor/env/export tests in both files continue to pass, including test_constructor_all_params_and_env_vars (explicit timeout= precedence) and test_constructor_env_vars (valid numeric env value).

Verification boundary: logic-level unit tests only (constructor configuration); no export round-trip against a live Zipkin instance was exercised, consistent with the existing tests in these modules which mock requests.Session.post.

Both Zipkin exporters parsed OTEL_EXPORTER_ZIPKIN_TIMEOUT with a bare
int() in __init__, so an invalid value (e.g. "10s") raised ValueError
during exporter construction and took SDK startup down, unlike the OTLP
HTTP/gRPC exporters which warn and fall back to the default.

Add _timeout_from_env() in each exporter that skips unset/empty values
silently, logs a warning for non-integer values, and falls back to the
10 second default. Explicit timeout argument precedence is unchanged.

Assisted-by: Doubao
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-10-08 15:50 UTC

Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):

  • Inline threads: 1
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

Restore the original public assignment expression for ZipkinExporter.timeout and wrap it in try/except ValueError so a malformed env var logs a warning and falls back to the default instead of breaking SDK startup.
@tammy-baylis-swi tammy-baylis-swi moved this to Ready for review in Python PR digest Oct 1, 2026

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Empty and whitespace-only values incorrectly emit warnings, and tests do not verify silent fallback.

Review effort: Balanced
Findings: 4 Medium severity

Open (4)
What changed in this PR

Adds resilient Zipkin timeout environment parsing to prevent malformed values from breaking SDK startup.

Changes:

  • Falls back to the default timeout for invalid values.
  • Adds warning and fallback tests.
  • Adds a changelog entry.
File Description
.changelog/​5704.fixed Documents the fix.
exporter/​opentelemetry-exporter-zipkin-json/​src/​opentelemetry/​exporter/​zipkin/​json/​__init__.py Adds timeout fallback handling.
exporter/​opentelemetry-exporter-zipkin-json/​tests/​test_zipkin_exporter.py Tests invalid and empty values.
exporter/​opentelemetry-exporter-zipkin-proto-http/​src/​opentelemetry/​exporter/​zipkin/​proto/​http/​__init__.py Adds timeout fallback handling.
exporter/​opentelemetry-exporter-zipkin-proto-http/​tests/​test_zipkin_exporter.py Tests invalid and empty values.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +132 to +142
# A malformed OTEL_EXPORTER_ZIPKIN_TIMEOUT must not break SDK startup.
try:
self.timeout = timeout or int(environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT, 10))
except ValueError:
logger.warning(
"Invalid value %r for %s, using default of %s seconds",
environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT),
OTEL_EXPORTER_ZIPKIN_TIMEOUT,
_DEFAULT_TIMEOUT,
)
self.timeout = _DEFAULT_TIMEOUT
Comment on lines +79 to +83
os.environ[OTEL_EXPORTER_ZIPKIN_TIMEOUT] = ""

exporter = ZipkinExporter()

self.assertEqual(exporter.timeout, 10)
Comment on lines +125 to +135
# A malformed OTEL_EXPORTER_ZIPKIN_TIMEOUT must not break SDK startup.
try:
self.timeout = timeout or int(environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT, 10))
except ValueError:
logger.warning(
"Invalid value %r for %s, using default of %s seconds",
environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT),
OTEL_EXPORTER_ZIPKIN_TIMEOUT,
_DEFAULT_TIMEOUT,
)
self.timeout = _DEFAULT_TIMEOUT
Comment on lines +81 to +85
os.environ[OTEL_EXPORTER_ZIPKIN_TIMEOUT] = ""

exporter = ZipkinExporter()

self.assertEqual(exporter.timeout, 10)
Handle unset and whitespace-only timeout values before integer conversion in both Zipkin exporters. Preserve explicit timeout precedence and existing numeric parsing semantics. Add regressions for silent defaults, warning count, valid values and constructor truthiness.

Assisted-by: OpenAI Codex
Signed-off-by: RichardoMrMu <947676438@qq.com>
…c-symbols check

griffe public-symbols-check compares the AST of instance attribute
assignments against main. Route the blank-timeout fallback through a
local variable instead of changing the self.timeout RHS, so the exported
attribute source text stays byte-identical to main.

Behavior unchanged: blank/invalid env falls back to _timeout_from_env()
(default 10s), explicit timeout wins.
self.session = session or requests.Session()
self.session.headers.update({"Content-Type": self.encoder.content_type()})
self._closed = False
timeout = timeout or _timeout_from_env()

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.

Why are you calling two times environ.get(OTEL_EXPORTER_ZIPKIN_TIMEOUT ? One here (line below) and one from timeout_from_env()?

This branch has not been deployed

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

Labels

None yet

Projects

Status: Approved PRs that need fixes

Development

Successfully merging this pull request may close these issues.

6 participants