Metadata-Version: 2.4
Name: respan-instrumentation-elasticsearch
Version: 0.1.0
Summary: Respan instrumentation plugin for Elasticsearch
License: Apache 2.0
Author: Respan
Author-email: team@respan.ai
Requires-Python: >=3.11,<3.14
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: elastic-transport (>=8.13.0,<10.0.0)
Requires-Dist: elasticsearch (>=8.13.0,<10.0.0)
Requires-Dist: opentelemetry-semantic-conventions-ai (>=0.4.1)
Requires-Dist: respan-sdk (>=2.6.1)
Requires-Dist: respan-tracing (>=2.17.0,<3.0.0)
Requires-Dist: wrapt (>=1.16.0)
Description-Content-Type: text/markdown

# respan-instrumentation-elasticsearch

Respan instrumentation for the official Elasticsearch Python client. It traces the shared transport boundary, so synchronous and asynchronous clients receive the same coverage for index, get, search, bulk, update, delete, cluster, and other API operations.

Every request emits a canonical Respan `task` span. Request and response bodies are JSON-serialized into `traceloop.entity.input` and `traceloop.entity.output`; transport failures and HTTP error responses record OpenTelemetry error status plus backend-visible `status_code` and `error.message` attributes.

## Install

```bash
pip install respan-ai respan-instrumentation-elasticsearch "elasticsearch[async]>=8.13,<10"
```

## Usage

```python
from elasticsearch import Elasticsearch
from respan import Respan, workflow
from respan_instrumentation_elasticsearch import ElasticsearchInstrumentor

respan = Respan(instrumentations=[ElasticsearchInstrumentor()])
client = Elasticsearch("http://localhost:9200")


@workflow(name="elasticsearch_search_workflow")
def search():
    return client.search(index="articles", query={"match": {"title": "tracing"}})


print(search())
client.close()
respan.shutdown()
```

`AsyncElasticsearch` is instrumented automatically as well.

## Content capture

Request and response content is captured by default. Disable it when payloads may contain sensitive data:

```python
ElasticsearchInstrumentor(capture_content=False)
```

With capture disabled, spans retain operation, sanitized target, status, and timing while omitting request and response bodies. Headers are never captured. `activate()` and `deactivate()` are idempotent.

See the Respan example projects for an offline, runnable sync/async suite backed by a local mock Elasticsearch HTTP server.

