def test_create_attrs_for_span(random_64bit_mock, random_128bit_mock): random_64bit_mock.return_value = '0000000000000042' expected_attrs = ZipkinAttrs( trace_id='0000000000000042', span_id='0000000000000042', parent_span_id=None, flags='0', is_sampled=True, ) assert expected_attrs == zipkin.create_attrs_for_span() # Test overrides expected_attrs = ZipkinAttrs( trace_id='0000000000000045', span_id='0000000000000046', parent_span_id=None, flags='0', is_sampled=False, ) assert expected_attrs == zipkin.create_attrs_for_span( sample_rate=0.0, trace_id='0000000000000045', span_id='0000000000000046', ) random_128bit_mock.return_value = '00000000000000420000000000000042' expected_attrs = ZipkinAttrs( trace_id='00000000000000420000000000000042', span_id='0000000000000042', parent_span_id=None, flags='0', is_sampled=True, ) assert expected_attrs == zipkin.create_attrs_for_span( use_128bit_trace_id=True, )
def test_stop_non_root_ts_duration_overridden(self): tracer = MockTracer() tracer.set_transport_configured(configured=True) tracer.get_context().push(zipkin.create_attrs_for_span()) ts = time.time() context = tracer.zipkin_span( service_name='test_service', span_name='test_span', timestamp=ts, duration=25, ) context.start() context.stop() assert len(tracer.get_spans()) == 1 endpoint = create_endpoint(service_name='test_service') assert tracer.get_spans()[0] == Span( trace_id=context.zipkin_attrs.trace_id, name='test_span', parent_id=context.zipkin_attrs.parent_span_id, span_id=context.zipkin_attrs.span_id, kind=Kind.LOCAL, timestamp=ts, duration=25, annotations={}, local_endpoint=endpoint, remote_endpoint=None, tags={}, ) assert tracer.is_transport_configured() is True
def test_stop_non_root(self, mock_time): tracer = MockTracer() tracer.set_transport_configured(configured=True) tracer.get_context().push(zipkin.create_attrs_for_span()) context = tracer.zipkin_span( service_name="test_service", span_name="test_span", ) context.start() context.stop() assert len(tracer.get_spans()) == 1 endpoint = create_endpoint(service_name="test_service") assert tracer.get_spans()[0] == Span( trace_id=context.zipkin_attrs.trace_id, name="test_span", parent_id=context.zipkin_attrs.parent_span_id, span_id=context.zipkin_attrs.span_id, kind=Kind.LOCAL, timestamp=123, duration=0, annotations={}, local_endpoint=endpoint, remote_endpoint=None, tags={}, ) assert tracer.is_transport_configured() is True
def start_workunit(self, workunit): """Implementation of Reporter callback.""" if workunit.has_label(WorkUnitLabel.GOAL): service_name = "pants goal" elif workunit.has_label(WorkUnitLabel.TASK): service_name = "pants task" else: service_name = "pants workunit" # Check if it is the first workunit first_span = not self._workunits_to_spans if first_span: # If trace_id and parent_id are given as flags create zipkin_attrs if self.trace_id is not None and self.parent_id is not None: zipkin_attrs = ZipkinAttrs( # trace_id and parent_id are passed to Pants by another process that collects # Zipkin trace trace_id=self.trace_id, span_id=generate_random_64bit_string(), parent_span_id=self.parent_id, flags='0', # flags: stores flags header. Currently unused is_sampled=True, ) else: zipkin_attrs = create_attrs_for_span( # trace_id is the same as run_uuid that is created in run_tracker and is the part of # pants_run id trace_id=self.trace_id, sample_rate=self. sample_rate, # Value between 0.0 and 100.0 ) self.trace_id = zipkin_attrs.trace_id # TODO delete this line when parent_id will be passed in v2 engine: # - with ExecutionRequest when Nodes from v2 engine are called by a workunit; # - when a v2 engine Node is called by another v2 engine Node. self.parent_id = zipkin_attrs.span_id span = zipkin_span( service_name=service_name, span_name=workunit.name, transport_handler=self.handler, encoding=Encoding.V1_THRIFT, zipkin_attrs=zipkin_attrs, span_storage=self.span_storage, ) else: span = zipkin_span( service_name=service_name, span_name=workunit.name, span_storage=self.span_storage, ) self._workunits_to_spans[workunit] = span span.start() # Goals and tasks save their start time at the beginning of their run. # This start time is passed to workunit, because the workunit may be created much later. span.start_timestamp = workunit.start_time if first_span and span.zipkin_attrs.is_sampled: span.logging_context.start_timestamp = workunit.start_time
def start_workunit(self, workunit): """Implementation of Reporter callback.""" if workunit.has_label(WorkUnitLabel.GOAL): service_name = "pants goal" elif workunit.has_label(WorkUnitLabel.TASK): service_name = "pants task" else: service_name = "pants workunit" # Check if it is the first workunit first_span = not self._workunits_to_spans if first_span: # If trace_id and parent_id are given as flags create zipkin_attrs if self.trace_id is not None and self.parent_id is not None: zipkin_attrs = ZipkinAttrs( # trace_id and parent_id are passed to Pants by another process that collects # Zipkin trace trace_id=self.trace_id, span_id=generate_random_64bit_string(), parent_span_id=self.parent_id, flags='0', # flags: stores flags header. Currently unused is_sampled=True, ) else: zipkin_attrs = create_attrs_for_span( # trace_id is the same as run_uuid that is created in run_tracker and is the part of # pants_run id trace_id=self.trace_id, sample_rate=self.sample_rate, # Value between 0.0 and 100.0 ) self.trace_id = zipkin_attrs.trace_id # TODO delete this line when parent_id will be passed in v2 engine: # - with ExecutionRequest when Nodes from v2 engine are called by a workunit; # - when a v2 engine Node is called by another v2 engine Node. self.parent_id = zipkin_attrs.span_id span = zipkin_span( service_name=service_name, span_name=workunit.name, transport_handler=self.handler, encoding=Encoding.V1_THRIFT, zipkin_attrs=zipkin_attrs, span_storage=self.span_storage, ) else: span = zipkin_span( service_name=service_name, span_name=workunit.name, span_storage=self.span_storage, ) self._workunits_to_spans[workunit] = span span.start() # Goals and tasks save their start time at the beginning of their run. # This start time is passed to workunit, because the workunit may be created much later. span.start_timestamp = workunit.start_time if first_span and span.zipkin_attrs.is_sampled: span.logging_context.start_timestamp = workunit.start_time
def test_init_local_root_transport_zipkin_attrs(self): # If transport_handler and zipkin_attrs are set, then this is a local root context = zipkin.zipkin_span( service_name='test_service', span_name='test_span', transport_handler=MockTransportHandler(), zipkin_attrs=zipkin.create_attrs_for_span(), ) assert context._is_local_root_span is True
def mkspan(self, name, parent=None, tags={}): "Helper to create (& optionally start) zipkin spans." # TODO(awinter): support tags on zipkin span = zipkin_span( service_name='pants', span_name=name, transport_handler=functools.partial(http_transport, self.opts.url), zipkin_attrs=create_attrs_for_span() if not parent else None, ) span.start() return span
def _start_call_span(self, app, sender, task_id): # type: (celery.app.Celery, str, str) -> py_zipkin.zipkin.server_span zipkin_attrs = zipkin.get_zipkin_attrs( ) # type: py_zipkin.zipkin.ZipkinAttrs """:type: py_zipkin.zipkin.ZipkinAttrs""" if zipkin_attrs: zipkin_attrs = zipkin.ZipkinAttrs( trace_id=zipkin_attrs.trace_id, span_id=zipkin.generate_random_64bit_string(), parent_span_id=zipkin_attrs.span_id, flags=zipkin_attrs.flags, is_sampled=zipkin_attrs.is_sampled, ) else: zipkin_attrs = zipkin.create_attrs_for_span(self.sample_rate) # Get task definition to see if task ignores result task = get_task_from_app(app, sender) # Is Call Complete at this point. if task.ignore_result or not self._has_result_event: call_type = 'async' backend = None else: call_type = 'call' backend = get_task_backend_name(task, is_eager) span = zipkin.zipkin_server_span( service_name='celery.{}'.format(sender.split('.', 1)[0]), span_name='task.{}:{}'.format(call_type, sender), transport_handler=self.transport_handler, sample_rate=self.sample_rate, zipkin_attrs=zipkin_attrs, ) print span.service_name print span.span_name print span.zipkin_attrs span.start() span.update_binary_annotations({ 'celery.task.name': sender, 'celery.task.type': call_type, 'celery.task.backend': backend, 'celery.machine': self._hostname, 'celery.platform': self._platform, }) return span
def test_update_binary_annotations_non_root(self): context = zipkin.zipkin_span(service_name='test_service', span_name='test_span', binary_annotations={'region': 'uswest-1'}) context.get_tracer()._context_stack.push( zipkin.create_attrs_for_span()) with context as span: span.update_binary_annotations({'status': '200'}) assert span.binary_annotations == { 'region': 'uswest-1', 'status': '200', }
def test_update_binary_annotations_non_root(self): context = zipkin.zipkin_span( service_name="test_service", span_name="test_span", binary_annotations={"region": "uswest-1"}, ) context.get_tracer()._context_stack.push(zipkin.create_attrs_for_span()) with context as span: span.update_binary_annotations({"status": "200"}) assert span.binary_annotations == { "region": "uswest-1", "status": "200", }
def start_workunit(self, workunit): """Implementation of Reporter callback.""" if workunit.has_label(WorkUnitLabel.GOAL): service_name = "pants goal" elif workunit.has_label(WorkUnitLabel.TASK): service_name = "pants task" else: service_name = "pants workunit" # Check if it is the first workunit first_span = not self._workunits_to_spans if first_span: # If trace_id and parent_id are given create zipkin_attrs if self.trace_id is not None: zipkin_attrs = ZipkinAttrs( trace_id=self.trace_id, span_id=generate_random_64bit_string(), parent_span_id=self.parent_id, flags='0', # flags: stores flags header. Currently unused is_sampled=True, ) else: zipkin_attrs = create_attrs_for_span( sample_rate=self. sample_rate, # Value between 0.0 and 100.0 ) self.trace_id = zipkin_attrs.trace_id span = zipkin_span(service_name=service_name, span_name=workunit.name, transport_handler=self.handler, encoding=Encoding.V1_THRIFT, zipkin_attrs=zipkin_attrs) else: span = zipkin_span( service_name=service_name, span_name=workunit.name, ) self._workunits_to_spans[workunit] = span span.start() # Goals and tasks save their start time at the beginning of their run. # This start time is passed to workunit, because the workunit may be created much later. span.start_timestamp = workunit.start_time if first_span and span.zipkin_attrs.is_sampled: span.logging_context.start_timestamp = workunit.start_time
def test_add_annotation_non_root(self): context = zipkin.zipkin_span( service_name="test_service", span_name="test_span", annotations={"abc": 123}, ) context.get_tracer()._context_stack.push(zipkin.create_attrs_for_span()) with context as span: span.add_annotation("def", 345) span.add_annotation("ghi", timestamp=678) with mock.patch("py_zipkin.zipkin.time.time") as mock_time: mock_time.return_value = 91011 span.add_annotation("jkl") assert span.annotations == { "abc": 123, "def": 345, "ghi": 678, "jkl": 91011, }
def start_span(self, operation_name=None, child_of=None, references=None, tags=None, start_time=None, ignore_active_span=False): logger.debug("Starting Zipkin span [%s] for service [%s]", operation_name, self.service_name) parent: Span = self.active_span if self.active_span and not ignore_active_span else child_of if parent is None: zipkin_attrs = zipkin.create_attrs_for_span(self._sample_rate) else: zipkin_attrs = zipkin.ZipkinAttrs( trace_id=parent.trace_id or zipkin.generate_random_64bit_string(), span_id=zipkin.generate_random_64bit_string(), parent_span_id=parent.span_id, flags=parent.flags, is_sampled=int(parent.flags) & SAMPLED_FLAG == SAMPLED_FLAG, ) logger.debug('ZipkinAttrs: %s', repr(zipkin_attrs)) zipkin_span = zipkin.zipkin_span( service_name=self.service_name, zipkin_attrs=zipkin_attrs, span_name=operation_name, transport_handler=self._transport_handler, port=self._port, sample_rate=self._sample_rate, binary_annotations=dict({ 'span.tag.environment': SPAN_TAG_ENVIRONMENT, 'span.tag.service': self.service_name, }, **(tags or {})) ) context = SpanContext(*zipkin_attrs) return Span(self, context, operation_name, zipkin_span)
def start_workunit(self, workunit): """Implementation of Reporter callback.""" if workunit.has_label(WorkUnitLabel.GOAL): service_name = "goal" elif workunit.has_label(WorkUnitLabel.TASK): service_name = "task" else: service_name = "workunit" # Set local_tracer. Tracer stores spans and span's zipkin_attrs. # If start_workunit is called from the root thread then local_tracer is the same as self.tracer. # If start_workunit is called from a new thread then local_tracer will have an empty span # storage and stack. local_tracer = get_default_tracer() # Check if it is the first workunit first_span = self.run_tracker.is_main_root_workunit(workunit) if first_span: # If trace_id and parent_id are given as flags create zipkin_attrs if self.trace_id is not None and self.parent_id is not None: zipkin_attrs = ZipkinAttrs( # trace_id and parent_id are passed to Pants by another process that collects # Zipkin trace trace_id=self.trace_id, span_id=generate_random_64bit_string(), parent_span_id=self.parent_id, flags='0', # flags: stores flags header. Currently unused is_sampled=True, ) else: zipkin_attrs = create_attrs_for_span( # trace_id is the same as run_uuid that is created in run_tracker and is the part of # pants_run id trace_id=self.trace_id, sample_rate=self.sample_rate, # Value between 0.0 and 100.0 ) # TODO delete this line when parent_id will be passed in v2 engine: # - with ExecutionRequest when Nodes from v2 engine are called by a workunit; # - when a v2 engine Node is called by another v2 engine Node. self.parent_id = zipkin_attrs.span_id span = local_tracer.zipkin_span( service_name=self.service_name_prefix.format("main"), span_name=workunit.name, transport_handler=self.handler, encoding=self.encoding, zipkin_attrs=zipkin_attrs, max_span_batch_size=self.max_span_batch_size, ) else: # If start_workunit is called from a new thread local_tracer doesn't have zipkin attributes. # Parent's attributes need to be added to the local_tracer zipkin_attrs storage. if not local_tracer.get_zipkin_attrs(): parent_attrs = workunit.parent.zipkin_span.zipkin_attrs local_tracer.push_zipkin_attrs(parent_attrs) local_tracer.set_transport_configured(configured=True) span = local_tracer.zipkin_span( service_name=self.service_name_prefix.format(service_name), span_name=workunit.name, ) # For all spans except the first span zipkin_attrs for span are created at this point span.start() if workunit.name == 'background' and self.run_tracker.is_main_root_workunit(workunit.parent): span.zipkin_attrs = span.zipkin_attrs._replace( parent_span_id=workunit.parent.zipkin_span.zipkin_attrs.span_id ) span.service_name = self.service_name_prefix.format("background") # Goals and tasks save their start time at the beginning of their run. # This start time is passed to workunit, because the workunit may be created much later. span.start_timestamp = workunit.start_time if first_span and span.zipkin_attrs.is_sampled: span.logging_context.start_timestamp = workunit.start_time workunit.zipkin_span = span
def _start_taskrun_span(self, sender, task, span_id=None, trace_id=None, parent_id=None, flags=None, is_sampled=None): # type: (str, str, str, str, str, str) -> py_zipkin.zipkin.server_span zipkin_attrs = zipkin.get_zipkin_attrs( ) # type: py_zipkin.zipkin.ZipkinAttrs """:type: py_zipkin.zipkin.ZipkinAttrs""" if not zipkin_attrs: zipkin_attrs = zipkin.create_attrs_for_span(self.sample_rate) zipkin_attrs = zipkin.ZipkinAttrs( trace_id=trace_id or zipkin_attrs.trace_id, span_id=span_id or zipkin.generate_random_64bit_string(), parent_span_id=parent_id or zipkin_attrs.span_id, flags=flags or zipkin_attrs.flags, is_sampled=zipkin_attrs.is_sampled if is_sampled is None else is_sampled, ) span = zipkin.zipkin_server_span( service_name='celery.{}'.format(sender.split('.', 1)[0]), span_name='task.run:{}'.format(sender), transport_handler=self.transport_handler, sample_rate=self.sample_rate, zipkin_attrs=zipkin_attrs, ) backend = None context = task.request is_eager = context.get('is_eager', False) if task.ignore_result or not self._has_result_event: call_type = 'async' else: call_type = 'call' if is_eager: backend = 'is_eager' else: backend = get_task_backend_name(task, is_eager) span.start() span.update_binary_annotations({ 'celery.task.name': sender, 'celery.task.type': call_type, 'celery.task.backend': backend, 'celery.machine': context.get('hostname', self._hostname), 'celery.is_eager': context.get('is_eager', False), 'celery.platform': self._platform, }) return span