Skip to content

Commit

Permalink
elasticsearch: don't produce spans if native elasticsearch support is…
Browse files Browse the repository at this point in the history
… enabled (#2524)
  • Loading branch information
xrmx authored May 24, 2024
1 parent 65b4f85 commit eb8e456
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2474](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2474))
- `opentelemetry-instrumentation-elasticsearch` Improved support for version 8
([#2420](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2420))
- `opentelemetry-instrumentation-elasticsearch` Disabling instrumentation with native OTel support enabled
([#2524](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2524))
- `opentelemetry-instrumentation-asyncio` Check for __name__ attribute in the coroutine
([#2521](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2521))
- `opentelemetry-util-http` Preserve brackets around literal IPv6 hosts ([#2552](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2552))


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

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
This library allows tracing HTTP elasticsearch made by the
`elasticsearch <https://elasticsearch-py.readthedocs.io/en/master/>`_ library.
.. warning::
The elasticsearch package got native OpenTelemetry support since version
`8.13 <https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/release-notes.html#rn-8-13-0>`_.
To avoid duplicated tracing this instrumentation disables itself if it finds an elasticsearch client
that has OpenTelemetry support enabled.
Please be aware that the two libraries may use a different semantic convention, see
`elasticsearch documentation <https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/opentelemetry.html>`_.
Usage
-----
Expand Down Expand Up @@ -54,7 +63,7 @@ def response_hook(span: Span, response: dict)
for example:
.. code: python
.. code-block: python
from opentelemetry.instrumentation.elasticsearch import ElasticsearchInstrumentor
import elasticsearch
Expand All @@ -81,6 +90,7 @@ def response_hook(span, response):
"""

import re
import warnings
from logging import getLogger
from os import environ
from typing import Collection
Expand Down Expand Up @@ -197,6 +207,16 @@ def _wrap_perform_request(
):
# pylint: disable=R0912,R0914
def wrapper(wrapped, _, args, kwargs):
# if wrapped elasticsearch has native OTel instrumentation just call the wrapped function
otel_span = kwargs.get("otel_span")
if otel_span and otel_span.otel_span:
warnings.warn(
"Instrumentation disabled, relying on elasticsearch native OTel support, see "
"https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/elasticsearch/elasticsearch.html",
Warning,
)
return wrapped(*args, **kwargs)

method = url = None
try:
method, url, *_ = args
Expand Down Expand Up @@ -249,6 +269,11 @@ def normalize_kwargs(k, v):
v = str(v)
elif isinstance(v, elastic_transport.HttpHeaders):
v = dict(v)
elif isinstance(
v, elastic_transport.OpenTelemetrySpan
):
# the transport Span is always a dummy one
v = None
return (k, v)

hook_kwargs = dict(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
asgiref==3.7.2
attrs==23.2.0
Deprecated==1.2.14
elasticsearch==8.12.1
elasticsearch-dsl==8.12.0
elastic-transport==8.12.0
elasticsearch==8.13.1
elasticsearch-dsl==8.13.1
elastic-transport==8.13.0
importlib-metadata==6.11.0
iniconfig==2.0.0
packaging==23.2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import elasticsearch.exceptions
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search
from pytest import mark

import opentelemetry.instrumentation.elasticsearch
from opentelemetry import trace
Expand All @@ -36,7 +37,7 @@

from . import sanitization_queries # pylint: disable=no-name-in-module

major_version = elasticsearch.VERSION[0]
major_version, minor_version = elasticsearch.VERSION[:2]

if major_version == 8:
from . import helpers_es8 as helpers # pylint: disable=no-name-in-module
Expand Down Expand Up @@ -70,6 +71,9 @@ def get_elasticsearch_client(*args, **kwargs):


@mock.patch(helpers.perform_request_mock_path)
@mock.patch.dict(
os.environ, {"OTEL_PYTHON_INSTRUMENTATION_ELASTICSEARCH_ENABLED": "false"}
)
class TestElasticsearchIntegration(TestBase):
search_attributes = {
SpanAttributes.DB_SYSTEM: "elasticsearch",
Expand Down Expand Up @@ -110,7 +114,6 @@ def test_instrumentor(self, request_mock):
span = spans_list[0]

# Check version and name in span's instrumentation info
# self.assertEqualSpanInstrumentationInfo(span, opentelemetry.instrumentation.elasticsearch)
self.assertEqualSpanInstrumentationInfo(
span, opentelemetry.instrumentation.elasticsearch
)
Expand Down Expand Up @@ -475,6 +478,7 @@ def request_hook(span, method, url, kwargs):
"headers": {
"accept": "application/vnd.elasticsearch+json; compatible-with=8"
},
"otel_span": None,
}
elif major_version == 7:
expected_kwargs = {
Expand Down Expand Up @@ -607,3 +611,30 @@ def test_bulk(self, request_mock):
self.assertEqualSpanInstrumentationInfo(
span, opentelemetry.instrumentation.elasticsearch
)

@mark.skipif(
(major_version, minor_version) < (8, 13),
reason="Native OTel since elasticsearch 8.13",
)
@mock.patch.dict(
os.environ,
{"OTEL_PYTHON_INSTRUMENTATION_ELASTICSEARCH_ENABLED": "true"},
)
def test_instrumentation_is_disabled_if_native_support_enabled(
self, request_mock
):
request_mock.return_value = helpers.mock_response("{}")

es = get_elasticsearch_client(hosts=["http://localhost:9200"])
es.index(
index="sw",
id=1,
**normalize_arguments(body={"name": "adam"}, doc_type="_doc"),
)

spans_list = self.get_finished_spans()
self.assertEqual(len(spans_list), 1)
span = spans_list[0]

# Check that name in span's instrumentation info is not from this instrumentation
self.assertEqual(span.instrumentation_info.name, "elasticsearch-api")
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ envlist =
; below mean these dependencies are being used:
; 0: elasticsearch-dsl==6.4.0 elasticsearch==6.8.2
; 1: elasticsearch-dsl==7.4.1 elasticsearch==7.17.9
; 2: elasticsearch-dsl>=8.0,<8.13 elasticsearch>=8.0,<8.13
; 2: elasticsearch-dsl==8.13.1 elasticsearch==8.13.1
py3{8,9,10,11}-test-instrumentation-elasticsearch-{0,1,2}
pypy3-test-instrumentation-elasticsearch-{0,1,2}
lint-instrumentation-elasticsearch
Expand Down

0 comments on commit eb8e456

Please sign in to comment.