def _extract_events(events: Sequence[Event]) -> ProtoSpan.TimeEvents: """Convert span.events to dict.""" if not events: return None logs = [] dropped_annontations = 0 if len(events) > MAX_NUM_EVENTS: logger.warning( "Exporting more then %s annotations, some will be truncated", MAX_NUM_EVENTS, ) dropped_annontations = len(events) - MAX_NUM_EVENTS events = events[:MAX_NUM_EVENTS] for event in events: if event.attributes and len(event.attributes) > MAX_EVENT_ATTRS: logger.warning( "Event %s has more then %s attributes, some will be truncated", event.name, MAX_EVENT_ATTRS, ) logs.append({ "time": _get_time_from_ns(event.timestamp), "annotation": { "description": _get_truncatable_str_object(event.name, 256), "attributes": _extract_attributes(event.attributes, MAX_EVENT_ATTRS), }, }) return ProtoSpan.TimeEvents( time_event=logs, dropped_annotations_count=dropped_annontations, dropped_message_events_count=0, )
def test_extract_events(self): self.assertIsNone(_extract_events([])) time_in_ns1 = 1589919268850900051 time_in_ms_and_ns1 = {"seconds": 1589919268, "nanos": 850899968} time_in_ns2 = 1589919438550020326 time_in_ms_and_ns2 = {"seconds": 1589919438, "nanos": 550020352} event1 = Event( name="event1", attributes=self.attributes_variety_pack, timestamp=time_in_ns1, ) event2 = Event( name="event2", attributes={"illegal_attr_value": dict()}, timestamp=time_in_ns2, ) self.assertEqual( _extract_events([event1, event2]), ProtoSpan.TimeEvents( time_event=[ { "time": time_in_ms_and_ns1, "annotation": { "description": TruncatableString( value="event1", truncated_byte_count=0 ), "attributes": self.extracted_attributes_variety_pack, }, }, { "time": time_in_ms_and_ns2, "annotation": { "description": TruncatableString( value="event2", truncated_byte_count=0 ), "attributes": ProtoSpan.Attributes( attribute_map={}, dropped_attributes_count=1 ), }, }, ] ), )
def test_event_name_truncation(self): event1 = Event(name=self.str_300, attributes={}, timestamp=self.example_time_in_ns) self.assertEqual( _extract_events([event1]), ProtoSpan.TimeEvents(time_event=[ { "time": self.example_time_stamp, "annotation": { "description": TruncatableString( value=self.str_256, truncated_byte_count=300 - 256, ), "attributes": {}, }, }, ]), )
def test_too_many_events(self): event = Event(name="event", timestamp=self.example_time_in_ns, attributes={}) too_many_events = [event] * (MAX_NUM_EVENTS + 5) self.assertEqual( _extract_events(too_many_events), ProtoSpan.TimeEvents( time_event=[ { "time": self.example_time_stamp, "annotation": { "description": TruncatableString(value="event", ), "attributes": {}, }, }, ] * MAX_NUM_EVENTS, dropped_annotations_count=len(too_many_events) - MAX_NUM_EVENTS, ), )
def test_extract_multiple_events(self): event1 = Event( name="event1", attributes=self.attributes_variety_pack, timestamp=self.example_time_in_ns, ) event2_nanos = 1589919438550020326 event2 = Event( name="event2", attributes={"illegal_attr_value": dict()}, timestamp=event2_nanos, ) self.assertEqual( _extract_events([event1, event2]), ProtoSpan.TimeEvents( time_event=[ { "time": self.example_time_stamp, "annotation": { "description": TruncatableString( value="event1", truncated_byte_count=0 ), "attributes": self.extracted_attributes_variety_pack, }, }, { "time": _get_time_from_ns(event2_nanos), "annotation": { "description": TruncatableString( value="event2", truncated_byte_count=0 ), "attributes": ProtoSpan.Attributes( attribute_map={}, dropped_attributes_count=1 ), }, }, ] ), )
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, )