def test_create_zipkin_attr_runs_custom_is_tracing_if_present(dummy_request):
    is_tracing = mock.Mock(return_value=True)
    dummy_request.registry.settings = {
        'zipkin.is_tracing': is_tracing,
    }
    request_helper.create_zipkin_attr(dummy_request)
    is_tracing.assert_called_once_with(dummy_request)
示例#2
0
    def tween(request):
        # Creates zipkin attributes, attaches a zipkin_trace_id attr to the
        # request, and pushes the attrs onto threadlocal stack.
        zipkin_attrs = create_zipkin_attr(request)
        push_zipkin_attrs(zipkin_attrs)

        try:
            # If this request isn't sampled, don't go through the work
            # of initializing the rest of the zipkin attributes
            if not zipkin_attrs.is_sampled:
                return handler(request)

            # If the request IS sampled, we create thrift objects and
            # enter zipkin logging context
            thrift_endpoint = create_endpoint(request)
            log_handler = ZipkinLoggerHandler(zipkin_attrs)
            with ZipkinLoggingContext(zipkin_attrs, thrift_endpoint,
                                      log_handler, request) as context:
                response = handler(request)
                context.response_status_code = response.status_code
                context.binary_annotations_dict = get_binary_annotations(
                        request, response)

                return response
        finally:
            # Regardless of what happens in the request we want to pop attrs
            pop_zipkin_attrs()
示例#3
0
    def tween(request):
        # Creates zipkin_attrs and attaches a zipkin_trace_id attr to the request
        zipkin_attrs = create_zipkin_attr(request)

        if 'zipkin.transport_handler' in request.registry.settings:
            transport_handler = request.registry.settings[
                'zipkin.transport_handler']
        else:
            raise ZipkinError(
                "`zipkin.transport_handler` is a required config property, which"
                " is missing. It is a callback method which takes a message as a"
                " param and logs it via scribe/kafka."
            )

        service_name = request.registry.settings.get('service_name', 'unknown')
        span_name = '{0} {1}'.format(request.method, request.path)

        with zipkin_span(
            service_name=service_name,
            span_name=span_name,
            zipkin_attrs=zipkin_attrs,
            transport_handler=transport_handler,
            port=request.server_port,
        ) as zipkin_context:
            response = handler(request)
            zipkin_context.update_binary_annotations_for_root_span(
                get_binary_annotations(request, response),
            )
            return response
示例#4
0
    def tween(request):
        zipkin_attrs = create_zipkin_attr(request)
        endpoint_attrs = create_endpoint(request)
        log_handler = ZipkinLoggerHandler(zipkin_attrs)
        with ZipkinLoggingContext(zipkin_attrs, endpoint_attrs, log_handler,
                                  request) as context:
            response = handler(request)
            context.response_status_code = response.status_code
            context.binary_annotations_dict = get_binary_annotations(
                    request, response)

            return response
示例#5
0
    def tween(request):
        zipkin_attrs = create_zipkin_attr(request)
        endpoint_attrs = create_endpoint(request)
        log_handler = ZipkinLoggerHandler(zipkin_attrs)
        with ZipkinLoggingContext(zipkin_attrs, endpoint_attrs, log_handler,
                                  request) as context:
            response = handler(request)
            context.response_status_code = response.status_code
            context.binary_annotations_dict = get_binary_annotations(
                request, response)

            return response
示例#6
0
def test_create_zipkin_attr_emit_zipkin_headers_default_true(dummy_request):
    """
    We must ensure zipkin.always_emit_zipkin_headers is True by default
    for backward compatibility.
    """
    dummy_request.registry.settings = {'zipkin.is_tracing': lambda _: False}
    attr = request_helper.create_zipkin_attr(dummy_request)

    assert dummy_request.set_property.call_count == 1
    assert attr.trace_id != ''
    assert attr.span_id != ''
    assert attr.is_sampled is False
def test_create_sampled_zipkin_attr_creates_ZipkinAttr_object(mock, request):
    mock.return_value = 'bla'
    request.zipkin_trace_id = '12'
    request.headers = {
        'X-B3-TraceId': '12',
        'X-B3-SpanId': '23',
        'X-B3-ParentSpanId': '34',
        'X-B3-Flags': '45',
        }
    zipkin_attr = request_helper.ZipkinAttrs(
        trace_id='12', span_id='23', parent_span_id='34', flags='45',
        is_sampled='bla')
    assert zipkin_attr == request_helper.create_zipkin_attr(request)
示例#8
0
def test_create_sampled_zipkin_attr_creates_ZipkinAttr_object(mock, request):
    mock.return_value = 'bla'
    request.zipkin_trace_id = '12'
    request.headers = {
        'X-B3-TraceId': '12',
        'X-B3-SpanId': '23',
        'X-B3-ParentSpanId': '34',
        'X-B3-Flags': '45',
        }
    zipkin_attr = request_helper.ZipkinAttrs(
        trace_id='12', span_id='23', parent_span_id='34', flags='45',
        is_sampled='bla')
    assert zipkin_attr == request_helper.create_zipkin_attr(request)
示例#9
0
    def tween(request):
        zipkin_attrs = create_zipkin_attr(request)

        # If this request isn't sampled, don't go through the work
        # of initializing the rest of the zipkin attributes
        if not zipkin_attrs.is_sampled:
            return handler(request)

        # If the request IS sampled, we create thrift objects, store
        # thread-local variables, etc, to enter zipkin logging context
        thrift_endpoint = create_endpoint(request)
        log_handler = ZipkinLoggerHandler(zipkin_attrs)
        with ZipkinLoggingContext(zipkin_attrs, thrift_endpoint, log_handler, request) as context:
            response = handler(request)
            context.response_status_code = response.status_code
            context.binary_annotations_dict = get_binary_annotations(request, response)

            return response
示例#10
0
    def tween(request):
        zipkin_attrs = create_zipkin_attr(request)

        # If this request isn't sampled, don't go through the work
        # of initializing the rest of the zipkin attributes
        if not zipkin_attrs.is_sampled:
            return handler(request)

        # If the request IS sampled, we create thrift objects, store
        # thread-local variables, etc, to enter zipkin logging context
        thrift_endpoint = create_endpoint(request)
        log_handler = ZipkinLoggerHandler(zipkin_attrs)
        with ZipkinLoggingContext(zipkin_attrs, thrift_endpoint, log_handler,
                                  request) as context:
            response = handler(request)
            context.response_status_code = response.status_code
            context.binary_annotations_dict = get_binary_annotations(
                    request, response)

            return response
示例#11
0
    def tween(request):
        settings = request.registry.settings

        # Creates zipkin_attrs and attaches a zipkin_trace_id attr to the request
        if 'zipkin.create_zipkin_attr' in settings:
            zipkin_attrs = settings['zipkin.create_zipkin_attr'](request)
        else:
            zipkin_attrs = create_zipkin_attr(request)

        if 'zipkin.transport_handler' in settings:
            transport_handler = settings['zipkin.transport_handler']
            stream_name = settings.get('zipkin.stream_name', 'zipkin')
            transport_handler = functools.partial(transport_handler, stream_name)
        else:
            raise ZipkinError(
                "`zipkin.transport_handler` is a required config property, which"
                " is missing. It is a callback method which takes a log stream"
                " and a message as params and logs the message via scribe/kafka."
            )

        service_name = request.registry.settings.get('service_name', 'unknown')
        span_name = '{0} {1}'.format(request.method, request.path)

        with zipkin_span(
            service_name=service_name,
            span_name=span_name,
            zipkin_attrs=zipkin_attrs,
            transport_handler=transport_handler,
            port=request.server_port,
            add_logging_annotation=settings.get(
                'zipkin.add_logging_annotation',
                False,
            ),
        ) as zipkin_context:
            response = handler(request)
            zipkin_context.update_binary_annotations_for_root_span(
                get_binary_annotations(request, response),
            )
            return response
示例#12
0
def test_create_zipkin_attr_add_headers(
    is_sampled,
    emit_headers,
    dummy_request
):
    """
    We should be setting the headers and zipkin_trace_id if the request is sampled
    or if zipkin.always_emit_zipkin_headers is True.
    """
    dummy_request.registry.settings = {
        'zipkin.is_tracing': lambda _: is_sampled,
        'zipkin.always_emit_zipkin_headers': emit_headers,
    }
    attr = request_helper.create_zipkin_attr(dummy_request)

    if is_sampled or emit_headers:
        assert dummy_request.set_property.call_count == 1
        assert attr.trace_id != ''
        assert attr.span_id != ''
    else:
        assert dummy_request.set_property.call_count == 0
        assert attr.trace_id == ''
        assert attr.span_id == ''
    assert attr.is_sampled is is_sampled
示例#13
0
def _get_settings_from_request(request):
    """Extracts Zipkin attributes and configuration from request attributes.
    See the `zipkin_span` context in py-zipkin for more detaied information on
    all the settings.

    Here are the supported Pyramid registry settings:

    zipkin.create_zipkin_attr: allows the service to override the creation of
        Zipkin attributes. For example, if you want to deterministically
        calculate trace ID from some service-specific attributes.
    zipkin.transport_handler: how py-zipkin will log the spans it generates.
    zipkin.stream_name: an additional parameter to be used as the first arg
        to the transport_handler function. A good example is a Kafka topic.
    zipkin.add_logging_annotation: if true, the outermost span in this service
        will have an annotation set when py-zipkin begins its logging.
    zipkin.report_root_timestamp: if true, the outermost span in this service
        will set its timestamp and duration attributes. Use this only if this
        service is not going to have a corresponding client span. See
        https://github.com/Yelp/pyramid_zipkin/issues/68
    zipkin.firehose_handler: [EXPERIMENTAL] this enables "firehose tracing",
        which will log 100% of the spans to this handler, regardless of
        sampling decision. This is experimental and may change or be removed
        at any time without warning.
    """
    settings = request.registry.settings

    # Creates zipkin_attrs and attaches a zipkin_trace_id attr to the request
    if 'zipkin.create_zipkin_attr' in settings:
        zipkin_attrs = settings['zipkin.create_zipkin_attr'](request)
    else:
        zipkin_attrs = create_zipkin_attr(request)

    if 'zipkin.transport_handler' in settings:
        transport_handler = settings['zipkin.transport_handler']
        stream_name = settings.get('zipkin.stream_name', 'zipkin')
        transport_handler = functools.partial(transport_handler, stream_name)
    else:
        raise ZipkinError(
            "`zipkin.transport_handler` is a required config property, which"
            " is missing. It is a callback method which takes a log stream"
            " and a message as params and logs the message via scribe/kafka."
        )

    context_stack = _getattr_path(request, settings.get('zipkin.request_context'))
    if context_stack is None:
        context_stack = py_zipkin.stack.ThreadLocalStack()

    service_name = settings.get('service_name', 'unknown')
    span_name = '{0} {1}'.format(request.method, request.path)
    add_logging_annotation = settings.get(
        'zipkin.add_logging_annotation',
        False,
    )

    # If the incoming request doesn't have Zipkin headers, this request is
    # assumed to be the root span of a trace. There's also a configuration
    # override to allow services to write their own logic for reporting
    # timestamp/duration.
    if 'zipkin.report_root_timestamp' in settings:
        report_root_timestamp = settings['zipkin.report_root_timestamp']
    else:
        report_root_timestamp = 'X-B3-TraceId' not in request.headers
    zipkin_host = settings.get('zipkin.host')
    zipkin_port = settings.get('zipkin.port', request.server_port)
    firehose_handler = settings.get('zipkin.firehose_handler')
    max_span_batch_size = settings.get('zipkin.max_span_batch_size')
    return _ZipkinSettings(
        zipkin_attrs,
        transport_handler,
        service_name,
        span_name,
        add_logging_annotation,
        report_root_timestamp,
        zipkin_host,
        zipkin_port,
        context_stack,
        firehose_handler,
        max_span_batch_size,
    )
示例#14
0
def _get_settings_from_request(request):
    """Extracts Zipkin attributes and configuration from request attributes.
    See the `zipkin_span` context in py-zipkin for more detaied information on
    all the settings.

    Here are the supported Pyramid registry settings:

    zipkin.create_zipkin_attr: allows the service to override the creation of
        Zipkin attributes. For example, if you want to deterministically
        calculate trace ID from some service-specific attributes.
    zipkin.transport_handler: how py-zipkin will log the spans it generates.
    zipkin.stream_name: an additional parameter to be used as the first arg
        to the transport_handler function. A good example is a Kafka topic.
    zipkin.add_logging_annotation: if true, the outermost span in this service
        will have an annotation set when py-zipkin begins its logging.
    zipkin.report_root_timestamp: if true, the outermost span in this service
        will set its timestamp and duration attributes. Use this only if this
        service is not going to have a corresponding client span. See
        https://github.com/Yelp/pyramid_zipkin/issues/68
    zipkin.firehose_handler: [EXPERIMENTAL] this enables "firehose tracing",
        which will log 100% of the spans to this handler, regardless of
        sampling decision. This is experimental and may change or be removed
        at any time without warning.
    zipkin.use_pattern_as_span_name: if true, we'll use the pyramid route pattern
        as span name. If false (default) we'll keep using the raw url path.
    """
    settings = request.registry.settings

    # Creates zipkin_attrs and attaches a zipkin_trace_id attr to the request
    if 'zipkin.create_zipkin_attr' in settings:
        zipkin_attrs = settings['zipkin.create_zipkin_attr'](request)
    else:
        zipkin_attrs = create_zipkin_attr(request)

    if 'zipkin.transport_handler' in settings:
        transport_handler = settings['zipkin.transport_handler']
        if not isinstance(transport_handler, BaseTransportHandler):
            warnings.warn(
                'Using a function as transport_handler is deprecated. '
                'Please extend py_zipkin.transport.BaseTransportHandler',
                DeprecationWarning,
            )
            stream_name = settings.get('zipkin.stream_name', 'zipkin')
            transport_handler = functools.partial(transport_handler,
                                                  stream_name)
    else:
        raise ZipkinError(
            "`zipkin.transport_handler` is a required config property, which"
            " is missing. Have a look at py_zipkin's docs for how to implement"
            " it: https://github.com/Yelp/py_zipkin#transport")

    context_stack = _getattr_path(request,
                                  settings.get('zipkin.request_context'))

    service_name = settings.get('service_name', 'unknown')
    span_name = '{0} {1}'.format(request.method, request.path)
    add_logging_annotation = settings.get(
        'zipkin.add_logging_annotation',
        False,
    )

    # If the incoming request doesn't have Zipkin headers, this request is
    # assumed to be the root span of a trace. There's also a configuration
    # override to allow services to write their own logic for reporting
    # timestamp/duration.
    if 'zipkin.report_root_timestamp' in settings:
        report_root_timestamp = settings['zipkin.report_root_timestamp']
    else:
        report_root_timestamp = 'X-B3-TraceId' not in request.headers
    zipkin_host = settings.get('zipkin.host')
    zipkin_port = settings.get('zipkin.port', request.server_port)
    firehose_handler = settings.get('zipkin.firehose_handler')
    post_handler_hook = settings.get('zipkin.post_handler_hook')
    max_span_batch_size = settings.get('zipkin.max_span_batch_size')
    use_pattern_as_span_name = bool(
        settings.get('zipkin.use_pattern_as_span_name', False), )
    encoding = settings.get('zipkin.encoding', Encoding.V1_THRIFT)
    return _ZipkinSettings(
        zipkin_attrs,
        transport_handler,
        service_name,
        span_name,
        add_logging_annotation,
        report_root_timestamp,
        zipkin_host,
        zipkin_port,
        context_stack,
        firehose_handler,
        post_handler_hook,
        max_span_batch_size,
        use_pattern_as_span_name,
        encoding=encoding,
    )
示例#15
0
def _get_settings_from_request(request):
    """Extracts Zipkin attributes and configuration from request attributes.
    See the `zipkin_span` context in py-zipkin for more detaied information on
    all the settings.

    Here are the supported Pyramid registry settings:

    zipkin.create_zipkin_attr: allows the service to override the creation of
        Zipkin attributes. For example, if you want to deterministically
        calculate trace ID from some service-specific attributes.
    zipkin.transport_handler: how py-zipkin will log the spans it generates.
    zipkin.stream_name: an additional parameter to be used as the first arg
        to the transport_handler function. A good example is a Kafka topic.
    zipkin.add_logging_annotation: if true, the outermost span in this service
        will have an annotation set when py-zipkin begins its logging.
    zipkin.report_root_timestamp: if true, the outermost span in this service
        will set its timestamp and duration attributes. Use this only if this
        service is not going to have a corresponding client span. See
        https://github.com/Yelp/pyramid_zipkin/issues/68
    zipkin.firehose_handler: [EXPERIMENTAL] this enables "firehose tracing",
        which will log 100% of the spans to this handler, regardless of
        sampling decision. This is experimental and may change or be removed
        at any time without warning.
    """
    settings = request.registry.settings

    # Creates zipkin_attrs and attaches a zipkin_trace_id attr to the request
    if 'zipkin.create_zipkin_attr' in settings:
        zipkin_attrs = settings['zipkin.create_zipkin_attr'](request)
    else:
        zipkin_attrs = create_zipkin_attr(request)

    if 'zipkin.transport_handler' in settings:
        transport_handler = settings['zipkin.transport_handler']
        stream_name = settings.get('zipkin.stream_name', 'zipkin')
        transport_handler = functools.partial(transport_handler, stream_name)
    else:
        raise ZipkinError(
            "`zipkin.transport_handler` is a required config property, which"
            " is missing. It is a callback method which takes a log stream"
            " and a message as params and logs the message via scribe/kafka.")

    context_stack = _getattr_path(request,
                                  settings.get('zipkin.request_context'))
    if context_stack is None:
        context_stack = py_zipkin.stack.ThreadLocalStack()

    service_name = settings.get('service_name', 'unknown')
    span_name = '{0} {1}'.format(request.method, request.path)
    add_logging_annotation = settings.get(
        'zipkin.add_logging_annotation',
        False,
    )

    # If the incoming request doesn't have Zipkin headers, this request is
    # assumed to be the root span of a trace. There's also a configuration
    # override to allow services to write their own logic for reporting
    # timestamp/duration.
    if 'zipkin.report_root_timestamp' in settings:
        report_root_timestamp = settings['zipkin.report_root_timestamp']
    else:
        report_root_timestamp = 'X-B3-TraceId' not in request.headers
    zipkin_host = settings.get('zipkin.host')
    zipkin_port = settings.get('zipkin.port', request.server_port)
    firehose_handler = settings.get('zipkin.firehose_handler')
    max_span_batch_size = settings.get('zipkin.max_span_batch_size')
    return _ZipkinSettings(
        zipkin_attrs,
        transport_handler,
        service_name,
        span_name,
        add_logging_annotation,
        report_root_timestamp,
        zipkin_host,
        zipkin_port,
        context_stack,
        firehose_handler,
        max_span_batch_size,
    )