From e6af0eaa4ba3c8c3250dca516ca91b30cc6b70ac Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 16:33:13 -0400 Subject: [PATCH 1/9] [exporter/datadog]: add support for extracting error info from exception span events --- .../exporter/datadog/constants.py | 7 +++++ .../exporter/datadog/exporter.py | 28 ++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/constants.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/constants.py index 90f15a7ffc..6f86c12cce 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/constants.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/constants.py @@ -7,3 +7,10 @@ ENV_KEY = "env" VERSION_KEY = "version" SERVICE_NAME_TAG = "service.name" +EVENT_NAME_EXCEPTION = "exception" +EXCEPTION_TYPE_ATTR_KEY = "exception.type" +EXCEPTION_MSG_ATTR_KEY = "exception.message" +EXCEPTION_STACK_ATTR_KEY = "exception.stacktrace" +DD_ERROR_TYPE_TAG_KEY = "error.type" +DD_ERROR_MSG_TAG_KEY = "error.msg" +DD_ERROR_STACK_TAG_KEY = "error.stack" diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index da1794afff..fa5f6fbaa6 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -22,8 +22,15 @@ import opentelemetry.trace as trace_api from opentelemetry.exporter.datadog.constants import ( + DD_ERROR_MSG_TAG_KEY, + DD_ERROR_STACK_TAG_KEY, + DD_ERROR_TYPE_TAG_KEY, DD_ORIGIN, ENV_KEY, + EVENT_NAME_EXCEPTION, + EXCEPTION_MSG_ATTR_KEY, + EXCEPTION_STACK_ATTR_KEY, + EXCEPTION_TYPE_ATTR_KEY, SAMPLE_RATE_METRIC_KEY, SERVICE_NAME_TAG, VERSION_KEY, @@ -144,11 +151,24 @@ def _translate_to_datadog(self, spans): if not span.status.is_ok: datadog_span.error = 1 - if span.status.description: + # loop over events and look for exception events, extract info. + # https://github.com/open-telemetry/opentelemetry-python/blob/71e3a7a192c0fc8a7503fac967ada36a74b79e58/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py#L810-L819 + if span.events: + for event in span.events: + if event.name is not None and event.name == EVENT_NAME_EXCEPTION: + for key, value in event.attributes.items(): + if key == EXCEPTION_TYPE_ATTR_KEY: + datadog_span.set_tag(DD_ERROR_TYPE_TAG_KEY, value) + elif key == EXCEPTION_MSG_ATTR_KEY: + datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, value) + elif key == EXCEPTION_STACK_ATTR_KEY: + datadog_span.set_tag(DD_ERROR_STACK_TAG_KEY, value) + # fallback to description but only if no exception events + elif span.status.description: exc_type, exc_val = _get_exc_info(span) # no mapping for error.stack since traceback not recorded - datadog_span.set_tag("error.msg", exc_val) - datadog_span.set_tag("error.type", exc_type) + datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, exc_val) + datadog_span.set_tag(DD_ERROR_TYPE_TAG_KEY, exc_type) # combine resource attributes and span attributes, don't modify existing span attributes combined_span_tags = {} @@ -177,7 +197,7 @@ def _translate_to_datadog(self, spans): if sampling_rate is not None: datadog_span.set_metric(SAMPLE_RATE_METRIC_KEY, sampling_rate) - # span events and span links are not supported + # span events and span links are not supported except for extracting exception event context datadog_spans.append(datadog_span) From 52a1c9437bce27ba27549c13ba087ab20c07e3dd Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 16:35:41 -0400 Subject: [PATCH 2/9] [exporter/datadog]: update tests to check exception tags are set as error tags on datadog span --- .../tests/test_datadog_exporter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exporter/opentelemetry-exporter-datadog/tests/test_datadog_exporter.py b/exporter/opentelemetry-exporter-datadog/tests/test_datadog_exporter.py index 9cc7ccbb21..d8a2db2a2e 100644 --- a/exporter/opentelemetry-exporter-datadog/tests/test_datadog_exporter.py +++ b/exporter/opentelemetry-exporter-datadog/tests/test_datadog_exporter.py @@ -381,6 +381,7 @@ def test_errors(self): self.assertEqual(span["error"], 1) self.assertEqual(span["meta"]["error.msg"], "bar") self.assertEqual(span["meta"]["error.type"], "ValueError") + self.assertTrue(span["meta"]["error.stack"] is not None) def test_shutdown(self): span_names = ["xxx", "bar", "foo"] From 6bcb44f5ce74ca4519c917f22ee6e48387651a1f Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 16:51:17 -0400 Subject: [PATCH 3/9] [exporter/datadog]: add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e351539e..5457ac5f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#415](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/415)) - `opentelemetry-instrumentation-tornado` Add request/response hooks. ([#426](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/426)) +- `opentelemetry-exporter-datadog` Add parsing exception events for error tags([#459](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/459)) ### Removed - Remove `http.status_text` from span attributes From b1b6aa307376998fcaa5e3bdfc85b8d0a7853421 Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 16:55:57 -0400 Subject: [PATCH 4/9] [exporter/datadog]: fix typos --- .../src/opentelemetry/exporter/datadog/exporter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index fa5f6fbaa6..4645ed41aa 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -163,8 +163,8 @@ def _translate_to_datadog(self, spans): datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, value) elif key == EXCEPTION_STACK_ATTR_KEY: datadog_span.set_tag(DD_ERROR_STACK_TAG_KEY, value) - # fallback to description but only if no exception events - elif span.status.description: + # fallback to description but only if no exception events. + elif span.status.description: exc_type, exc_val = _get_exc_info(span) # no mapping for error.stack since traceback not recorded datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, exc_val) From 946e9a5dad8623a8343538080c4a4ac24baaa2e6 Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 17:18:55 -0400 Subject: [PATCH 5/9] [exporter/datadog]: linting --- .../opentelemetry/exporter/datadog/exporter.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index 4645ed41aa..bea7e7a148 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -155,14 +155,23 @@ def _translate_to_datadog(self, spans): # https://github.com/open-telemetry/opentelemetry-python/blob/71e3a7a192c0fc8a7503fac967ada36a74b79e58/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py#L810-L819 if span.events: for event in span.events: - if event.name is not None and event.name == EVENT_NAME_EXCEPTION: + if ( + event.name is not None + and event.name == EVENT_NAME_EXCEPTION + ): for key, value in event.attributes.items(): if key == EXCEPTION_TYPE_ATTR_KEY: - datadog_span.set_tag(DD_ERROR_TYPE_TAG_KEY, value) + datadog_span.set_tag( + DD_ERROR_TYPE_TAG_KEY, value + ) elif key == EXCEPTION_MSG_ATTR_KEY: - datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, value) + datadog_span.set_tag( + DD_ERROR_MSG_TAG_KEY, value + ) elif key == EXCEPTION_STACK_ATTR_KEY: - datadog_span.set_tag(DD_ERROR_STACK_TAG_KEY, value) + datadog_span.set_tag( + DD_ERROR_STACK_TAG_KEY, value + ) # fallback to description but only if no exception events. elif span.status.description: exc_type, exc_val = _get_exc_info(span) From dad11f3a59b6eeb1be1a1d4cbd4258d22a24536e Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 17:33:11 -0400 Subject: [PATCH 6/9] [exporter/datdog]: fixing linting --- .../exporter/datadog/exporter.py | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index bea7e7a148..c2a839c320 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -149,29 +149,13 @@ def _translate_to_datadog(self, spans): datadog_span.start_ns = span.start_time datadog_span.duration_ns = span.end_time - span.start_time + if not span.status.is_ok: datadog_span.error = 1 # loop over events and look for exception events, extract info. # https://github.com/open-telemetry/opentelemetry-python/blob/71e3a7a192c0fc8a7503fac967ada36a74b79e58/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py#L810-L819 if span.events: - for event in span.events: - if ( - event.name is not None - and event.name == EVENT_NAME_EXCEPTION - ): - for key, value in event.attributes.items(): - if key == EXCEPTION_TYPE_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_TYPE_TAG_KEY, value - ) - elif key == EXCEPTION_MSG_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_MSG_TAG_KEY, value - ) - elif key == EXCEPTION_STACK_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_STACK_TAG_KEY, value - ) + _extract_tags_from_exception_events(span.events, datadog_span) # fallback to description but only if no exception events. elif span.status.description: exc_type, exc_val = _get_exc_info(span) @@ -346,3 +330,25 @@ def _extract_tags_from_resource(resource): else: tags[attribute_key] = attribute_value return [tags, service_name] + +def _extract_tags_from_exception_events(events, datadog_span): + """Parse error tags from exception events, error.msg error.type + and error.stack have special significance within datadog""" + for event in events: + if ( + event.name is not None + and event.name == EVENT_NAME_EXCEPTION + ): + for key, value in event.attributes.items(): + if key == EXCEPTION_TYPE_ATTR_KEY: + datadog_span.set_tag( + DD_ERROR_TYPE_TAG_KEY, value + ) + elif key == EXCEPTION_MSG_ATTR_KEY: + datadog_span.set_tag( + DD_ERROR_MSG_TAG_KEY, value + ) + elif key == EXCEPTION_STACK_ATTR_KEY: + datadog_span.set_tag( + DD_ERROR_STACK_TAG_KEY, value + ) From e66290a7a9223a770986a273492b340c5b30d88a Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 17:39:28 -0400 Subject: [PATCH 7/9] [exporter/datadog]: more linting fixes --- .../exporter/datadog/exporter.py | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index c2a839c320..f7248377c3 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -155,7 +155,9 @@ def _translate_to_datadog(self, spans): # loop over events and look for exception events, extract info. # https://github.com/open-telemetry/opentelemetry-python/blob/71e3a7a192c0fc8a7503fac967ada36a74b79e58/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py#L810-L819 if span.events: - _extract_tags_from_exception_events(span.events, datadog_span) + _extract_tags_from_exception_events( + span.events, datadog_span + ) # fallback to description but only if no exception events. elif span.status.description: exc_type, exc_val = _get_exc_info(span) @@ -331,24 +333,16 @@ def _extract_tags_from_resource(resource): tags[attribute_key] = attribute_value return [tags, service_name] + def _extract_tags_from_exception_events(events, datadog_span): """Parse error tags from exception events, error.msg error.type and error.stack have special significance within datadog""" for event in events: - if ( - event.name is not None - and event.name == EVENT_NAME_EXCEPTION - ): + if event.name is not None and event.name == EVENT_NAME_EXCEPTION: for key, value in event.attributes.items(): if key == EXCEPTION_TYPE_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_TYPE_TAG_KEY, value - ) + datadog_span.set_tag(DD_ERROR_TYPE_TAG_KEY, value) elif key == EXCEPTION_MSG_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_MSG_TAG_KEY, value - ) + datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, value) elif key == EXCEPTION_STACK_ATTR_KEY: - datadog_span.set_tag( - DD_ERROR_STACK_TAG_KEY, value - ) + datadog_span.set_tag(DD_ERROR_STACK_TAG_KEY, value) From 179fe8c77c68ce5a754ede975e142a468cb1b150 Mon Sep 17 00:00:00 2001 From: ericmustin Date: Mon, 19 Apr 2021 17:43:41 -0400 Subject: [PATCH 8/9] [exporter/datadog]: final lint, the lintinging --- .../src/opentelemetry/exporter/datadog/exporter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index f7248377c3..31cc1d49df 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -149,7 +149,6 @@ def _translate_to_datadog(self, spans): datadog_span.start_ns = span.start_time datadog_span.duration_ns = span.end_time - span.start_time - if not span.status.is_ok: datadog_span.error = 1 # loop over events and look for exception events, extract info. From 362dd28869d68b4a2e16e60011604dfc046eefba Mon Sep 17 00:00:00 2001 From: ericmustin Date: Thu, 22 Apr 2021 14:57:10 -0400 Subject: [PATCH 9/9] [exporter/datadog]: remove old error tagging --- .../src/opentelemetry/exporter/datadog/exporter.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py index 31cc1d49df..bcaf070eaf 100644 --- a/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py +++ b/exporter/opentelemetry-exporter-datadog/src/opentelemetry/exporter/datadog/exporter.py @@ -157,12 +157,6 @@ def _translate_to_datadog(self, spans): _extract_tags_from_exception_events( span.events, datadog_span ) - # fallback to description but only if no exception events. - elif span.status.description: - exc_type, exc_val = _get_exc_info(span) - # no mapping for error.stack since traceback not recorded - datadog_span.set_tag(DD_ERROR_MSG_TAG_KEY, exc_val) - datadog_span.set_tag(DD_ERROR_TYPE_TAG_KEY, exc_type) # combine resource attributes and span attributes, don't modify existing span attributes combined_span_tags = {}