def stop(self, _exc_type=None, _exc_value=None, _exc_traceback=None): """Exit the span context. Zipkin attrs are pushed onto the threadlocal stack regardless of sampling, so they always need to be popped off. The actual logging of spans depends on sampling and that the logging was correctly set up. """ if self.do_pop_attrs: pop_zipkin_attrs() if not self.logging_configured: return # Add the error annotation if an exception occurred if any((_exc_type, _exc_value, _exc_traceback)): error_msg = '{0}: {1}'.format(_exc_type.__name__, _exc_value) self.update_binary_annotations({ zipkin_core.ERROR: error_msg, }) # Logging context is only initialized for "root" spans of the local # process (i.e. this zipkin_span not inside of any other local # zipkin_spans) if self.logging_context: self.logging_context.stop() self.logging_context = None return # If we've gotten here, that means that this span is a child span of # this context's root span (i.e. it's a zipkin_span inside another # zipkin_span). end_timestamp = time.time() self.log_handler.parent_span_id = self.old_parent_span_id # We are simulating a full two-part span locally, so set cs=sr and ss=cr full_annotations = { 'cs': self.start_timestamp, 'sr': self.start_timestamp, 'ss': end_timestamp, 'cr': end_timestamp, } # But we filter down if we only want to emit some of the annotations filtered_annotations = { k: v for k, v in full_annotations.items() if k in self.annotation_filter } self.annotations.update(filtered_annotations) self.log_handler.store_local_span( span_name=self.span_name, service_name=self.service_name, annotations=self.annotations, binary_annotations=self.binary_annotations, sa_binary_annotations=self.sa_binary_annotations, span_id=self.zipkin_attrs.span_id, )
def stop(self, _exc_type=None, _exc_value=None, _exc_traceback=None, start_timestamp=None, end_timestamp=None): """Exit the span context. Zipkin attrs are pushed onto the threadlocal stack regardless of sampling, so they always need to be popped off. The actual logging of spans depends on sampling and that the logging was correctly set up. """ # Always remove the stored zipkin_attrs if self.do_pop_attrs: pop_zipkin_attrs() # Exit early if this request is not being sampled if not self.zipkin_attrs or not self.zipkin_attrs.is_sampled: return # If this is the root span, exit the context (which will handle logging) if self.logging_context: # FIXME sunyan self.logging_context.stop(end_timestamp) self.logging_context = None return # Put the old parent_span_id back on the handler self.log_handler.parent_span_id = self.old_parent_span_id # To get a full span we just set cs=sr and ss=cr. full_annotations = { 'cs': start_timestamp, 'sr': start_timestamp, 'ss': end_timestamp, 'cr': end_timestamp, } # But we filter down if we only want to emit some of the annotations filtered_annotations = { k: v for k, v in full_annotations.items() if k in self.annotation_filter } self.annotations.update(filtered_annotations) # Store this span on the logging handler object. self.log_handler.store_client_span( span_name=self.span_name, service_name=self.service_name, annotations=self.annotations, binary_annotations=self.binary_annotations, span_id=self.zipkin_attrs.span_id, )
def __exit__(self, _exc_type, _exc_value, _exc_traceback): """Exit the span context. Zipkin attrs are pushed onto the threadlocal stack regardless of sampling, so they always need to be popped off. The actual logging of spans depends on sampling and that the logging was correctly set up. """ # Always remove the stored zipkin_attrs if self.do_pop_attrs: pop_zipkin_attrs() # Exit early if this request is not being sampled if not self.zipkin_attrs or not self.zipkin_attrs.is_sampled: return # If this is the root span, exit the context (which will handle logging) if self.logging_context: self.logging_context.__exit__(_exc_type, _exc_value, _exc_traceback) self.logging_context = None return end_timestamp = time.time() # Put the old parent_span_id back on the handler self.log_handler.parent_span_id = self.old_parent_span_id # To get a full span we just set cs=sr and ss=cr. self.annotations.update({ 'cs': self.start_timestamp, 'sr': self.start_timestamp, 'ss': end_timestamp, 'cr': end_timestamp, }) # Store this span on the logging handler object. self.log_handler.store_client_span( span_name=self.span_name, service_name=self.service_name, annotations=self.annotations, binary_annotations=self.binary_annotations, span_id=self.zipkin_attrs.span_id, )
def test_pop_zipkin_attrs_removes_the_last_zipkin_attrs(): assert 'bar' == thread_local.pop_zipkin_attrs() assert 'foo' == thread_local.get_zipkin_attrs()
def test_pop_zipkin_attrs_removes_the_last_zipkin_attrs(): tracer = storage.get_default_tracer() with mock.patch.object(tracer._context_stack, "_storage", ["foo", "bar"]): assert "bar" == thread_local.pop_zipkin_attrs() assert "foo" == thread_local.get_zipkin_attrs()
def test_pop_zipkin_attrs_does_nothing_if_no_requests(): assert not thread_local.pop_zipkin_attrs()
def test_pop_zipkin_attrs_removes_the_last_zipkin_attrs(): tracer = storage.get_default_tracer() with mock.patch.object(tracer._context_stack, '_storage', ['foo', 'bar']): assert 'bar' == thread_local.pop_zipkin_attrs() assert 'foo' == thread_local.get_zipkin_attrs()