def start(self): """Enter the new span context. All annotations logged inside this context will be attributed to this span. All new spans generated inside this context will have this span as their parent. In the unsampled case, this context still generates new span IDs and pushes them onto the threadlocal stack, so downstream services calls made will pass the correct headers. However, the logging handler is never attached in the unsampled case, so the spans are never logged. """ self.do_pop_attrs = False # If zipkin_attrs are passed in or this span is doing its own sampling, # it will need to actually log spans at __exit__. self.perform_logging = self.zipkin_attrs or self.sample_rate is not None if self.sample_rate is not None: # This clause allows for sampling this service independently # of the passed-in zipkin_attrs. if self.zipkin_attrs and not self.zipkin_attrs.is_sampled: self.zipkin_attrs = create_attrs_for_span( sample_rate=self.sample_rate, trace_id=self.zipkin_attrs.trace_id, ) elif not self.zipkin_attrs: self.zipkin_attrs = create_attrs_for_span( sample_rate=self.sample_rate, ) if not self.zipkin_attrs: # This span is inside the context of an existing trace existing_zipkin_attrs = get_zipkin_attrs() if existing_zipkin_attrs: self.zipkin_attrs = ZipkinAttrs( trace_id=existing_zipkin_attrs.trace_id, span_id=generate_random_64bit_string(), parent_span_id=existing_zipkin_attrs.span_id, flags=existing_zipkin_attrs.flags, is_sampled=existing_zipkin_attrs.is_sampled, ) # If zipkin_attrs are not set up by now, that means this span is not # configured to perform logging itself, and it's not in an existing # Zipkin trace. That means there's nothing else to do and it can exit # early. if not self.zipkin_attrs: return self push_zipkin_attrs(self.zipkin_attrs) self.do_pop_attrs = True self.start_timestamp = time.time() # Set up logging if this is the root span if self.perform_logging: # Don't set up any logging if we're not sampling if not self.zipkin_attrs.is_sampled: return self endpoint = create_endpoint(self.port, self.service_name) self.log_handler = ZipkinLoggerHandler(self.zipkin_attrs) self.logging_context = ZipkinLoggingContext( self.zipkin_attrs, endpoint, self.log_handler, self.span_name, self.transport_handler, self.binary_annotations, add_logging_annotation=self.add_logging_annotation, ) self.logging_context.start() return self else: # In the sampled case, patch the ZipkinLoggerHandler. if self.zipkin_attrs.is_sampled: # Be defensive about logging setup. Since ZipkinAttrs are local to # the thread, multithreaded frameworks can get in strange states. # The logging is not going to be correct in these cases, so we set # a flag that turns off logging on __exit__. if len(zipkin_logger.handlers) > 0: # Put span ID on logging handler. Assume there's only a single # handler, since all logging should be set up in this package. self.log_handler = zipkin_logger.handlers[0] # Store the old parent_span_id, probably None, in case we have # nested zipkin_spans self.old_parent_span_id = self.log_handler.parent_span_id self.log_handler.parent_span_id = self.zipkin_attrs.span_id return self
def test_push_zipkin_attrs_adds_new_zipkin_attrs_to_list(): tracer = storage.get_default_tracer() with mock.patch.object(tracer._context_stack, "_storage", ["foo"]): assert "foo" == thread_local.get_zipkin_attrs() thread_local.push_zipkin_attrs("bar") assert "bar" == thread_local.get_zipkin_attrs()
def test_push_zipkin_attrs_adds_new_zipkin_attrs_to_list(): assert 'foo' == thread_local.get_zipkin_attrs() thread_local.push_zipkin_attrs('bar') assert 'bar' == thread_local.get_zipkin_attrs()
def test_push_zipkin_attrs_adds_new_zipkin_attrs_to_list(): tracer = storage.get_default_tracer() with mock.patch.object(tracer._context_stack, '_storage', ['foo']): assert 'foo' == thread_local.get_zipkin_attrs() thread_local.push_zipkin_attrs('bar') assert 'bar' == thread_local.get_zipkin_attrs()