Ejemplo n.º 1
0
def inject_trace_header(headers, entity):
    """
    Extract trace id, entity id and sampling decision
    from the input entity and inject these information
    to headers.

    :param dict headers: http headers to inject
    :param Entity entity: trace entity that the trace header
        value generated from.
    """
    if not entity:
        return

    if hasattr(entity, 'type') and entity.type == 'subsegment':
        header = entity.parent_segment.get_origin_trace_header()
    else:
        header = entity.get_origin_trace_header()
    data = header.data if header else None

    to_insert = TraceHeader(
        root=entity.trace_id,
        parent=entity.id,
        sampled=entity.sampled,
        data=data,
    )

    value = to_insert.to_header_str()

    headers[http.XRAY_HEADER] = value
def test_no_sample():
    header = TraceHeader(root=TRACE_ID, parent=PARENT_ID)
    assert header.sampled is None
    assert header.root == TRACE_ID
    assert header.parent == PARENT_ID
    assert header.to_header_str() == 'Root=%s;Parent=%s' % (TRACE_ID,
                                                            PARENT_ID)
Ejemplo n.º 3
0
def construct_xray_header(headers):
    """
    Construct a ``TraceHeader`` object from dictionary headers
    of the incoming request. This method should always return
    a ``TraceHeader`` object regardless of tracing header's presence
    in the incoming request.
    """
    header_str = headers.get(http.XRAY_HEADER) or headers.get(http.ALT_XRAY_HEADER)
    if header_str:
        return TraceHeader.from_header_str(header_str)
    else:
        return TraceHeader()
Ejemplo n.º 4
0
def prepare_response_header(origin_header, segment):
    """
    Prepare a trace header to be inserted into response
    based on original header and the request segment.
    """
    if origin_header and origin_header.sampled == '?':
        new_header = TraceHeader(root=segment.trace_id,
                                 sampled=segment.sampled)
    else:
        new_header = TraceHeader(root=segment.trace_id)

    return new_header.to_header_str()
def test_arbitrary_fields():
    origin_header_str = 'Root=%s;k1=v1;k2=v2' % TRACE_ID
    header = TraceHeader.from_header_str(origin_header_str)
    header_str = header.to_header_str()

    assert 'k1=v1' in header_str
    assert 'k2=v2' in header_str
def test_from_str():
    # a full header string that has all fields present
    header_str1 = 'Root=%s;Parent=%s;Sampled=1' % (TRACE_ID, PARENT_ID)
    header1 = TraceHeader.from_header_str(header_str1)
    assert header1.root == TRACE_ID
    assert header1.parent == PARENT_ID
    assert header1.sampled == 1

    # missing parent id
    header_str2 = 'Root=%s;Sampled=?' % TRACE_ID
    header2 = TraceHeader.from_header_str(header_str2)
    assert header2.root == TRACE_ID
    assert header2.parent is None
    assert header2.sampled == '?'

    # missing sampled
    header_str3 = 'Root=%s;Parent=%s' % (TRACE_ID, PARENT_ID)
    header3 = TraceHeader.from_header_str(header_str3)
    assert header3.root == TRACE_ID
    assert header3.parent == PARENT_ID
    assert header3.sampled is None
Ejemplo n.º 7
0
def inject_trace_header(headers, entity):
    """
    Extract trace id, entity id and sampling decision
    from the input entity and inject these information
    to headers.

    :param dict headers: http headers to inject
    :param Entity entity: trace entity that the trace header
        value generated from.
    """
    if not entity:
        return

    to_insert = TraceHeader(
        root=entity.trace_id,
        parent=entity.id,
        sampled=entity.sampled,
    )

    value = to_insert.to_header_str()

    headers[http.XRAY_HEADER] = value
Ejemplo n.º 8
0
def _read_sqs_message():
    sqs = boto3.resource("sqs", **config.BOTO_RESOURCE_KWARGS)

    """
    It is possible that the queue was not created by the time
    the worker launches, because the work queue creation (if needed)
    and the Job spawn are on separate promises and work asyncrhonously.
    This is a performance improvement but it causes the race condition above.

    If this is the case, we just return an empty response
    as if we didn't receive a message in this time frame.
    """
    try:
        queue = sqs.get_queue_by_name(QueueName=config.QUEUE_NAME)
    except ClientError as e:
        if e.response["Error"]["Code"] == "AWS.SimpleQueueService.NonExistentQueue":
            return None
        else:
            raise e

    message = queue.receive_messages(
        WaitTimeSeconds=20, AttributeNames=["AWSTraceHeader"]
    )

    if not message:
        return None

    # Try to parse it as JSON
    try:
        message = message[0]

        trace_header = message.attributes and message.attributes.get(
            "AWSTraceHeader", None
        )

        if trace_header:
            xray.global_sdk_config.set_sdk_enabled(True)

            header = TraceHeader.from_header_str(trace_header)
            trace_id = header.root
            sampled = header.sampled

            xray_recorder.begin_segment(
                f"worker-{config.CLUSTER_ENV}-{config.SANDBOX_ID}",
                traceid=trace_id,
                sampling=sampled,
                parent_id=header.parent,
            )

        body = json.loads(message.body)
        info("Consumed a message from SQS.")
    except Exception as e:
        xray_recorder.current_segment().add_exception(e, traceback.format_exc())

        info("Exception when loading message", message.body)
        info("Exception:", e)
        return None
    finally:
        message.delete()

    return body
def test_invalid_str():
    header = TraceHeader.from_header_str('some invalid string')
    assert header.root is None
    assert header.parent is None
    assert header.sampled is None
Ejemplo n.º 10
0
def test_no_parent():
    header = TraceHeader(root=TRACE_ID, sampled=1)
    assert header.parent is None
    assert header.to_header_str() == 'Root=%s;Sampled=1' % TRACE_ID