Skip to content

Commit d724573

Browse files
author
alrex
authored
Report dropped attributes/events/links for otlp/jaeger/zipkin exporters (open-telemetry#1893)
1 parent 01c6954 commit d724573

File tree

14 files changed

+324
-12
lines changed

14 files changed

+324
-12
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD)
88

9+
### Added
10+
- Dropped attributes/events/links count available exposed on ReadableSpans.
11+
([#1893](https://github.com/open-telemetry/opentelemetry-python/pull/1893))
12+
- Added dropped count to otlp, jaeger and zipkin exporters.
13+
([#1893](https://github.com/open-telemetry/opentelemetry-python/pull/1893))
14+
915
### Changed
1016
- Updated `opentelemetry-opencensus-exporter` to use `service_name` of spans instead of resource
1117
([#1897](https://github.com/open-telemetry/opentelemetry-python/pull/1897))

exporter/opentelemetry-exporter-jaeger-proto-grpc/src/opentelemetry/exporter/jaeger/proto/grpc/translate/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,24 @@ def _extract_tags(
313313
if not span.status.is_ok:
314314
translated.append(_get_bool_key_value("error", True))
315315

316+
if span.dropped_attributes:
317+
translated.append(
318+
_get_long_key_value(
319+
"otel.dropped_attributes_count", span.dropped_attributes
320+
)
321+
)
322+
if span.dropped_events:
323+
translated.append(
324+
_get_long_key_value(
325+
"otel.dropped_events_count", span.dropped_events
326+
)
327+
)
328+
if span.dropped_links:
329+
translated.append(
330+
_get_long_key_value(
331+
"otel.dropped_links_count", span.dropped_links
332+
)
333+
)
316334
return translated
317335

318336
def _extract_refs(
@@ -358,6 +376,15 @@ def _extract_logs(
358376
if tag:
359377
fields.append(tag)
360378

379+
if event.attributes.dropped:
380+
fields.append(
381+
_translate_attribute(
382+
"otel.dropped_attributes_count",
383+
event.attributes.dropped,
384+
self._max_tag_value_length,
385+
)
386+
)
387+
361388
fields.append(
362389
_get_string_key_value(
363390
key="message",

exporter/opentelemetry-exporter-jaeger-proto-grpc/tests/test_jaeger_exporter_protobuf.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,20 @@
3939
from opentelemetry.sdk.trace import TracerProvider
4040
from opentelemetry.sdk.trace.export import SpanExportResult
4141
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
42+
from opentelemetry.test.spantestutil import (
43+
get_span_with_dropped_attributes_events_links,
44+
)
4245
from opentelemetry.trace.status import Status, StatusCode
4346

4447

48+
def _translate_spans_with_dropped_attributes():
49+
span = get_span_with_dropped_attributes_events_links()
50+
translate = Translate([span])
51+
52+
# pylint: disable=protected-access
53+
return translate._translate(pb_translator.ProtobufTranslator("svc"))
54+
55+
4556
# pylint:disable=no-member
4657
class TestJaegerExporter(unittest.TestCase):
4758
def setUp(self):
@@ -475,8 +486,23 @@ def test_export_span_service_name(self):
475486
exporter.export([span])
476487
self.assertEqual(exporter.service_name, "test")
477488

478-
479-
class MockResponse:
480-
def __init__(self, status_code):
481-
self.status_code = status_code
482-
self.text = status_code
489+
def test_dropped_span_attributes(self):
490+
spans = _translate_spans_with_dropped_attributes()
491+
tags_by_keys = {
492+
tag.key: tag.v_str or tag.v_int64 for tag in spans[0].tags
493+
}
494+
self.assertEqual(1, tags_by_keys["otel.dropped_links_count"])
495+
self.assertEqual(2, tags_by_keys["otel.dropped_attributes_count"])
496+
self.assertEqual(3, tags_by_keys["otel.dropped_events_count"])
497+
498+
def test_dropped_event_attributes(self):
499+
spans = _translate_spans_with_dropped_attributes()
500+
fields_by_keys = {
501+
tag.key: tag.v_str or tag.v_int64
502+
for tag in spans[0].logs[0].fields
503+
}
504+
# get events
505+
self.assertEqual(
506+
2,
507+
fields_by_keys["otel.dropped_attributes_count"],
508+
)

exporter/opentelemetry-exporter-jaeger-thrift/src/opentelemetry/exporter/jaeger/thrift/translate/__init__.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def _convert_int_to_i64(val):
4646
return val
4747

4848

49+
def _append_dropped(tags, key, val):
50+
if val:
51+
tags.append(_get_long_tag(key, val))
52+
53+
4954
class Translator(abc.ABC):
5055
def __init__(self, max_tag_value_length: Optional[int] = None):
5156
self._max_tag_value_length = max_tag_value_length
@@ -181,7 +186,7 @@ def _translate_span(self, span: ReadableSpan) -> TCollector.Span:
181186
return jaeger_span
182187

183188
def _extract_tags(self, span: ReadableSpan) -> Sequence[TCollector.Tag]:
184-
189+
# pylint: disable=too-many-branches
185190
translated = []
186191
if span.attributes:
187192
for key, value in span.attributes.items():
@@ -226,6 +231,18 @@ def _extract_tags(self, span: ReadableSpan) -> Sequence[TCollector.Tag]:
226231
if not span.status.is_ok:
227232
translated.append(_get_bool_tag("error", True))
228233

234+
_append_dropped(
235+
translated,
236+
"otel.dropped_attributes_count",
237+
span.dropped_attributes,
238+
)
239+
_append_dropped(
240+
translated, "otel.dropped_events_count", span.dropped_events
241+
)
242+
_append_dropped(
243+
translated, "otel.dropped_links_count", span.dropped_links
244+
)
245+
229246
return translated
230247

231248
def _extract_refs(
@@ -269,6 +286,12 @@ def _extract_logs(
269286
if tag:
270287
fields.append(tag)
271288

289+
_append_dropped(
290+
fields,
291+
"otel.dropped_attributes_count",
292+
event.attributes.dropped,
293+
)
294+
272295
fields.append(
273296
TCollector.Tag(
274297
key="message",

exporter/opentelemetry-exporter-jaeger-thrift/tests/test_jaeger_exporter_thrift.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,21 @@
3838
from opentelemetry.sdk.resources import SERVICE_NAME
3939
from opentelemetry.sdk.trace import Resource, TracerProvider
4040
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
41+
from opentelemetry.test.spantestutil import (
42+
get_span_with_dropped_attributes_events_links,
43+
)
4144
from opentelemetry.trace import SpanKind
4245
from opentelemetry.trace.status import Status, StatusCode
4346

4447

48+
def _translate_spans_with_dropped_attributes():
49+
span = get_span_with_dropped_attributes_events_links()
50+
translate = Translate([span])
51+
52+
# pylint: disable=protected-access
53+
return translate._translate(ThriftTranslator(max_tag_value_length=5))
54+
55+
4556
class TestJaegerExporter(unittest.TestCase):
4657
def setUp(self):
4758
# create and save span to be used in tests
@@ -562,7 +573,9 @@ def test_max_tag_value_length(self):
562573
# pylint: disable=protected-access
563574
spans = translate._translate(ThriftTranslator())
564575
tags_by_keys = {
565-
tag.key: tag.vStr for tag in spans[0].tags if tag.vType == 0
576+
tag.key: tag.vStr
577+
for tag in spans[0].tags
578+
if tag.vType == jaeger.TagType.STRING
566579
}
567580
self.assertEqual(
568581
"hello_world hello_world hello_world", tags_by_keys["key_string"]
@@ -579,12 +592,38 @@ def test_max_tag_value_length(self):
579592
# pylint: disable=protected-access
580593
spans = translate._translate(ThriftTranslator(max_tag_value_length=5))
581594
tags_by_keys = {
582-
tag.key: tag.vStr for tag in spans[0].tags if tag.vType == 0
595+
tag.key: tag.vStr
596+
for tag in spans[0].tags
597+
if tag.vType == jaeger.TagType.STRING
583598
}
584599
self.assertEqual("hello", tags_by_keys["key_string"])
585600
self.assertEqual("('tup", tags_by_keys["key_tuple"])
586601
self.assertEqual("some_", tags_by_keys["key_resource"])
587602

603+
def test_dropped_span_attributes(self):
604+
spans = _translate_spans_with_dropped_attributes()
605+
tags_by_keys = {
606+
tag.key: tag.vLong
607+
for tag in spans[0].tags
608+
if tag.vType == jaeger.TagType.LONG
609+
}
610+
611+
self.assertEqual(1, tags_by_keys["otel.dropped_links_count"])
612+
self.assertEqual(2, tags_by_keys["otel.dropped_attributes_count"])
613+
self.assertEqual(3, tags_by_keys["otel.dropped_events_count"])
614+
615+
def test_dropped_event_attributes(self):
616+
spans = _translate_spans_with_dropped_attributes()
617+
tags_by_keys = {
618+
tag.key: tag.vLong
619+
for tag in spans[0].logs[0].fields
620+
if tag.vType == jaeger.TagType.LONG
621+
}
622+
self.assertEqual(
623+
2,
624+
tags_by_keys["otel.dropped_attributes_count"],
625+
)
626+
588627
def test_agent_client_split(self):
589628
agent_client = jaeger_exporter.AgentClientUDP(
590629
host_name="localhost",

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def _translate_events(self, sdk_span: ReadableSpan) -> None:
175175
collector_span_event = CollectorSpan.Event(
176176
name=sdk_span_event.name,
177177
time_unix_nano=sdk_span_event.timestamp,
178+
dropped_attributes_count=sdk_span_event.attributes.dropped,
178179
)
179180

180181
for key, value in sdk_span_event.attributes.items():
@@ -201,6 +202,7 @@ def _translate_links(self, sdk_span: ReadableSpan) -> None:
201202
sdk_span_link.context.trace_id.to_bytes(16, "big")
202203
),
203204
span_id=(sdk_span_link.context.span_id.to_bytes(8, "big")),
205+
dropped_attributes_count=sdk_span_link.attributes.dropped,
204206
)
205207

206208
for key, value in sdk_span_link.attributes.items():
@@ -272,6 +274,18 @@ def _translate_data(
272274
self._translate_events(sdk_span)
273275
self._translate_links(sdk_span)
274276
self._translate_status(sdk_span)
277+
if sdk_span.dropped_attributes:
278+
self._collector_span_kwargs[
279+
"dropped_attributes_count"
280+
] = sdk_span.dropped_attributes
281+
if sdk_span.dropped_events:
282+
self._collector_span_kwargs[
283+
"dropped_events_count"
284+
] = sdk_span.dropped_events
285+
if sdk_span.dropped_links:
286+
self._collector_span_kwargs[
287+
"dropped_links_count"
288+
] = sdk_span.dropped_links
275289

276290
self._collector_span_kwargs["kind"] = getattr(
277291
CollectorSpan.SpanKind,

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from google.rpc.error_details_pb2 import RetryInfo
2323
from grpc import ChannelCredentials, Compression, StatusCode, server
2424

25+
from opentelemetry.attributes import BoundedAttributes
2526
from opentelemetry.exporter.otlp.proto.grpc.exporter import (
2627
_translate_key_values,
2728
)
@@ -68,6 +69,9 @@
6869
SpanExportResult,
6970
)
7071
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
72+
from opentelemetry.test.spantestutil import (
73+
get_span_with_dropped_attributes_events_links,
74+
)
7175

7276
THIS_DIR = os.path.dirname(__file__)
7377

@@ -134,7 +138,9 @@ def setUp(self):
134138
event_mock = Mock(
135139
**{
136140
"timestamp": 1591240820506462784,
137-
"attributes": OrderedDict([("a", 1), ("b", False)]),
141+
"attributes": BoundedAttributes(
142+
attributes={"a": 1, "b": False}
143+
),
138144
}
139145
)
140146

@@ -151,14 +157,16 @@ def setUp(self):
151157
),
152158
resource=SDKResource(OrderedDict([("a", 1), ("b", False)])),
153159
parent=Mock(**{"span_id": 12345}),
154-
attributes=OrderedDict([("a", 1), ("b", True)]),
160+
attributes=BoundedAttributes(attributes={"a": 1, "b": True}),
155161
events=[event_mock],
156162
links=[
157163
Mock(
158164
**{
159165
"context.trace_id": 1,
160166
"context.span_id": 2,
161-
"attributes": OrderedDict([("a", 1), ("b", False)]),
167+
"attributes": BoundedAttributes(
168+
attributes={"a": 1, "b": False}
169+
),
162170
"kind": OTLPSpan.SpanKind.SPAN_KIND_INTERNAL, # pylint: disable=no-member
163171
}
164172
)
@@ -601,6 +609,48 @@ def test_translate_key_values(self):
601609
# self.assertEqual(kvlist_value.values[0].key, "asd")
602610
# self.assertEqual(kvlist_value.values[0].value.string_value, "123")
603611

612+
def test_dropped_values(self):
613+
span = get_span_with_dropped_attributes_events_links()
614+
# pylint:disable=protected-access
615+
translated = self.exporter._translate_data([span])
616+
self.assertEqual(
617+
1,
618+
translated.resource_spans[0]
619+
.instrumentation_library_spans[0]
620+
.spans[0]
621+
.dropped_links_count,
622+
)
623+
self.assertEqual(
624+
2,
625+
translated.resource_spans[0]
626+
.instrumentation_library_spans[0]
627+
.spans[0]
628+
.dropped_attributes_count,
629+
)
630+
self.assertEqual(
631+
3,
632+
translated.resource_spans[0]
633+
.instrumentation_library_spans[0]
634+
.spans[0]
635+
.dropped_events_count,
636+
)
637+
self.assertEqual(
638+
2,
639+
translated.resource_spans[0]
640+
.instrumentation_library_spans[0]
641+
.spans[0]
642+
.links[0]
643+
.dropped_attributes_count,
644+
)
645+
self.assertEqual(
646+
2,
647+
translated.resource_spans[0]
648+
.instrumentation_library_spans[0]
649+
.spans[0]
650+
.events[0]
651+
.dropped_attributes_count,
652+
)
653+
604654

605655
def _create_span_with_status(status: SDKStatus):
606656
span = _Span(

exporter/opentelemetry-exporter-zipkin-json/src/opentelemetry/exporter/zipkin/encoder/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,20 @@ def _extract_tags_from_span(self, span: Span) -> Dict[str, str]:
207207
tags.update({"otel.status_code": span.status.status_code.name})
208208
if span.status.status_code is StatusCode.ERROR:
209209
tags.update({"error": span.status.description or ""})
210+
211+
if span.dropped_attributes:
212+
tags.update(
213+
{"otel.dropped_attributes_count": str(span.dropped_attributes)}
214+
)
215+
216+
if span.dropped_events:
217+
tags.update(
218+
{"otel.dropped_events_count": str(span.dropped_events)}
219+
)
220+
221+
if span.dropped_links:
222+
tags.update({"otel.dropped_links_count": str(span.dropped_links)})
223+
210224
return tags
211225

212226
def _extract_annotations_from_events(

0 commit comments

Comments
 (0)