Skip to content

Commit df7438e

Browse files
committed
elasticsearch: tests against elasticsearch 8
1 parent 1d3dea0 commit df7438e

File tree

8 files changed

+186
-49
lines changed

8 files changed

+186
-49
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4949
([#2404](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2404))
5050
- Remove SDK dependency from opentelemetry-instrumentation-grpc
5151
([#2474](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2474))
52+
- `opentelemetry-instrumentation-elasticsearch` Improved support for version 8
53+
([#2420](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2420))
5254

5355
## Version 1.24.0/0.45b0 (2024-03-28)
5456

Diff for: instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py

+52-7
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def response_hook(span, response):
9494
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
9595
from opentelemetry.instrumentation.utils import unwrap
9696
from opentelemetry.semconv.trace import SpanAttributes
97-
from opentelemetry.trace import SpanKind, get_tracer
97+
from opentelemetry.trace import SpanKind, Status, StatusCode, get_tracer
9898

9999
from .utils import sanitize_body
100100

@@ -103,6 +103,7 @@ def response_hook(span, response):
103103
es_transport_split = elasticsearch.VERSION[0] > 7
104104
if es_transport_split:
105105
import elastic_transport
106+
from elastic_transport._models import DefaultType
106107

107108
logger = getLogger(__name__)
108109

@@ -173,7 +174,12 @@ def _instrument(self, **kwargs):
173174

174175
def _uninstrument(self, **kwargs):
175176
# pylint: disable=no-member
176-
unwrap(elasticsearch.Transport, "perform_request")
177+
transport_class = (
178+
elastic_transport.Transport
179+
if es_transport_split
180+
else elasticsearch.Transport
181+
)
182+
unwrap(transport_class, "perform_request")
177183

178184

179185
_regex_doc_url = re.compile(r"/_doc/([^/]+)")
@@ -234,7 +240,21 @@ def wrapper(wrapped, _, args, kwargs):
234240
kind=SpanKind.CLIENT,
235241
) as span:
236242
if callable(request_hook):
237-
request_hook(span, method, url, kwargs)
243+
if es_transport_split:
244+
245+
def normalize_kwargs(k, v):
246+
if isinstance(v, DefaultType):
247+
v = str(v)
248+
elif isinstance(v, elastic_transport.HttpHeaders):
249+
v = dict(v)
250+
return (k, v)
251+
252+
hook_kwargs = dict(
253+
normalize_kwargs(k, v) for k, v in kwargs.items()
254+
)
255+
else:
256+
hook_kwargs = kwargs
257+
request_hook(span, method, url, hook_kwargs)
238258

239259
if span.is_recording():
240260
attributes = {
@@ -260,16 +280,41 @@ def wrapper(wrapped, _, args, kwargs):
260280
span.set_attribute(key, value)
261281

262282
rv = wrapped(*args, **kwargs)
263-
if isinstance(rv, dict) and span.is_recording():
283+
284+
body = rv.body if es_transport_split else rv
285+
if isinstance(body, dict) and span.is_recording():
264286
for member in _ATTRIBUTES_FROM_RESULT:
265-
if member in rv:
287+
if member in body:
266288
span.set_attribute(
267289
f"elasticsearch.{member}",
268-
str(rv[member]),
290+
str(body[member]),
291+
)
292+
293+
# since the transport split the raising of exceptions that set the error status
294+
# are called after this code so need to set error status manually
295+
if es_transport_split and span.is_recording():
296+
if not (method == "HEAD" and rv.meta.status == 404) and (
297+
not 200 <= rv.meta.status < 299
298+
):
299+
exception = elasticsearch.exceptions.HTTP_EXCEPTIONS.get(
300+
rv.meta.status, elasticsearch.exceptions.ApiError
301+
)
302+
message = str(body)
303+
if isinstance(body, dict):
304+
error = body.get("error", message)
305+
if isinstance(error, dict) and "type" in error:
306+
error = error["type"]
307+
message = error
308+
309+
span.set_status(
310+
Status(
311+
status_code=StatusCode.ERROR,
312+
description=f"{exception.__name__}: {message}",
269313
)
314+
)
270315

271316
if callable(response_hook):
272-
response_hook(span, rv)
317+
response_hook(span, body)
273318
return rv
274319

275320
return wrapper
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
asgiref==3.7.2
2+
attrs==23.2.0
3+
Deprecated==1.2.14
4+
elasticsearch==8.12.1
5+
elasticsearch-dsl==8.12.0
6+
elastic-transport==8.12.0
7+
importlib-metadata==7.1.0
8+
iniconfig==2.0.0
9+
packaging==23.2
10+
pluggy==1.4.0
11+
py==1.11.0
12+
py-cpuinfo==9.0.0
13+
pytest==7.1.3
14+
pytest-benchmark==4.0.0
15+
python-dateutil==2.8.2
16+
six==1.16.0
17+
tomli==2.0.1
18+
typing_extensions==4.10.0
19+
urllib3==2.2.1
20+
wrapt==1.16.0
21+
zipp==3.17.0
22+
-e opentelemetry-instrumentation
23+
-e instrumentation/opentelemetry-instrumentation-elasticsearch

Diff for: instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es6.py

+6
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,9 @@ class Index:
3131
dsl_index_span_name = "Elasticsearch/test-index/doc/2"
3232
dsl_index_url = "/test-index/doc/2"
3333
dsl_search_method = "GET"
34+
35+
perform_request_mock_path = "elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request"
36+
37+
38+
def mock_response(body: str, status_code: int = 200):
39+
return (status_code, {}, body)

Diff for: instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es7.py

+6
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ class Index:
2929
dsl_index_span_name = "Elasticsearch/test-index/_doc/:id"
3030
dsl_index_url = "/test-index/_doc/2"
3131
dsl_search_method = "POST"
32+
33+
perform_request_mock_path = "elasticsearch.connection.http_urllib3.Urllib3HttpConnection.perform_request"
34+
35+
36+
def mock_response(body: str, status_code: int=200):
37+
return (status_code, {}, body)

Diff for: instrumentation/opentelemetry-instrumentation-elasticsearch/tests/helpers_es8.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414

1515
from elasticsearch_dsl import Document, Keyword, Text
16+
from elastic_transport._node import NodeApiResponse
17+
from elastic_transport import ApiResponseMeta, HttpHeaders
1618

1719

1820
class Article(Document):
@@ -36,6 +38,23 @@ class Index:
3638
}
3739
}
3840
dsl_index_result = (1, {}, '{"result": "created"}')
39-
dsl_index_span_name = "Elasticsearch/test-index/_doc/2"
41+
dsl_index_span_name = "Elasticsearch/test-index/_doc/:id"
4042
dsl_index_url = "/test-index/_doc/2"
4143
dsl_search_method = "POST"
44+
45+
perform_request_mock_path = (
46+
"elastic_transport._node._http_urllib3.Urllib3HttpNode.perform_request"
47+
)
48+
49+
50+
def mock_response(body: str, status_code: int = 200):
51+
return NodeApiResponse(
52+
ApiResponseMeta(
53+
status=status_code,
54+
headers=HttpHeaders({}),
55+
duration=100,
56+
http_version="1.1",
57+
node="node",
58+
),
59+
body.encode(),
60+
)

0 commit comments

Comments
 (0)