def test_too_many_links(self): link = Link( context=SpanContext( trace_id=int(self.example_trace_id, 16), span_id=int(self.example_span_id, 16), is_remote=False, ), attributes={}, ) too_many_links = [link] * (MAX_NUM_LINKS + 5) self.assertEqual( _extract_links(too_many_links), ProtoSpan.Links( link=[ { "trace_id": self.example_trace_id, "span_id": self.example_span_id, "type": "TYPE_UNSPECIFIED", "attributes": {}, } ] * MAX_NUM_LINKS, dropped_links_count=len(too_many_links) - MAX_NUM_LINKS, ), )
def _extract_links(links: Sequence[trace_api.Link]) -> ProtoSpan.Links: """Convert span.links""" if not links: return None extracted_links = [] dropped_links = 0 if len(links) > MAX_NUM_LINKS: logger.warning( "Exporting more then %s links, some will be truncated", MAX_NUM_LINKS, ) dropped_links = len(links) - MAX_NUM_LINKS links = links[:MAX_NUM_LINKS] for link in links: link_attributes = link.attributes or {} if len(link_attributes) > MAX_LINK_ATTRS: logger.warning( "Link has more then %s attributes, some will be truncated", MAX_LINK_ATTRS, ) trace_id = get_hexadecimal_trace_id(link.context.trace_id) span_id = get_hexadecimal_span_id(link.context.span_id) extracted_links.append({ "trace_id": trace_id, "span_id": span_id, "type": "TYPE_UNSPECIFIED", "attributes": _extract_attributes(link_attributes, MAX_LINK_ATTRS), }) return ProtoSpan.Links(link=extracted_links, dropped_links_count=dropped_links)
def test_extract_links(self): self.assertIsNone(_extract_links([])) trace_id = "6e0c63257de34c92bf9efcd03927272e" span_id1 = "95bb5edabd45950f" span_id2 = "b6b86ad2915c9ddc" link1 = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id1, 16), is_remote=False, ), attributes={}, ) link2 = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id1, 16), is_remote=False, ), attributes=self.attributes_variety_pack, ) link3 = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id2, 16), is_remote=False, ), attributes={ "illegal_attr_value": dict(), "int_attr_value": 123 }, ) self.assertEqual( _extract_links([link1, link2, link3]), ProtoSpan.Links(link=[ { "trace_id": trace_id, "span_id": span_id1, "type": "TYPE_UNSPECIFIED", "attributes": ProtoSpan.Attributes(attribute_map={}), }, { "trace_id": trace_id, "span_id": span_id1, "type": "TYPE_UNSPECIFIED", "attributes": self.extracted_attributes_variety_pack, }, { "trace_id": trace_id, "span_id": span_id2, "type": "TYPE_UNSPECIFIED", "attributes": { "attribute_map": { "int_attr_value": AttributeValue(int_value=123) }, "dropped_attributes_count": 1, }, }, ]), )
def test_extract_link_with_none_attribute(self): link = Link( context=SpanContext( trace_id=int(self.example_trace_id, 16), span_id=int(self.example_span_id, 16), is_remote=False, ), attributes=None, ) self.assertEqual( _extract_links([link]), ProtoSpan.Links(link=[ { "trace_id": self.example_trace_id, "span_id": self.example_span_id, "type": "TYPE_UNSPECIFIED", "attributes": ProtoSpan.Attributes(attribute_map={}), }, ]), )
def test_extract_link_with_none_attribute(self): trace_id = "6e0c63257de34c92bf9efcd03927272e" span_id = "95bb5edabd45950f" link = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), is_remote=False, ), attributes=None, ) self.assertEqual( _extract_links([link]), ProtoSpan.Links( link=[ { "trace_id": trace_id, "span_id": span_id, "type": "TYPE_UNSPECIFIED", "attributes": ProtoSpan.Attributes(attribute_map={}), }, ] ), )
def test_truncate(self): """Cloud Trace API imposes limits on the length of many things, e.g. strings, number of events, number of attributes. We truncate these things before sending it to the API as an optimization. """ str_300 = "a" * 300 str_256 = "a" * 256 str_128 = "a" * 128 self.assertEqual(_truncate_str("aaaa", 1), ("a", 3)) self.assertEqual(_truncate_str("aaaa", 5), ("aaaa", 0)) self.assertEqual(_truncate_str("aaaa", 4), ("aaaa", 0)) self.assertEqual(_truncate_str("中文翻译", 4), ("中", 9)) self.assertEqual( _format_attribute_value(str_300), AttributeValue( string_value=TruncatableString( value=str_256, truncated_byte_count=300 - 256 ) ), ) self.assertEqual( _extract_attributes({str_300: str_300}, 4), ProtoSpan.Attributes( attribute_map={ str_128: AttributeValue( string_value=TruncatableString( value=str_256, truncated_byte_count=300 - 256 ) ) } ), ) time_in_ns1 = 1589919268850900051 time_in_ms_and_ns1 = {"seconds": 1589919268, "nanos": 850899968} event1 = Event(name=str_300, attributes={}, timestamp=time_in_ns1) self.assertEqual( _extract_events([event1]), ProtoSpan.TimeEvents( time_event=[ { "time": time_in_ms_and_ns1, "annotation": { "description": TruncatableString( value=str_256, truncated_byte_count=300 - 256 ), "attributes": {}, }, }, ] ), ) trace_id = "6e0c63257de34c92bf9efcd03927272e" span_id = "95bb5edabd45950f" link = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), is_remote=False, ), attributes={}, ) too_many_links = [link] * (MAX_NUM_LINKS + 1) self.assertEqual( _extract_links(too_many_links), ProtoSpan.Links( link=[ { "trace_id": trace_id, "span_id": span_id, "type": "TYPE_UNSPECIFIED", "attributes": {}, } ] * MAX_NUM_LINKS, dropped_links_count=len(too_many_links) - MAX_NUM_LINKS, ), ) link_attrs = {} for attr_key in range(MAX_LINK_ATTRS + 1): link_attrs[str(attr_key)] = 0 attr_link = Link( context=SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), is_remote=False, ), attributes=link_attrs, ) proto_link = _extract_links([attr_link]) self.assertEqual( len(proto_link.link[0].attributes.attribute_map), MAX_LINK_ATTRS ) too_many_events = [event1] * (MAX_NUM_EVENTS + 1) self.assertEqual( _extract_events(too_many_events), ProtoSpan.TimeEvents( time_event=[ { "time": time_in_ms_and_ns1, "annotation": { "description": TruncatableString( value=str_256, truncated_byte_count=300 - 256 ), "attributes": {}, }, }, ] * MAX_NUM_EVENTS, dropped_annotations_count=len(too_many_events) - MAX_NUM_EVENTS, ), ) time_in_ns1 = 1589919268850900051 event_attrs = {} for attr_key in range(MAX_EVENT_ATTRS + 1): event_attrs[str(attr_key)] = 0 proto_events = _extract_events( [Event(name="a", attributes=event_attrs, timestamp=time_in_ns1)] ) self.assertEqual( len( proto_events.time_event[0].annotation.attributes.attribute_map ), MAX_EVENT_ATTRS, )