Skip to content

fix(qdrant): restore search instrumentation on qdrant-client >= 1.12 - #4470

Open
basil-k-aji-dev wants to merge 1 commit into
traceloop:mainfrom
basil-k-aji-dev:fix/qdrant-async-query-instrumentation
Open

basil-k-aji-dev wants to merge 1 commit into
traceloop:mainfrom
basil-k-aji-dev:fix/qdrant-async-query-instrumentation

Conversation

@basil-k-aji-dev

@basil-k-aji-dev basil-k-aji-dev commented Sep 13, 2026 •

Copy link
Copy Markdown
  • I have added tests that cover my changes.
  • If adding a new instrumentation or changing an existing one, I've added screenshots from some observability platform showing the change.
  • PR name follows conventional commits format: feat(instrumentation): ... or fix(instrumentation): ....
  • (If applicable) I have updated the documentation accordingly.

No screenshots: the change is the absence vs. presence of spans, which the added tests assert directly. Happy to attach a trace view if you'd prefer.


The problem

AsyncQdrantClient emits no search spans at all on qdrant-client >= 1.12.

Every search method in async_qdrant_client_methods.json — search, search_batch, search_groups, query, query_batch, discover, discover_batch, recommend, recommend_batch, recommend_groups — was removed from qdrant-client in 1.12. The modern replacements were added to the sync list but never to the async one.

Because _instrument() guards each wrap with hasattr, nothing raises. The instrumentor just silently wraps nothing:

Async search-path coverage on qdrant-client 1.19.0

  search                 exists=False  instrumented=True
  search_batch           exists=False  instrumented=True
  search_groups          exists=False  instrumented=True
  query                  exists=False  instrumented=True
  query_batch            exists=False  instrumented=True
  discover               exists=False  instrumented=True
  discover_batch         exists=False  instrumented=True
  recommend              exists=False  instrumented=True
  recommend_batch        exists=False  instrumented=True
  recommend_groups       exists=False  instrumented=True
  query_points           exists=True   instrumented=False
  query_batch_points     exists=True   instrumented=False
  query_points_groups    exists=True   instrumented=False

Across both lists, 24 of 48 entries no longer resolve. The sync client is largely fine — query_points and query_batch_points are listed — but it is missing query_points_groups, so grouped queries are untraced there too.

This went unnoticed because the test dependency group pins qdrant-client>=1.9.1,<1.12, so CI has never run against a client where these methods are absent.

The fix

  • Add query_points, query_points_groups and query_batch_points to the async list; add query_points_groups to the sync list.
  • Route query_points_groups through _set_search_attributes, and map its collection-name attribute to search_groups, matching the existing query_points → search and query_batch_points → search_batch mappings.
  • Lift the test pin to qdrant-client>=1.12.
  • Add tests/test_method_coverage.py: asserts the sync and async lists stay in parity, that the modern query surface is covered, and that every non-legacy entry resolves against the installed client — so this cannot silently rot again.

Legacy entries are deliberately kept. The package declares qdrant-client >= 1.7, where those methods still exist and are still worth tracing. The hasattr guard makes them harmless on newer clients. The new coverage test excludes them explicitly.

On #3492

This started from #3492, which reports AttributeError: type object 'QdrantClient' has no attribute 'upload_records'. That crash no longer reproduces — the hasattr guard in _instrument() fixed it after v0.48.1. What the guard did was convert a loud failure into silent span loss, which is what this PR addresses. Happy to retitle or split if you'd rather track that separately.

Note on uv.lock

The lockfile is regenerated for the dependency change. Its requires-python was stale at ">=3.9, <4" while pyproject.toml already declared ">=3.10,<4", so the Python 3.9 wheel entries drop out. That is a lockfile realignment, not a change to supported Python versions.

Verification

8/8 tests pass against qdrant-client 1.19.0, ruff clean. The new coverage tests fail against the pre-fix method lists and pass after:

 parity  : FAIL -> sync-only: ['query_batch_points', 'query_points']
 req sync : FAIL -> missing ['query_points_groups']
 req async: FAIL -> missing ['query_batch_points', 'query_points', 'query_points_groups']

Possible follow-ups

retrieve, count, facet and search_matrix_pairs/search_matrix_offsets are public data-plane operations that are currently untraced. Left out to keep this focused — glad to add them in a separate PR if wanted.

Summary by CodeRabbit

  • New Features
    • Added OpenTelemetry tracing for additional Qdrant point-query and grouped-query operations.
    • Added collection and search attributes for grouped point queries.
  • Bug Fixes
    • Improved instrumentation coverage across supported synchronous and asynchronous Qdrant client methods.
  • Tests
    • Added coverage checks to ensure instrumented methods remain aligned with the Qdrant client API and use valid, unique span names.

@CLAassistant

CLAassistant commented Sep 13, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⛔ Files ignored due to path filters (1)
  • packages/opentelemetry-instrumentation-qdrant/uv.lock is excluded by !**/*.lock
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 3abe3950-0b3b-433c-a671-954a00f339e4

📥 Commits

Reviewing files that changed from the base of the PR and between cda44a6 and 19bc238.

⛔ Files ignored due to path filters (1)
  • packages/opentelemetry-instrumentation-qdrant/uv.lock is excluded by !**/*.lock

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 85ba0c46-e751-4d07-b7bc-b8669d56c617

📥 Commits

Reviewing files that changed from the base of the PR and between dac2534 and cda44a6.

⛔ Files ignored due to path filters (1)
  • packages/opentelemetry-instrumentation-qdrant/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • packages/opentelemetry-instrumentation-qdrant/opentelemetry/instrumentation/qdrant/async_qdrant_client_methods.json
  • packages/opentelemetry-instrumentation-qdrant/opentelemetry/instrumentation/qdrant/qdrant_client_methods.json
  • packages/opentelemetry-instrumentation-qdrant/opentelemetry/instrumentation/qdrant/wrapper.py
  • packages/opentelemetry-instrumentation-qdrant/pyproject.toml
  • packages/opentelemetry-instrumentation-qdrant/tests/test_method_coverage.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The Qdrant instrumentation adds sync and async query methods, updates query_points_groups attribute handling, raises the test client minimum to 1.12, and adds method coverage tests.

Changes

Qdrant method coverage

Layer / File(s) Summary
Method configuration
packages/opentelemetry-instrumentation-qdrant/.../*_client_methods.json
The sync and async configurations add query_points, query_points_groups, and query_batch_points entries with qdrant.* span names.
Wrapper routing
packages/opentelemetry-instrumentation-qdrant/.../wrapper.py
query_points_groups uses search attributes and maps its collection name attribute through search_groups.
Coverage validation
packages/opentelemetry-instrumentation-qdrant/pyproject.toml, packages/opentelemetry-instrumentation-qdrant/tests/test_method_coverage.py
The test dependency requires qdrant-client>=1.12. New tests validate sync and async method parity, required methods, client resolution, and unique qdrant. span names.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to cda44

The PR adds tracing for modern Qdrant query methods and validates method coverage without an identified merge-blocking risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 2 files. (3 skipped: 3… 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 and concisely describes the main change: restoring Qdrant search instrumentation for qdrant-client version 1.12 and newer.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 2 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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

AsyncQdrantClient emitted no search spans at all on qdrant-client 1.12+.
Every search method in its wrapped-method list (search, search_batch,
search_groups, query, query_batch, discover, discover_batch, recommend,
recommend_batch, recommend_groups) was removed upstream in 1.12, and the
modern replacements were never added to the async list. The hasattr guard
in _instrument() skips the missing ones, so this degraded silently rather
than raising.

Add query_points, query_points_groups and query_batch_points to the async
list, and query_points_groups to the sync list. Legacy entries are kept:
the package declares support for qdrant-client >= 1.7, where they exist.

The test group pinned qdrant-client >= 1.9.1, < 1.12, so CI never ran
against a client where these methods were absent. Lift the pin to >= 1.12
and add tests asserting the sync and async lists stay in parity, that the
modern query surface is covered, and that non-legacy entries resolve on
the installed client.

Note: uv.lock is regenerated here. Its requires-python was stale at
">=3.9, <4" while pyproject.toml already declared ">=3.10,<4", so the
py39 wheel entries drop out. This is a lockfile realignment, not a change
to supported Python versions.

Fixes traceloop#3492

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@basil-k-aji-dev
basil-k-aji-dev force-pushed the fix/qdrant-async-query-instrumentation branch from cda44a6 to 19bc238 Compare September 26, 2026 05:15
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