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)
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)
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"
def test_multi_item_envelope(mini_sentry, relay, rule_type, event_factory): """ Associated items are removed together with event item. The event is sent twice to account for both fast and slow paths. When sampling decides to remove a transaction it should also remove all dependent items (attachments). """ 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 a sampling rule to project config that drops all events (sample_rate=0), it should be ignored # because there is an invalid rule in the configuration _add_sampling_config(config, sample_rate=0, rule_type=rule_type) for i in range(2): # create an envelope with a trace context that is initiated by this project (for simplicity) envelope = Envelope() # create an envelope with a trace context that is initiated by this project (for simplicity) envelope, trace_id, event_id = event_factory(public_key) envelope.add_item( Item(payload=PayloadRef(json={"x": "some attachment"}), type="attachment")) envelope.add_item( Item( payload=PayloadRef(json={"y": "some other attachment"}), type="attachment", )) # 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
def send_client_report(self, project_id, payload): envelope = Envelope() envelope.add_item(Item(PayloadRef(json=payload), type="client_report")) self.send_envelope(project_id, envelope)
def send_session_aggregates(self, project_id, payload): envelope = Envelope() envelope.add_item(Item(payload=PayloadRef(json=payload), type="sessions")) self.send_envelope(project_id, envelope)
def capture_event( self, event, # type: Event hint=None, # type: Optional[Hint] scope=None, # type: Optional[Scope] ): # type: (...) -> Optional[str] """Captures an event. :param event: A ready-made event that can be directly sent to Sentry. :param hint: Contains metadata about the event that can be read from `before_send`, such as the original exception object or a HTTP request object. :returns: An event ID. May be `None` if there is no DSN set or of if the SDK decided to discard the event for other reasons. In such situations setting `debug=True` on `init()` may help. """ if disable_capture_event.get(False): return None if self.transport is None: return None if hint is None: hint = {} event_id = event.get("event_id") hint = dict(hint or ()) # type: Hint if event_id is None: event["event_id"] = event_id = uuid.uuid4().hex if not self._should_capture(event, hint, scope): return None event_opt = self._prepare_event(event, hint, scope) if event_opt is None: return None # whenever we capture an event we also check if the session needs # to be updated based on that information. session = scope._session if scope else None if session: self._update_session_from_event(session, event) attachments = hint.get("attachments") is_transaction = event_opt.get("type") == "transaction" if is_transaction or attachments: # Transactions or events with attachments should go to the # /envelope/ endpoint. envelope = Envelope( headers={ "event_id": event_opt["event_id"], "sent_at": format_timestamp(datetime.utcnow()), }) if is_transaction: envelope.add_transaction(event_opt) else: envelope.add_event(event_opt) for attachment in attachments or (): envelope.add_item(attachment.to_envelope_item()) self.transport.capture_envelope(envelope) else: # All other events go to the /store/ endpoint. self.transport.capture_event(event_opt) return event_id
def send_metrics(self, project_id, payload): envelope = Envelope() envelope.add_item( Item(payload=PayloadRef(bytes=payload.encode()), type="metrics")) self.send_envelope(project_id, envelope)
def capture_event( self, event, # type: Event hint=None, # type: Optional[Hint] scope=None, # type: Optional[Scope] ): # type: (...) -> Optional[str] """Captures an event. :param event: A ready-made event that can be directly sent to Sentry. :param hint: Contains metadata about the event that can be read from `before_send`, such as the original exception object or a HTTP request object. :returns: An event ID. May be `None` if there is no DSN set or of if the SDK decided to discard the event for other reasons. In such situations setting `debug=True` on `init()` may help. """ if disable_capture_event.get(False): return None if self.transport is None: return None if hint is None: hint = {} event_id = event.get("event_id") hint = dict(hint or ()) # type: Hint if event_id is None: event["event_id"] = event_id = uuid.uuid4().hex if not self._should_capture(event, hint, scope): return None event_opt = self._prepare_event(event, hint, scope) if event_opt is None: return None # whenever we capture an event we also check if the session needs # to be updated based on that information. session = scope._session if scope else None if session: self._update_session_from_event(session, event) is_transaction = event_opt.get("type") == "transaction" if not is_transaction and not self._should_sample_error(event): return None attachments = hint.get("attachments") # this is outside of the `if` immediately below because even if we don't # use the value, we want to make sure we remove it before the event is # sent raw_tracestate = (event_opt.get("contexts", {}).get("trace", {}).pop("tracestate", "")) # Transactions or events with attachments should go to the /envelope/ # endpoint. if is_transaction or attachments: headers = { "event_id": event_opt["event_id"], "sent_at": format_timestamp(datetime.utcnow()), } tracestate_data = raw_tracestate and reinflate_tracestate( raw_tracestate.replace("sentry=", "")) if tracestate_data and has_tracestate_enabled(): headers["trace"] = tracestate_data envelope = Envelope(headers=headers) if is_transaction: envelope.add_transaction(event_opt) else: envelope.add_event(event_opt) for attachment in attachments or (): envelope.add_item(attachment.to_envelope_item()) self.transport.capture_envelope(envelope) else: # All other events go to the /store/ endpoint. self.transport.capture_event(event_opt) return event_id