Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/backends/native/sentry_crash_daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -3571,6 +3571,33 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
#endif

cleanup:
// Send the staged session-replay envelope same-session, enriched from the
// crash event (`<run>/__sentry-event`) so it shares the crash's
// tags/contexts/trace. Only flush when the crash itself was delivered:
// `cleanup` is also reached via `goto` on error paths where the crash was
// never captured, and flushing there would consume (and delete) the staged
// replay for a crash that never arrived.
if (crash_captured && options && options->transport) {
sentry_value_t crash_event = sentry_value_new_null();
if (run_folder) {
sentry_path_t *sentry_event_path
= sentry__path_join_str(run_folder, "__sentry-event");
if (sentry_event_path) {
size_t ev_len = 0;
char *ev_json
= sentry__path_read_to_buffer(sentry_event_path, &ev_len);
if (ev_json) {
crash_event = sentry__value_from_json(ev_json, ev_len);
sentry_free(ev_json);
}
sentry__path_free(sentry_event_path);
}
}
sentry__session_replay_flush_pending(
options, options->transport, crash_event);
sentry_value_decref(crash_event);
}
Comment thread
tustanivsky marked this conversation as resolved.

// Send all other envelopes from run folder (logs, etc.) before cleanup
if (run_folder && options && options->transport && options->run) {
SENTRY_DEBUG("Checking for additional envelopes in run folder");
Expand Down
1 change: 1 addition & 0 deletions src/sentry_client_report.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef enum {
SENTRY_DATA_CATEGORY_LOG_ITEM,
SENTRY_DATA_CATEGORY_FEEDBACK,
SENTRY_DATA_CATEGORY_TRACE_METRIC,
SENTRY_DATA_CATEGORY_REPLAY,
SENTRY_DATA_CATEGORY_MAX
} sentry_data_category_t;

Expand Down
6 changes: 6 additions & 0 deletions src/sentry_envelope.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ envelope_item_get_ratelimiter_category(const sentry_envelope_item_t *item)
return SENTRY_RL_CATEGORY_SESSION;
} else if (sentry__string_eq(ty, "transaction")) {
return SENTRY_RL_CATEGORY_TRANSACTION;
} else if (sentry__string_eq(ty, "replay_video")) {
return SENTRY_RL_CATEGORY_REPLAY;
} else if (sentry__string_eq(ty, "client_report")) {
// internal telemetry, bypass rate limiting
return -1;
Expand All @@ -160,6 +162,8 @@ item_type_to_data_category(const char *ty)
return SENTRY_DATA_CATEGORY_FEEDBACK;
} else if (sentry__string_eq(ty, "trace_metric")) {
return SENTRY_DATA_CATEGORY_TRACE_METRIC;
} else if (sentry__string_eq(ty, "replay_video")) {
return SENTRY_DATA_CATEGORY_REPLAY;
}
return SENTRY_DATA_CATEGORY_ERROR;
}
Expand Down Expand Up @@ -1347,6 +1351,8 @@ data_category_to_string(sentry_data_category_t category)
return "feedback";
case SENTRY_DATA_CATEGORY_TRACE_METRIC:
return "trace_metric";
case SENTRY_DATA_CATEGORY_REPLAY:
return "replay";
case SENTRY_DATA_CATEGORY_MAX:
default:
return "unknown";
Expand Down
5 changes: 4 additions & 1 deletion src/sentry_ratelimiter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "sentry_slice.h"
#include "sentry_utils.h"

#define MAX_RATE_LIMITS 4
#define MAX_RATE_LIMITS 5
#define MAX_RETRY_AFTER (24 * 60 * 60) // 24h

struct sentry_rate_limiter_s {
Expand All @@ -28,6 +28,7 @@ sentry__rate_limiter_new(void)
rl->disabled_until[SENTRY_RL_CATEGORY_ERROR] = 0;
rl->disabled_until[SENTRY_RL_CATEGORY_SESSION] = 0;
rl->disabled_until[SENTRY_RL_CATEGORY_TRANSACTION] = 0;
rl->disabled_until[SENTRY_RL_CATEGORY_REPLAY] = 0;
}
return rl;
}
Expand Down Expand Up @@ -64,6 +65,8 @@ sentry__rate_limiter_update_from_header(
} else if (sentry__slice_eqs(category, "transaction")) {
rl->disabled_until[SENTRY_RL_CATEGORY_TRANSACTION]
= retry_after;
} else if (sentry__slice_eqs(category, "replay")) {
rl->disabled_until[SENTRY_RL_CATEGORY_REPLAY] = retry_after;
}

categories = sentry__slice_advance(categories, category.len);
Expand Down
1 change: 1 addition & 0 deletions src/sentry_ratelimiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define SENTRY_RL_CATEGORY_ERROR 1
#define SENTRY_RL_CATEGORY_SESSION 2
#define SENTRY_RL_CATEGORY_TRANSACTION 3
#define SENTRY_RL_CATEGORY_REPLAY 4

typedef struct sentry_rate_limiter_s sentry_rate_limiter_t;

Expand Down
19 changes: 19 additions & 0 deletions src/sentry_session_replay.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,23 @@ bool sentry__session_replay_capture(
*/
sentry_path_t *sentry__session_replay_get_path(const sentry_options_t *options);

/**
* Build and send the session-replay envelope for the crash described by
* `scope_source`. The replay is identified by the crash event's
* `contexts.replay.replay_id` and staged by the embedder as
* `<database>/replays/replay-<id>.{json,mp4}`.
*
* Native-daemon-only: called out-of-process by the crash
* daemon, so it runs only on a crash and delivers same-session. The sidecar and
* mp4 are consumed once and removed after the flush attempt, regardless of
* whether the envelope was built or sent, so a failed flush is not retried.
*
* `scope_source` is the crash event (`<run>/__sentry-event`); its scope fields
* and trace id are copied onto the replay, and its timestamp ends the replay
* window. If it is NULL or carries no `contexts.replay.replay_id`, nothing is
* flushed.
*/
void sentry__session_replay_flush_pending(const sentry_options_t *options,
sentry_transport_t *transport, sentry_value_t scope_source);

#endif
Loading
Loading