def clean_thread_local(): yield stack = ThreadLocalStack() while stack.pop(): pass default_span_storage().clear() while get_default_tracer().pop_zipkin_attrs(): pass get_default_tracer()._span_storage.clear()
def test_memory_leak(): # In py_zipkin >= 0.13.0 and <= 0.14.0 this test fails since the # span_storage contains 10 spans once you exit the for loop. mock_transport_handler, mock_logs = mock_logger() assert len(storage.default_span_storage()) == 0 for _ in range(10): with zipkin.zipkin_client_span( service_name='test_service_name', span_name='test_span_name', transport_handler=mock_transport_handler, sample_rate=0.0, encoding=Encoding.V2_JSON, ): with zipkin.zipkin_span( service_name='inner_service_name', span_name='inner_span_name', ): pass assert len(mock_logs) == 0 assert len(storage.default_span_storage()) == 0
def __init__(self, run_tracker, settings, endpoint, trace_id, parent_id, sample_rate): """ When trace_id and parent_id are set a Zipkin trace will be created with given trace_id and parent_id. If trace_id and parent_id are set to None, a trace_id will be randomly generated for a Zipkin trace. trace-id and parent-id must both either be set or not set. :param RunTracker run_tracker: Tracks and times the execution of a pants run. :param Settings settings: Generic reporting settings. :param string endpoint: The full HTTP URL of a zipkin server to which traces should be posted. :param string trace_id: The overall 64 or 128-bit ID of the trace. May be None. :param string parent_id: The 64-bit ID for a parent span that invokes Pants. May be None. :param float sample_rate: Rate at which to sample Zipkin traces. Value 0.0 - 100.0. """ super(ZipkinReporter, self).__init__(run_tracker, settings) # We keep track of connection between workunits and spans self._workunits_to_spans = {} # Create a transport handler self.handler = HTTPTransportHandler(endpoint) self.trace_id = trace_id self.parent_id = parent_id self.sample_rate = float(sample_rate) self.endpoint = endpoint self.span_storage = storage.default_span_storage()
def test_default_span_storage_warns(): with mock.patch.object(storage.log, 'warning') as mock_log: storage.default_span_storage() assert mock_log.call_count == 1
def __init__( self, service_name, span_name='span', zipkin_attrs=None, transport_handler=None, max_span_batch_size=None, annotations=None, binary_annotations=None, port=0, sample_rate=None, include=None, add_logging_annotation=False, report_root_timestamp=False, use_128bit_trace_id=False, host=None, context_stack=None, span_storage=None, firehose_handler=None, kind=None, timestamp=None, duration=None, encoding=Encoding.V1_THRIFT, ): """Logs a zipkin span. If this is the root span, then a zipkin trace is started as well. :param service_name: The name of the called service :type service_name: string :param span_name: Optional name of span, defaults to 'span' :type span_name: string :param zipkin_attrs: Optional set of zipkin attributes to be used :type zipkin_attrs: ZipkinAttrs :param transport_handler: Callback function that takes a message parameter and handles logging it :type transport_handler: BaseTransportHandler :param max_span_batch_size: Spans in a trace are sent in batches, max_span_batch_size defines max size of one batch :type max_span_batch_size: int :param annotations: Optional dict of str -> timestamp annotations :type annotations: dict of str -> int :param binary_annotations: Optional dict of str -> str span attrs :type binary_annotations: dict of str -> str :param port: The port number of the service. Defaults to 0. :type port: int :param sample_rate: Rate at which to sample; 0.0 - 100.0. If passed-in zipkin_attrs have is_sampled=False and the sample_rate param is > 0, a new span will be generated at this rate. This means that if you propagate sampling decisions to downstream services, but still have sample_rate > 0 in those services, the actual rate of generated spans for those services will be > sampling_rate. :type sample_rate: float :param include: which annotations to include can be one of {'client', 'server'} corresponding to ('cs', 'cr') and ('ss', 'sr') respectively. DEPRECATED: use kind instead. `include` will be removed in 1.0. :type include: iterable :param add_logging_annotation: Whether to add a 'logging_end' annotation when py_zipkin finishes logging spans :type add_logging_annotation: boolean :param report_root_timestamp: Whether the span should report timestamp and duration. Only applies to "root" spans in this local context, so spans created inside other span contexts will always log timestamp/duration. Note that this is only an override for spans that have zipkin_attrs passed in. Spans that make their own sampling decisions (i.e. are the root spans of entire traces) will always report timestamp/duration. :type report_root_timestamp: boolean :param use_128bit_trace_id: If true, generate 128-bit trace_ids. :type use_128bit_trace_id: boolean :param host: Contains the ipv4 or ipv6 value of the host. The ip value isn't automatically determined in a docker environment. :type host: string :param context_stack: explicit context stack for storing zipkin attributes :type context_stack: object :param span_storage: explicit Span storage for storing zipkin spans before they're emitted. :type span_storage: py_zipkin.storage.SpanStorage :param firehose_handler: [EXPERIMENTAL] Similar to transport_handler, except that it will receive 100% of the spans regardless of trace sampling rate. :type firehose_handler: BaseTransportHandler :param kind: Span type (client, server, local, etc...). :type kind: Kind :param timestamp: Timestamp in seconds, defaults to `time.time()`. Set this if you want to use a custom timestamp. :type timestamp: float :param duration: Duration in seconds, defaults to the time spent in the context. Set this if you want to use a custom duration. :type duration: float :param encoding: Output encoding format, defaults to V1 thrift spans. :type encoding: Encoding """ self.service_name = service_name self.span_name = span_name self.zipkin_attrs = zipkin_attrs self.transport_handler = transport_handler self.max_span_batch_size = max_span_batch_size self.annotations = annotations or {} self.binary_annotations = binary_annotations or {} self.port = port self.sample_rate = sample_rate self.add_logging_annotation = add_logging_annotation self.report_root_timestamp_override = report_root_timestamp self.use_128bit_trace_id = use_128bit_trace_id self.host = host self._context_stack = context_stack or ThreadLocalStack() if span_storage is not None: self._span_storage = span_storage else: self._span_storage = storage.default_span_storage() self.firehose_handler = firehose_handler self.kind = self._generate_kind(kind, include) self.timestamp = timestamp self.duration = duration self.encoding = encoding self._is_local_root_span = False self.logging_context = None self.do_pop_attrs = False # Spans that log a 'cs' timestamp can additionally record a # 'sa' binary annotation that shows where the request is going. self.sa_endpoint = None # It used to be possible to override timestamp and duration by passing # in the cs/cr or sr/ss annotations. We want to keep backward compatibility # for now, so this logic overrides self.timestamp and self.duration in the # same way. # This doesn't fit well with v2 spans since those annotations are gone, so # we also log a deprecation warning. if 'sr' in self.annotations and 'ss' in self.annotations: self.duration = self.annotations['ss'] - self.annotations['sr'] self.timestamp = self.annotations['sr'] log.warning( "Manually setting 'sr'/'ss' annotations is deprecated. Please " "use the timestamp and duration parameters.") if 'cr' in self.annotations and 'cs' in self.annotations: self.duration = self.annotations['cr'] - self.annotations['cs'] self.timestamp = self.annotations['cs'] log.warning( "Manually setting 'cr'/'cs' annotations is deprecated. Please " "use the timestamp and duration parameters.") # Root spans have transport_handler and at least one of zipkin_attrs # or sample_rate. if self.zipkin_attrs or self.sample_rate is not None: # transport_handler is mandatory for root spans if self.transport_handler is None: raise ZipkinError( 'Root spans require a transport handler to be given') self._is_local_root_span = True # If firehose_handler than this is a local root span. if self.firehose_handler: self._is_local_root_span = True if self.sample_rate is not None and not (0.0 <= self.sample_rate <= 100.0): raise ZipkinError('Sample rate must be between 0.0 and 100.0') if not isinstance(self._span_storage, storage.SpanStorage): raise ZipkinError('span_storage should be an instance ' 'of py_zipkin.storage.SpanStorage')