Skip to content

feat: add Azure AI Search instrumentation#4317

Open
sarthak-env wants to merge 4 commits into
traceloop:mainfrom
sarthak-env:main
Open

feat: add Azure AI Search instrumentation#4317
sarthak-env wants to merge 4 commits into
traceloop:mainfrom
sarthak-env:main

Conversation

@sarthak-env

@sarthak-env sarthak-env commented Jun 21, 2026

Copy link
Copy Markdown

Closes #2303

What this PR does

Adds a new instrumentation package for Azure AI Search (azure-search-documents SDK).

Package: opentelemetry-instrumentation-azure-search

Instrumented methods

  • SearchClient.search()
  • SearchClient.upload_documents()
  • SearchClient.merge_documents()
  • SearchClient.merge_or_upload_documents()
  • SearchClient.delete_documents()

Span attributes captured

  • db.system — always azure_search
  • server.address — endpoint URL
  • azure_search.index_name — index being queried
  • azure_search.search_text — query string
  • azure_search.top — max results requested
  • azure_search.filter — OData filter expression
  • azure_search.duration — operation duration in seconds
  • azure_search.affected_documents — documents in write operations
  • azure_search.succeeded_documents — successfully written documents

Testing

6 tests covering search, upload, merge, and delete operations including error handling.

Notes

Follows the same pattern as opentelemetry-instrumentation-pinecone.

  • 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.
Screenshot 2026-06-21 223045

Summary by CodeRabbit

  • New Features
    • Added Azure AI Search OpenTelemetry instrumentation for tracing search and document operations (search, upload, merge, delete).
    • Supports both auto-instrumentation via SDK and manual instrumentation.
    • Added a package entry point for registering the Azure Search instrumentor and set the package version.
  • Documentation
    • Added end-user README with installation options, usage examples, and the span names/attributes captured.
  • Tests
    • Added unit tests covering span creation, key attributes, and error/status handling for search and document operations.
  • Chores
    • Updated project configuration to create virtual environments inside the project directory.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 21, 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: 62f9a860-4b57-477d-94f0-c6954f4d4f45

📥 Commits

Reviewing files that changed from the base of the PR and between 992a664 and 7be4222.

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

📝 Walkthrough

Walkthrough

A new opentelemetry-instrumentation-azure-search package is added from scratch. It wraps azure.search.documents.SearchClient methods to create OpenTelemetry spans, collect input attributes (index name, endpoint, query parameters), record document-count metrics from responses, and capture exceptions. Package metadata, test infrastructure, pytest tests, a standalone test script, and README documentation are included.

Changes

Azure AI Search OpenTelemetry Instrumentation

Layer / File(s) Summary
Package metadata and project configuration
packages/opentelemetry-instrumentation-azure-search/pyproject.toml, packages/opentelemetry-instrumentation-azure-search/poetry.toml, packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/version.py
Defines distribution metadata, runtime and optional instruments dependencies, the opentelemetry_instrumentor entry point mapping azure_search to AzureSearchInstrumentor, build/coverage/Ruff config, in-project virtualenvs setting, and __version__ = "0.1.0".
Core instrumentation: WRAPPED_METHODS, span lifecycle, AzureSearchInstrumentor
packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/__init__.py
WRAPPED_METHODS lists all SearchClient methods and their span names. _set_input_attributes attaches index name, endpoint, and search query parameters to the span. _set_response_attributes iterates write-operation responses to compute and set azure_search.affected_documents and azure_search.succeeded_documents. _wrap starts a CLIENT span with db.system="azure_search", measures duration, captures exceptions with error status and error-type attribute, and returns original response. AzureSearchInstrumentor registers and deregisters all wrappers.
Test fixtures and setup
packages/opentelemetry-instrumentation-azure-search/tests/conftest.py
Session-scoped InMemorySpanExporter fixture wired to a TracerProvider with SimpleSpanProcessor, installs AzureSearchInstrumentor for the test session (and uninstalls on teardown), and provides an autouse clear_exporter fixture that clears the exporter before each test.
Tests for search and document operations
packages/opentelemetry-instrumentation-azure-search/tests/test_search.py, packages/opentelemetry-instrumentation-azure-search/tests/test_documents.py
test_search.py verifies span creation for search operations, asserts db.system == "azure_search" attribute, and validates error capture with StatusCode.ERROR. test_documents.py verifies span creation for upload_documents and merge_documents, and confirms error capture with StatusCode.ERROR status for delete_documents.
Documentation and end-to-end smoke test
packages/opentelemetry-instrumentation-azure-search/README.md, packages/opentelemetry-instrumentation-azure-search/test_trace.py
README documents installation, auto-instrumentation via Traceloop SDK, manual instrumentation via AzureSearchInstrumentor, instrumented methods table, and span attributes table. test_trace.py provides a standalone instrumentation demo with console export and mocked SearchClient invocation.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant _wrap
  participant SearchClient
  participant OTelSpan

  Caller->>_wrap: invoke wrapped SearchClient method
  _wrap->>OTelSpan: start CLIENT span (db.system="azure_search")
  _wrap->>_wrap: _set_input_attributes(span, instance, args, kwargs)
  _wrap->>SearchClient: call original method(*args, **kwargs)
  alt success (write operation)
    SearchClient-->>_wrap: IndexDocumentsBatch response
    _wrap->>_wrap: _set_response_attributes → affected/succeeded counts
    _wrap->>OTelSpan: set duration, StatusCode.OK
    _wrap-->>Caller: response
  else success (search)
    SearchClient-->>_wrap: SearchItemPaged iterator
    _wrap->>OTelSpan: set duration, StatusCode.OK
    _wrap-->>Caller: iterator
  else exception raised
    SearchClient-->>_wrap: raise Exception
    _wrap->>OTelSpan: record_exception, set error.type, StatusCode.ERROR
    _wrap-->>Caller: re-raise Exception
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hippity-hop through the search index tree,
Spans now bloom where queries run free!
Upload, merge, delete — all traced with care,
db.system set with a fluffy flair.
Azure AI Search hops into the light,
OpenTelemetry watching each search take flight! 🔍✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 'feat: add Azure AI Search instrumentation' directly and concisely summarizes the main change—adding instrumentation for Azure AI Search—matching the PR's primary objective.
Linked Issues check ✅ Passed The PR fully implements the feature requested in #2303: an autoinstrumentor for Azure AI Search covering five SearchClient methods with comprehensive span attributes and error handling.
Out of Scope Changes check ✅ Passed All changes are scoped to the new Azure Search instrumentation package; no unrelated modifications to existing code or out-of-scope functionality are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

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

🧹 Nitpick comments (2)
packages/opentelemetry-instrumentation-azure-search/tests/test_documents.py (1)

26-29: ⚡ Quick win

Remove blanket exception swallowing in success-path document tests.

Catching and ignoring all exceptions here can make failing behavior look green.

Proposed fix
 def test_upload_documents_creates_span(exporter):
     client = _make_client()
     with patch("azure.core.pipeline.Pipeline.run", return_value=_mock_pipeline_response()):
-        try:
-            client.upload_documents(documents=[{"id": "1"}, {"id": "2"}])
-        except Exception:
-            pass
+        client.upload_documents(documents=[{"id": "1"}, {"id": "2"}])
@@
 def test_merge_documents_creates_span(exporter):
     client = _make_client()
     with patch("azure.core.pipeline.Pipeline.run", return_value=_mock_pipeline_response()):
-        try:
-            client.merge_documents(documents=[{"id": "1", "title": "updated"}])
-        except Exception:
-            pass
+        client.merge_documents(documents=[{"id": "1", "title": "updated"}])

Also applies to: 39-42

🤖 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-azure-search/tests/test_documents.py`
around lines 26 - 29, The try-except block in the test for
client.upload_documents is catching and ignoring all exceptions without any
assertion or verification, which masks test failures and makes them appear to
pass. Since this is a success-path test, remove the blanket exception handling
entirely so that any unexpected errors will properly fail the test. Apply this
same fix to the other occurrence mentioned at lines 39-42 where the same pattern
appears.
packages/opentelemetry-instrumentation-azure-search/tests/test_search.py (1)

15-19: ⚡ Quick win

Avoid except Exception: pass in tests; assert expected outcomes explicitly.

These blocks can hide real regressions by allowing unexpected failures to pass silently.

Proposed fix
     client = _make_client()
     with patch("azure.core.pipeline.Pipeline.run", return_value=MagicMock(http_response=MagicMock(status_code=200, text=lambda encoding=None: '{"value": []}', headers={}))):
-        try:
-            client.search("hello world", top=5)
-        except Exception:
-            pass
+        client.search("hello world", top=5)
@@
     client._index_name = "my-index"
     with patch("azure.core.pipeline.Pipeline.run", return_value=MagicMock(http_response=MagicMock(status_code=200, text=lambda encoding=None: '{"value": []}', headers={}))):
-        try:
-            client.search("test query", top=10)
-        except Exception:
-            pass
+        client.search("test query", top=10)
@@
     client = _make_client()
     with patch("azure.core.pipeline.Pipeline.run", side_effect=Exception("Service unavailable")):
-        try:
-            results = client.search("query")
-            list(results)
-        except Exception:
-            pass
+        with pytest.raises(Exception, match="Service unavailable"):
+            list(client.search("query"))

Also applies to: 30-33, 43-47

🤖 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-azure-search/tests/test_search.py`
around lines 15 - 19, The bare except Exception: pass block in the client.search
call silently swallows any exceptions without asserting expected outcomes, which
can hide regressions. Remove the try/except block around the
client.search("hello world", top=5) call and instead add an explicit assertion
to verify the expected result. Since the mock is configured to return a
successful response with status_code=200, assert on the actual return value or
behavior of the search method rather than catching and ignoring exceptions.
🤖 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
`@packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/__init__.py`:
- Around line 74-85: The _set_response_attributes function is materializing the
response to a new list on line 78 with `results = list(response)` and then
returning that materialized list on line 82, which breaks the SDK's documented
return type. Instead, extract the needed attributes by iterating directly over
the response object without materializing it into a separate list variable, and
remove the explicit return statement on line 82 so the function returns the
original response object unchanged at the end.

In
`@packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/version.py`:
- Line 1: The version.py file is missing a trailing newline at the end, which
violates Ruff rule W292. Add a newline character at the end of the file after
the __version__ variable assignment to satisfy this lint requirement and ensure
the file ends with a proper newline as per PEP 8 conventions.

In `@packages/opentelemetry-instrumentation-azure-search/tests/conftest.py`:
- Around line 9-16: The exporter fixture in conftest.py instruments the
AzureSearchInstrumentor globally but never uninstruments it, causing wrappers to
persist across the test session and contaminate unrelated tests. Refactor the
exporter fixture to use yield instead of return, yielding the exporter object,
and then add cleanup code after the yield that calls uninstrument() on the
AzureSearchInstrumentor instance to properly clean up the instrumentation when
the session ends.

---

Nitpick comments:
In `@packages/opentelemetry-instrumentation-azure-search/tests/test_documents.py`:
- Around line 26-29: The try-except block in the test for
client.upload_documents is catching and ignoring all exceptions without any
assertion or verification, which masks test failures and makes them appear to
pass. Since this is a success-path test, remove the blanket exception handling
entirely so that any unexpected errors will properly fail the test. Apply this
same fix to the other occurrence mentioned at lines 39-42 where the same pattern
appears.

In `@packages/opentelemetry-instrumentation-azure-search/tests/test_search.py`:
- Around line 15-19: The bare except Exception: pass block in the client.search
call silently swallows any exceptions without asserting expected outcomes, which
can hide regressions. Remove the try/except block around the
client.search("hello world", top=5) call and instead add an explicit assertion
to verify the expected result. Since the mock is configured to return a
successful response with status_code=200, assert on the actual return value or
behavior of the search method rather than catching and ignoring exceptions.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: c2a39584-c8f4-4777-b271-0805947e53df

📥 Commits

Reviewing files that changed from the base of the PR and between fb292d0 and 5e0cadd.

📒 Files selected for processing (8)
  • packages/opentelemetry-instrumentation-azure-search/README.md
  • packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/__init__.py
  • packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/version.py
  • packages/opentelemetry-instrumentation-azure-search/poetry.toml
  • packages/opentelemetry-instrumentation-azure-search/pyproject.toml
  • packages/opentelemetry-instrumentation-azure-search/tests/conftest.py
  • packages/opentelemetry-instrumentation-azure-search/tests/test_documents.py
  • packages/opentelemetry-instrumentation-azure-search/tests/test_search.py

Comment thread packages/opentelemetry-instrumentation-azure-search/tests/conftest.py Outdated

@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

🤖 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
`@packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/__init__.py`:
- Around line 121-123: The span status on lines 121-123 is unconditionally set
to OK after calling _set_response_attributes, which masks partial indexing
failures in batch operations. Update the _set_response_attributes function to
return the count of succeeded and affected documents from the IndexingResult
entries in the response. Then, after calling _set_response_attributes, check if
succeeded is less than affected; if so, set the span status to ERROR using
Status(StatusCode.ERROR) instead of unconditionally setting OK, ensuring partial
failures in batch operations like upload_documents, merge_documents,
merge_or_upload_documents, and delete_documents are properly reflected in
observability.

In `@packages/opentelemetry-instrumentation-azure-search/test_trace.py`:
- Line 26: The file test_trace.py is missing a trailing newline at the end of
the file after the print("Done") statement. Add a newline character at the very
end of the file, after the final print("Done") line, to comply with the file
formatting standard (Ruff W292).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8056060-bd68-4177-b01f-3aa713a2e373

📥 Commits

Reviewing files that changed from the base of the PR and between 5e0cadd and 5dab758.

📒 Files selected for processing (3)
  • packages/opentelemetry-instrumentation-azure-search/opentelemetry/instrumentation/azure_search/__init__.py
  • packages/opentelemetry-instrumentation-azure-search/test_trace.py
  • packages/opentelemetry-instrumentation-azure-search/tests/conftest.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opentelemetry-instrumentation-azure-search/tests/conftest.py

Comment thread packages/opentelemetry-instrumentation-azure-search/test_trace.py Outdated
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.

🚀 Feature: Support for Azure AI Search

2 participants