Skip to content

Propagate variable version in baggage alongside label#1927

Merged
dmontagu merged 3 commits into
mainfrom
dmontagu/baggage-variable-version
May 15, 2026
Merged

Propagate variable version in baggage alongside label#1927
dmontagu merged 3 commits into
mainfrom
dmontagu/baggage-variable-version

Conversation

@dmontagu
Copy link
Copy Markdown
Contributor

Summary

ResolvedVariable.__enter__ now sets two baggage entries instead of one:

  • logfire.variables.<name> — the resolved label (unchanged).
  • logfire.variables.<name>.version — the resolved version, string-formatted (new).

The version entry is only set when a version actually resolved; code-default resolutions (where version is None) emit just the label entry, same as before.

Why

Today, downstream spans inside a variable's resolution context carry the label via baggage but not the version. The version is available on the SDK-emitted Resolve variable <name> span as an attribute, but that span is opened and closed entirely inside _get_result_and_record_span — before the context manager body runs — so it does not share a trace_id with any user-created spans. There is no SQL-only path to attach the version to a downstream span.

That gap is hit hardest by A/B-test analytics. The marquee SQL query for src/walkthroughs/managed-variables/ab-testing-rollout/ (in the platform repo) aggregates request metrics by logfire.variables.ranking_config (the label). After a label gets moved to a new version mid-experiment — the canonical "promote canary v2 → v3" flow — aggregating by label alone mixes data from the old and new versions, which is precisely the failure mode an A/B harness is supposed to surface. The walkthrough today works around it by setting span.set_attribute('config_version', resolved.version) in application code. With this change, that workaround becomes unnecessary: GROUP BY label, attributes->>'logfire.variables.ranking_config.version' works directly.

Backwards compatibility

Strictly additive — existing SQL queries that filter or group on logfire.variables.<name> (the label entry) continue to work unchanged. New queries can pull the version off the new key when they need it.

The new baggage value is a stringified integer (e.g. '3'); OTel baggage values are strings.

Test plan

  • Added an assertion in the existing test_context_manager_sets_label_in_baggage test that the version entry is present and matches the resolved version ('1' in that fixture).
  • Added a new test test_context_manager_omits_version_for_code_default confirming that resolutions with no remote config (so version is None) emit only the label entry, not a version entry.
  • All 7 existing context-manager tests still pass.

Follow-up in platform repo

Once this lands and a release goes out (and the platform's pinned logfire revision bumps), the walkthrough's 02_send_queries.py workaround can be removed and the SQL query simplifies. That cleanup is referenced from the platform PR that bundles the rename work and the walkthrough's interim workaround.

`ResolvedVariable.__enter__` now sets a second baggage entry
`logfire.variables.<name>.version` (string-formatted integer)
whenever the resolved variable has a version, in addition to the
existing `logfire.variables.<name>` entry that carries the label.

Why: downstream spans inside the resolution context now carry both
attributes, so observability queries that compare variants of an
A/B test can `GROUP BY (label, version)` directly. Previously the
version was only on the `Resolve variable <name>` span itself, and
that span isn't in the same trace as user-created spans (it opens
and closes inside `_get_result_and_record_span` before the context
manager body runs), so there was no SQL-only way to associate a
downstream span with the version that served it.

Code-default resolutions have `version=None` and don't emit the new
baggage entry — only versioned resolutions do.

Two test additions in `test_variables.py`:
- The existing context-manager-sets-label test now also asserts the
  version baggage entry is present and matches the resolved version.
- A new test asserts that code-default resolutions don't emit a
  version baggage entry (no key, not just an empty value).
@dmontagu dmontagu self-assigned this May 14, 2026
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 14, 2026

Deploying logfire-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4578860
Status:⚡️  Build in progress...

View logs

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Comment thread logfire/variables/abstract.py
Comment thread tests/test_variables.py Outdated
Comment thread tests/test_variables.py Outdated
dmontagu added 2 commits May 15, 2026 05:44
- Drop the redundant logfire.configure(**config_kwargs) call; the
  autouse `config` fixture in conftest.py already configures the
  default logfire instance and clears variables between tests.
- Replace the two separate `assert ... in/== baggage` checks with a
  single `assert baggage == snapshot({...})`, matching the project's
  testing convention.
@dmontagu dmontagu merged commit 737bf50 into main May 15, 2026
16 of 17 checks passed
@dmontagu dmontagu deleted the dmontagu/baggage-variable-version branch May 15, 2026 14:07
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