Skip to content

fix(instrumentation): pinecone span attributes for upsert and delete (#2688) - #4084

Open
WatchTree-19 wants to merge 3 commits into
traceloop:mainfrom
WatchTree-19:fix/pinecone-upsert-delete-span-attrs
Open

fix(instrumentation): pinecone span attributes for upsert and delete (#2688)#4084
WatchTree-19 wants to merge 3 commits into
traceloop:mainfrom
WatchTree-19:fix/pinecone-upsert-delete-span-attrs

Conversation

@WatchTree-19

@WatchTree-19 WatchTree-19 commented May 7, 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.

Fixes #2688

Pinecone instrumentation only set span attributes for query(). upsert() and delete() produced spans with the bare vendor tag and nothing operation-specific.

Following the pattern from chromadb (_set_upsert_attributes, _set_delete_attributes in chromadb's wrapper), this PR adds:

  • 7 new SpanAttributes constants in semconv_ai:
    • PINECONE_UPSERT_VECTORS_COUNT, PINECONE_UPSERT_NAMESPACE, PINECONE_UPSERT_BATCH_SIZE
    • PINECONE_DELETE_IDS_COUNT, PINECONE_DELETE_NAMESPACE, PINECONE_DELETE_DELETE_ALL, PINECONE_DELETE_FILTER
  • set_upsert_input_attributes and set_delete_input_attributes in query_handlers.py. Both @dont_throw. Both check kwargs then fall back to args[0] for vectors / ids since Pinecone callers usually pass them positionally. len() is wrapped in try / except TypeError so a generator-typed vectors doesn't get materialised just to count.
  • Dispatch in _wrap switched to a small if/elif on to_wrap.get("method").

Did not touch response-side attributes. The existing _set_response_attributes already records read_units / write_units for any response with a usage block, which covers the metric side for upsert. Pure upsert/delete-specific response attributes (vector IDs returned, etc.) can be a follow-up.

No tests added in this PR; cassette-based tests for the new setters would be a small follow-up. Happy to add if you'd like.

Summary by CodeRabbit

  • New Features
    • Enhanced Pinecone tracing to record additional span details for upsert and delete, including vectors/IDs counts (when available), namespaces, upsert batch size, the delete-all flag, and filter information.
  • Semantic Conventions
    • Added new Pinecone-specific span attribute keys to standardize these telemetry fields.
  • Bug Fixes
    • Improved when certain response/usage attributes are captured by treating None responses differently from other responses.
  • Tests
    • Added unit tests for attribute extraction from keyword and positional inputs, including generator handling and JSON-serialization for dict filters.

@CLAassistant

CLAassistant commented May 7, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 028b0d29-e5b0-4ab7-8022-dd4422beb85c

📥 Commits

Reviewing files that changed from the base of the PR and between c51b9f6 and 901ba84.

📒 Files selected for processing (1)
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/init.py

📝 Walkthrough

Walkthrough

This PR adds Pinecone span attributes for upsert and delete, defines new semantic constants, implements input-attribute helpers, and updates the Pinecone wrapper to dispatch by method and record responses when present.

Changes

Pinecone Instrumentation Expansion

Layer / File(s) Summary
Semantic Attribute Definitions
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
Seven new SpanAttributes constants are added for Pinecone upsert and delete inputs and counts.
Operation Handlers
packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py
New helpers derive vectors and ids from kwargs or positional args, set count and metadata attributes, and serialize dict filters for delete.
Wrapper Method Dispatch
packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py, packages/opentelemetry-instrumentation-pinecone/tests/test_input_attributes.py
The Pinecone wrapper imports and calls the new helpers for query, upsert, and delete, broadens response handling to non-None values, and new tests cover kwargs, positional args, generator inputs, and dict filter serialization.

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

Sequence Diagram(s)

sequenceDiagram
  participant _wrap as _wrap
  participant query as set_query_input_attributes
  participant upsert as set_upsert_input_attributes
  participant delete as set_delete_input_attributes

  _wrap->>_wrap: Read to_wrap.get("method")
  alt query
    _wrap->>query: Set query span attributes
  else upsert
    _wrap->>upsert: Set upsert span attributes
  else delete
    _wrap->>delete: Set delete span attributes
  end
Loading

Possibly related PRs

  • traceloop/openllmetry#4102: Also modifies the Pinecone _wrap tracing wrapper in opentelemetry/instrumentation/pinecone/__init__.py.
    Suggested reviewers: nina-kollman, galzilber, max-deygin-traceloop, netanel-tl
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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 describes the Pinecone upsert/delete span-attribute fix and matches the PR's main change.
Linked Issues check ✅ Passed The PR adds span attributes for Pinecone upsert and delete, which directly addresses #2688's reported missing instrumentation.
Out of Scope Changes check ✅ Passed The response-handling tweak and new tests are directly related to ensuring the new Pinecone attributes are recorded correctly.
✨ 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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py (1)

171-186: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Change if response: guard to if response is not None: to ensure delete operations record metrics and status.

When Pinecone's delete() returns an empty dict {}, the current guard if response: evaluates to False, preventing:

  • span.set_status(Status(StatusCode.OK)) from being called — delete spans remain with status UNSET
  • _set_response_attributes() from being called — write_units metrics are never recorded

This defeats the observability improvements being added for the delete operation in this PR. Use an explicit None check instead:

Proposed fix
-        if response:
+        if response is not None:
🤖 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
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py`
around lines 171 - 186, The guard currently using "if response:" skips handling
when Pinecone returns an empty dict (e.g., delete()); change the condition in
the response handling block to "if response is not None:" so that
_set_response_attributes(span, read_units_metric, write_units_metric,
shared_attributes, response) and span.set_status(Status(StatusCode.OK)) (and the
query-specific set_query_response call) run for empty responses as well; update
the conditional in the function where response is checked (the block that calls
set_query_response, _set_response_attributes, and span.set_status) to use an
explicit None check.
🧹 Nitpick comments (1)
packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py (1)

97-159: 🏗️ Heavy lift

No tests for the new handlers.

The two new input-attribute setters have no accompanying test coverage. For instrumentation code, at minimum there should be unit tests that pass mock spans and assert the expected attributes are set — covering keyword-arg calls, positional-arg fallback, generator inputs (no count), delete_all, and filter serialization.

🤖 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
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py`
around lines 97 - 159, Add unit tests for set_upsert_input_attributes and
set_delete_input_attributes: create mock/span objects (or spy on
set_span_attribute) and assert correct attributes are set for (1) keyword-arg
invocation (vectors, ids) that records counts, (2) positional-arg fallback when
kwargs missing, (3) generator or non-len iterable inputs where no count is
recorded (ensure no exception), (4) delete_all is recorded via
SpanAttributes.PINECONE_DELETE_DELETE_ALL, and (5) filter is serialized to JSON
when a dict is provided and passed through when non-dict. Use the exact function
names set_upsert_input_attributes and set_delete_input_attributes and assert
against the SpanAttributes keys used in the functions.
🤖 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.

Outside diff comments:
In
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py`:
- Around line 171-186: The guard currently using "if response:" skips handling
when Pinecone returns an empty dict (e.g., delete()); change the condition in
the response handling block to "if response is not None:" so that
_set_response_attributes(span, read_units_metric, write_units_metric,
shared_attributes, response) and span.set_status(Status(StatusCode.OK)) (and the
query-specific set_query_response call) run for empty responses as well; update
the conditional in the function where response is checked (the block that calls
set_query_response, _set_response_attributes, and span.set_status) to use an
explicit None check.

---

Nitpick comments:
In
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py`:
- Around line 97-159: Add unit tests for set_upsert_input_attributes and
set_delete_input_attributes: create mock/span objects (or spy on
set_span_attribute) and assert correct attributes are set for (1) keyword-arg
invocation (vectors, ids) that records counts, (2) positional-arg fallback when
kwargs missing, (3) generator or non-len iterable inputs where no count is
recorded (ensure no exception), (4) delete_all is recorded via
SpanAttributes.PINECONE_DELETE_DELETE_ALL, and (5) filter is serialized to JSON
when a dict is provided and passed through when non-dict. Use the exact function
names set_upsert_input_attributes and set_delete_input_attributes and assert
against the SpanAttributes keys used in the functions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f67658e5-082d-4846-9d45-f7464738fef0

📥 Commits

Reviewing files that changed from the base of the PR and between 3735204 and d57143d.

📒 Files selected for processing (3)
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py
  • packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py

@WatchTree-19

Copy link
Copy Markdown
Author

gentle bump on this when you get a chance. PR adds pinecone span attributes for upsert/delete following the chromadb pattern (#2688). CLA cleared and coderabbit-bot reviewed positively. happy to address any feedback or rebase if it's gone stale.

Signed-off-by: WatchTree-19 <119982314+WatchTree-19@users.noreply.github.com>
@WatchTree-19
WatchTree-19 force-pushed the fix/pinecone-upsert-delete-span-attrs branch from d57143d to c51b9f6 Compare July 3, 2026 13:21
@WatchTree-19

Copy link
Copy Markdown
Author

rebased onto main and resolved the conflict in semconv_ai/__init__.py (kept both the new db.pinecone.query.* constants and these pinecone.upsert.* / pinecone.delete.* ones - no name overlap). also added unit tests for the upsert/delete attribute helpers. conflict-free and CLA green now.

one thing worth a call: i kept the pinecone.* prefix to match the existing pinecone.query.* / pinecone.usage.* attributes, but i see newer additions are moving to db.pinecone.*. happy to rename these to db.pinecone.upsert.* / db.pinecone.delete.* if that's the direction you'd prefer.

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

🧹 Nitpick comments (2)
packages/opentelemetry-instrumentation-pinecone/tests/test_input_attributes.py (1)

39-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding edge-case coverage.

Tests correctly validate the dict-filter path and positional-arg counting, but a few branches in the upstream handlers (query_handlers.py) remain untested: non-dict filter values (string filter fallback), non-len()-supporting ids (TypeError/generator path for delete), and the __init__.py dispatch if/elif itself routing to the correct handler by method name.

♻️ Suggested additional tests
+def test_delete_non_dict_filter_passed_through():
+    span = MagicMock()
+    set_delete_input_attributes(span, {"filter": "raw-string-filter"}, ())
+    assert _attrs(span)[SpanAttributes.PINECONE_DELETE_FILTER] == "raw-string-filter"
+
+
+def test_delete_generator_ids_not_counted():
+    span = MagicMock()
+    set_delete_input_attributes(span, {"ids": (x for x in range(3))}, ())
+    assert SpanAttributes.PINECONE_DELETE_IDS_COUNT not in _attrs(span)
🤖 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
`@packages/opentelemetry-instrumentation-pinecone/tests/test_input_attributes.py`
around lines 39 - 56, Add edge-case tests for the Pinecone input attribute
handlers: cover the string-filter fallback path in the delete/query logic,
verify delete IDs counting when ids is an iterator or otherwise lacks len(), and
add dispatch coverage in __init__.py to confirm the method-name if/elif routes
to the correct handler. Use the existing set_delete_input_attributes,
set_query_input_attributes, and the method-dispatch entrypoint symbols to keep
the tests aligned with the upstream query_handlers.py behavior.
packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py (1)

125-186: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated len()/TypeError pattern across both new setters.

The "compute count, catch TypeError for non-len()-able iterables" logic is duplicated verbatim between set_upsert_input_attributes and set_delete_input_attributes. Consider extracting a small helper, e.g. _safe_len(x), to avoid the repetition.

🤖 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
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py`
around lines 125 - 186, The len()/TypeError fallback for counting iterable
inputs is duplicated in set_upsert_input_attributes and
set_delete_input_attributes. Extract the repeated “safe count” logic into a
small shared helper (for example, a private _safe_len-like utility) and use it
from both functions, keeping the existing behavior for vectors and ids while
reducing repetition.
🤖 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.

Nitpick comments:
In
`@packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py`:
- Around line 125-186: The len()/TypeError fallback for counting iterable inputs
is duplicated in set_upsert_input_attributes and set_delete_input_attributes.
Extract the repeated “safe count” logic into a small shared helper (for example,
a private _safe_len-like utility) and use it from both functions, keeping the
existing behavior for vectors and ids while reducing repetition.

In
`@packages/opentelemetry-instrumentation-pinecone/tests/test_input_attributes.py`:
- Around line 39-56: Add edge-case tests for the Pinecone input attribute
handlers: cover the string-filter fallback path in the delete/query logic,
verify delete IDs counting when ids is an iterator or otherwise lacks len(), and
add dispatch coverage in __init__.py to confirm the method-name if/elif routes
to the correct handler. Use the existing set_delete_input_attributes,
set_query_input_attributes, and the method-dispatch entrypoint symbols to keep
the tests aligned with the upstream query_handlers.py behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 407376fc-41e7-4815-b7ec-acd3540f4d7d

📥 Commits

Reviewing files that changed from the base of the PR and between d57143d and c51b9f6.

📒 Files selected for processing (4)
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/__init__.py
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/query_handlers.py
  • packages/opentelemetry-instrumentation-pinecone/tests/test_input_attributes.py
  • packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/init.py
  • packages/opentelemetry-instrumentation-pinecone/opentelemetry/instrumentation/pinecone/init.py

a successful delete returns an empty dict, which the truthiness guard
skipped; check 'is not None' so delete span attributes are still set.

Signed-off-by: WatchTree-19 <119982314+WatchTree-19@users.noreply.github.com>
@WatchTree-19

Copy link
Copy Markdown
Author

thanks - addressed the coderabbit note: a successful pinecone delete returns an empty dict, which the truthiness guard skipped, so switched to if response is not None: (901ba84) and the delete span attributes are now set.

still one open question for a maintainer when someone has a moment: i kept the pinecone.upsert.* / pinecone.delete.* prefix to match the existing pinecone.query.* / pinecone.usage.* attributes, but main also added newer db.pinecone.query.* constants. happy to rename to db.pinecone.* if that's the preferred direction - just didn't want to make that call unilaterally in a rebase.

@WatchTree-19
WatchTree-19 force-pushed the fix/pinecone-upsert-delete-span-attrs branch from bb01458 to acac730 Compare August 20, 2026 13:02
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.

🐛 Bug Report: Pinecone - No Span Attributes defined for upsert and delete of pinecone.Index class

2 participants