Skip to content

Commit

Permalink
Merge branch 'main' into repeated-headers-list
Browse files Browse the repository at this point in the history
  • Loading branch information
lzchen authored May 28, 2024
2 parents 8dc8c16 + 88111d0 commit 06c9816
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,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-instrumentation-requests` Fix wrong time unit for duration histogram
([#2553](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2553))
- `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)

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")
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,7 @@ def get_or_create_headers():
exception = exc
result = getattr(exc, "response", None)
finally:
elapsed_time = max(
round((default_timer() - start_time) * 1000), 0
)
elapsed_time = max(default_timer() - start_time, 0)

if isinstance(result, Response):
span_attributes = {}
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,7 @@ def remove_url_credentials(url: str) -> str:
parsed = urlparse(url)
if all([parsed.scheme, parsed.netloc]): # checks for valid url
parsed_url = urlparse(url)
netloc = (
(":".join(((parsed_url.hostname or ""), str(parsed_url.port))))
if parsed_url.port
else (parsed_url.hostname or "")
)
_, _, netloc = parsed.netloc.rpartition("@")
return urlunparse(
(
parsed_url.scheme,
Expand Down
27 changes: 27 additions & 0 deletions util/opentelemetry-util-http/tests/test_remove_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import unittest

from opentelemetry.util.http import remove_url_credentials


class TestRemoveUrlCredentials(unittest.TestCase):
def test_remove_no_credentials(self):
url = "http://opentelemetry.io:8080/test/path?query=value"
cleaned_url = remove_url_credentials(url)
self.assertEqual(cleaned_url, url)

def test_remove_credentials(self):
url = "http://someuser:[email protected]:8080/test/path?query=value"
cleaned_url = remove_url_credentials(url)
self.assertEqual(
cleaned_url, "http://opentelemetry.io:8080/test/path?query=value"
)

def test_remove_credentials_ipv4_literal(self):
url = "http://someuser:[email protected]:8080/test/path?query=value"
cleaned_url = remove_url_credentials(url)
self.assertEqual(cleaned_url, "http://127.0.0.1:8080/test/path?query=value")

def test_remove_credentials_ipv6_literal(self):
url = "http://someuser:somepass@[::1]:8080/test/path?query=value"
cleaned_url = remove_url_credentials(url)
self.assertEqual(cleaned_url, "http://[::1]:8080/test/path?query=value")

0 comments on commit 06c9816

Please sign in to comment.