diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c62672bf7..6784dc9e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#999])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/999) - `opentelemetry-instrumentation-falcon` Falcon: Capture custom request/response headers in span attributes ([#1003])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1003) +- `opentelemetry-instrumentation-elasticsearch` no longer creates unique span names by including search target, replaces them with `` and puts the value in attribute `elasticsearch.target` + ([#1018](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1018)) ## [1.10.0-0.29b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.10.0-0.29b0) - 2022-03-10 diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py index cdd49fe1d7..6f29b1f43d 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/__init__.py @@ -150,11 +150,14 @@ def _uninstrument(self, **kwargs): _regex_doc_url = re.compile(r"/_doc/([^/]+)") +# search api https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html +_regex_search_url = re.compile(r"/([^/]+)/_search[/]?") + def _wrap_perform_request( tracer, span_name_prefix, request_hook=None, response_hook=None ): - # pylint: disable=R0912 + # pylint: disable=R0912,R0914 def wrapper(wrapped, _, args, kwargs): method = url = None try: @@ -167,7 +170,10 @@ def wrapper(wrapped, _, args, kwargs): ) op_name = span_name_prefix + (url or method or _DEFAULT_OP_NAME) + doc_id = None + search_target = None + if url: # TODO: This regex-based solution avoids creating an unbounded number of span names, but should be replaced by instrumenting individual Elasticsearch methods instead of Transport.perform_request() # A limitation of the regex is that only the '_doc' mapping type is supported. Mapping types are deprecated since Elasticsearch 7 @@ -184,6 +190,11 @@ def wrapper(wrapped, _, args, kwargs): ) # Put the document ID in attributes doc_id = match.group(1) + match = _regex_search_url.search(url) + if match is not None: + op_name = span_name_prefix + "//_search" + search_target = match.group(1) + params = kwargs.get("params", {}) body = kwargs.get("body", None) @@ -209,6 +220,8 @@ def wrapper(wrapped, _, args, kwargs): attributes["elasticsearch.params"] = str(params) if doc_id: attributes["elasticsearch.id"] = doc_id + if search_target: + attributes["elasticsearch.target"] = search_target for key, value in attributes.items(): span.set_attribute(key, value) diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py index 91e4df7ecd..1a2cf30738 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/tests/test_elasticsearch.py @@ -237,7 +237,7 @@ def test_dsl_search(self, request_mock): spans = self.get_finished_spans() span = spans[0] self.assertEqual(1, len(spans)) - self.assertEqual(span.name, "Elasticsearch/test-index/_search") + self.assertEqual(span.name, "Elasticsearch//_search") self.assertIsNotNone(span.end_time) self.assertEqual( span.attributes, @@ -245,6 +245,7 @@ def test_dsl_search(self, request_mock): SpanAttributes.DB_SYSTEM: "elasticsearch", "elasticsearch.url": "/test-index/_search", "elasticsearch.method": helpers.dsl_search_method, + "elasticsearch.target": "test-index", SpanAttributes.DB_STATEMENT: str( { "query": {