Ejemplo n.º 1
0
    def inner(user):
        project_info = get_project_info(user)

        envelope = Envelope()
        envelope.add_event(event)
        return send_envelope(user.client, project_info.id, project_info.key,
                             envelope)
Ejemplo n.º 2
0
def test_empty_measurement_interface(mini_sentry, relay_chain):

    # set up relay

    relay = relay_chain()
    mini_sentry.add_basic_project_config(42)

    # construct envelope

    transaction_item = generate_transaction_item()

    transaction_item.update({"measurements": {}})

    envelope = Envelope()
    envelope.add_transaction(transaction_item)

    # ingest envelope

    relay.send_envelope(42, envelope)

    envelope = mini_sentry.captured_events.get(timeout=1)

    event = envelope.get_transaction_event()

    # test actual output

    assert event["transaction"] == "/organizations/:orgId/performance/:eventSlug/"
    assert "measurements" not in event, event
Ejemplo n.º 3
0
def test_basic_event():
    envelope = Envelope()

    expected = {"message": "Hello, World!"}
    envelope.add_event(expected)

    assert envelope.get_event() == {"message": "Hello, World!"}
Ejemplo n.º 4
0
 def inner(task_set: TaskSet):
     event = event_generator()
     project_info = get_project_info(task_set)
     envelope = Envelope()
     envelope.add_event(event)
     return send_envelope(task_set.client, project_info.id,
                          project_info.key, envelope)
Ejemplo n.º 5
0
 def inner(user):
     transaction_data = generator()
     project_info = get_project_info(user)
     envelope = Envelope()
     envelope.add_transaction(transaction_data)
     return send_envelope(user.client, project_info.id, project_info.key,
                          envelope)
Ejemplo n.º 6
0
def test_strip_measurement_interface(mini_sentry, relay_with_processing,
                                     events_consumer):
    events_consumer = events_consumer()

    relay = relay_with_processing()
    mini_sentry.add_basic_project_config(42)

    envelope = Envelope()
    envelope.add_event({
        "message": "Hello, World!",
        "measurements": {
            "LCP": {
                "value": 420.69
            },
            "fid": {
                "value": 2020
            },
            "cls": {
                "value": None
            },
        },
    })
    relay.send_envelope(42, envelope)

    event, _ = events_consumer.get_event()
    assert event["logentry"] == {"formatted": "Hello, World!"}
    # expect measurements interface object to be stripped out since it's attached to a non-transaction event
    assert "measurements" not in event, event
Ejemplo n.º 7
0
def test_it_keeps_transactions(mini_sentry, relay):
    """
    Tests that when sampling is set to 100% for the trace context project the transactions are kept
    """
    project_id = 42
    relay = relay(mini_sentry, _outcomes_enabled_config())

    # create a basic project config
    config = mini_sentry.add_basic_project_config(project_id)
    # add a sampling rule to project config that keeps all transactions (sample_rate=1)
    public_key = config["publicKeys"][0]["publicKey"]
    _add_sampling_config(config, project_ids=[project_id], sample_rate=1)

    # create an envelope with a trace context that is initiated by this project (for simplicity)
    envelope = Envelope()
    transaction, trace_id = _create_transaction_item()
    envelope.add_transaction(transaction)
    _add_trace_info(envelope, trace_id=trace_id, public_key=public_key)

    # send the event, the transaction should be removed.
    relay.send_envelope(project_id, envelope)
    # the event should be left alone by Relay sampling
    evt = mini_sentry.captured_events.get(timeout=1).get_transaction_event()
    assert evt is not None
    # double check that we get back our trace object (check the trace_id from the object)
    evt_trace_id = (evt.setdefault("contexts",
                                   {}).setdefault("trace", {}).get("trace_id"))
    assert evt_trace_id == trace_id

    # no outcome should be generated since we forward the event to upstream
    with pytest.raises(queue.Empty):
        mini_sentry.captured_outcomes.get(timeout=2)
Ejemplo n.º 8
0
def test_sample_rates_metrics(mini_sentry, relay_with_processing,
                              events_consumer):
    events_consumer = events_consumer()

    relay = relay_with_processing()
    mini_sentry.add_basic_project_config(42)

    sample_rates = [
        {
            "id": "client_sampler",
            "rate": 0.01
        },
        {
            "id": "dyanmic_user",
            "rate": 0.5
        },
    ]

    envelope = Envelope()
    envelope.add_event({"message": "hello, world!"})
    envelope.items[0].headers["sample_rates"] = sample_rates
    relay.send_envelope(42, envelope)

    event, _ = events_consumer.get_event()
    assert event["_metrics"]["sample_rates"] == sample_rates
Ejemplo n.º 9
0
    def flush(self):
        # type: (...) -> None
        pending_sessions = self.pending_sessions
        self.pending_sessions = []

        with self._aggregate_lock:
            pending_aggregates = self.pending_aggregates
            self.pending_aggregates = {}

        envelope = Envelope()
        for session in pending_sessions:
            if len(envelope.items) == MAX_ENVELOPE_ITEMS:
                self.capture_func(envelope)
                envelope = Envelope()

            envelope.add_session(session)

        for (attrs, states) in pending_aggregates.items():
            if len(envelope.items) == MAX_ENVELOPE_ITEMS:
                self.capture_func(envelope)
                envelope = Envelope()

            envelope.add_sessions(make_aggregate_envelope(states, attrs))

        if len(envelope.items) > 0:
            self.capture_func(envelope)
Ejemplo n.º 10
0
 def send_session(self, project_id, payload, item_headers=None):
     envelope = Envelope()
     envelope.add_session(payload)
     if item_headers:
         item = envelope.items[0]
         item.headers = {**item.headers, **item_headers}
     self.send_envelope(project_id, envelope)
Ejemplo n.º 11
0
def test_it_removes_transactions(mini_sentry, relay):
    """
    Tests that when sampling is set to 0% for the trace context project the transactions are removed
    """
    project_id = 42
    relay = relay(mini_sentry, _outcomes_enabled_config())

    # create a basic project config
    config = mini_sentry.add_basic_project_config(project_id)
    # add a sampling rule to project config that removes all transactions (sample_rate=0)
    public_key = config["publicKeys"][0]["publicKey"]
    _add_sampling_config(config, project_ids=[project_id], sample_rate=0)

    # create an envelope with a trace context that is initiated by this project (for simplicity)
    envelope = Envelope()
    transaction, trace_id = _create_transaction_item()
    envelope.add_transaction(transaction)
    _add_trace_info(envelope, trace_id=trace_id, public_key=public_key)

    # send the event, the transaction should be removed.
    relay.send_envelope(project_id, envelope)
    # the event should be removed by Relay sampling
    with pytest.raises(queue.Empty):
        mini_sentry.captured_events.get(timeout=1)

    outcomes = mini_sentry.captured_outcomes.get(timeout=2)
    assert outcomes is not None
    outcome = outcomes["outcomes"][0]
    assert outcome.get("outcome") == 3
    assert outcome.get("reason") == "transaction_sampled"
Ejemplo n.º 12
0
def test_fast_path(mini_sentry, relay):
    """
    Tests that the fast path works.

    When the project config is already fetched and the envelope only
    contains a transaction a fast evaluation path is used.

    While this is an implementation detail of Relay that is not visible
    here we test that Relay behaves normally for the conditions that we
    know are going to trigger a fast-path evaluation
    """
    project_id = 42
    relay = relay(mini_sentry, _outcomes_enabled_config())

    # create a basic project config
    config = mini_sentry.add_basic_project_config(project_id)
    # add a sampling rule to project config that removes all transactions (sample_rate=0)
    public_key = config["publicKeys"][0]["publicKey"]
    _add_sampling_config(config, project_ids=[project_id], sample_rate=0)

    for i in range(2):
        # create an envelope with a trace context that is initiated by this project (for simplicity)
        envelope = Envelope()
        transaction, trace_id = _create_transaction_item()
        envelope.add_transaction(transaction)
        _add_trace_info(envelope, trace_id=trace_id, public_key=public_key)

        # send the event, the transaction should be removed.
        relay.send_envelope(project_id, envelope)
        # the event should be removed by Relay sampling
        with pytest.raises(queue.Empty):
            mini_sentry.captured_events.get(timeout=1)

        outcomes = mini_sentry.captured_outcomes.get(timeout=2)
        assert outcomes is not None
Ejemplo n.º 13
0
def _create_event_envelope(public_key):
    envelope = Envelope()
    event, trace_id, event_id = _create_event_item()
    envelope.add_event(event)
    _add_trace_info(envelope, trace_id=trace_id, public_key=public_key)

    return envelope, trace_id, event_id
Ejemplo n.º 14
0
def test_normalize_measurement_interface(mini_sentry, relay_with_processing,
                                         transactions_consumer):
    relay = relay_with_processing()
    mini_sentry.add_basic_project_config(42)

    events_consumer = transactions_consumer()

    transaction_item = generate_transaction_item()
    transaction_item.update({
        "measurements": {
            "LCP": {
                "value": 420.69
            },
            "   lcp_final.element-Size123  ": {
                "value": 1
            },
            "fid": {
                "value": 2020
            },
            "cls": {
                "value": None
            },
            "fp": {
                "value": "im a first paint"
            },
            "Total Blocking Time": {
                "value": 3.14159
            },
            "missing_value": "string",
        }
    })

    envelope = Envelope()
    envelope.add_transaction(transaction_item)
    relay.send_envelope(42, envelope)

    event, _ = events_consumer.get_event()
    assert event[
        "transaction"] == "/organizations/:orgId/performance/:eventSlug/"
    assert "trace" in event["contexts"]
    assert "measurements" in event, event
    assert event["measurements"] == {
        "lcp": {
            "value": 420.69
        },
        "lcp_final.element-size123": {
            "value": 1
        },
        "fid": {
            "value": 2020
        },
        "cls": {
            "value": None
        },
        "fp": {
            "value": None
        },
        "missing_value": None,
    }
Ejemplo n.º 15
0
 def _send_sessions(sessions):
     # type: (List[Any]) -> None
     transport = self.transport
     if sessions and transport:
         envelope = Envelope()
         for session in sessions:
             envelope.add_session(session)
         transport.capture_envelope(envelope)
Ejemplo n.º 16
0
def test_session():
    envelope = Envelope()

    expected = Session()
    envelope.add_session(expected)

    for item in envelope:
        if item.type == "session":
            assert item.payload.json == expected.to_json()
Ejemplo n.º 17
0
 def send_metrics(self, project_id, payload, timestamp=None):
     envelope = Envelope()
     envelope.add_item(
         Item(
             payload=PayloadRef(bytes=payload.encode()),
             type="metrics",
             headers=None if timestamp is None else {"timestamp": timestamp},
         )
     )
     self.send_envelope(project_id, envelope)
Ejemplo n.º 18
0
def test_empty_span_attributes(
    mini_sentry, relay_with_processing, transactions_consumer
):
    events_consumer = transactions_consumer()

    relay = relay_with_processing()
    config = mini_sentry.add_basic_project_config(42)

    config["config"].setdefault("spanAttributes", [])

    transaction_item = generate_transaction_item()
    transaction_item.update(
        {
            "spans": [
                {
                    "description": "GET /api/0/organizations/?member=1",
                    "op": "http",
                    "parent_span_id": "aaaaaaaaaaaaaaaa",
                    "span_id": "bbbbbbbbbbbbbbbb",
                    "start_timestamp": 1000,
                    "timestamp": 3000,
                    "trace_id": "ff62a8b040f340bda5d830223def1d81",
                },
                {
                    "description": "GET /api/0/organizations/?member=1",
                    "op": "http",
                    "parent_span_id": "bbbbbbbbbbbbbbbb",
                    "span_id": "cccccccccccccccc",
                    "start_timestamp": 1400,
                    "timestamp": 2600,
                    "trace_id": "ff62a8b040f340bda5d830223def1d81",
                },
                {
                    "description": "GET /api/0/organizations/?member=1",
                    "op": "http",
                    "parent_span_id": "cccccccccccccccc",
                    "span_id": "dddddddddddddddd",
                    "start_timestamp": 1700,
                    "timestamp": 2300,
                    "trace_id": "ff62a8b040f340bda5d830223def1d81",
                },
            ],
        }
    )

    envelope = Envelope()
    envelope.add_transaction(transaction_item)
    relay.send_envelope(42, envelope)

    event, _ = events_consumer.get_event()
    assert event["transaction"] == "/organizations/:orgId/performance/:eventSlug/"
    assert "trace" in event["contexts"]
    assert "exclusive_time" not in event["contexts"]["trace"]
    for span in event["spans"]:
        assert "exclusive_time" not in span
Ejemplo n.º 19
0
    def _send_envelope(
            self,
            envelope  # type: Envelope
    ):
        # type: (...) -> None

        # remove all items from the envelope which are over quota
        new_items = []
        for item in envelope.items:
            if self._check_disabled(item.data_category):
                if item.data_category in ("transaction", "error", "default"):
                    self.on_dropped_event("self_rate_limits")
                self.record_lost_event("ratelimit_backoff", item=item)
            else:
                new_items.append(item)

        # Since we're modifying the envelope here make a copy so that others
        # that hold references do not see their envelope modified.
        envelope = Envelope(headers=envelope.headers, items=new_items)

        if not envelope.items:
            return None

        # since we're already in the business of sending out an envelope here
        # check if we have one pending for the stats session envelopes so we
        # can attach it to this enveloped scheduled for sending.  This will
        # currently typically attach the client report to the most recent
        # session update.
        client_report_item = self._fetch_pending_client_report(interval=30)
        if client_report_item is not None:
            envelope.items.append(client_report_item)

        body = io.BytesIO()
        with gzip.GzipFile(fileobj=body, mode="w") as f:
            envelope.serialize_into(f)

        assert self.parsed_dsn is not None
        logger.debug(
            "Sending envelope [%s] project:%s host:%s",
            envelope.description,
            self.parsed_dsn.project_id,
            self.parsed_dsn.host,
        )

        self._send_request(
            body.getvalue(),
            headers={
                "Content-Type": "application/x-sentry-envelope",
                "Content-Encoding": "gzip",
            },
            endpoint_type="envelope",
            envelope=envelope,
        )
        return None
Ejemplo n.º 20
0
def test_envelope(mini_sentry, relay_chain):
    relay = relay_chain()
    mini_sentry.project_configs[42] = relay.basic_project_config()

    envelope = Envelope()
    envelope.add_event({"message": "Hello, World!"})
    relay.send_envelope(42, envelope)

    event = mini_sentry.captured_events.get(timeout=1).get_event()

    assert event["logentry"] == {"formatted": "Hello, World!"}
Ejemplo n.º 21
0
 def _send_sessions(sessions):
     # type: (List[Any]) -> None
     transport = self.transport
     if not transport or not sessions:
         return
     sessions_iter = iter(sessions)
     while True:
         envelope = Envelope()
         for session in islice(sessions_iter, 100):
             envelope.add_session(session)
         if not envelope.items:
             break
         transport.capture_envelope(envelope)
Ejemplo n.º 22
0
def test_drop_unknown_item(mini_sentry, relay):
    relay = relay(mini_sentry, {"routing": {"accept_unknown_items": False}})
    PROJECT_ID = 42
    mini_sentry.add_basic_project_config(PROJECT_ID)

    envelope = Envelope()
    envelope.add_item(
        Item(payload=PayloadRef(bytes=b"something"), type="invalid_unknown")
    )
    relay.send_envelope(PROJECT_ID, envelope)

    # there is nothing sent to the upstream
    with pytest.raises(queue.Empty):
        mini_sentry.captured_events.get(timeout=1)
Ejemplo n.º 23
0
def test_unknown_item(mini_sentry, relay):
    relay = relay(mini_sentry)
    PROJECT_ID = 42
    mini_sentry.add_basic_project_config(PROJECT_ID)

    envelope = Envelope()
    envelope.add_item(
        Item(payload=PayloadRef(bytes=b"something"), type="invalid_unknown")
    )
    relay.send_envelope(PROJECT_ID, envelope)

    envelope = mini_sentry.captured_events.get(timeout=1)
    assert len(envelope.items) == 1
    assert envelope.items[0].type == "invalid_unknown"
Ejemplo n.º 24
0
def test_envelope_without_header(mini_sentry, relay):
    relay = relay(mini_sentry)
    PROJECT_ID = 42
    mini_sentry.add_basic_project_config(PROJECT_ID)

    envelope = Envelope(headers={"dsn": relay.get_dsn(PROJECT_ID)})
    envelope.add_event({"message": "Hello, World!"})
    relay.send_envelope(
        PROJECT_ID,
        envelope,
        headers={"X-Sentry-Auth": ""},  # Empty auth header is ignored by Relay
    )

    event = mini_sentry.captured_events.get(timeout=1).get_event()
    assert event["logentry"] == {"formatted": "Hello, World!"}
Ejemplo n.º 25
0
def test_sample_rates(mini_sentry, relay_chain):
    relay = relay_chain(min_relay_version="21.1.0")
    mini_sentry.add_basic_project_config(42)

    sample_rates = [
        {"id": "client_sampler", "rate": 0.01},
        {"id": "dyanmic_user", "rate": 0.5},
    ]

    envelope = Envelope()
    envelope.add_event({"message": "hello, world!"})
    envelope.items[0].headers["sample_rates"] = sample_rates
    relay.send_envelope(42, envelope)

    envelope = mini_sentry.captured_events.get(timeout=1)
    assert envelope.items[0].headers["sample_rates"] == sample_rates
Ejemplo n.º 26
0
def test_empty_measurement_interface(mini_sentry, relay_chain):
    relay = relay_chain(min_relay_version="20.10.0")
    mini_sentry.add_basic_project_config(42)

    transaction_item = generate_transaction_item()
    transaction_item.update({"measurements": {}})

    envelope = Envelope()
    envelope.add_transaction(transaction_item)
    relay.send_envelope(42, envelope)

    envelope = mini_sentry.captured_events.get(timeout=1)
    event = envelope.get_transaction_event()

    assert event["transaction"] == "/organizations/:orgId/performance/:eventSlug/"
    assert "measurements" not in event, event
Ejemplo n.º 27
0
def test_envelope_with_implicitly_sized_items():
    """
    Tests that it successfully parses envelopes with
    the item size not specified in the header
    """
    envelope_raw = (b'{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n' +
                    b'{"type":"type1"}\n1234\n' + b'{"type":"type2"}\nabcd\n' +
                    b'{"type":"type3"}\n\n' + b'{"type":"type4"}\nab12\n')
    envelope_raw_eof_terminated = envelope_raw[:-1]

    for envelope_raw in (envelope_raw, envelope_raw_eof_terminated):
        actual = Envelope.deserialize(envelope_raw)
        assert actual.headers["event_id"] == "9ec79c33ec9942ab8353589fcb2e04dc"

        items = [item for item in actual]

        assert len(items) == 4

        assert items[0].type == "type1"
        assert items[0].get_bytes() == b"1234"

        assert items[1].type == "type2"
        assert items[1].get_bytes() == b"abcd"

        assert items[2].type == "type3"
        assert items[2].get_bytes() == b""

        assert items[3].type == "type4"
        assert items[3].get_bytes() == b"ab12"
Ejemplo n.º 28
0
    def store_internal_error_event():
        envelope = Envelope.deserialize(flask_request.data)
        event = envelope.get_event()

        if event is not None:
            error = AssertionError("Relay sent us event: " + get_error_message(event))
            sentry.test_failures.append(("/api/666/envelope/", error))

        return jsonify({"event_id": uuid.uuid4().hex})
Ejemplo n.º 29
0
def test_envelope_empty(mini_sentry, relay):
    relay = relay(mini_sentry)
    PROJECT_ID = 42
    mini_sentry.add_basic_project_config(PROJECT_ID)

    envelope = Envelope()
    relay.send_envelope(PROJECT_ID, envelope)

    # there is nothing sent to the upstream
    with pytest.raises(queue.Empty):
        mini_sentry.captured_events.get(timeout=1)
Ejemplo n.º 30
0
def test_envelope_empty(mini_sentry, relay):
    relay = relay(mini_sentry)
    PROJECT_ID = 42
    mini_sentry.add_basic_project_config(PROJECT_ID)

    envelope = Envelope()

    with pytest.raises(HTTPError) as excinfo:
        relay.send_envelope(PROJECT_ID, envelope)

    assert excinfo.value.response.status_code == 400