├── .cargo └── config.toml ├── .codecov.yml ├── .craft.yml ├── .dockerignore ├── .envrc ├── .flake8 ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── epic.md │ └── flaky.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ └── changelog │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── prettier.config.js ├── dependabot.yml └── workflows │ ├── beta.yml │ ├── build_binary.yml │ ├── build_library.yml │ ├── changelog.yml │ ├── ci.yml │ ├── deploy.yml │ ├── enforce-license-compliance.yml │ ├── release-ghcr-version-tag.yml │ ├── release_binary.yml │ ├── release_library.yml │ └── validate-pipelines.yml ├── .gitignore ├── .gitmodules ├── .pre-commit-config.yaml ├── .python-version ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── Dockerfile.release ├── LICENSE.md ├── Makefile ├── README.md ├── artwork ├── relay-icon-bw-white.png ├── relay-icon-bw.png ├── relay-icon-white.png ├── relay-icon.png ├── relay-logo-white.png ├── relay-logo.png └── semaphore.jpg ├── clippy.toml ├── deny.toml ├── devservices ├── config.yml ├── config │ ├── devservices-credentials.json │ └── relay.yml └── programs.conf ├── docker-entrypoint.sh ├── gocd ├── README.md ├── pipelines │ ├── relay-experimental.yaml │ ├── relay-pop-experimental.yaml │ └── relay.yaml └── templates │ ├── bash │ ├── check-datadog-status.sh │ ├── check-sentry-errors.sh │ ├── check-sentry-new-errors.sh │ ├── create-sentry-relay-pop-release.sh │ ├── create-sentry-relay-release.sh │ ├── deploy-pop-canary.sh │ ├── deploy-pop.sh │ ├── deploy-processing-canary.sh │ ├── deploy-processing.sh │ ├── deploy-relay.sh │ ├── github-check-runs.sh │ ├── pause-current-pipeline.sh │ ├── wait-canary.sh │ └── wait-soak.sh │ ├── jsonnetfile.json │ ├── jsonnetfile.lock.json │ ├── libs │ └── utils.libsonnet │ ├── pipelines │ ├── pops.libsonnet │ └── processing.libsonnet │ ├── pops.jsonnet │ └── processing.jsonnet ├── migrations ├── 20230311081917_envelopes_table.sql ├── 20240724144200_change_index.sql └── 20241107115400_count_column.sql ├── py ├── .craft.yml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── MANIFEST.in ├── README ├── manylinux.sh ├── sentry_relay │ ├── __init__.py │ ├── auth.py │ ├── consts.py │ ├── exceptions.py │ ├── processing.py │ ├── py.typed │ └── utils.py ├── setup.py └── tests │ ├── test_auth.py │ ├── test_consts.py │ ├── test_processing.py │ └── test_utils.py ├── pyproject.toml ├── relay-auth ├── Cargo.toml ├── build.rs └── src │ └── lib.rs ├── relay-base-schema ├── Cargo.toml └── src │ ├── data_category.rs │ ├── events.rs │ ├── lib.rs │ ├── metrics │ ├── mod.rs │ ├── mri.rs │ ├── name.rs │ └── units.rs │ ├── organization.rs │ ├── project.rs │ └── spans.rs ├── relay-cabi ├── .gitignore ├── Cargo.toml ├── Makefile ├── cbindgen.toml ├── include │ └── relay.h └── src │ ├── auth.rs │ ├── codeowners.rs │ ├── constants.rs │ ├── core.rs │ ├── ffi.rs │ ├── glob.rs │ ├── lib.rs │ └── processing.rs ├── relay-cardinality ├── Cargo.toml ├── benches │ ├── redis.rs │ └── redis_impl.rs └── src │ ├── config.rs │ ├── error.rs │ ├── lib.rs │ ├── limiter.rs │ ├── redis │ ├── cache.rs │ ├── limiter.rs │ ├── mod.rs │ ├── quota.rs │ ├── script.rs │ └── state.rs │ ├── statsd.rs │ └── window.rs ├── relay-cogs ├── Cargo.toml └── src │ ├── cogs.rs │ ├── lib.rs │ ├── measurement.rs │ ├── recorder.rs │ ├── test.rs │ └── time.rs ├── relay-common ├── Cargo.toml └── src │ ├── glob2.rs │ ├── lib.rs │ ├── macros.rs │ └── time.rs ├── relay-config ├── Cargo.toml └── src │ ├── aggregator.rs │ ├── byte_size.rs │ ├── config.rs │ ├── lib.rs │ ├── redis.rs │ └── upstream.rs ├── relay-crash ├── Cargo.toml ├── build.rs └── src │ └── lib.rs ├── relay-dynamic-config ├── Cargo.toml └── src │ ├── defaults.rs │ ├── error_boundary.rs │ ├── feature.rs │ ├── global.rs │ ├── lib.rs │ ├── metrics.rs │ ├── project.rs │ └── utils.rs ├── relay-event-derive ├── Cargo.toml └── src │ ├── lib.rs │ └── utils.rs ├── relay-event-normalization ├── Cargo.toml ├── src │ ├── clock_drift.rs │ ├── event.rs │ ├── event_error.rs │ ├── geo.rs │ ├── legacy.rs │ ├── lib.rs │ ├── logentry.rs │ ├── mechanism.rs │ ├── normalize │ │ ├── android_models.csv │ │ ├── breakdowns.rs │ │ ├── contexts.rs │ │ ├── mod.rs │ │ ├── nel.rs │ │ ├── request.rs │ │ ├── snapshots │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_empty.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_exact_length.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_short_no_trimming.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_too_long_single_word.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_trimmed.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_word_leading_dots.snap │ │ │ ├── relay_event_normalization__normalize__tests__normalize_logger_word_trimmed_at_max.snap │ │ │ └── relay_event_normalization__normalize__tests__normalize_logger_word_trimmed_before_max.snap │ │ ├── span │ │ │ ├── ai.rs │ │ │ ├── country_subregion.rs │ │ │ ├── description │ │ │ │ ├── mod.rs │ │ │ │ ├── redis.rs │ │ │ │ ├── resource.rs │ │ │ │ └── sql │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── parser.rs │ │ │ ├── exclusive_time.rs │ │ │ ├── mod.rs │ │ │ ├── reparent_broken_spans.rs │ │ │ ├── snapshots │ │ │ │ ├── relay_event_normalization__normalize__span__tag_extraction__tests__cache_extraction.snap │ │ │ │ └── relay_event_normalization__normalize__span__tag_extraction__tests__extracts_searchable_contexts_into_segment_span.snap │ │ │ └── tag_extraction.rs │ │ ├── user_agent.rs │ │ └── utils.rs │ ├── regexes.rs │ ├── remove_other.rs │ ├── replay.rs │ ├── schema.rs │ ├── snapshots │ │ ├── relay_event_normalization__event__tests__compute_performance_score_for_mobile_android_profile.snap │ │ ├── relay_event_normalization__event__tests__compute_performance_score_for_mobile_ios_profile.snap │ │ └── relay_event_normalization__trimming__tests__databag_array_stripping.snap │ ├── stacktrace.rs │ ├── statsd.rs │ ├── timestamp.rs │ ├── transactions │ │ ├── mod.rs │ │ ├── processor.rs │ │ └── rules.rs │ ├── trimming.rs │ └── validation.rs └── tests │ └── fixtures │ ├── GeoIP2-Enterprise-Test.mmdb │ └── README ├── relay-event-schema ├── Cargo.toml ├── src │ ├── lib.rs │ ├── processor │ │ ├── attrs.rs │ │ ├── chunks.rs │ │ ├── funcs.rs │ │ ├── impls.rs │ │ ├── mod.rs │ │ └── traits.rs │ └── protocol │ │ ├── attributes.rs │ │ ├── base.rs │ │ ├── breadcrumb.rs │ │ ├── breakdowns.rs │ │ ├── client_report.rs │ │ ├── clientsdk.rs │ │ ├── constants.rs │ │ ├── contexts │ │ ├── app.rs │ │ ├── browser.rs │ │ ├── cloud_resource.rs │ │ ├── device.rs │ │ ├── flags.rs │ │ ├── gpu.rs │ │ ├── mod.rs │ │ ├── monitor.rs │ │ ├── nel.rs │ │ ├── os.rs │ │ ├── ota_updates.rs │ │ ├── otel.rs │ │ ├── performance_score.rs │ │ ├── profile.rs │ │ ├── replay.rs │ │ ├── reprocessing.rs │ │ ├── response.rs │ │ ├── runtime.rs │ │ ├── spring.rs │ │ ├── trace.rs │ │ └── user_report_v2.rs │ │ ├── debugmeta.rs │ │ ├── device_class.rs │ │ ├── event.rs │ │ ├── exception.rs │ │ ├── fingerprint.rs │ │ ├── logentry.rs │ │ ├── measurements.rs │ │ ├── mechanism.rs │ │ ├── metrics.rs │ │ ├── metrics_summary.rs │ │ ├── mod.rs │ │ ├── nel.rs │ │ ├── ourlog.rs │ │ ├── relay_info.rs │ │ ├── replay.rs │ │ ├── request.rs │ │ ├── security_report.rs │ │ ├── session.rs │ │ ├── span.rs │ │ ├── span │ │ └── convert.rs │ │ ├── span_v2.rs │ │ ├── stacktrace.rs │ │ ├── tags.rs │ │ ├── templateinfo.rs │ │ ├── thread.rs │ │ ├── transaction.rs │ │ ├── types.rs │ │ ├── user.rs │ │ ├── user_report.rs │ │ └── utils.rs └── tests │ └── test_derive.rs ├── relay-ffi-macros ├── Cargo.toml └── src │ └── lib.rs ├── relay-ffi ├── Cargo.toml ├── src │ └── lib.rs └── tests │ └── test_macro.rs ├── relay-filter ├── Cargo.toml └── src │ ├── browser_extensions.rs │ ├── client_ips.rs │ ├── common.rs │ ├── config.rs │ ├── csp.rs │ ├── error_messages.rs │ ├── generic.rs │ ├── interface.rs │ ├── legacy_browsers.rs │ ├── lib.rs │ ├── localhost.rs │ ├── releases.rs │ ├── testutils.rs │ ├── transaction_name.rs │ └── web_crawlers.rs ├── relay-kafka ├── Cargo.toml └── src │ ├── config.rs │ ├── debounced.rs │ ├── lib.rs │ ├── limits.rs │ ├── producer │ ├── mod.rs │ ├── schemas.rs │ └── utils.rs │ └── statsd.rs ├── relay-log ├── Cargo.toml ├── build.rs └── src │ ├── lib.rs │ ├── setup.rs │ ├── test.rs │ └── utils.rs ├── relay-metrics ├── Cargo.toml ├── benches │ └── benches.rs ├── src │ ├── aggregator │ │ ├── config.rs │ │ ├── cost.rs │ │ ├── inner.rs │ │ ├── mod.rs │ │ ├── snapshots │ │ │ ├── relay_metrics__aggregator__inner__tests__merge_flush-3.snap │ │ │ ├── relay_metrics__aggregator__inner__tests__merge_flush-5.snap │ │ │ └── relay_metrics__aggregator__inner__tests__merge_flush.snap │ │ └── stats.rs │ ├── bucket.rs │ ├── cogs.rs │ ├── finite.rs │ ├── lib.rs │ ├── protocol.rs │ ├── snapshots │ │ └── relay_metrics__view__tests__buckets_view_serialize_partial.snap │ ├── statsd.rs │ ├── utils.rs │ └── view.rs └── tests │ └── fixtures │ ├── buckets.json │ ├── buckets.statsd.txt │ ├── kafka.json │ ├── set.json │ └── set.statsd.txt ├── relay-monitors ├── Cargo.toml └── src │ └── lib.rs ├── relay-ourlogs ├── Cargo.toml └── src │ ├── lib.rs │ └── ourlog.rs ├── relay-pattern ├── Cargo.toml ├── benches │ └── benches.rs ├── fuzz │ ├── Cargo.toml │ └── fuzz_targets │ │ ├── is_match_case_insensitive.rs │ │ └── is_match_case_sensitive.rs └── src │ ├── lib.rs │ ├── typed.rs │ └── wildmatch.rs ├── relay-pii ├── Cargo.toml ├── src │ ├── attachments.rs │ ├── builtin.rs │ ├── compiledconfig.rs │ ├── config.rs │ ├── convert.rs │ ├── generate_selectors.rs │ ├── json.rs │ ├── legacy.rs │ ├── lib.rs │ ├── minidumps.rs │ ├── processor.rs │ ├── redactions.rs │ ├── regexes.rs │ ├── selector.pest │ ├── selector.rs │ ├── snapshots │ │ ├── relay_pii__convert__tests__authorization_scrubbing.snap │ │ ├── relay_pii__convert__tests__bearer_tokens_scrubbed.snap │ │ ├── relay_pii__convert__tests__breadcrumb_message-2.snap │ │ ├── relay_pii__convert__tests__contexts.snap │ │ ├── relay_pii__convert__tests__csp_blocked_uri.snap │ │ ├── relay_pii__convert__tests__debug_meta_files_not_strippable.snap │ │ ├── relay_pii__convert__tests__does_sanitize_encrypted_private_key.snap │ │ ├── relay_pii__convert__tests__does_sanitize_private_key.snap │ │ ├── relay_pii__convert__tests__does_sanitize_public_key.snap │ │ ├── relay_pii__convert__tests__does_sanitize_rsa_private_key.snap │ │ ├── relay_pii__convert__tests__does_sanitize_social_security_number.snap │ │ ├── relay_pii__convert__tests__doesnt_scrub_not_scrubbed.snap │ │ ├── relay_pii__convert__tests__event_message_not_strippable.snap │ │ ├── relay_pii__convert__tests__exclude_fields_on_field_name.snap │ │ ├── relay_pii__convert__tests__explicit_fields.snap │ │ ├── relay_pii__convert__tests__explicit_fields_case_insensitive.snap │ │ ├── relay_pii__convert__tests__extra.snap │ │ ├── relay_pii__convert__tests__http.snap │ │ ├── relay_pii__convert__tests__http_remote_addr_stripped.snap │ │ ├── relay_pii__convert__tests__ip_stripped.snap │ │ ├── relay_pii__convert__tests__no_scrub_object_with_safe_fields.snap │ │ ├── relay_pii__convert__tests__odd_keys.snap │ │ ├── relay_pii__convert__tests__pairlist_scrubbed_with_matching_keys.snap │ │ ├── relay_pii__convert__tests__pairlist_scrubbed_with_matching_values.snap │ │ ├── relay_pii__convert__tests__querystring_as_pairlist.snap │ │ ├── relay_pii__convert__tests__querystring_as_pairlist_with_partials.snap │ │ ├── relay_pii__convert__tests__querystring_as_string.snap │ │ ├── relay_pii__convert__tests__querystring_as_string_with_partials.snap │ │ ├── relay_pii__convert__tests__regression_more_odd_keys.snap │ │ ├── relay_pii__convert__tests__safe_fields_for_token.snap │ │ ├── relay_pii__convert__tests__sanitize_additional_sensitive_fields.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_amex.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_discover.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_mastercard.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_visa.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_within_value_1.snap │ │ ├── relay_pii__convert__tests__sanitize_credit_card_within_value_2.snap │ │ ├── relay_pii__convert__tests__sanitize_http_body.snap │ │ ├── relay_pii__convert__tests__sanitize_http_body_string.snap │ │ ├── relay_pii__convert__tests__sanitize_url_1.snap │ │ ├── relay_pii__convert__tests__sanitize_url_2.snap │ │ ├── relay_pii__convert__tests__sanitize_url_3.snap │ │ ├── relay_pii__convert__tests__sanitize_url_4.snap │ │ ├── relay_pii__convert__tests__sanitize_url_5.snap │ │ ├── relay_pii__convert__tests__sanitize_url_6.snap │ │ ├── relay_pii__convert__tests__sanitize_url_7.snap │ │ ├── relay_pii__convert__tests__scrub_object.snap │ │ ├── relay_pii__convert__tests__sdk_client_ip_stripped.snap │ │ ├── relay_pii__convert__tests__sensitive_cookies.snap │ │ ├── relay_pii__convert__tests__should_have_mysql_pwd_as_a_default_1.snap │ │ ├── relay_pii__convert__tests__should_have_mysql_pwd_as_a_default_2.snap │ │ ├── relay_pii__convert__tests__stacktrace.snap │ │ ├── relay_pii__convert__tests__stacktrace_paths_not_strippable.snap │ │ ├── relay_pii__convert__tests__user.snap │ │ ├── relay_pii__convert__tests__user_ip_stripped.snap │ │ ├── relay_pii__processor__tests__anything_hash_on_container.snap │ │ ├── relay_pii__processor__tests__anything_hash_on_string.snap │ │ ├── relay_pii__processor__tests__basic_stripping.snap │ │ ├── relay_pii__processor__tests__debugmeta_path_not_addressible_with_wildcard_selector.snap │ │ ├── relay_pii__processor__tests__does_not_scrub_if_no_graphql.snap │ │ ├── relay_pii__processor__tests__hash_debugmeta_path.snap │ │ ├── relay_pii__processor__tests__ignore_user_agent_ip_scrubbing.snap │ │ ├── relay_pii__processor__tests__no_field_upsert.snap │ │ ├── relay_pii__processor__tests__quoted_keys.snap │ │ ├── relay_pii__processor__tests__redact_containers.snap │ │ ├── relay_pii__processor__tests__redact_custom_pattern.snap │ │ ├── relay_pii__processor__tests__remove_debugmeta_path.snap │ │ ├── relay_pii__processor__tests__replace_debugmeta_path.snap │ │ ├── relay_pii__processor__tests__scrub_breadcrumb_data_http_not_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_breadcrumb_data_http_objects_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_breadcrumb_data_http_strings_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_breadcrumb_data_untyped_props_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_graphql_response_data_with_variables.snap │ │ ├── relay_pii__processor__tests__scrub_graphql_response_data_without_variables.snap │ │ ├── relay_pii__processor__tests__scrub_original_value.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_http_not_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_http_objects_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_http_strings_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_not_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_object_is_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_string_is_scrubbed.snap │ │ ├── relay_pii__processor__tests__scrub_span_data_untyped_props_are_scrubbed.snap │ │ ├── relay_pii__processor__tests__sentry_user.snap │ │ └── relay_pii__processor__tests__trace_route_params_scrubbed.snap │ ├── transform.rs │ └── utils.rs └── tests │ └── replay.rs ├── relay-profiling ├── Cargo.toml ├── src │ ├── android │ │ ├── chunk.rs │ │ ├── legacy.rs │ │ └── mod.rs │ ├── debug_image.rs │ ├── error.rs │ ├── extract_from_transaction.rs │ ├── lib.rs │ ├── measurements.rs │ ├── outcomes.rs │ ├── sample │ │ ├── mod.rs │ │ ├── v1.rs │ │ └── v2.rs │ ├── transaction_metadata.rs │ ├── types.rs │ └── utils.rs └── tests │ └── fixtures │ ├── android │ ├── chunk │ │ ├── remove_invalid_events.json │ │ ├── roundtrip.rn.json │ │ ├── valid-rn.json │ │ └── valid.json │ └── legacy │ │ ├── multiple_transactions.json │ │ ├── no_transaction.json │ │ ├── remove_invalid_events.json │ │ ├── roundtrip.json │ │ ├── roundtrip.rn.json │ │ └── valid.json │ └── sample │ ├── v1 │ ├── segment_id.json │ └── valid.json │ └── v2 │ └── valid.json ├── relay-prosperoconv ├── Cargo.toml ├── build.rs ├── clippy.toml ├── prosperoconv.version └── src │ └── lib.rs ├── relay-protocol-derive ├── Cargo.toml └── src │ ├── lib.rs │ └── utils.rs ├── relay-protocol ├── Cargo.toml ├── src │ ├── annotated.rs │ ├── condition.rs │ ├── impls.rs │ ├── lib.rs │ ├── macros.rs │ ├── meta.rs │ ├── size.rs │ ├── traits.rs │ └── value.rs └── tests │ ├── test_annotated.rs │ ├── test_derive.rs │ └── test_derive_flatten.rs ├── relay-quotas ├── Cargo.toml └── src │ ├── global.rs │ ├── lib.rs │ ├── quota.rs │ ├── rate_limit.rs │ └── redis.rs ├── relay-redis ├── Cargo.toml └── src │ ├── config.rs │ ├── lib.rs │ ├── noop.rs │ ├── pool.rs │ ├── real.rs │ ├── scripts.rs │ └── scripts │ ├── cardinality.lua │ ├── global_quota.lua │ └── is_rate_limited.lua ├── relay-replays ├── Cargo.toml ├── benches │ └── benchmarks.rs ├── src │ ├── lib.rs │ ├── recording.rs │ └── snapshots │ │ └── relay_replays__recording__tests__scrub_pii_key_based_edge_cases.snap └── tests │ └── fixtures │ ├── rrweb-binary.txt │ ├── rrweb-diff.json │ ├── rrweb-event-2.json │ ├── rrweb-event-3.json │ ├── rrweb-event-5.json │ ├── rrweb-node-2-style.json │ ├── rrweb-node-2.json │ ├── rrweb-performance-navigation.json │ ├── rrweb-performance-resource.json │ ├── rrweb-pii-ip-address.json │ ├── rrweb-pii.json │ ├── rrweb-request-edge-cases.json │ ├── rrweb-request.json │ └── rrweb.json ├── relay-sampling ├── Cargo.toml ├── src │ ├── config.rs │ ├── dsc.rs │ ├── evaluation.rs │ ├── lib.rs │ └── redis_sampling.rs └── tests │ └── fixtures │ ├── dynamic_sampling_context.json │ └── sampling_config.json ├── relay-server ├── Cargo.toml ├── benches │ └── benches.rs ├── build.rs ├── src │ ├── constants.rs │ ├── endpoints │ │ ├── attachments.rs │ │ ├── autoscaling.rs │ │ ├── batch_metrics.rs │ │ ├── batch_outcomes.rs │ │ ├── common.rs │ │ ├── envelope.rs │ │ ├── events.rs │ │ ├── forward.rs │ │ ├── health_check.rs │ │ ├── minidump.rs │ │ ├── mod.rs │ │ ├── monitor.rs │ │ ├── nel.rs │ │ ├── playstation.rs │ │ ├── project_configs.rs │ │ ├── public_keys.rs │ │ ├── security_report.rs │ │ ├── statics.rs │ │ ├── store.rs │ │ ├── traces.rs │ │ └── unreal.rs │ ├── envelope │ │ ├── attachment.rs │ │ ├── container.rs │ │ ├── content_type.rs │ │ ├── item.rs │ │ └── mod.rs │ ├── extractors │ │ ├── content_type.rs │ │ ├── forwarded_for.rs │ │ ├── mime.rs │ │ ├── mod.rs │ │ ├── received_at.rs │ │ ├── remote.rs │ │ ├── request_meta.rs │ │ └── signed_json.rs │ ├── http.rs │ ├── lib.rs │ ├── metrics │ │ ├── bucket_encoding.rs │ │ ├── metric_stats.rs │ │ ├── minimal.rs │ │ ├── mod.rs │ │ ├── outcomes.rs │ │ └── rate_limits.rs │ ├── metrics_extraction │ │ ├── event.rs │ │ ├── generic.rs │ │ ├── mod.rs │ │ ├── sessions │ │ │ ├── mod.rs │ │ │ └── types.rs │ │ ├── snapshots │ │ │ ├── relay_server__metrics_extraction__event__tests__both_feature_flags_enabled.snap │ │ │ ├── relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap │ │ │ └── relay_server__metrics_extraction__event__tests__only_common.snap │ │ └── transactions │ │ │ ├── mod.rs │ │ │ └── types.rs │ ├── middlewares │ │ ├── body_timing.rs │ │ ├── cors.rs │ │ ├── decompression.rs │ │ ├── handle_panic.rs │ │ ├── metrics.rs │ │ ├── mod.rs │ │ ├── normalize_path.rs │ │ └── trace.rs │ ├── service.rs │ ├── services │ │ ├── autoscaling.rs │ │ ├── buffer │ │ │ ├── common.rs │ │ │ ├── envelope_buffer │ │ │ │ └── mod.rs │ │ │ ├── envelope_stack │ │ │ │ ├── caching.rs │ │ │ │ ├── memory.rs │ │ │ │ ├── mod.rs │ │ │ │ └── sqlite.rs │ │ │ ├── envelope_store │ │ │ │ ├── mod.rs │ │ │ │ └── sqlite.rs │ │ │ ├── mod.rs │ │ │ ├── stack_provider │ │ │ │ ├── memory.rs │ │ │ │ ├── mod.rs │ │ │ │ └── sqlite.rs │ │ │ └── testutils.rs │ │ ├── cogs.rs │ │ ├── global_config.rs │ │ ├── global_rate_limits.rs │ │ ├── health_check.rs │ │ ├── metrics │ │ │ ├── aggregator.rs │ │ │ ├── mod.rs │ │ │ └── router.rs │ │ ├── mod.rs │ │ ├── outcome.rs │ │ ├── outcome_aggregator.rs │ │ ├── processor.rs │ │ ├── processor │ │ │ ├── attachment.rs │ │ │ ├── dying_message.md │ │ │ ├── dynamic_sampling.rs │ │ │ ├── event.rs │ │ │ ├── metrics.rs │ │ │ ├── nnswitch.rs │ │ │ ├── ourlog.rs │ │ │ ├── ourlog │ │ │ │ └── processing.rs │ │ │ ├── playstation.rs │ │ │ ├── profile.rs │ │ │ ├── profile_chunk.rs │ │ │ ├── replay.rs │ │ │ ├── report.rs │ │ │ ├── session.rs │ │ │ ├── span.rs │ │ │ ├── span │ │ │ │ └── processing.rs │ │ │ ├── standalone.rs │ │ │ ├── transaction.rs │ │ │ └── unreal.rs │ │ ├── projects │ │ │ ├── cache │ │ │ │ ├── handle.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── project.rs │ │ │ │ ├── service.rs │ │ │ │ └── state.rs │ │ │ ├── mod.rs │ │ │ ├── project │ │ │ │ ├── info.rs │ │ │ │ └── mod.rs │ │ │ └── source │ │ │ │ ├── local.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── redis.rs │ │ │ │ └── upstream.rs │ │ ├── relays.rs │ │ ├── server │ │ │ ├── acceptor.rs │ │ │ ├── concurrency_limit.rs │ │ │ ├── io.rs │ │ │ └── mod.rs │ │ ├── stats.rs │ │ ├── store.rs │ │ ├── test_store.rs │ │ └── upstream.rs │ ├── statsd.rs │ ├── testutils.rs │ └── utils │ │ ├── api.rs │ │ ├── dynamic_sampling.rs │ │ ├── managed_envelope.rs │ │ ├── memory.rs │ │ ├── mod.rs │ │ ├── multipart.rs │ │ ├── native.rs │ │ ├── param_parser.rs │ │ ├── pick.rs │ │ ├── rate_limits.rs │ │ ├── retry.rs │ │ ├── scheduled │ │ ├── futures.rs │ │ ├── mod.rs │ │ └── queue.rs │ │ ├── serde.rs │ │ ├── sizes.rs │ │ ├── sleep_handle.rs │ │ ├── snapshots │ │ ├── relay_server__utils__unreal__tests__merge_unreal_context.snap │ │ ├── relay_server__utils__unreal__tests__merge_unreal_context_event.snap │ │ └── relay_server__utils__unreal__tests__merge_unreal_logs.snap │ │ ├── split_off.rs │ │ ├── statsd.rs │ │ ├── thread_pool.rs │ │ └── unreal.rs └── tests │ ├── fixtures │ └── payloads │ │ ├── android.json │ │ ├── cocoa.json │ │ ├── cordova.json │ │ ├── dotnet.json │ │ ├── electron_main.json │ │ ├── electron_renderer.json │ │ ├── legacy_js_exception.json │ │ ├── legacy_js_message.json │ │ ├── legacy_js_onerror.json │ │ ├── legacy_js_promise.json │ │ ├── legacy_node_exception.json │ │ ├── legacy_node_express.json │ │ ├── legacy_node_message.json │ │ ├── legacy_node_onerror.json │ │ ├── legacy_node_promise.json │ │ ├── legacy_python.json │ │ ├── legacy_swift.json │ │ ├── unity_android.json │ │ ├── unity_ios.json │ │ ├── unity_linux.json │ │ ├── unity_macos.json │ │ └── unity_windows.json │ ├── snapshots │ ├── test_fixtures__android__pii_stripping.snap │ ├── test_fixtures__cocoa__pii_stripping.snap │ ├── test_fixtures__cordova__pii_stripping.snap │ ├── test_fixtures__dotnet__pii_stripping.snap │ ├── test_fixtures__event_schema.snap │ ├── test_fixtures__legacy_node_exception__pii_stripping.snap │ ├── test_fixtures__legacy_python__pii_stripping.snap │ ├── test_fixtures__unity_android__pii_stripping.snap │ ├── test_fixtures__unity_ios__pii_stripping.snap │ ├── test_fixtures__unity_linux__pii_stripping.snap │ ├── test_fixtures__unity_macos__pii_stripping.snap │ ├── test_fixtures__unity_windows__pii_stripping.snap │ └── test_pii__reponse_context_pii.snap │ ├── test_fixtures.rs │ └── test_pii.rs ├── relay-spans ├── Cargo.toml └── src │ ├── lib.rs │ ├── otel_to_sentry.rs │ ├── otel_to_sentry_v2.rs │ ├── status_codes.rs │ └── v2_to_v1.rs ├── relay-statsd ├── Cargo.toml └── src │ └── lib.rs ├── relay-system ├── Cargo.toml └── src │ ├── controller.rs │ ├── lib.rs │ ├── monitor.rs │ ├── runtime │ ├── handle.rs │ ├── metrics.rs │ ├── mod.rs │ ├── runtime.rs │ └── spawn.rs │ ├── service │ ├── mod.rs │ ├── registry.rs │ └── status.rs │ └── statsd.rs ├── relay-test ├── Cargo.toml └── src │ └── lib.rs ├── relay-threading ├── Cargo.toml ├── benches │ └── pool.rs └── src │ ├── builder.rs │ ├── lib.rs │ ├── metrics.rs │ ├── multiplexing.rs │ └── pool.rs ├── relay-ua ├── Cargo.toml └── src │ └── lib.rs ├── relay ├── Cargo.toml └── src │ ├── cli.rs │ ├── cliapp.rs │ ├── main.rs │ ├── setup.rs │ └── utils.rs ├── requirements-dev.txt ├── scripts ├── bump-library.sh ├── bump-version.sh ├── create-sentry-release ├── docker-manylinux.sh ├── get-sentry-release-name ├── git-archive-all └── git-precommit-hook ├── tests ├── fixtures │ ├── GeoIP2-Enterprise-Test.mmdb │ ├── basic-event-input.json │ ├── basic-event-output.json │ ├── extended-event-input.json │ ├── extended-event-output.json │ ├── linux.dmp │ ├── macos.dmp │ ├── replay.json │ ├── replay_failure_22_08_31.json │ ├── replay_missing_user.json │ ├── replay_missing_user_ip_address.json │ ├── replay_no_requests.json │ └── windows.dmp ├── integration │ ├── __init__.py │ ├── asserts │ │ ├── __init__.py │ │ └── time.py │ ├── conftest.py │ ├── consts.py │ ├── fixtures │ │ ├── 10GB.gz │ │ ├── __init__.py │ │ ├── gobetween.py │ │ ├── haproxy.py │ │ ├── histogram-outliers.yml │ │ ├── mini_sentry.py │ │ ├── native │ │ │ ├── .gitattributes │ │ │ ├── annotations.dmp │ │ │ ├── bad_electron_simple.dmp │ │ │ ├── electron.dmp │ │ │ ├── electron_simple.dmp │ │ │ ├── minidump.dmp │ │ │ ├── minidump.dmp.bz2 │ │ │ ├── minidump.dmp.gz │ │ │ ├── minidump.dmp.xz │ │ │ ├── minidump.dmp.zst │ │ │ ├── nnswitch_dying_message_plain.dat │ │ │ ├── nnswitch_dying_message_zstandard.dat │ │ │ ├── playstation.prosperodmp │ │ │ ├── unreal_crash │ │ │ ├── unreal_crash_apple │ │ │ ├── unreal_crash_with_config │ │ │ └── user_data.prosperodmp │ │ ├── processing.py │ │ ├── relay.py │ │ └── security_report │ │ │ ├── csp.input.json │ │ │ ├── csp.no_processing.output.json │ │ │ ├── csp.normalized.output.json │ │ │ ├── csp_chrome.input.json │ │ │ ├── csp_chrome.no_processing.output.json │ │ │ ├── csp_chrome_blocked_asset.input.json │ │ │ ├── csp_chrome_blocked_asset.no_processing.output.json │ │ │ ├── csp_firefox_blocked_asset.input.json │ │ │ ├── csp_firefox_blocked_asset.no_processing.output.json │ │ │ ├── expect_ct.input.json │ │ │ ├── expect_ct.no_processing.output.json │ │ │ ├── expect_staple.input.json │ │ │ ├── expect_staple.no_processing.output.json │ │ │ ├── hpkp.input.json │ │ │ └── hpkp.no_processing.output.json │ ├── test_attachments.py │ ├── test_autoscaling.py │ ├── test_basic.py │ ├── test_cardinality_limiter.py │ ├── test_client_report.py │ ├── test_clock_drift.py │ ├── test_config.py │ ├── test_dynamic_sampling.py │ ├── test_envelope.py │ ├── test_ephemeral_config.py │ ├── test_feedback.py │ ├── test_filters.py │ ├── test_flags.py │ ├── test_forwarding.py │ ├── test_healthchecks.py │ ├── test_ingest_path.py │ ├── test_metric_stats.py │ ├── test_metrics.py │ ├── test_metrics_encoding.py │ ├── test_minidump.py │ ├── test_monitors.py │ ├── test_nnswitch.py │ ├── test_normalization.py │ ├── test_ourlogs.py │ ├── test_outcome.py │ ├── test_pii.py │ ├── test_playstation.py │ ├── test_profile_chunks.py │ ├── test_projectconfigs.py │ ├── test_proxy.py │ ├── test_publickeys.py │ ├── test_query.py │ ├── test_replay_combined_payload.py │ ├── test_replay_events.py │ ├── test_replay_recordings.py │ ├── test_replay_videos.py │ ├── test_security_report.py │ ├── test_session.py │ ├── test_span_links.py │ ├── test_spans.py │ ├── test_store.py │ ├── test_unreal.py │ └── test_user_report.py ├── pytest.ini └── test_pii_docs │ ├── Cargo.toml │ └── src │ ├── anothermod.rs │ └── main.rs └── tools ├── bench-buffer ├── Cargo.toml └── src │ └── main.rs ├── document-metrics ├── Cargo.toml └── src │ └── main.rs ├── document-pii ├── Cargo.toml └── src │ ├── item_collector.rs │ ├── main.rs │ ├── pii_finder.rs │ └── snapshots │ ├── document_pii__tests__find_rs_files.snap │ ├── document_pii__tests__pii_all.snap │ ├── document_pii__tests__pii_false.snap │ ├── document_pii__tests__pii_retain_additional_properties_truth_table.snap │ ├── document_pii__tests__pii_true.snap │ ├── document_pii__tests__scoped_paths.snap │ └── document_pii__tests__single_type.snap ├── process-event ├── Cargo.toml └── src │ └── main.rs └── scrub-minidump ├── Cargo.toml └── src └── main.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["--cfg", "tokio_unstable"] 3 | 4 | [env] 5 | # Workaround for https://github.com/confluentinc/librdkafka/pull/5012 6 | CMAKE_POLICY_VERSION_MINIMUM = "3.10" 7 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "relay-cabi/**/*.rs" 3 | - "relay-general/derive/**/*.rs" 4 | -------------------------------------------------------------------------------- /.craft.yml: -------------------------------------------------------------------------------- 1 | minVersion: 0.23.1 2 | changelogPolicy: auto 3 | 4 | targets: 5 | - name: github 6 | - name: registry 7 | apps: 8 | app:relay: 9 | urlTemplate: https://downloads.sentry-cdn.com/relay/{{version}}/{{file}} 10 | includeNames: /^relay-(Darwin|Linux|Windows).*$/i 11 | - name: gcs 12 | bucket: sentry-sdk-assets 13 | includeNames: /^relay-(Darwin|Windows|Linux).*$/ 14 | paths: 15 | - path: /relay/{{version}}/ 16 | metadata: 17 | cacheControl: public, max-age=2592000 18 | - path: /relay/latest/ 19 | metadata: 20 | cacheControl: public, max-age=600 21 | - id: release 22 | name: docker 23 | source: us-central1-docker.pkg.dev/sentryio/relay/relay 24 | target: getsentry/relay 25 | - id: latest 26 | name: docker 27 | source: us-central1-docker.pkg.dev/sentryio/relay/relay 28 | target: getsentry/relay 29 | targetFormat: "{{{target}}}:latest" 30 | 31 | requireNames: 32 | - /^relay-Darwin-x86_64$/ 33 | - /^relay-Darwin-x86_64-dsym.zip$/ 34 | - /^relay-Linux-x86_64$/ 35 | - /^relay-Linux-x86_64-debug.zip$/ 36 | - /^relay-Linux-aarch64$/ 37 | - /^relay-Linux-aarch64-debug.zip$/ 38 | - /^relay-Windows-x86_64-pdb.zip$/ 39 | - /^relay-Windows-x86_64\.exe$/ 40 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Ignore every file change 2 | * 3 | # Except the following matches (lines starting with exclamation marks) 4 | # Read: Include these files as part of the build process and if they change 5 | # it will rebuild the Docker image 6 | !.git/ 7 | !.gitmodules 8 | 9 | !relay*/ 10 | !tools/ 11 | !Cargo.toml 12 | !Cargo.lock 13 | 14 | !docker-entrypoint.sh 15 | !Makefile 16 | 17 | # CI files necessary for building the docker file 18 | !linux/ 19 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Our policy is that the .envrc is entirely optional, and a user 4 | # without direnv should not really have a worse dev experience in any way. 5 | 6 | # 'make' is in charge of creating and managing virtualenvs, and things like 7 | # pytest can still be directly invoked using .venv/bin/pytest 8 | 9 | if ! source .venv/bin/activate; then 10 | echo "!!! you have no virtualenv, run 'make setup' to fix that." 11 | # XXX: ideally, direnv is able to export PS1 as modified by sourcing venvs 12 | # but we'd have to patch direnv, and ".venv" isn't descriptive anyways 13 | unset PS1 14 | fi 15 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | extend-ignore = E203,E501,E731 3 | max-complexity = 18 4 | exclude=py/sentry_relay/_lowlevel*,.eggs,build,dist 5 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default code owners 2 | * @getsentry/ingest 3 | 4 | # Legal 5 | /LICENSE.md @getsentry/owners-legal 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/epic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Epic 3 | about: Plan a new initative 4 | title: '[EPIC] ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Background 11 | 12 | Add context and motivation here. 13 | 14 | ## Requirements 15 | 16 | What is the desired outcome of this initiative? What are the hard technical requirements. 17 | Add measurable success criteria here. 18 | 19 | ## Design 20 | 21 | Describe how you want to meet the requirements above. 22 | 23 | ## Infrastructure checklist 24 | 25 | Be sure to assess the infrastructure impact of your initiative early on, such that 26 | the required work can be planned in advance. 27 | 28 | - [ ] Will this affect CPU and / or memory usage? 29 | - [ ] Does this plan require different machine types (different memory to CPU ratio)? 30 | - [ ] Does this plan require new autoscaling rules? Will it impact the metric that the autoscaler uses? 31 | - [ ] Will this increase the load on redis, kafka, or the HTTP upstream? 32 | - [ ] Does this plan require larger disks or different disk types? 33 | - [ ] Will it affect health checks and/or HTTP response times? 34 | 35 | ## Implementation 36 | 37 | Once the planning is done, list implementation tasks here. 38 | 39 | ```[tasklist] 40 | ### Implementation tasks 41 | - [ ] ... 42 | ``` 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/flaky.yml: -------------------------------------------------------------------------------- 1 | name: ❅ Flaky Test 2 | description: Report a flaky test in CI 3 | title: "[Flaky CI]: " 4 | labels: ["Type: Tests"] 5 | body: 6 | - type: dropdown 7 | id: type 8 | attributes: 9 | label: Flakiness Type 10 | description: What are you observing 11 | options: 12 | - Timeout 13 | - Assertion failure 14 | - Other / Unknown 15 | validations: 16 | required: true 17 | - type: input 18 | id: test-name 19 | attributes: 20 | label: Name of Test 21 | placeholder: tests/integration/test_metrics.py::test 22 | description: file name or function name of failing test 23 | validations: 24 | required: false 25 | - type: input 26 | id: test-run-link 27 | attributes: 28 | label: Link to Test Run 29 | placeholder: https://github.com/getsentry/relay/actions/runs/7032804839/job/19137301178 30 | description: paste the URL to a test run showing the failing test 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: details 35 | attributes: 36 | label: Details 37 | description: If you know anything else, please add it here 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <!-- Describe your PR here. --> 5 | 6 | 7 | 8 | <!-- 9 | 10 | Sentry employees and contractors can delete or ignore the following. 11 | 12 | --> 13 | 14 | ### Legal Boilerplate 15 | 16 | Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. 17 | -------------------------------------------------------------------------------- /.github/actions/changelog/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.github/actions/changelog/README.md: -------------------------------------------------------------------------------- 1 | # Changelog Checker 2 | 3 | This is a custom script to check if the changelog files contain the entry for the current pull request. 4 | 5 | 6 | ### Development 7 | 8 | To make any contributions or changes to this code you must make sure that you have `node` installed. Once you have it, just 9 | run `npm install` in this folder to install all the dependencies. 10 | 11 | The main entry point is `changelog.js` file. This file contain all the supported checks. 12 | -------------------------------------------------------------------------------- /.github/actions/changelog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ChangelogChecker", 3 | "version": "1.0.0", 4 | "description": "Makes sure that the CHANGELOG.md has the entry for the current pull request.", 5 | "main": "index.js", 6 | "scripts": { 7 | "format": "prettier --write index.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/getsentry/relay.git" 12 | }, 13 | "author": "Oleksandr Kylymnychenko <oleksandr@sentry.io>", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/getsentry/relay/issues" 17 | }, 18 | "homepage": "https://github.com/getsentry/relay#readme", 19 | "dependencies": { 20 | "@actions/core": "^1.10.0", 21 | "@actions/github": "^5.1.1" 22 | }, 23 | "devDependencies": { 24 | "prettier": "2.8.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/actions/changelog/prettier.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | bracketSpacing: false, 4 | bracketSameLine: false, 5 | printWidth: 90, 6 | semi: true, 7 | singleQuote: true, 8 | tabWidth: 2, 9 | trailingComma: 'es5', 10 | useTabs: false, 11 | arrowParens: 'avoid', 12 | }; 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | open-pull-requests-limit: 0 # security updates only 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | reviewers: 9 | - "@getsentry/ingest" 10 | 11 | - package-ecosystem: "docker" 12 | directory: "/" 13 | schedule: 14 | interval: "daily" 15 | reviewers: 16 | - "@getsentry/ingest" 17 | open-pull-requests-limit: 0 # security updates only 18 | 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | # Check for updates to GitHub Actions every week 23 | interval: "weekly" 24 | reviewers: 25 | - "@getsentry/ingest" 26 | -------------------------------------------------------------------------------- /.github/workflows/beta.yml: -------------------------------------------------------------------------------- 1 | name: Beta CI 2 | 3 | on: 4 | schedule: 5 | - cron: "11 7 * * 1,4" # At 07:11 AM, only on Monday and Thursday 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | RELAY_CARGO_ARGS: "--locked" 10 | 11 | jobs: 12 | test-all: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | rust: [beta] 17 | 18 | services: 19 | redis: # https://docs.github.com/en/actions/guides/creating-redis-service-containers 20 | image: redis 21 | ports: 22 | - 6379:6379 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: recursive 28 | 29 | - name: Install Rust Toolchain 30 | run: | 31 | rustup toolchain install ${{ matrix.rust }} --profile minimal --component clippy --no-self-update 32 | rustup default ${{ matrix.rust }} 33 | 34 | - name: Run Clippy 35 | run: cargo clippy --workspace --all-targets --all-features --no-deps -- -D warnings 36 | 37 | - name: Run Cargo Tests 38 | run: cargo test --workspace --all-features 39 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Changelog" 2 | on: 3 | pull_request: 4 | types: [opened, synchronize, reopened, edited, ready_for_review] 5 | 6 | jobs: 7 | build: 8 | name: Changelogs 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | with: 16 | script: | 17 | const changelog = require('./.github/actions/changelog/index.js') 18 | await changelog({github, context, core}) 19 | -------------------------------------------------------------------------------- /.github/workflows/enforce-license-compliance.yml: -------------------------------------------------------------------------------- 1 | name: Enforce License Compliance 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - release/** 8 | - release-library/** 9 | 10 | pull_request: 11 | branches: [master] 12 | 13 | jobs: 14 | enforce-license-compliance: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: "Enforce License Compliance" 18 | uses: getsentry/action-enforce-license-compliance@main 19 | with: 20 | fossa_api_key: ${{ secrets.FOSSA_API_KEY }} 21 | -------------------------------------------------------------------------------- /.github/workflows/release-ghcr-version-tag.yml: -------------------------------------------------------------------------------- 1 | name: Release GHCR Versioned Image 2 | 3 | on: 4 | release: 5 | types: [prereleased, released] 6 | 7 | jobs: 8 | release-ghcr-version-tag: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Log in to GitHub Container Registry 12 | uses: docker/login-action@v3 13 | with: 14 | registry: ghcr.io 15 | username: ${{ github.actor }} 16 | password: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | - name: Tag release version 19 | run: | 20 | docker buildx imagetools create --tag \ 21 | ghcr.io/getsentry/relay:${{ github.ref_name }} \ 22 | ghcr.io/getsentry/relay:${{ github.sha }} 23 | -------------------------------------------------------------------------------- /.github/workflows/release_library.yml: -------------------------------------------------------------------------------- 1 | name: Release Library 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: Version to release 8 | required: true 9 | force: 10 | description: Force a release even when there are release-blockers (optional) 11 | required: false 12 | 13 | jobs: 14 | release: 15 | runs-on: ubuntu-latest 16 | name: "Release a new librelay version" 17 | 18 | steps: 19 | - name: Get auth token 20 | id: token 21 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 22 | with: 23 | app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} 24 | private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} 25 | 26 | - uses: actions/checkout@v4 27 | with: 28 | token: ${{ steps.token.outputs.token }} 29 | fetch-depth: 0 30 | 31 | - name: Prepare release 32 | uses: getsentry/action-prepare-release@v1 33 | env: 34 | GITHUB_TOKEN: ${{ steps.token.outputs.token }} 35 | with: 36 | version: ${{ github.event.inputs.version }} 37 | force: ${{ github.event.inputs.force }} 38 | path: py 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | **/*.rs.bk 3 | target 4 | **/fuzz/corpus 5 | **/fuzz/artifacts 6 | **/fuzz/coverage 7 | **/fuzz/*.html 8 | *.pending-snap 9 | 10 | # Python 11 | .venv/ 12 | .pytest_cache 13 | *.pyc 14 | 15 | # Runtime files 16 | /.relay/ 17 | 18 | # Editors 19 | /.idea/ 20 | .DS_Store 21 | 22 | # NPM utilities for building docs 23 | /node_modules/ 24 | package-lock.json 25 | 26 | # Jsonnet-bundler 27 | gocd/templates/vendor/ 28 | gocd/generated-pipelines/ 29 | 30 | # Relay credentials file 31 | credentials.json 32 | 33 | # Internal code 34 | relay-prosperoconv/src/** 35 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "general/uap-core"] 2 | path = relay-ua/uap-core 3 | url = https://github.com/ua-parser/uap-core.git 4 | [submodule "sentry-native"] 5 | path = relay-crash/sentry-native 6 | url = https://github.com/getsentry/sentry-native.git 7 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/python-jsonschema/check-jsonschema 3 | rev: 0.16.0 4 | hooks: 5 | - id: check-github-actions 6 | - id: check-github-workflows 7 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.11.9 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | // TOML language support 6 | "tamasfe.even-better-toml", 7 | // Rust language server 8 | "rust-lang.rust-analyzer", 9 | // Python including Pylance 10 | "ms-python.python", 11 | // Crates.io dependency versions 12 | "fill-labs.dependi", 13 | // Debugger support for Rust and native 14 | "vadimcn.vscode-lldb", 15 | // Snapshot tests integration 16 | "mitsuhiko.insta", 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Formatting 3 | "editor.formatOnPaste": true, 4 | "editor.formatOnSave": true, 5 | "editor.formatOnType": true, 6 | "editor.tabSize": 4, 7 | "editor.rulers": [100], 8 | "files.autoSave": "onWindowChange", 9 | "files.trimTrailingWhitespace": true, 10 | "files.insertFinalNewline": true, 11 | 12 | // Python configuration 13 | "python.defaultInterpreterPath": ".venv/bin/python", 14 | "python.linting.enabled": true, 15 | "python.formatting.provider": "black", 16 | 17 | // Rust Analyzer 18 | "rust-analyzer.cargo.features": "all", 19 | "rust-analyzer.check.command": "clippy", 20 | "rust-analyzer.imports.granularity.group": "module", 21 | "rust-analyzer.imports.prefix": "crate", 22 | 23 | // Language-specific overrides 24 | "[markdown]": { 25 | "editor.rulers": [80], 26 | "editor.tabSize": 2, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Dockerfile.release: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim 2 | 3 | ARG TARGETPLATFORM 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y ca-certificates gosu curl --no-install-recommends \ 7 | && apt-get clean \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | ENV \ 11 | RELAY_UID=10001 \ 12 | RELAY_GID=10001 13 | 14 | # Create a new user and group with fixed uid/gid 15 | RUN groupadd --system relay --gid $RELAY_GID \ 16 | && useradd --system --gid relay --uid $RELAY_UID relay 17 | 18 | RUN mkdir /work /etc/relay \ 19 | && chown relay:relay /work /etc/relay 20 | VOLUME ["/work", "/etc/relay"] 21 | WORKDIR /work 22 | 23 | EXPOSE 3000 24 | 25 | COPY $TARGETPLATFORM/relay /bin/relay 26 | RUN chmod +x /bin/relay 27 | COPY $TARGETPLATFORM/relay-debug.zip /opt/relay-debug.zip 28 | COPY $TARGETPLATFORM/relay.src.zip /opt/relay.src.zip 29 | 30 | COPY ./docker-entrypoint.sh / 31 | ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"] 32 | CMD ["run"] 33 | 34 | -------------------------------------------------------------------------------- /artwork/relay-icon-bw-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-icon-bw-white.png -------------------------------------------------------------------------------- /artwork/relay-icon-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-icon-bw.png -------------------------------------------------------------------------------- /artwork/relay-icon-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-icon-white.png -------------------------------------------------------------------------------- /artwork/relay-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-icon.png -------------------------------------------------------------------------------- /artwork/relay-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-logo-white.png -------------------------------------------------------------------------------- /artwork/relay-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/relay-logo.png -------------------------------------------------------------------------------- /artwork/semaphore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/artwork/semaphore.jpg -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | disallowed-methods = [ 2 | { path = "tokio::spawn", reason = "use `relay_system::spawn!` instead" }, 3 | ] 4 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | targets = [ 2 | { triple = "x86_64-unknown-linux-gnu" }, 3 | { triple = "x86_64-apple-darwin" }, 4 | { triple = "x86_64-pc-windows-msvc" }, 5 | ] 6 | 7 | [advisories] 8 | db-path = "~/.cargo/advisory-db" 9 | db-url = "https://github.com/rustsec/advisory-db" 10 | vulnerability = "deny" 11 | unmaintained = "warn" 12 | yanked = "warn" 13 | notice = "warn" 14 | 15 | [licenses] 16 | unlicensed = "deny" 17 | allow = [ 18 | "MIT", 19 | "ISC", 20 | "BSD-2-Clause", 21 | "BSD-3-Clause", 22 | "CC0-1.0", 23 | "Apache-2.0", 24 | #"Apache-2.0 WITH LLVM-exception", 25 | "Unlicense", 26 | "Zlib", 27 | ] 28 | 29 | copyleft = "warn" 30 | allow-osi-fsf-free = "neither" 31 | default = "deny" 32 | 33 | exceptions = [ 34 | { allow = ["BSL-1.0"], name = "ryu", version = "*" }, 35 | { allow = ["MPL-2.0"], name = "im", version = "*" }, 36 | { allow = ["MPL-2.0"], name = "sized-chunks", version = "*" }, 37 | ] 38 | 39 | 40 | [licenses.private] 41 | ignore = true 42 | 43 | [bans] 44 | multiple-versions = "warn" 45 | highlight = "all" 46 | 47 | [sources] 48 | unknown-registry = "warn" 49 | unknown-git = "allow" 50 | allow-registry = ["https://github.com/rust-lang/crates.io-index"] 51 | allow-git = [] 52 | 53 | -------------------------------------------------------------------------------- /devservices/config/devservices-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "secret_key": "OxE6Du8quMxWj19f7YDCpIxm6XyU9nWGQJkMWFlkchA", 3 | "public_key": "SMSesqan65THCV6M4qs4kBzPai60LzuDn-xNsvYpuP8", 4 | "id": "88888888-4444-4444-8444-cccccccccccc" 5 | } 6 | -------------------------------------------------------------------------------- /devservices/config/relay.yml: -------------------------------------------------------------------------------- 1 | --- 2 | relay: 3 | upstream: "http://host.docker.internal:8001/" 4 | host: 0.0.0.0 5 | port: 7899 6 | logging: 7 | level: INFO 8 | enable_backtraces: false 9 | limits: 10 | shutdown_timeout: 0 11 | processing: 12 | enabled: true 13 | kafka_config: 14 | - { name: "bootstrap.servers", value: "kafka:9093" } 15 | # The maximum attachment chunk size is 1MB. Together with some meta data, 16 | # messages will never get larger than 2MB in total. 17 | - { name: "message.max.bytes", value: 2097176 } 18 | redis: redis://redis:6379 19 | -------------------------------------------------------------------------------- /devservices/programs.conf: -------------------------------------------------------------------------------- 1 | [program:devserver] 2 | command=cargo run 3 | autostart=false 4 | -------------------------------------------------------------------------------- /gocd/templates/bash/check-datadog-status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /devinfra/scripts/checks/datadog/monitor_status.py \ 4 | ${DATADOG_MONITOR_IDS} \ 5 | --skip-check=false 6 | -------------------------------------------------------------------------------- /gocd/templates/bash/create-sentry-relay-pop-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./relay/scripts/create-sentry-release "${GO_REVISION_RELAY_REPO}" "relay-pop" 4 | -------------------------------------------------------------------------------- /gocd/templates/bash/create-sentry-relay-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./relay/scripts/create-sentry-release "${GO_REVISION_RELAY_REPO}" "relay" 4 | -------------------------------------------------------------------------------- /gocd/templates/bash/deploy-pop-canary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | eval $(/devinfra/scripts/regions/project_env_vars.py --region="${SENTRY_REGION}") 4 | 5 | /devinfra/scripts/k8s/k8stunnel 6 | 7 | /devinfra/scripts/k8s/k8s-deploy.py \ 8 | --label-selector="service=relay-pop,env=canary" \ 9 | --image="us-central1-docker.pkg.dev/internal-sentry/relay/relay-pop:${GO_REVISION_RELAY_REPO}" \ 10 | --container-name="relay" 11 | -------------------------------------------------------------------------------- /gocd/templates/bash/deploy-pop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | eval $(/devinfra/scripts/regions/project_env_vars.py --region="${SENTRY_REGION}") 4 | 5 | /devinfra/scripts/k8s/k8stunnel 6 | 7 | /devinfra/scripts/k8s/k8s-deploy.py \ 8 | --label-selector="service=relay-pop" \ 9 | --image="us-central1-docker.pkg.dev/internal-sentry/relay/relay-pop:${GO_REVISION_RELAY_REPO}" \ 10 | --container-name="relay" 11 | -------------------------------------------------------------------------------- /gocd/templates/bash/deploy-processing-canary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | eval $(/devinfra/scripts/regions/project_env_vars.py --region="${SENTRY_REGION}") 4 | 5 | /devinfra/scripts/k8s/k8stunnel 6 | 7 | /devinfra/scripts/k8s/k8s-deploy.py \ 8 | --label-selector="service=relay,env=canary" \ 9 | --image="us-central1-docker.pkg.dev/internal-sentry/relay/relay:${GO_REVISION_RELAY_REPO}" \ 10 | --container-name="relay" 11 | -------------------------------------------------------------------------------- /gocd/templates/bash/deploy-processing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | eval $(/devinfra/scripts/regions/project_env_vars.py --region="${SENTRY_REGION}") 4 | 5 | /devinfra/scripts/k8s/k8stunnel 6 | 7 | /devinfra/scripts/k8s/k8s-deploy.py \ 8 | --label-selector="service=relay" \ 9 | --image="us-central1-docker.pkg.dev/internal-sentry/relay/relay:${GO_REVISION_RELAY_REPO}" \ 10 | --container-name="relay" 11 | -------------------------------------------------------------------------------- /gocd/templates/bash/deploy-relay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | eval $(/devinfra/scripts/regions/project_env_vars.py --region="${SENTRY_REGION}") 4 | 5 | /devinfra/scripts/k8s/k8stunnel 6 | 7 | /devinfra/scripts/k8s/k8s-deploy.py \ 8 | --label-selector="service=relay" \ 9 | --image="us-central1-docker.pkg.dev/internal-sentry/relay/relay:${GO_REVISION_RELAY_REPO}" \ 10 | --container-name="relay" 11 | -------------------------------------------------------------------------------- /gocd/templates/bash/github-check-runs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /devinfra/scripts/checks/githubactions/checkruns.py \ 4 | getsentry/relay \ 5 | "${GO_REVISION_RELAY_REPO}" \ 6 | "Integration Tests" \ 7 | "Test All Features (ubuntu-latest)" \ 8 | "Publish Relay to Internal AR (relay)" \ 9 | "Publish Relay to Internal AR (relay-pop)" \ 10 | "Upload build artifacts to gocd (relay, linux/amd64)" \ 11 | "Upload build artifacts to gocd (relay, linux/arm64)" \ 12 | "Upload build artifacts to gocd (relay-pop, linux/amd64)" \ 13 | "Upload build artifacts to gocd (relay-pop, linux/arm64)" \ 14 | -------------------------------------------------------------------------------- /gocd/templates/bash/pause-current-pipeline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gocd-pause-current-pipeline \ 4 | --pause-message="${PAUSE_MESSAGE}" 5 | -------------------------------------------------------------------------------- /gocd/templates/bash/wait-canary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Wait for 5 minutes 4 | sleep 300 5 | -------------------------------------------------------------------------------- /gocd/templates/bash/wait-soak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Wait for 5 minutes 4 | sleep 300 5 | -------------------------------------------------------------------------------- /gocd/templates/jsonnetfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": [ 4 | { 5 | "source": { 6 | "git": { 7 | "remote": "https://github.com/getsentry/gocd-jsonnet.git", 8 | "subdir": "libs" 9 | } 10 | }, 11 | "version": "v2.13.0" 12 | } 13 | ], 14 | "legacyImports": true 15 | } 16 | -------------------------------------------------------------------------------- /gocd/templates/jsonnetfile.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": [ 4 | { 5 | "source": { 6 | "git": { 7 | "remote": "https://github.com/getsentry/gocd-jsonnet.git", 8 | "subdir": "libs" 9 | } 10 | }, 11 | "version": "6ddc943ae87444b48e16995639dfe89f33a0f444", 12 | "sum": "NH9U5jQ8oCSPXLuBw27OqAaPLBUDqMGHvRLxfo84hNQ=" 13 | } 14 | ], 15 | "legacyImports": false 16 | } 17 | -------------------------------------------------------------------------------- /gocd/templates/libs/utils.libsonnet: -------------------------------------------------------------------------------- 1 | local gocdtasks = import 'github.com/getsentry/gocd-jsonnet/libs/gocd-tasks.libsonnet'; 2 | 3 | { 4 | pause_on_failure(): { 5 | plugin: { 6 | options: gocdtasks.script(importstr '../bash/pause-current-pipeline.sh'), 7 | run_if: 'failed', 8 | configuration: { 9 | id: 'script-executor', 10 | version: 1, 11 | }, 12 | }, 13 | }, 14 | github_checks(): [ 15 | { 16 | checks: { 17 | fetch_materials: true, 18 | jobs: { 19 | checks: { 20 | environment_variables: { 21 | GITHUB_TOKEN: '{{SECRET:[devinfra-github][token]}}', 22 | }, 23 | timeout: 1800, 24 | elastic_profile_id: 'relay', 25 | tasks: [ 26 | gocdtasks.script(importstr '../bash/github-check-runs.sh'), 27 | ], 28 | }, 29 | }, 30 | }, 31 | }, 32 | ], 33 | } 34 | -------------------------------------------------------------------------------- /gocd/templates/pops.jsonnet: -------------------------------------------------------------------------------- 1 | // Learn more about GoCD Pipedream here: 2 | // https://www.notion.so/sentry/Pipedreams-in-GoCD-with-Jsonnet-430f46b87fa14650a80adf6708b088d9 3 | 4 | local pops = import './pipelines/pops.libsonnet'; 5 | local pipedream = import 'github.com/getsentry/gocd-jsonnet/libs/pipedream.libsonnet'; 6 | 7 | local pipedream_config = { 8 | name: 'relay-pop', 9 | auto_deploy: false, 10 | exclude_regions: [ 11 | 'customer-1', 12 | 'customer-2', 13 | 'customer-4', 14 | ], 15 | materials: { 16 | relay_repo: { 17 | git: 'git@github.com:getsentry/relay.git', 18 | shallow_clone: true, 19 | branch: 'master', 20 | destination: 'relay', 21 | }, 22 | }, 23 | rollback: { 24 | material_name: 'relay_repo', 25 | stage: 'deploy-primary', 26 | elastic_profile_id: 'relay-pop', 27 | }, 28 | }; 29 | 30 | pipedream.render(pipedream_config, pops) 31 | -------------------------------------------------------------------------------- /gocd/templates/processing.jsonnet: -------------------------------------------------------------------------------- 1 | // Learn more about GoCD Pipedream here: 2 | // https://www.notion.so/sentry/Pipedreams-in-GoCD-with-Jsonnet-430f46b87fa14650a80adf6708b088d9 3 | 4 | local processing = import './pipelines/processing.libsonnet'; 5 | local pipedream = import 'github.com/getsentry/gocd-jsonnet/libs/pipedream.libsonnet'; 6 | 7 | local pipedream_config = { 8 | name: 'relay-processing', 9 | auto_deploy: false, 10 | materials: { 11 | relay_repo: { 12 | git: 'git@github.com:getsentry/relay.git', 13 | shallow_clone: true, 14 | branch: 'master', 15 | destination: 'relay', 16 | }, 17 | }, 18 | rollback: { 19 | material_name: 'relay_repo', 20 | stage: 'deploy-primary', 21 | elastic_profile_id: 'relay', 22 | }, 23 | }; 24 | 25 | pipedream.render(pipedream_config, processing) 26 | -------------------------------------------------------------------------------- /migrations/20230311081917_envelopes_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS envelopes ( 2 | id INTEGER PRIMARY KEY AUTOINCREMENT, 3 | received_at INTEGER, -- milliseconds since epoch 4 | own_key TEXT, 5 | sampling_key TEXT, 6 | envelope BLOB 7 | ); 8 | 9 | CREATE INDEX IF NOT EXISTS project_keys ON envelopes (own_key, sampling_key); 10 | -------------------------------------------------------------------------------- /migrations/20240724144200_change_index.sql: -------------------------------------------------------------------------------- 1 | DROP INDEX IF EXISTS project_keys; 2 | 3 | CREATE INDEX IF NOT EXISTS project_keys_received_at ON envelopes (own_key, sampling_key, received_at); 4 | -------------------------------------------------------------------------------- /migrations/20241107115400_count_column.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE envelopes 2 | ADD COLUMN count INTEGER DEFAULT 1 NOT NULL; 3 | -------------------------------------------------------------------------------- /py/.craft.yml: -------------------------------------------------------------------------------- 1 | --- 2 | minVersion: 0.34.1 3 | changelogPolicy: auto 4 | preReleaseCommand: ../scripts/bump-library.sh 5 | releaseBranchPrefix: release-library 6 | 7 | targets: 8 | - name: pypi 9 | - name: sentry-pypi 10 | internalPypiRepo: getsentry/pypi 11 | - name: gcs 12 | bucket: sentry-sdk-assets 13 | includeNames: /^sentry[_-]relay.*\.(whl|tar\.gz)$/ 14 | paths: 15 | - path: /librelay/{{version}}/ 16 | metadata: 17 | cacheControl: "public, max-age=2592000" 18 | 19 | requireNames: 20 | - /^sentry_relay-.*-py2\.py3-none-macosx_13_0_x86_64.whl$/ 21 | - /^sentry_relay-.*-py2\.py3-none-macosx_14_0_arm64.whl$/ 22 | - /^sentry_relay-.*-py2\.py3-none-.*manylinux_2_28_x86_64.*\.whl$/ 23 | - /^sentry_relay-.*-py2\.py3-none-.*manylinux_2_28_aarch64.*\.whl$/ 24 | - /^sentry-relay-.*\.tar\.gz$/ 25 | -------------------------------------------------------------------------------- /py/.gitignore: -------------------------------------------------------------------------------- 1 | # FFI 2 | sentry_relay/_lowlevel* 3 | 4 | # Wheels 5 | dist 6 | build 7 | *.egg-info 8 | .eggs 9 | 10 | # sdist 11 | version.txt 12 | rustsrc.zip 13 | MANIFEST 14 | -------------------------------------------------------------------------------- /py/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include rustsrc.zip version.txt 2 | -------------------------------------------------------------------------------- /py/README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/py/README -------------------------------------------------------------------------------- /py/manylinux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Install dependencies needed by our wheel 5 | echo "Installing packages..." 6 | yum -y -q install gcc libffi-devel 7 | 8 | export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig/ 9 | 10 | # Build wheels 11 | /opt/python/cp37-cp37m/bin/python setup.py bdist_wheel 12 | 13 | # Audit wheels 14 | for wheel in dist/*-linux_*.whl; do 15 | auditwheel repair $wheel -w dist/ 16 | rm $wheel 17 | done 18 | -------------------------------------------------------------------------------- /py/sentry_relay/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [] 2 | 3 | 4 | def _import_all(): 5 | import pkgutil 6 | 7 | glob = globals() 8 | for _, modname, _ in pkgutil.iter_modules(__path__): 9 | if modname[:1] == "_": 10 | continue 11 | mod = __import__("sentry_relay.%s" % modname, glob, glob, ["__name__"]) 12 | if not hasattr(mod, "__all__"): 13 | continue 14 | __all__.extend(mod.__all__) 15 | for name in mod.__all__: 16 | obj = getattr(mod, name) 17 | if hasattr(obj, "__module__"): 18 | obj.__module__ = "sentry_relay" 19 | glob[name] = obj 20 | 21 | 22 | _import_all() 23 | del _import_all 24 | -------------------------------------------------------------------------------- /py/sentry_relay/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/py/sentry_relay/py.typed -------------------------------------------------------------------------------- /py/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from sentry_relay._lowlevel import lib 4 | from sentry_relay.utils import rustcall 5 | from sentry_relay.exceptions import Panic 6 | 7 | 8 | def test_panic(): 9 | with pytest.raises(Panic): 10 | rustcall(lib.relay_test_panic) 11 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | exclude = ''' 3 | /( 4 | \.git 5 | | \.hg 6 | | \.mypy_cache 7 | | \.tox 8 | | \.venv 9 | | _build 10 | | buck-out 11 | | build 12 | | dist 13 | | venv 14 | | target 15 | )/ 16 | ''' 17 | 18 | [tool.mypy] 19 | exclude = ["^py/sentry_relay/_lowlevel__ffi.py"] 20 | 21 | [[tool.mypy.overrides]] 22 | module = [ 23 | "confluent_kafka.*", 24 | "msgpack.*", 25 | "pytest_localserver.*", 26 | "opentelemetry.*" 27 | ] 28 | ignore_missing_imports = true 29 | -------------------------------------------------------------------------------- /relay-auth/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-auth" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Authentication and crypto for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | build = "build.rs" 12 | 13 | [lints] 14 | workspace = true 15 | 16 | [dependencies] 17 | chrono = { workspace = true, features = ["clock"] } 18 | data-encoding = { workspace = true } 19 | ed25519-dalek = { workspace = true, features = ["rand_core"] } 20 | hmac = { workspace = true } 21 | rand = { workspace = true } 22 | relay-common = { workspace = true } 23 | serde = { workspace = true } 24 | serde_json = { workspace = true } 25 | sha2 = { workspace = true } 26 | thiserror = { workspace = true } 27 | uuid = { workspace = true } 28 | -------------------------------------------------------------------------------- /relay-auth/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::Write; 4 | use std::path::Path; 5 | 6 | fn main() { 7 | let out_dir = env::var("OUT_DIR").unwrap(); 8 | let dest_path = Path::new(&out_dir).join("constants.gen.rs"); 9 | let mut f = File::create(dest_path).unwrap(); 10 | 11 | macro_rules! write_version { 12 | ($component:literal) => {{ 13 | let value = env::var(concat!("CARGO_PKG_VERSION_", $component)).unwrap(); 14 | writeln!(f, "#[allow(missing_docs)]").unwrap(); 15 | writeln!(f, "pub const VERSION_{}: u8 = {value};", $component).unwrap(); 16 | }}; 17 | } 18 | 19 | write_version!("MAJOR"); 20 | write_version!("MINOR"); 21 | write_version!("PATCH"); 22 | 23 | println!("cargo:rerun-if-changed=build.rs\n"); 24 | println!("cargo:rerun-if-changed=Cargo.toml\n"); 25 | } 26 | -------------------------------------------------------------------------------- /relay-base-schema/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-base-schema" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Basic types for Relay's API schema used across multiple services" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | regex = { workspace = true } 17 | relay-common = { workspace = true } 18 | relay-protocol = { workspace = true } 19 | serde = { workspace = true } 20 | 21 | [dev-dependencies] 22 | serde_json = { workspace = true } 23 | 24 | [features] 25 | default = [] 26 | -------------------------------------------------------------------------------- /relay-base-schema/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Basic types for Relay's API schema used across multiple services. 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | 9 | pub mod data_category; 10 | pub mod events; 11 | pub mod metrics; 12 | pub mod organization; 13 | pub mod project; 14 | pub mod spans; 15 | -------------------------------------------------------------------------------- /relay-cabi/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /relay-cabi/Makefile: -------------------------------------------------------------------------------- 1 | all: header release 2 | .PHONY: all 3 | 4 | header: include/relay.h 5 | .PHONY: header 6 | 7 | release: 8 | cargo build --release 9 | .PHONY: release 10 | 11 | clean: 12 | cargo clean 13 | .PHONY: clean 14 | 15 | include/relay.h: *.toml src/*.rs 16 | @touch src/lib.rs # Ensure that rustc outputs something 17 | cbindgen -c cbindgen.toml . -o $@ 18 | @touch include/relay.h # Ensure that we don't build again 19 | 20 | .PHONY: include/relay.h 21 | -------------------------------------------------------------------------------- /relay-cabi/cbindgen.toml: -------------------------------------------------------------------------------- 1 | header = "/* C bindings to the sentry relay library */" 2 | include_guard = "RELAY_H_INCLUDED" 3 | autogen_warning = "/* Warning, this file is autogenerated. Do not modify this manually. */" 4 | include_version = true 5 | line_length = 80 6 | tab_width = 2 7 | language = "C" 8 | 9 | [parse] 10 | include = ["relay-base-schema"] 11 | parse_deps = true 12 | 13 | [enum] 14 | rename_variants = "ScreamingSnakeCase" 15 | prefix_with_name = true 16 | 17 | [export] 18 | include = ["SpanStatus"] 19 | 20 | [export.rename] 21 | "DataCategory" = "RelayDataCategory" 22 | "SpanStatus" = "RelaySpanStatus" 23 | -------------------------------------------------------------------------------- /relay-cabi/src/constants.rs: -------------------------------------------------------------------------------- 1 | pub use relay_base_schema::data_category::DataCategory; 2 | pub use relay_base_schema::events::EventType; 3 | pub use relay_base_schema::spans::SpanStatus; 4 | 5 | use crate::core::RelayStr; 6 | 7 | /// Returns the API name of the given `DataCategory`. 8 | #[unsafe(no_mangle)] 9 | #[relay_ffi::catch_unwind] 10 | pub unsafe extern "C" fn relay_data_category_name(category: DataCategory) -> RelayStr { 11 | RelayStr::new(category.name()) 12 | } 13 | 14 | /// Parses a `DataCategory` from its API name. 15 | #[unsafe(no_mangle)] 16 | #[relay_ffi::catch_unwind] 17 | pub unsafe extern "C" fn relay_data_category_parse(name: *const RelayStr) -> DataCategory { 18 | unsafe { (*name).as_str() } 19 | .parse() 20 | .unwrap_or(DataCategory::Unknown) 21 | } 22 | 23 | /// Parses a `DataCategory` from an event type. 24 | #[unsafe(no_mangle)] 25 | #[relay_ffi::catch_unwind] 26 | pub unsafe extern "C" fn relay_data_category_from_event_type( 27 | event_type: *const RelayStr, 28 | ) -> DataCategory { 29 | unsafe { (*event_type).as_str() } 30 | .parse::<EventType>() 31 | .unwrap_or_default() 32 | .into() 33 | } 34 | -------------------------------------------------------------------------------- /relay-cardinality/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-cardinality" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Metrics Cardinality Limiter" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE" 10 | publish = false 11 | autobenches = false 12 | 13 | [features] 14 | default = [] 15 | redis = ["relay-redis/impl"] 16 | 17 | [lints] 18 | workspace = true 19 | 20 | [dependencies] 21 | async-trait = { workspace = true } 22 | hash32 = { workspace = true } 23 | hashbrown = { workspace = true } 24 | parking_lot = { workspace = true } 25 | relay-base-schema = { workspace = true } 26 | relay-common = { workspace = true } 27 | relay-log = { workspace = true } 28 | relay-redis = { workspace = true } 29 | relay-statsd = { workspace = true } 30 | serde = { workspace = true } 31 | thiserror = { workspace = true } 32 | tokio = { workspace = true, features = ["sync"] } 33 | 34 | [dev-dependencies] 35 | criterion = { workspace = true } 36 | serde_json = { workspace = true } 37 | uuid = { workspace = true } 38 | tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } 39 | 40 | [[bench]] 41 | name = "redis" 42 | harness = false 43 | -------------------------------------------------------------------------------- /relay-cardinality/benches/redis.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "redis")] 2 | mod redis_impl; 3 | 4 | #[cfg(feature = "redis")] 5 | use redis_impl::*; 6 | 7 | #[cfg(feature = "redis")] 8 | criterion::criterion_group!( 9 | benches, 10 | bench_simple, 11 | bench_big_set_small_queries, 12 | bench_high_cardinality, 13 | bench_cache_never_full, 14 | bench_cache_worst_case, 15 | ); 16 | #[cfg(feature = "redis")] 17 | criterion::criterion_main!(benches); 18 | 19 | #[cfg(not(feature = "redis"))] 20 | fn main() {} 21 | -------------------------------------------------------------------------------- /relay-cardinality/src/error.rs: -------------------------------------------------------------------------------- 1 | use relay_redis::RedisError; 2 | 3 | /// Result type for the cardinality module, using [`Error`] as the default error type. 4 | pub type Result<T, E = Error> = std::result::Result<T, E>; 5 | 6 | /// Error for the cardinality module. 7 | #[derive(Debug, thiserror::Error)] 8 | pub enum Error { 9 | /// Something went wrong with Redis. 10 | #[error("failed to talk to redis: {0}")] 11 | RedisError(#[from] RedisError), 12 | } 13 | -------------------------------------------------------------------------------- /relay-cardinality/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Relay Cardinality Module 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | 9 | mod config; 10 | mod error; 11 | pub mod limiter; 12 | #[cfg(feature = "redis")] 13 | mod redis; 14 | mod statsd; 15 | mod window; 16 | 17 | pub use self::config::*; 18 | pub use self::error::*; 19 | pub use self::limiter::{ 20 | CardinalityItem, CardinalityLimits, CardinalityLimitsSplit, CardinalityReport, Scoping, 21 | }; 22 | #[cfg(feature = "redis")] 23 | pub use self::redis::{RedisSetLimiter, RedisSetLimiterOptions}; 24 | pub use self::window::SlidingWindow; 25 | 26 | /// Redis Set based cardinality limiter. 27 | #[cfg(feature = "redis")] 28 | pub type CardinalityLimiter = self::limiter::CardinalityLimiter<RedisSetLimiter>; 29 | -------------------------------------------------------------------------------- /relay-cardinality/src/redis/mod.rs: -------------------------------------------------------------------------------- 1 | mod cache; 2 | mod limiter; 3 | mod quota; 4 | mod script; 5 | mod state; 6 | 7 | pub use self::limiter::{RedisSetLimiter, RedisSetLimiterOptions}; 8 | 9 | /// Key prefix used for Redis keys. 10 | const KEY_PREFIX: &str = "relay:cardinality"; 11 | /// Redis key version. 12 | /// 13 | /// The version is embedded in the key as a static segment, increment the version whenever there are 14 | /// breaking changes made to the keys or storage format in Redis. 15 | const KEY_VERSION: u32 = 1; 16 | -------------------------------------------------------------------------------- /relay-cogs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-cogs" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Break down the cost of Relay by its features" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE" 10 | publish = false 11 | autobenches = false 12 | 13 | [lints] 14 | workspace = true 15 | 16 | [dev-dependencies] 17 | insta = { workspace = true } 18 | -------------------------------------------------------------------------------- /relay-cogs/src/recorder.rs: -------------------------------------------------------------------------------- 1 | use crate::CogsMeasurement; 2 | 3 | /// Cogs recorder, recording actual measurements. 4 | pub trait CogsRecorder: Send + Sync { 5 | /// Record a single COGS measurement. 6 | fn record(&self, measurement: CogsMeasurement); 7 | } 8 | 9 | /// A recorder which discards all measurements. 10 | #[derive(Debug)] 11 | pub struct NoopRecorder; 12 | 13 | impl CogsRecorder for NoopRecorder { 14 | fn record(&self, _: CogsMeasurement) {} 15 | } 16 | -------------------------------------------------------------------------------- /relay-cogs/src/test.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex, PoisonError}; 2 | 3 | use crate::{CogsMeasurement, CogsRecorder}; 4 | 5 | /// A [`CogsRecorder`] for testing which allows access to all recorded measurements. 6 | #[derive(Clone, Default)] 7 | pub struct TestRecorder(Arc<Mutex<Vec<CogsMeasurement>>>); 8 | 9 | impl TestRecorder { 10 | /// Returns the recorded measurements. 11 | pub fn measurements(&self) -> Vec<CogsMeasurement> { 12 | let inner = self.0.lock().unwrap_or_else(PoisonError::into_inner); 13 | inner.clone() 14 | } 15 | } 16 | 17 | impl CogsRecorder for TestRecorder { 18 | fn record(&self, measurement: CogsMeasurement) { 19 | let mut inner = self.0.lock().unwrap_or_else(PoisonError::into_inner); 20 | inner.push(measurement); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /relay-cogs/src/time.rs: -------------------------------------------------------------------------------- 1 | pub use std::time::Duration; 2 | 3 | #[cfg(not(test))] 4 | pub use self::real::*; 5 | #[cfg(test)] 6 | pub use self::test::*; 7 | 8 | #[cfg(not(test))] 9 | mod real { 10 | pub use std::time::Instant; 11 | } 12 | 13 | #[cfg(test)] 14 | mod test { 15 | use std::sync::atomic::{AtomicU64, Ordering}; 16 | use std::time::Duration; 17 | 18 | std::thread_local! { 19 | static NOW: AtomicU64 = const { AtomicU64::new(0) }; 20 | } 21 | 22 | fn now() -> u64 { 23 | NOW.with(|now| now.load(Ordering::Relaxed)) 24 | } 25 | 26 | pub fn advance_millis(time: u64) { 27 | NOW.with(|now| now.fetch_add(time, Ordering::Relaxed)); 28 | } 29 | 30 | pub struct Instant(u64); 31 | 32 | impl Instant { 33 | pub fn now() -> Self { 34 | Self(now()) 35 | } 36 | 37 | pub fn elapsed(&self) -> Duration { 38 | match now() - self.0 { 39 | 0 => Duration::from_nanos(100), 40 | v => Duration::from_millis(v), 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /relay-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-common" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Common utilities and crate re-exports for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | chrono = { workspace = true } 17 | once_cell = { workspace = true } 18 | regex-lite = { workspace = true } 19 | relay-pattern = { workspace = true } 20 | sentry-types = { workspace = true } 21 | serde = { workspace = true } 22 | 23 | [dev-dependencies] 24 | serde_test = { workspace = true } 25 | criterion = { workspace = true } 26 | -------------------------------------------------------------------------------- /relay-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Common functionality for the sentry relay. 2 | #![warn(missing_docs)] 3 | #![doc( 4 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 5 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 6 | )] 7 | #![allow(clippy::derive_partial_eq_without_eq)] 8 | 9 | mod macros; 10 | 11 | pub mod glob2; 12 | pub mod time; 13 | 14 | pub use sentry_types::{Auth, Dsn, ParseAuthError, ParseDsnError, Scheme}; 15 | -------------------------------------------------------------------------------- /relay-config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-config" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Configuration for the Relay CLI and server" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [features] 13 | default = [] 14 | processing = [] 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | anyhow = { workspace = true } 21 | human-size = { workspace = true } 22 | num_cpus = { workspace = true } 23 | relay-auth = { workspace = true } 24 | relay-common = { workspace = true } 25 | relay-kafka = { workspace = true } 26 | relay-log = { workspace = true, features = ["init"] } 27 | relay-metrics = { workspace = true } 28 | relay-redis = { workspace = true } 29 | serde = { workspace = true } 30 | serde-vars = { workspace = true } 31 | serde_json = { workspace = true } 32 | serde_yaml = { workspace = true } 33 | thiserror = { workspace = true } 34 | url = { workspace = true } 35 | uuid = { workspace = true } 36 | 37 | [dev-dependencies] 38 | insta = { workspace = true } 39 | -------------------------------------------------------------------------------- /relay-config/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Configuration for the Relay CLI and server. 2 | #![warn(missing_docs)] 3 | #![doc( 4 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 5 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 6 | )] 7 | #![allow(clippy::derive_partial_eq_without_eq)] 8 | 9 | pub mod aggregator; 10 | mod byte_size; 11 | mod config; 12 | mod redis; 13 | mod upstream; 14 | 15 | pub use crate::aggregator::{AggregatorServiceConfig, ScopedAggregatorConfig}; 16 | pub use crate::byte_size::*; 17 | pub use crate::config::*; 18 | pub use crate::redis::*; 19 | pub use crate::upstream::*; 20 | -------------------------------------------------------------------------------- /relay-crash/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-crash" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Native crash reporting for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | build = "build.rs" 10 | license-file = "../LICENSE.md" 11 | publish = false 12 | 13 | [lints] 14 | workspace = true 15 | 16 | [dependencies] 17 | 18 | [build-dependencies] 19 | bindgen = { workspace = true } 20 | cmake = { workspace = true } 21 | -------------------------------------------------------------------------------- /relay-dynamic-config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-dynamic-config" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Dynamic configuration passed down from sentry" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [features] 13 | default = [] 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [dependencies] 19 | anyhow = { workspace = true } 20 | relay-auth = { workspace = true } 21 | relay-base-schema = { workspace = true } 22 | relay-cardinality = { workspace = true } 23 | relay-common = { workspace = true } 24 | relay-event-normalization = { workspace = true } 25 | relay-filter = { workspace = true } 26 | relay-log = { workspace = true } 27 | relay-pattern = { workspace = true } 28 | relay-pii = { workspace = true } 29 | relay-protocol = { workspace = true } 30 | relay-quotas = { workspace = true } 31 | relay-sampling = { workspace = true } 32 | serde = { workspace = true } 33 | serde_json = { workspace = true } 34 | url = { workspace = true } 35 | 36 | [dev-dependencies] 37 | similar-asserts = { workspace = true } 38 | -------------------------------------------------------------------------------- /relay-dynamic-config/src/utils.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Normalizes the given value by deserializing it and serializing it back. 4 | pub fn normalize_json<'de, S>(value: &'de str) -> anyhow::Result<String> 5 | where 6 | S: Serialize + Deserialize<'de>, 7 | { 8 | let deserialized: S = serde_json::from_str(value)?; 9 | let serialized = serde_json::to_value(&deserialized)?.to_string(); 10 | Ok(serialized) 11 | } 12 | -------------------------------------------------------------------------------- /relay-event-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-event-derive" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Derive for visitor traits on the Event schema" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | quote = { workspace = true } 17 | syn = { workspace = true } 18 | synstructure = { workspace = true } 19 | proc-macro2 = { workspace = true } 20 | 21 | [lib] 22 | proc-macro = true 23 | -------------------------------------------------------------------------------- /relay-event-derive/src/utils.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::ToTokens; 3 | use synstructure::{Structure, VariantInfo}; 4 | 5 | pub trait SynstructureExt { 6 | fn try_each_variant<F, R>(&self, f: F) -> syn::Result<TokenStream> 7 | where 8 | F: FnMut(&VariantInfo<'_>) -> syn::Result<R>, 9 | R: ToTokens; 10 | } 11 | 12 | impl SynstructureExt for Structure<'_> { 13 | fn try_each_variant<F, R>(&self, mut f: F) -> syn::Result<TokenStream> 14 | where 15 | F: FnMut(&VariantInfo<'_>) -> syn::Result<R>, 16 | R: ToTokens, 17 | { 18 | let mut t = TokenStream::new(); 19 | for variant in self.variants() { 20 | let pat = variant.pat(); 21 | let body = f(variant)?; 22 | quote::quote!(#pat => { #body }).to_tokens(&mut t); 23 | } 24 | if self.omitted_variants() { 25 | quote::quote!(_ => {}).to_tokens(&mut t); 26 | } 27 | Ok(t) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_empty.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "", 10 | "platform": "java" 11 | } 12 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_exact_length.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "this_is-exactly-the_max_len.012345678901234567890123456789012345", 10 | "platform": "java" 11 | } 12 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_short_no_trimming.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "my.short-logger.isnt_trimmed", 10 | "platform": "java" 11 | } 12 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_too_long_single_word.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "*is-way_too_long-and_we_only_have_one_word-so_we_cant_smart_trim", 10 | "platform": "java", 11 | "_meta": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@logger:replace", 16 | "s", 17 | 0, 18 | 5 19 | ] 20 | ], 21 | "len": 68 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_trimmed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "", 10 | "platform": "java", 11 | "_meta": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@logger:remove", 16 | "x", 17 | 0, 18 | 8 19 | ] 20 | ], 21 | "len": 8 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_word_leading_dots.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "*this-tests-the-smart-trimming-and-word-removal-around-dot.words", 10 | "platform": "java", 11 | "_meta": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@logger:replace", 16 | "s", 17 | 0, 18 | 3 19 | ] 20 | ], 21 | "len": 66 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_word_trimmed_at_max.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "*.in.this_part-is-kept.this_right_here-is_an-extremely_long_word", 10 | "platform": "java", 11 | "_meta": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@logger:replace", 16 | "s", 17 | 0, 18 | 15 19 | ] 20 | ], 21 | "len": 78 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/snapshots/relay_event_normalization__normalize__tests__normalize_logger_word_trimmed_before_max.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/store/normalize.rs 3 | expression: event 4 | --- 5 | { 6 | "event_id": "7637af36578e4e4592692e28a1d6e2ca", 7 | "level": "error", 8 | "type": "default", 9 | "logger": "*.this_part-is-kept.this_right_here-is_a-very_long_word", 10 | "platform": "java", 11 | "_meta": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@logger:replace", 16 | "s", 17 | 0, 18 | 33 19 | ] 20 | ], 21 | "len": 87 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/span/mod.rs: -------------------------------------------------------------------------------- 1 | //! Span normalization logic. 2 | 3 | use once_cell::sync::Lazy; 4 | use regex::Regex; 5 | 6 | pub mod ai; 7 | pub mod country_subregion; 8 | pub mod description; 9 | pub mod exclusive_time; 10 | pub mod reparent_broken_spans; 11 | pub mod tag_extraction; 12 | 13 | /// Regex used to scrub hex IDs and multi-digit numbers from table names and other identifiers. 14 | pub static TABLE_NAME_REGEX: Lazy<Regex> = Lazy::new(|| { 15 | Regex::new( 16 | r"(?ix) 17 | [0-9a-f]{8}_[0-9a-f]{4}_[0-9a-f]{4}_[0-9a-f]{4}_[0-9a-f]{12} | 18 | [0-9a-f]{8,} | 19 | \d\d+ 20 | ", 21 | ) 22 | .unwrap() 23 | }); 24 | -------------------------------------------------------------------------------- /relay-event-normalization/src/normalize/span/snapshots/relay_event_normalization__normalize__span__tag_extraction__tests__extracts_searchable_contexts_into_segment_span.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-event-normalization/src/normalize/span/tag_extraction.rs 3 | expression: segment_span.to_json_pretty().unwrap() 4 | --- 5 | { 6 | "timestamp": 1619420400.0, 7 | "start_timestamp": 1619420341.0, 8 | "span_id": "bd429c44b67a3eb4", 9 | "trace_id": "ff62a8b040f340bda5d830223def1d81", 10 | "segment_id": "bd429c44b67a3eb4", 11 | "is_segment": true, 12 | "is_remote": true, 13 | "description": "foo", 14 | "data": { 15 | "browser.name": "Chrome", 16 | "sentry.segment.name": "foo" 17 | }, 18 | "sentry_tags": { 19 | "device.family": "K", 20 | "app.device": "3e06efaccaec678afef02f3fc2b5289ee5f613d5", 21 | "device.model": "Generic_Android", 22 | "runtime": "CPython 3.13.1", 23 | "runtime.name": "CPython", 24 | "browser": "Chrome 134", 25 | "request.url": "http://us.sentry.io/api/0/organizations/", 26 | "request.method": "GET" 27 | }, 28 | "platform": "javascript", 29 | "was_transaction": true 30 | } 31 | -------------------------------------------------------------------------------- /relay-event-normalization/src/statsd.rs: -------------------------------------------------------------------------------- 1 | use relay_statsd::TimerMetric; 2 | 3 | pub enum Timers { 4 | /// Measures how log normalization of SQL queries in span description take. 5 | /// 6 | /// This metric is tagged with: 7 | /// - `mode`: The method used for normalization (either `parser` or `regex`). 8 | SpanDescriptionNormalizeSQL, 9 | } 10 | 11 | impl TimerMetric for Timers { 12 | fn name(&self) -> &'static str { 13 | match *self { 14 | Self::SpanDescriptionNormalizeSQL => "normalize.span.description.sql", 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /relay-event-normalization/src/transactions/mod.rs: -------------------------------------------------------------------------------- 1 | mod processor; 2 | mod rules; 3 | 4 | pub use processor::*; 5 | pub use rules::*; 6 | -------------------------------------------------------------------------------- /relay-event-normalization/tests/fixtures/GeoIP2-Enterprise-Test.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/relay-event-normalization/tests/fixtures/GeoIP2-Enterprise-Test.mmdb -------------------------------------------------------------------------------- /relay-event-normalization/tests/fixtures/README: -------------------------------------------------------------------------------- 1 | GeoIP2-Enterprise-Test.mmdb 2 | =========================== 3 | 4 | Obtained from: 5 | https://github.com/maxmind/MaxMind-DB/blob/6e99232bb6a70d5169ecc96ed0614a52017ff654/test-data/GeoIP2-Enterprise-Test.mmdb 6 | 7 | Source: 8 | https://github.com/maxmind/MaxMind-DB/blob/6e99232bb6a70d5169ecc96ed0614a52017ff654/source-data/GeoIP2-Enterprise-Test.json 9 | 10 | README: 11 | The Enterprise file was a single example IP address, modified slightly to 12 | include all fields. It now has more than that. 13 | 14 | LICENSE: 15 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 16 | Unported License. To view a copy of this license, visit 17 | http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative 18 | Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. 19 | -------------------------------------------------------------------------------- /relay-event-schema/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Event schema (Error, Transaction, Security) and types for event processing. 2 | 3 | #![doc( 4 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 5 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 6 | )] 7 | 8 | pub mod processor; 9 | pub mod protocol; 10 | -------------------------------------------------------------------------------- /relay-event-schema/src/processor/mod.rs: -------------------------------------------------------------------------------- 1 | //! Provides support for processing structures. 2 | 3 | mod attrs; 4 | mod chunks; 5 | mod funcs; 6 | mod impls; 7 | mod traits; 8 | 9 | pub use self::attrs::*; 10 | pub use self::chunks::*; 11 | pub use self::funcs::*; 12 | pub use self::traits::*; 13 | -------------------------------------------------------------------------------- /relay-event-schema/src/protocol/base.rs: -------------------------------------------------------------------------------- 1 | use crate::processor::ProcessValue; 2 | 3 | impl ProcessValue for relay_base_schema::events::EventType {} 4 | impl ProcessValue for relay_base_schema::metrics::MetricUnit {} 5 | impl ProcessValue for relay_base_schema::spans::SpanStatus {} 6 | -------------------------------------------------------------------------------- /relay-event-schema/src/protocol/constants.rs: -------------------------------------------------------------------------------- 1 | /// A list of all valid [`platform`](super::Event::platform) identifiers. 2 | pub const VALID_PLATFORMS: &[&str] = &[ 3 | "as3", 4 | "c", 5 | "cfml", 6 | "cocoa", 7 | "csharp", 8 | "elixir", 9 | "go", 10 | "groovy", 11 | "haskell", 12 | "java", 13 | "javascript", 14 | "native", 15 | "node", 16 | "objc", 17 | "other", 18 | "perl", 19 | "php", 20 | "python", 21 | "ruby", 22 | ]; 23 | 24 | /// The latest version of the protocol. 25 | pub const PROTOCOL_VERSION: u16 = 7; 26 | -------------------------------------------------------------------------------- /relay-event-schema/src/protocol/relay_info.rs: -------------------------------------------------------------------------------- 1 | use relay_protocol::{Annotated, Empty, FromValue, IntoValue, Object, Value}; 2 | 3 | use crate::processor::ProcessValue; 4 | 5 | /// The Relay Interface describes a Sentry Relay and its configuration used to process an event during ingest. 6 | #[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)] 7 | pub struct RelayInfo { 8 | /// Version of the Relay. Required. 9 | #[metastructure(required = true, max_chars = 256, max_chars_allowance = 20)] 10 | pub version: Annotated<String>, 11 | 12 | /// Public key of the Relay. 13 | #[metastructure(required = false, max_chars = 256, max_chars_allowance = 20)] 14 | pub public_key: Annotated<String>, 15 | 16 | /// Additional arbitrary fields for forwards compatibility. 17 | #[metastructure(additional_properties)] 18 | pub other: Object<Value>, 19 | } 20 | -------------------------------------------------------------------------------- /relay-event-schema/src/protocol/utils.rs: -------------------------------------------------------------------------------- 1 | use serde::de::DeserializeOwned; 2 | use serde::{Deserialize, Deserializer}; 3 | 4 | /// Returns the default value for a type if the provided value is `null`. 5 | pub fn null_to_default<'de, D, V>(deserializer: D) -> Result<V, D::Error> 6 | where 7 | D: Deserializer<'de>, 8 | V: Default + DeserializeOwned, 9 | { 10 | let opt = Option::deserialize(deserializer)?; 11 | Ok(opt.unwrap_or_default()) 12 | } 13 | -------------------------------------------------------------------------------- /relay-ffi-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-ffi-macros" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Macros for error handling in FFI bindings" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [dependencies] 19 | syn = { workspace = true, features = ["fold", "full"] } 20 | quote = { workspace = true } 21 | -------------------------------------------------------------------------------- /relay-ffi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-ffi" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Utilities for error handling in FFI bindings" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | anyhow = { workspace = true } 17 | relay-ffi-macros = { workspace = true } 18 | -------------------------------------------------------------------------------- /relay-ffi/tests/test_macro.rs: -------------------------------------------------------------------------------- 1 | use relay_ffi::with_last_error; 2 | 3 | #[relay_ffi::catch_unwind] 4 | unsafe fn returns_unit() {} 5 | 6 | #[relay_ffi::catch_unwind] 7 | unsafe fn returns_int() -> i32 { 8 | "42".parse()? 9 | } 10 | 11 | #[relay_ffi::catch_unwind] 12 | unsafe fn returns_error() -> i32 { 13 | "invalid".parse()? 14 | } 15 | 16 | #[relay_ffi::catch_unwind] 17 | #[allow(clippy::diverging_sub_expression)] 18 | unsafe fn panics() { 19 | panic!("this is fine"); 20 | } 21 | 22 | #[test] 23 | fn test_unit() { 24 | unsafe { returns_unit() } 25 | assert!(with_last_error(|_| ()).is_none()) 26 | } 27 | 28 | #[test] 29 | fn test_ok() { 30 | unsafe { returns_int() }; 31 | assert!(with_last_error(|_| ()).is_none()) 32 | } 33 | 34 | #[test] 35 | fn test_error() { 36 | unsafe { returns_error() }; 37 | assert_eq!( 38 | with_last_error(|e| e.to_string()).as_deref(), 39 | Some("invalid digit found in string") 40 | ) 41 | } 42 | 43 | #[test] 44 | fn test_panics() { 45 | relay_ffi::set_panic_hook(); 46 | 47 | unsafe { panics() }; 48 | 49 | let last_error = with_last_error(|e| e.to_string()).expect("returned error"); 50 | assert!(last_error.starts_with("panic: thread \'test_panics\' panicked with \'this is fine\'")); 51 | } 52 | -------------------------------------------------------------------------------- /relay-filter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-filter" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Inbound data filters for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | ipnetwork = { workspace = true } 17 | once_cell = { workspace = true } 18 | indexmap = { workspace = true } 19 | regex = { workspace = true } 20 | relay-common = { workspace = true } 21 | relay-pattern = { workspace = true } 22 | relay-event-schema = { workspace = true } 23 | relay-protocol = { workspace = true } 24 | relay-ua = { workspace = true } 25 | serde = { workspace = true } 26 | url = { workspace = true } 27 | 28 | [dev-dependencies] 29 | insta = { workspace = true } 30 | serde_json = { workspace = true } 31 | -------------------------------------------------------------------------------- /relay-filter/src/testutils.rs: -------------------------------------------------------------------------------- 1 | //! Utilities used by the event filter tests. 2 | 3 | use relay_event_schema::protocol::{Event, Headers, Request}; 4 | use relay_protocol::Annotated; 5 | 6 | /// Creates an Event with the specified user agent. 7 | pub fn get_event_with_user_agent(user_agent: &str) -> Event { 8 | let headers = vec![Annotated::new(( 9 | Annotated::new("UsEr-AgeNT".to_string().into()), 10 | Annotated::new(user_agent.to_string().into()), 11 | ))]; 12 | 13 | Event { 14 | request: Annotated::new(Request { 15 | headers: Annotated::new(Headers(headers.into())), 16 | ..Request::default() 17 | }), 18 | ..Event::default() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /relay-log/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-log" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Error reporting and logging for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | build = "build.rs" 12 | 13 | [lints] 14 | workspace = true 15 | 16 | [dependencies] 17 | console = { workspace = true, optional = true } 18 | relay-common = { workspace = true } 19 | relay-crash = { workspace = true, optional = true } 20 | sentry = { workspace = true, features = [ 21 | "debug-images", 22 | "tracing", 23 | ], optional = true } 24 | sentry-core = { workspace = true } 25 | serde = { workspace = true, optional = true } 26 | tracing = { workspace = true } 27 | tracing-subscriber = { workspace = true, features = [ 28 | "env-filter", 29 | "json", 30 | "time", 31 | ], optional = true } 32 | 33 | [features] 34 | default = [] 35 | test = ["dep:tracing-subscriber"] 36 | init = ["dep:console", "dep:sentry", "dep:serde", "dep:tracing-subscriber"] 37 | crash-handler = ["init", "dep:relay-crash"] 38 | sentry = ["dep:sentry"] 39 | -------------------------------------------------------------------------------- /relay-log/src/test.rs: -------------------------------------------------------------------------------- 1 | use tracing_subscriber::EnvFilter; 2 | 3 | // Import CRATE_NAMES, which lists all crates in the workspace. 4 | include!(concat!(env!("OUT_DIR"), "/constants.gen.rs")); 5 | 6 | #[doc(hidden)] 7 | pub fn __init_test() { 8 | let mut env_filter = EnvFilter::new("ERROR"); 9 | 10 | // Add all internal modules with maximum log-level. 11 | for name in CRATE_NAMES { 12 | env_filter = env_filter.add_directive(format!("{name}=TRACE").parse().unwrap()); 13 | } 14 | 15 | tracing_subscriber::fmt::fmt() 16 | .with_env_filter(env_filter) 17 | .with_target(true) 18 | .with_test_writer() 19 | .compact() 20 | .try_init() 21 | .ok(); 22 | } 23 | 24 | /// Initialize the logger for testing. 25 | /// 26 | /// This logs to the stdout registered by the Rust test runner, and only captures logs from the 27 | /// calling crate. 28 | /// 29 | /// # Example 30 | /// 31 | /// ``` 32 | /// relay_log::init_test!(); 33 | /// ``` 34 | #[macro_export] 35 | macro_rules! init_test { 36 | () => { 37 | $crate::__init_test(); 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /relay-metrics/tests/fixtures/buckets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "timestamp": 1615889440, 4 | "width": 0, 5 | "name": "d:custom/endpoint.response_time@millisecond", 6 | "type": "d", 7 | "value": [ 8 | 36.0, 9 | 49.0, 10 | 57.0, 11 | 68.0 12 | ], 13 | "tags": { 14 | "route": "user_index" 15 | } 16 | }, 17 | { 18 | "timestamp": 1615889440, 19 | "width": 0, 20 | "name": "c:custom/endpoint.hits@none", 21 | "type": "c", 22 | "value": 4.0, 23 | "tags": { 24 | "route": "user_index" 25 | } 26 | }, 27 | { 28 | "timestamp": 1615889440, 29 | "width": 0, 30 | "name": "g:custom/endpoint.parallel_requests@none", 31 | "type": "g", 32 | "value": { 33 | "last": 25.0, 34 | "min": 17.0, 35 | "max": 42.0, 36 | "sum": 220.0, 37 | "count": 85 38 | }, 39 | "tags": { 40 | "route": "user_index" 41 | } 42 | }, 43 | { 44 | "timestamp": 1615889440, 45 | "width": 0, 46 | "name": "s:custom/endpoint.users@none", 47 | "type": "s", 48 | "value": [ 49 | 3182887624, 50 | 4267882815 51 | ], 52 | "tags": { 53 | "route": "user_index" 54 | } 55 | } 56 | ] 57 | -------------------------------------------------------------------------------- /relay-metrics/tests/fixtures/buckets.statsd.txt: -------------------------------------------------------------------------------- 1 | endpoint.response_time@millisecond:36:49:57:68|d|#route:user_index|T1615889440 2 | endpoint.hits:4|c|#route:user_index|T1615889440 3 | endpoint.parallel_requests:25:17:42:220:85|g|#route:user_index|T1615889440 4 | endpoint.users:3182887624:4267882815|s|#route:user_index|T1615889440 5 | -------------------------------------------------------------------------------- /relay-metrics/tests/fixtures/kafka.json: -------------------------------------------------------------------------------- 1 | { 2 | "org_id": 1, 3 | "project_id": 42, 4 | "name": "endpoint.response_time", 5 | "unit": "millisecond", 6 | "value": [ 7 | 36.0, 8 | 49.0, 9 | 57.0, 10 | 68.0 11 | ], 12 | "type": "d", 13 | "timestamp": 1615889440, 14 | "tags": { 15 | "route": "user_index" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /relay-metrics/tests/fixtures/set.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "s:custom/endpoint.users@none", 3 | "width": 0, 4 | "timestamp": 1615889449, 5 | "value": [4267882815], 6 | "type": "s" 7 | } 8 | -------------------------------------------------------------------------------- /relay-metrics/tests/fixtures/set.statsd.txt: -------------------------------------------------------------------------------- 1 | endpoint.users:e2546e4c-ecd0-43ad-ae27-87960e57a658|s 2 | -------------------------------------------------------------------------------- /relay-monitors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-monitors" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Monitors processing for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | relay-base-schema = { workspace = true } 17 | relay-event-schema = { workspace = true } 18 | serde = { workspace = true } 19 | serde_json = { workspace = true } 20 | thiserror = { workspace = true } 21 | uuid = { workspace = true, features = ["v5"] } 22 | 23 | [dev-dependencies] 24 | similar-asserts = { workspace = true } 25 | -------------------------------------------------------------------------------- /relay-ourlogs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-ourlogs" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Log normalization and processing" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | chrono = { workspace = true } 17 | hex = { workspace = true } 18 | once_cell = { workspace = true } 19 | opentelemetry-proto = { workspace = true, features = [ 20 | "gen-tonic", 21 | "with-serde", 22 | "logs", 23 | ] } 24 | relay-event-schema = { workspace = true } 25 | relay-protocol = { workspace = true } 26 | relay-common = { workspace = true } 27 | serde_json = { workspace = true } 28 | 29 | [dev-dependencies] 30 | insta = { workspace = true } 31 | -------------------------------------------------------------------------------- /relay-ourlogs/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Structs and functions needed to ingest OpenTelemetry logs. 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | 9 | pub use crate::ourlog::otel_to_sentry_log; 10 | pub use crate::ourlog::ourlog_merge_otel; 11 | pub use opentelemetry_proto::tonic::logs::v1::LogRecord as OtelLog; 12 | 13 | mod ourlog; 14 | -------------------------------------------------------------------------------- /relay-pattern/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-pattern" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "A glob like pattern used throughout Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [features] 16 | default = ["serde"] 17 | serde = ["dep:serde"] 18 | 19 | [dependencies] 20 | memchr = { workspace = true } 21 | serde = { workspace = true, optional = true} 22 | 23 | [dev-dependencies] 24 | criterion = { workspace = true } 25 | serde_json = { workspace = true } 26 | 27 | [[bench]] 28 | name = "benches" 29 | harness = false 30 | -------------------------------------------------------------------------------- /relay-pattern/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-pattern-fuzz" 3 | version = "25.5.1" 4 | publish = false 5 | edition = "2024" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = "0.4" 12 | relay-pattern = { path = ".." } 13 | 14 | [[bin]] 15 | name = "is_match_case_sensitive" 16 | path = "fuzz_targets/is_match_case_sensitive.rs" 17 | test = false 18 | doc = false 19 | bench = false 20 | 21 | [[bin]] 22 | name = "is_match_case_insensitive" 23 | path = "fuzz_targets/is_match_case_insensitive.rs" 24 | test = false 25 | doc = false 26 | bench = false 27 | -------------------------------------------------------------------------------- /relay-pattern/fuzz/fuzz_targets/is_match_case_insensitive.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | 5 | fuzz_target!(|input: (&str, &str)| { 6 | let (pattern, haystack) = input; 7 | if let Ok(pattern) = relay_pattern::Pattern::builder(pattern) 8 | .case_insensitive(true) 9 | .build() 10 | { 11 | std::hint::black_box(pattern.is_match(haystack)); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /relay-pattern/fuzz/fuzz_targets/is_match_case_sensitive.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | 5 | fuzz_target!(|input: (&str, &str)| { 6 | let (pattern, haystack) = input; 7 | if let Ok(pattern) = relay_pattern::Pattern::new(pattern) { 8 | std::hint::black_box(pattern.is_match(haystack)); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /relay-pii/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Scrubbing of personally identifiable information (PII) from events 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | 9 | mod attachments; 10 | mod builtin; 11 | mod compiledconfig; 12 | mod config; 13 | mod convert; 14 | mod generate_selectors; 15 | mod json; 16 | mod legacy; 17 | mod minidumps; 18 | mod processor; 19 | mod redactions; 20 | mod regexes; 21 | mod selector; 22 | mod utils; 23 | 24 | pub mod transform; 25 | 26 | pub use self::attachments::*; 27 | pub use self::compiledconfig::*; 28 | pub use self::config::*; 29 | pub use self::generate_selectors::selector_suggestions_from_value; 30 | pub use self::json::*; 31 | pub use self::legacy::*; 32 | pub use self::minidumps::*; 33 | pub use self::processor::*; 34 | pub use self::redactions::*; 35 | pub use self::selector::*; 36 | -------------------------------------------------------------------------------- /relay-pii/src/selector.pest: -------------------------------------------------------------------------------- 1 | WHITESPACE = _{ " " } 2 | 3 | ObjectType = @{ "$" ~ ('a' .. 'z' | "_")+ } 4 | Wildcard = @{ "*" } 5 | DeepWildcard = @{ "**" } 6 | 7 | Quote = _{ "'" } 8 | And = _{ "&&" | "&" } 9 | Or = _{ "||" | "|" } 10 | Not = _{ "~" | "!" } 11 | EscapedQuote = @{ "'" } 12 | 13 | UnquotedKey = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "-" | "_") * } 14 | RootUnquotedKey = { SOI ~ UnquotedKey ~ EOI } 15 | QuotedCharacter = @{ ((!"'") ~ ANY) } 16 | QuotedKey = ${ (QuotedCharacter | ("'" ~ EscapedQuote))+ } 17 | Key = { UnquotedKey | Quote ~ QuotedKey ~ Quote } 18 | 19 | Index = @{ ASCII_DIGIT+ } 20 | 21 | SelectorPathItem = { ObjectType | DeepWildcard | Wildcard | Index | Key } 22 | SelectorPath = { SelectorPathItem ~ ("." ~ SelectorPathItem)* } 23 | 24 | ParenthesisOrPath = { "(" ~ OrSelector ~ ")" | SelectorPath } 25 | NotSelector = { Not ~ ParenthesisOrPath } 26 | MaybeNotSelector = { NotSelector | ParenthesisOrPath } 27 | AndSelector = { MaybeNotSelector ~ (And ~ MaybeNotSelector)* } 28 | OrSelector = { AndSelector ~ (Or ~ AndSelector)* } 29 | RootSelector = { SOI ~ OrSelector ~ EOI } 30 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__authorization_scrubbing.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "auXth": "foobar", 8 | "auth": "[Filtered]", 9 | "authorization": "[Filtered]" 10 | }, 11 | "_meta": { 12 | "extra": { 13 | "auth": { 14 | "": { 15 | "rem": [ 16 | [ 17 | "@password:filter", 18 | "s", 19 | 0, 20 | 10 21 | ] 22 | ], 23 | "len": 6 24 | } 25 | }, 26 | "authorization": { 27 | "": { 28 | "rem": [ 29 | [ 30 | "@password:filter", 31 | "s", 32 | 0, 33 | 10 34 | ] 35 | ], 36 | "len": 6 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__breadcrumb_message-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "breadcrumbs": { 7 | "values": [ 8 | { 9 | "message": "[Filtered]" 10 | } 11 | ] 12 | }, 13 | "_meta": { 14 | "breadcrumbs": { 15 | "values": { 16 | "0": { 17 | "message": { 18 | "": { 19 | "rem": [ 20 | [ 21 | "strip-fields", 22 | "s", 23 | 0, 24 | 10 25 | ] 26 | ], 27 | "len": 68 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__csp_blocked_uri.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "csp": { 7 | "blocked_uri": "https://example.com/?foo=[Filtered]&bar=baz" 8 | }, 9 | "_meta": { 10 | "csp": { 11 | "blocked_uri": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 25, 18 | 35 19 | ] 20 | ], 21 | "len": 49 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__debug_meta_files_not_strippable.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "debug_meta": { 7 | "images": [ 8 | { 9 | "code_file": "foo/bar.txt", 10 | "debug_file": "foo/bar.txt", 11 | "type": "macho" 12 | } 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__does_sanitize_encrypted_private_key.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "s": "\"\"-----BEGIN ENCRYPTED PRIVATE KEY-----\n[Filtered]\n-----END ENCRYPTED PRIVATE KEY-----\"\"" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "s": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@pemkey:filter", 16 | "s", 17 | 40, 18 | 50 19 | ] 20 | ], 21 | "len": 277 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__does_sanitize_private_key.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "s": "\"\"-----BEGIN PRIVATE KEY-----\n[Filtered]\n-----END PRIVATE KEY-----\"\"" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "s": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@pemkey:filter", 16 | "s", 17 | 30, 18 | 40 19 | ] 20 | ], 21 | "len": 252 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__does_sanitize_public_key.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "s": "\"\"-----BEGIN PUBLIC KEY-----\n[Filtered]\n-----END PUBLIC KEY-----\"\"" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "s": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@pemkey:filter", 16 | "s", 17 | 29, 18 | 39 19 | ] 20 | ], 21 | "len": 283 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__does_sanitize_rsa_private_key.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "s": "\"\"-----BEGIN RSA PRIVATE KEY-----\n[Filtered]\n-----END RSA PRIVATE KEY-----\"\"" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "s": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@pemkey:filter", 16 | "s", 17 | 34, 18 | 44 19 | ] 20 | ], 21 | "len": 260 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__does_sanitize_social_security_number.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "s": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "s": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@usssn:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 11 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__doesnt_scrub_not_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "test1": { 8 | "is_authenticated": "[Filtered]" 9 | }, 10 | "test2": { 11 | "is_authenticated": "null" 12 | }, 13 | "test3": { 14 | "is_authenticated": true 15 | } 16 | }, 17 | "_meta": { 18 | "extra": { 19 | "test1": { 20 | "is_authenticated": { 21 | "": { 22 | "rem": [ 23 | [ 24 | "@password:filter", 25 | "s", 26 | 0, 27 | 10 28 | ] 29 | ], 30 | "len": 6 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__event_message_not_strippable.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "logentry": { 7 | "formatted": "hello world!" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__exclude_fields_on_field_name.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "password": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "password": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@password:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 11 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__explicit_fields.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "mystuff": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "mystuff": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "strip-fields", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 3 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__explicit_fields_case_insensitive.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "MYSTUFF": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "MYSTUFF": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "strip-fields", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 3 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__http_remote_addr_stripped.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "request": { 7 | "env": { 8 | "REMOTE_ADDR": null 9 | } 10 | }, 11 | "_meta": { 12 | "request": { 13 | "env": { 14 | "REMOTE_ADDR": { 15 | "": { 16 | "rem": [ 17 | [ 18 | "@ip:replace", 19 | "s", 20 | 0, 21 | 4 22 | ], 23 | [ 24 | "@anything:remove", 25 | "x" 26 | ] 27 | ], 28 | "len": 9 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__no_scrub_object_with_safe_fields.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "request": { 7 | "url": "https://www.example.com/fr/testing/authenticate", 8 | "method": "POST", 9 | "data": { 10 | "credentials": { 11 | "email": "testing@example.com", 12 | "password": "[Filtered]" 13 | }, 14 | "password": "[Filtered]", 15 | "submit": "Se connecter" 16 | } 17 | }, 18 | "_meta": { 19 | "request": { 20 | "data": { 21 | "credentials": { 22 | "password": { 23 | "": { 24 | "rem": [ 25 | [ 26 | "@password:filter", 27 | "s", 28 | 0, 29 | 10 30 | ] 31 | ], 32 | "len": 4 33 | } 34 | } 35 | }, 36 | "password": { 37 | "": { 38 | "rem": [ 39 | [ 40 | "@password:filter", 41 | "s", 42 | 0, 43 | 10 44 | ] 45 | ], 46 | "len": 4 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__odd_keys.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "do not ,./<>?!@#$%^&*())'ßtrip'": "foo", 8 | "special ,./<>?!@#$%^&*())'gärbage'": "[Filtered]" 9 | }, 10 | "_meta": { 11 | "extra": { 12 | "special ,./<>?!@#$%^&*())'gärbage'": { 13 | "": { 14 | "rem": [ 15 | [ 16 | "strip-fields", 17 | "s", 18 | 0, 19 | 10 20 | ] 21 | ], 22 | "len": 3 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__querystring_as_pairlist_with_partials.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "request": { 7 | "query_string": [ 8 | [ 9 | "foo", 10 | "bar" 11 | ], 12 | [ 13 | "password", 14 | "" 15 | ], 16 | [ 17 | "baz", 18 | "bar" 19 | ] 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__querystring_as_string_with_partials.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "request": { 7 | "query_string": [ 8 | [ 9 | "foo", 10 | "bar" 11 | ], 12 | [ 13 | "password", 14 | "" 15 | ], 16 | [ 17 | "baz", 18 | "bar" 19 | ] 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__regression_more_odd_keys.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-pii/src/convert.rs 3 | expression: pii_config 4 | --- 5 | { 6 | "applications": { 7 | "($string || $number || $array || $object) && !(debug_meta.** || $frame.filename || $frame.abs_path || $logentry.formatted || $error.value || $http.headers.user-agent) && !url && !message && !http.request.url && !'*url*' && !'*message*' && !'*http.request.url*'": [ 8 | "@common:filter", 9 | "@ip:replace" 10 | ], 11 | "$http.env.REMOTE_ADDR || $user.ip_address || $sdk.client_ip || $span.sentry_tags.'user.ip'": [ 12 | "@anything:remove" 13 | ], 14 | "*.cookies.sentrysid || *.cookies.sudo || *.cookies.su || *.cookies.session || *.cookies.__session || *.cookies.sessionid || *.cookies.user_session || *.cookies.symfony || *.cookies.phpsessid || *.cookies.fasthttpsessionid || *.cookies.mysession || *.cookies.irissessionid || *.cookies.csrf || *.cookies.xsrf || *.cookies._xsrf || *.cookies._csrf || *.cookies.csrf-token || *.cookies.csrf_token || *.cookies.xsrf-token || *.cookies.xsrf_token || *.cookies.fastcsrf || *.cookies._iris_csrf": [ 15 | "@anything:filter" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 16 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_amex.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 15 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_discover.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 16 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_mastercard.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 16 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_visa.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 16 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_within_value_1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "'[Filtered]'" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 1, 18 | 11 19 | ] 20 | ], 21 | "len": 18 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_credit_card_within_value_2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "foo [Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@creditcard:filter", 16 | "s", 17 | 4, 18 | 14 19 | ] 20 | ], 21 | "len": 20 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_http_body.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data.value().unwrap().request 4 | --- 5 | { 6 | "data": { 7 | "email": "zzzz@gmail.com", 8 | "password": "[Filtered]" 9 | }, 10 | "_meta": { 11 | "data": { 12 | "password": { 13 | "": { 14 | "rem": [ 15 | [ 16 | "@password:filter", 17 | "s", 18 | 0, 19 | 10 20 | ] 21 | ], 22 | "len": 5 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_http_body_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data.value().unwrap().request 4 | --- 5 | { 6 | "data": "[Filtered]", 7 | "_meta": { 8 | "data": { 9 | "": { 10 | "rem": [ 11 | [ 12 | "@password:filter", 13 | "s", 14 | 0, 15 | 10 16 | ] 17 | ], 18 | "len": 48 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "pg://matt:[Filtered]@localhost/1" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 10, 18 | 20 19 | ] 20 | ], 21 | "len": 26 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "foo 'redis://redis:[Filtered]@localhost:6379/0' bar" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 19, 18 | 29 19 | ] 20 | ], 21 | "len": 44 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "'redis://redis:[Filtered]@localhost:6379/0'" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 15, 18 | 25 19 | ] 20 | ], 21 | "len": 36 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "foo redis://redis:[Filtered]@localhost:6379/0 bar" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 18, 18 | 28 19 | ] 20 | ], 21 | "len": 42 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "foo redis://redis:[Filtered]@localhost:6379/0 bar pg://matt:[Filtered]@localhost/1" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 18, 18 | 28 19 | ], 20 | [ 21 | "@urlauth:legacy", 22 | "s", 23 | 60, 24 | 70 25 | ] 26 | ], 27 | "len": 68 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "postgres:///path" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sanitize_url_7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "foo": "{\"a\":\"https://localhost\",\"b\":\"foo@localhost\",\"c\":\"pg://matt:[Filtered]@localhost/1\",\"d\":\"lol\"}" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "foo": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@urlauth:legacy", 16 | "s", 17 | 60, 18 | 70 19 | ] 20 | ], 21 | "len": 88 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__scrub_object.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "request": { 7 | "url": "https://www.example.com/fr/testing/authenticate", 8 | "method": "POST", 9 | "data": { 10 | "password": "[Filtered]", 11 | "profile": { 12 | "email": "testing@example.com", 13 | "password": null 14 | }, 15 | "submit": "Se connecter" 16 | } 17 | }, 18 | "_meta": { 19 | "request": { 20 | "data": { 21 | "password": { 22 | "": { 23 | "rem": [ 24 | [ 25 | "@password:filter", 26 | "s", 27 | 0, 28 | 10 29 | ] 30 | ], 31 | "len": 4 32 | } 33 | }, 34 | "profile": { 35 | "password": { 36 | "": { 37 | "rem": [ 38 | [ 39 | "@password:filter", 40 | "x" 41 | ] 42 | ] 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__sdk_client_ip_stripped.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "sdk": { 7 | "client_ip": "[ip]" 8 | }, 9 | "_meta": { 10 | "sdk": { 11 | "client_ip": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@ip:replace", 16 | "s", 17 | 0, 18 | 4 19 | ] 20 | ], 21 | "len": 9 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__should_have_mysql_pwd_as_a_default_1.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "MYSQL_PWD": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "MYSQL_PWD": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@password:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 7 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__should_have_mysql_pwd_as_a_default_2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "extra": { 7 | "mysql_pwd": "[Filtered]" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "mysql_pwd": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@password:filter", 16 | "s", 17 | 0, 18 | 10 19 | ] 20 | ], 21 | "len": 7 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__convert__tests__stacktrace_paths_not_strippable.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/convert.rs 3 | expression: data 4 | --- 5 | { 6 | "stacktrace": { 7 | "frames": [ 8 | { 9 | "filename": "C:\\Windows\\BogusValue\\foo.txt", 10 | "abs_path": "C:\\Windows\\BogusValue\\foo.txt" 11 | } 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__anything_hash_on_container.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": null, 7 | "_meta": { 8 | "extra": { 9 | "": { 10 | "rem": [ 11 | [ 12 | "@anything:hash", 13 | "x" 14 | ] 15 | ] 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__anything_hash_on_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": { 7 | "myvalue": "168197CA3A9D4FE60EDE05116B0A125DA1AB3BD0" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "myvalue": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "@anything:hash", 16 | "p", 17 | 0, 18 | 40 19 | ] 20 | ], 21 | "len": 6 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__debugmeta_path_not_addressible_with_wildcard_selector.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "debug_meta": { 7 | "images": [ 8 | { 9 | "code_id": "59b0d8f3183000", 10 | "code_file": "C:\\Windows\\System32\\ntdll.dll", 11 | "debug_id": "971f98e5-ce60-41ff-b2d7-235bbeb34578-1", 12 | "debug_file": "wntdll.pdb", 13 | "arch": "arm64", 14 | "image_addr": "0x0", 15 | "image_size": 4096, 16 | "image_vmaddr": "0x8000", 17 | "other": "value", 18 | "type": "symbolic" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__hash_debugmeta_path.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "debug_meta": { 7 | "images": [ 8 | { 9 | "code_id": "59b0d8f3183000", 10 | "code_file": "16941E20B31710B72716F91FE4F0F27DE81DD6F1\\ntdll.dll", 11 | "debug_id": "971f98e5-ce60-41ff-b2d7-235bbeb34578-1", 12 | "debug_file": "wntdll.pdb", 13 | "arch": "arm64", 14 | "image_addr": "0x0", 15 | "image_size": 4096, 16 | "image_vmaddr": "0x8000", 17 | "other": "value", 18 | "type": "symbolic" 19 | } 20 | ] 21 | }, 22 | "_meta": { 23 | "debug_meta": { 24 | "images": { 25 | "0": { 26 | "code_file": { 27 | "": { 28 | "rem": [ 29 | [ 30 | "@anything:hash", 31 | "p", 32 | 0, 33 | 40 34 | ] 35 | ], 36 | "len": 19 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__ignore_user_agent_ip_scrubbing.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-pii/src/processor.rs 3 | expression: "&data" 4 | --- 5 | { 6 | "request": { 7 | "headers": [ 8 | [ 9 | "User-Agent", 10 | "127.0.0.1" 11 | ], 12 | [ 13 | "X-Client-Ip", 14 | "[ip]" 15 | ] 16 | ] 17 | }, 18 | "_meta": { 19 | "request": { 20 | "headers": { 21 | "1": { 22 | "1": { 23 | "": { 24 | "rem": [ 25 | [ 26 | "@ip:replace", 27 | "s", 28 | 0, 29 | 4 30 | ] 31 | ], 32 | "len": 8 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__no_field_upsert.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": null, 7 | "_meta": { 8 | "extra": { 9 | "": { 10 | "rem": [ 11 | [ 12 | "@anything:remove", 13 | "x" 14 | ] 15 | ] 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__quoted_keys.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": { 7 | "do not ,./<>?!@#$%^&*())'ßtrip'": "foo", 8 | "special ,./<>?!@#$%^&*())'gärbage'": null 9 | }, 10 | "_meta": { 11 | "extra": { 12 | "special ,./<>?!@#$%^&*())'gärbage'": { 13 | "": { 14 | "rem": [ 15 | [ 16 | "@anything:remove", 17 | "x" 18 | ] 19 | ] 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__redact_containers.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": null, 7 | "_meta": { 8 | "extra": { 9 | "": { 10 | "rem": [ 11 | [ 12 | "@anything", 13 | "x" 14 | ] 15 | ] 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__redact_custom_pattern.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "extra": { 7 | "myvalue": "asdbar" 8 | }, 9 | "_meta": { 10 | "extra": { 11 | "myvalue": { 12 | "": { 13 | "rem": [ 14 | [ 15 | "myrule", 16 | "s", 17 | 0, 18 | 3 19 | ] 20 | ], 21 | "len": 6 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__remove_debugmeta_path.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "debug_meta": { 7 | "images": [ 8 | { 9 | "code_id": "59b0d8f3183000", 10 | "code_file": "ntdll.dll", 11 | "debug_id": "971f98e5-ce60-41ff-b2d7-235bbeb34578-1", 12 | "debug_file": "wntdll.pdb", 13 | "arch": "arm64", 14 | "image_addr": "0x0", 15 | "image_size": 4096, 16 | "image_vmaddr": "0x8000", 17 | "other": "value", 18 | "type": "symbolic" 19 | } 20 | ] 21 | }, 22 | "_meta": { 23 | "debug_meta": { 24 | "images": { 25 | "0": { 26 | "code_file": { 27 | "": { 28 | "rem": [ 29 | [ 30 | "@anything:remove", 31 | "x" 32 | ] 33 | ] 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__replace_debugmeta_path.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: event 4 | --- 5 | { 6 | "debug_meta": { 7 | "images": [ 8 | { 9 | "code_id": "59b0d8f3183000", 10 | "code_file": "[Filtered]\\ntdll.dll", 11 | "debug_id": "971f98e5-ce60-41ff-b2d7-235bbeb34578-1", 12 | "debug_file": "wntdll.pdb", 13 | "arch": "arm64", 14 | "image_addr": "0x0", 15 | "image_size": 4096, 16 | "image_vmaddr": "0x8000", 17 | "other": "value", 18 | "type": "symbolic" 19 | } 20 | ] 21 | }, 22 | "_meta": { 23 | "debug_meta": { 24 | "images": { 25 | "0": { 26 | "code_file": { 27 | "": { 28 | "rem": [ 29 | [ 30 | "@anything:replace", 31 | "s", 32 | 0, 33 | 10 34 | ] 35 | ], 36 | "len": 19 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_breadcrumb_data_http_not_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: breadcrumb 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "query": "dance=true" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_breadcrumb_data_http_strings_are_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: breadcrumb 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "fragment": "ccnumber=[Filtered],process_id=123", 9 | "query": "ccnumber=[Filtered]&process_id=123" 10 | } 11 | }, 12 | "_meta": { 13 | "data": { 14 | "http": { 15 | "fragment": { 16 | "": { 17 | "rem": [ 18 | [ 19 | "@creditcard:filter", 20 | "s", 21 | 9, 22 | 19 23 | ] 24 | ], 25 | "len": 40 26 | } 27 | }, 28 | "query": { 29 | "": { 30 | "rem": [ 31 | [ 32 | "@creditcard:filter", 33 | "s", 34 | 9, 35 | 19 36 | ] 37 | ], 38 | "len": 40 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_breadcrumb_data_untyped_props_are_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: breadcrumb 4 | --- 5 | { 6 | "data": { 7 | "more_untyped": { 8 | "ccnumber": "[Filtered]", 9 | "scrubbed": "yes", 10 | "typed": "no" 11 | }, 12 | "untyped": "ccnumber=[Filtered]" 13 | }, 14 | "_meta": { 15 | "data": { 16 | "more_untyped": { 17 | "ccnumber": { 18 | "": { 19 | "rem": [ 20 | [ 21 | "@creditcard:filter", 22 | "s", 23 | 0, 24 | 10 25 | ] 26 | ], 27 | "len": 16 28 | } 29 | } 30 | }, 31 | "untyped": { 32 | "": { 33 | "rem": [ 34 | [ 35 | "@creditcard:filter", 36 | "s", 37 | 9, 38 | 19 39 | ] 40 | ], 41 | "len": 25 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_http_not_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "query": "dance=true" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_http_objects_are_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "fragment": { 9 | "ccnumber": "[Filtered]", 10 | "process_id": "123" 11 | }, 12 | "query": { 13 | "ccnumber": "[Filtered]", 14 | "process_id": "123" 15 | } 16 | } 17 | }, 18 | "_meta": { 19 | "data": { 20 | "http": { 21 | "fragment": { 22 | "ccnumber": { 23 | "": { 24 | "rem": [ 25 | [ 26 | "@creditcard:filter", 27 | "s", 28 | 0, 29 | 10 30 | ] 31 | ], 32 | "len": 16 33 | } 34 | } 35 | }, 36 | "query": { 37 | "ccnumber": { 38 | "": { 39 | "rem": [ 40 | [ 41 | "@creditcard:filter", 42 | "s", 43 | 0, 44 | 10 45 | ] 46 | ], 47 | "len": 16 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_http_strings_are_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "fragment": "ccnumber=[Filtered],process_id=123", 9 | "query": "ccnumber=[Filtered]&process_id=123" 10 | } 11 | }, 12 | "_meta": { 13 | "data": { 14 | "http": { 15 | "fragment": { 16 | "": { 17 | "rem": [ 18 | [ 19 | "@creditcard:filter", 20 | "s", 21 | 9, 22 | 19 23 | ] 24 | ], 25 | "len": 40 26 | } 27 | }, 28 | "query": { 29 | "": { 30 | "rem": [ 31 | [ 32 | "@creditcard:filter", 33 | "s", 34 | 9, 35 | 19 36 | ] 37 | ], 38 | "len": 40 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_not_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "query": "dance=true" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_object_is_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "fragment": { 9 | "ccnumber": "[Filtered]", 10 | "process_id": "123" 11 | }, 12 | "query": { 13 | "ccnumber": "[Filtered]", 14 | "process_id": "123" 15 | } 16 | } 17 | }, 18 | "_meta": { 19 | "data": { 20 | "http": { 21 | "fragment": { 22 | "ccnumber": { 23 | "": { 24 | "rem": [ 25 | [ 26 | "@creditcard:filter", 27 | "s", 28 | 0, 29 | 10 30 | ] 31 | ], 32 | "len": 16 33 | } 34 | } 35 | }, 36 | "query": { 37 | "ccnumber": { 38 | "": { 39 | "rem": [ 40 | [ 41 | "@creditcard:filter", 42 | "s", 43 | 0, 44 | 10 45 | ] 46 | ], 47 | "len": 16 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_string_is_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "http": { 8 | "fragment": "ccnumber=[Filtered],process_id=123", 9 | "query": "ccnumber=[Filtered]&process_id=123" 10 | } 11 | }, 12 | "_meta": { 13 | "data": { 14 | "http": { 15 | "fragment": { 16 | "": { 17 | "rem": [ 18 | [ 19 | "@creditcard:filter", 20 | "s", 21 | 9, 22 | 19 23 | ] 24 | ], 25 | "len": 40 26 | } 27 | }, 28 | "query": { 29 | "": { 30 | "rem": [ 31 | [ 32 | "@creditcard:filter", 33 | "s", 34 | 9, 35 | 19 36 | ] 37 | ], 38 | "len": 40 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__scrub_span_data_untyped_props_are_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-general/src/pii/processor.rs 3 | expression: span 4 | --- 5 | { 6 | "data": { 7 | "more_untyped": { 8 | "ccnumber": "[Filtered]", 9 | "scrubbed": "yes", 10 | "typed": "no" 11 | }, 12 | "untyped": "ccnumber=[Filtered]" 13 | }, 14 | "_meta": { 15 | "data": { 16 | "more_untyped": { 17 | "ccnumber": { 18 | "": { 19 | "rem": [ 20 | [ 21 | "@creditcard:filter", 22 | "s", 23 | 0, 24 | 10 25 | ] 26 | ], 27 | "len": 16 28 | } 29 | } 30 | }, 31 | "untyped": { 32 | "": { 33 | "rem": [ 34 | [ 35 | "@creditcard:filter", 36 | "s", 37 | 9, 38 | 19 39 | ] 40 | ], 41 | "len": 25 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /relay-pii/src/snapshots/relay_pii__processor__tests__trace_route_params_scrubbed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-pii/src/processor.rs 3 | expression: trace_context 4 | --- 5 | { 6 | "trace_id": "4c79f60c11214eb38604f4ae0781bfb2", 7 | "span_id": "fa90fdead5f74052", 8 | "data": { 9 | "previousRoute": { 10 | "params": { 11 | "password": "[Filtered]" 12 | } 13 | } 14 | }, 15 | "type": "trace", 16 | "_meta": { 17 | "data": { 18 | "previousRoute": { 19 | "params": { 20 | "password": { 21 | "": { 22 | "rem": [ 23 | [ 24 | "@password:filter", 25 | "s", 26 | 0, 27 | 10 28 | ] 29 | ], 30 | "len": 4 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /relay-profiling/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-profiling" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Profiling processing for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | android_trace_log = { workspace = true, features = ["serde"] } 17 | bytes = { workspace = true } 18 | chrono = { workspace = true } 19 | data-encoding = { workspace = true } 20 | hashbrown = { workspace = true } 21 | itertools = { workspace = true } 22 | relay-base-schema = { workspace = true } 23 | relay-dynamic-config = { workspace = true } 24 | relay-event-schema = { workspace = true } 25 | relay-filter = { workspace = true } 26 | relay-log = { workspace = true } 27 | relay-metrics = { workspace = true } 28 | relay-protocol = { workspace = true } 29 | serde = { workspace = true } 30 | serde_json = { workspace = true } 31 | serde_path_to_error = { workspace = true } 32 | thiserror = { workspace = true } 33 | url = { workspace = true } 34 | uuid = { workspace = true } 35 | 36 | [dev-dependencies] 37 | insta = { workspace = true } 38 | -------------------------------------------------------------------------------- /relay-profiling/src/android/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod chunk; 2 | pub mod legacy; 3 | -------------------------------------------------------------------------------- /relay-profiling/src/types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::debug_image::DebugImage; 4 | 5 | /// This is a serde-friendly version of <https://github.com/getsentry/relay/blob/52bc345871b4e5cca19ed73c17730eeef092028b/relay-event-schema/src/protocol/debugmeta.rs#L516> 6 | #[derive(Default, Debug, Serialize, Deserialize, Clone)] 7 | pub struct DebugMeta { 8 | pub(crate) images: Vec<DebugImage>, 9 | } 10 | 11 | /// This is a serde-friendly version of <https://github.com/getsentry/relay/blob/52bc345871b4e5cca19ed73c17730eeef092028b/relay-event-schema/src/protocol/clientsdk.rs#L8> 12 | #[derive(Debug, Serialize, Deserialize, Clone)] 13 | pub struct ClientSdk { 14 | pub name: String, 15 | 16 | #[serde(default, skip_serializing_if = "String::is_empty")] 17 | pub version: String, 18 | } 19 | -------------------------------------------------------------------------------- /relay-prosperoconv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-prosperoconv" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | homepage = "https://getsentry.github.io/relay/" 5 | repository = "https://github.com/getsentry/relay" 6 | version = "25.5.1" 7 | edition = "2024" 8 | license-file = "../LICENSE.md" 9 | publish = false 10 | 11 | 12 | [lints] 13 | workspace = true 14 | 15 | 16 | [dependencies] 17 | anyhow = "1.0.69" 18 | lz4_flex = "0.11.3" 19 | mime_guess = "2.0.4" 20 | minidump-writer = "0.9.0" 21 | object = "0.36.0" 22 | rmpv = "1.3.0" 23 | sentry = "0.36.0" 24 | tracing = "0.1.40" 25 | watto = "0.1.0" 26 | 27 | [build-dependencies] 28 | dircpy = "0.3.19" 29 | tempfile = "3.19.1" 30 | -------------------------------------------------------------------------------- /relay-prosperoconv/clippy.toml: -------------------------------------------------------------------------------- 1 | allow-expect-in-tests = true 2 | allow-unwrap-in-tests = true 3 | -------------------------------------------------------------------------------- /relay-prosperoconv/prosperoconv.version: -------------------------------------------------------------------------------- 1 | 43031710e0eca9d86221fad8524ee5eccb8c9faf 2 | -------------------------------------------------------------------------------- /relay-prosperoconv/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /relay-protocol-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-protocol-derive" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Derives for Relay's protocol traits" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | quote = { workspace = true } 17 | syn = { workspace = true } 18 | synstructure = { workspace = true } 19 | proc-macro2 = { workspace = true } 20 | 21 | [lib] 22 | proc-macro = true 23 | -------------------------------------------------------------------------------- /relay-protocol-derive/src/utils.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::ToTokens; 3 | use synstructure::{Structure, VariantInfo}; 4 | 5 | pub trait SynstructureExt { 6 | fn try_each_variant<F, R>(&self, f: F) -> syn::Result<TokenStream> 7 | where 8 | F: FnMut(&VariantInfo<'_>) -> syn::Result<R>, 9 | R: ToTokens; 10 | } 11 | 12 | impl SynstructureExt for Structure<'_> { 13 | fn try_each_variant<F, R>(&self, mut f: F) -> syn::Result<TokenStream> 14 | where 15 | F: FnMut(&VariantInfo<'_>) -> syn::Result<R>, 16 | R: ToTokens, 17 | { 18 | let mut t = TokenStream::new(); 19 | for variant in self.variants() { 20 | let pat = variant.pat(); 21 | let body = f(variant)?; 22 | quote::quote!(#pat => { #body }).to_tokens(&mut t); 23 | } 24 | if self.omitted_variants() { 25 | quote::quote!(_ => {}).to_tokens(&mut t); 26 | } 27 | Ok(t) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /relay-protocol/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-protocol" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Types and traits for building JSON-based protocols and schemas" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | num-traits = { workspace = true } 17 | relay-common = { workspace = true } 18 | relay-pattern = { workspace = true } 19 | relay-protocol-derive = { workspace = true, optional = true } 20 | serde = { workspace = true } 21 | serde_json = { workspace = true } 22 | smallvec = { workspace = true } 23 | unicase = { workspace = true } 24 | uuid = { workspace = true } 25 | 26 | [dev-dependencies] 27 | insta = { workspace = true } 28 | similar-asserts = { workspace = true } 29 | 30 | [features] 31 | default = [] 32 | derive = ["dep:relay-protocol-derive"] 33 | test = [] 34 | -------------------------------------------------------------------------------- /relay-quotas/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-quotas" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Sentry quotas and rate limiting" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [features] 13 | default = [] 14 | redis = ["dep:thiserror", "dep:relay-log", "relay-redis/impl"] 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | hashbrown = { workspace = true } 21 | relay-base-schema = { workspace = true } 22 | relay-common = { workspace = true } 23 | relay-log = { workspace = true, optional = true } 24 | relay-redis = { workspace = true, optional = true } 25 | serde = { workspace = true } 26 | smallvec = { workspace = true } 27 | thiserror = { workspace = true, optional = true } 28 | itertools = { workspace = true } 29 | tokio = { workspace = true, features = ["sync"] } 30 | 31 | [dev-dependencies] 32 | insta = { workspace = true } 33 | serde_json = { workspace = true } 34 | uuid = { workspace = true } 35 | tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } 36 | -------------------------------------------------------------------------------- /relay-quotas/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Quotas and rate limiting for Relay. 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | #![allow(clippy::derive_partial_eq_without_eq)] 9 | 10 | /// The default timeout to apply when a scope is fully rejected. This 11 | /// typically happens for disabled keys, projects, or organizations. 12 | const REJECT_ALL_SECS: u64 = 60; 13 | 14 | mod quota; 15 | mod rate_limit; 16 | 17 | pub use self::quota::*; 18 | pub use self::rate_limit::*; 19 | 20 | #[cfg(feature = "redis")] 21 | mod global; 22 | #[cfg(feature = "redis")] 23 | pub use self::global::{GlobalLimiter, GlobalRateLimiter}; 24 | 25 | #[cfg(feature = "redis")] 26 | mod redis; 27 | #[cfg(feature = "redis")] 28 | pub use self::redis::*; 29 | -------------------------------------------------------------------------------- /relay-redis/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-redis" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Pooled Redis and Redis cluster abstraction for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | deadpool = { workspace = true, optional = true } 17 | deadpool-redis = { workspace = true, optional = true, features = ["rt_tokio_1", "cluster", "script"] } 18 | futures = { workspace = true } 19 | redis = { workspace = true, optional = true, features = [ 20 | "cluster", 21 | "r2d2", 22 | "tls-native-tls", 23 | "keep-alive", 24 | "script", 25 | "tokio-native-tls-comp", 26 | "cluster-async", 27 | "connection-manager" 28 | ], default-features = false } 29 | serde = { workspace = true } 30 | tokio = { workspace = true, features = ["time"] } 31 | thiserror = { workspace = true } 32 | 33 | relay-system = { workspace = true } 34 | 35 | [features] 36 | default = [] 37 | impl = ["dep:deadpool", "dep:deadpool-redis", "dep:redis"] 38 | -------------------------------------------------------------------------------- /relay-redis/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Abstraction over Redis caches. 2 | //! 3 | //! By default, this library only implements an empty noop client. With the `impl` feature, the 4 | //! actual Redis client is implemented. 5 | #![warn(missing_docs)] 6 | #![doc( 7 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 8 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 9 | )] 10 | #![allow(clippy::derive_partial_eq_without_eq)] 11 | 12 | mod config; 13 | pub use self::config::*; 14 | 15 | #[cfg(feature = "impl")] 16 | mod pool; 17 | 18 | #[cfg(feature = "impl")] 19 | mod real; 20 | #[cfg(feature = "impl")] 21 | pub use self::real::*; 22 | 23 | #[cfg(feature = "impl")] 24 | mod scripts; 25 | #[cfg(feature = "impl")] 26 | pub use self::scripts::*; 27 | 28 | #[cfg(not(feature = "impl"))] 29 | mod noop; 30 | 31 | #[cfg(not(feature = "impl"))] 32 | pub use self::noop::*; 33 | -------------------------------------------------------------------------------- /relay-replays/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-replays" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Session replay functionality for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | flate2 = { workspace = true } 17 | once_cell = { workspace = true } 18 | relay-event-schema = { workspace = true } 19 | relay-log = { workspace = true } 20 | relay-pii = { workspace = true } 21 | relay-protocol = { workspace = true } 22 | serde = { workspace = true } 23 | serde_json = { workspace = true, features = ["raw_value"] } 24 | serde-transcode = { workspace = true } 25 | 26 | [dev-dependencies] 27 | criterion = { workspace = true } 28 | insta = { workspace = true } 29 | 30 | [[bench]] 31 | name = "benchmarks" 32 | harness = false 33 | -------------------------------------------------------------------------------- /relay-replays/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Session replay protocol and processing for Sentry. 2 | //! 3 | //! [Session Replay] provides a video-like reproduction of user interactions on a site or web app. 4 | //! All user interactions — including page visits, mouse movements, clicks, and scrolls — are 5 | //! captured, helping developers connect the dots between a known issue and how a user experienced 6 | //! it in the UI. 7 | //! 8 | //! [session replay]: https://docs.sentry.io/product/session-replay/ 9 | 10 | #![doc( 11 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 12 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 13 | )] 14 | #![warn(missing_docs)] 15 | 16 | pub mod recording; 17 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-binary.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/relay-replays/tests/fixtures/rrweb-binary.txt -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-event-3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": 3, 4 | "data": { 5 | "source": 0, 6 | "texts": [ 7 | { 8 | "id": 44, 9 | "value": "111-11-1111" 10 | } 11 | ], 12 | "attributes": [], 13 | "removes": [], 14 | "isAttachIframe": true, 15 | "adds": [ 16 | { 17 | "parentId": 74, 18 | "previousId": null, 19 | "nextId": null, 20 | "node": { 21 | "type": 2, 22 | "tagName": "h1", 23 | "attributes": {}, 24 | "childNodes": [ 25 | { 26 | "type": 3, 27 | "textContent": "4111-1111-1111-1111", 28 | "id": 284 29 | } 30 | ], 31 | "id": 283 32 | } 33 | } 34 | ] 35 | }, 36 | "timestamp": 1665063926945 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-node-2-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 2, 3 | "tagName": "style", 4 | "attributes": { 5 | "id": "react-tooltip" 6 | }, 7 | "childNodes": [ 8 | { 9 | "type": 3, 10 | "textContent": "test", 11 | "isStyle": true, 12 | "id": 284 13 | } 14 | ], 15 | "id": 283 16 | } 17 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-node-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 2, 3 | "tagName": "h1", 4 | "attributes": { 5 | "id": "react-tooltip", 6 | "rr_scrollLeft": 1070, 7 | "rr_scrollTop": 385 8 | }, 9 | "childNodes": [ 10 | { 11 | "type": 3, 12 | "textContent": "test", 13 | "id": -1 14 | } 15 | ], 16 | "id": 283 17 | } 18 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-performance-navigation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": 5, 4 | "timestamp": 1665063926.125, 5 | "data": { 6 | "tag": "performanceSpan", 7 | "payload": { 8 | "op": "navigation.navigate", 9 | "description": "https://sentry.io?credit-card=4111-1111-1111-1111", 10 | "startTimestamp": 1665063926.125, 11 | "endTimestamp": 1665063926.833, 12 | "data": { 13 | "size": 9538, 14 | "duration": 710 15 | } 16 | } 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-performance-resource.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": 5, 4 | "timestamp": 1665063926.263, 5 | "data": { 6 | "tag": "performanceSpan", 7 | "payload": { 8 | "op": "resource.link", 9 | "description": "https://sentry.io?credit-card=4111-1111-1111-1111", 10 | "startTimestamp": 1665063926.263, 11 | "endTimestamp": 1665063926.386, 12 | "data": { 13 | "size": 31872, 14 | "encodedBodySize": 31356 15 | } 16 | } 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-pii-ip-address.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": 3, 4 | "data": { 5 | "source": 0, 6 | "texts": [ 7 | { 8 | "id": 1, 9 | "value": "127.0.0.1" 10 | } 11 | ], 12 | "attributes": [], 13 | "removes": [], 14 | "adds": [ 15 | { 16 | "parentId": 74, 17 | "nextId": null, 18 | "node": { 19 | "type": 2, 20 | "tagName": "h1", 21 | "attributes": { 22 | "id": "react-tooltip" 23 | }, 24 | "childNodes": [ 25 | { 26 | "type": 3, 27 | "textContent": "127.0.0.1", 28 | "id": 284 29 | } 30 | ], 31 | "id": 283 32 | } 33 | } 34 | ] 35 | }, 36 | "timestamp": 1665063926945 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /relay-replays/tests/fixtures/rrweb-pii.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": 3, 4 | "data": { 5 | "source": 0, 6 | "texts": [], 7 | "attributes": [], 8 | "removes": [], 9 | "isAttachIframe": true, 10 | "adds": [ 11 | { 12 | "parentId": 74, 13 | "previousId": null, 14 | "nextId": null, 15 | "node": { 16 | "type": 2, 17 | "tagName": "h1", 18 | "attributes": { 19 | "id": "react-tooltip" 20 | }, 21 | "childNodes": [ 22 | { 23 | "type": 3, 24 | "textContent": "4917-4845-8989-7107", 25 | "id": 284 26 | } 27 | ], 28 | "id": 283 29 | } 30 | } 31 | ] 32 | }, 33 | "timestamp": 1665063926945 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /relay-sampling/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-sampling" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Dynamic sampling functionality for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [features] 13 | default = [] 14 | redis = ["dep:anyhow", "relay-redis/impl"] 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | anyhow = { workspace = true, optional = true } 21 | chrono = { workspace = true, features = ["now"] } 22 | rand = { workspace = true } 23 | rand_pcg = { workspace = true } 24 | relay-base-schema = { workspace = true } 25 | relay-event-schema = { workspace = true } 26 | relay-log = { workspace = true } 27 | relay-protocol = { workspace = true } 28 | relay-redis = { workspace = true, optional = true } 29 | serde = { workspace = true } 30 | serde_json = { workspace = true } 31 | uuid = { workspace = true } 32 | tokio = { workspace = true, features = ["rt", "macros"] } 33 | 34 | [dev-dependencies] 35 | chrono = { workspace = true, features = ["clock"] } 36 | insta = { workspace = true } 37 | similar-asserts = { workspace = true } 38 | -------------------------------------------------------------------------------- /relay-sampling/tests/fixtures/dynamic_sampling_context.json: -------------------------------------------------------------------------------- 1 | { 2 | "trace_id": "00000000-0000-0000-0000-000000000000", 3 | "public_key": "abd0f232775f45feab79864e580d160b", 4 | "release": "1.0", 5 | "environment": "dev", 6 | "transaction": "/foo", 7 | "sample_rate": "0.5", 8 | "user_id": "some-id", 9 | "user_segment": "all", 10 | "user": null 11 | } -------------------------------------------------------------------------------- /relay-sampling/tests/fixtures/sampling_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "rules": [ 4 | { 5 | "condition": { 6 | "op": "and", 7 | "inner": [ 8 | { 9 | "op": "glob", 10 | "name": "releases", 11 | "value": [ 12 | "1.1.1", 13 | "1.1.2" 14 | ] 15 | } 16 | ] 17 | }, 18 | "samplingValue": { 19 | "type": "sampleRate", 20 | "value": 0.7 21 | }, 22 | "type": "transaction", 23 | "id": 2 24 | }, 25 | { 26 | "condition": { 27 | "op": "and", 28 | "inner": [ 29 | { 30 | "op": "eq", 31 | "name": "transaction", 32 | "value": "/foo" 33 | } 34 | ] 35 | }, 36 | "samplingValue": { 37 | "type": "factor", 38 | "value": 5.0 39 | }, 40 | "type": "trace", 41 | "id": 1, 42 | "timeRange": { 43 | "start": "2022-10-10T00:00:00.000000Z", 44 | "end": "2022-10-20T00:00:00.000000Z" 45 | } 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /relay-server/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::Write; 4 | use std::path::Path; 5 | 6 | fn main() { 7 | let out_dir = env::var("OUT_DIR").unwrap(); 8 | let dest_path = Path::new(&out_dir).join("constants.gen.rs"); 9 | let mut f = File::create(dest_path).unwrap(); 10 | 11 | writeln!( 12 | f, 13 | "pub const SERVER: &str = \"sentry-relay/{}\";", 14 | env::var("CARGO_PKG_VERSION").unwrap() 15 | ) 16 | .unwrap(); 17 | writeln!( 18 | f, 19 | "pub const CLIENT: &str = \"sentry.relay/{}\";", 20 | env::var("CARGO_PKG_VERSION").unwrap() 21 | ) 22 | .unwrap(); 23 | println!("cargo:rerun-if-changed=build.rs\n"); 24 | println!("cargo:rerun-if-changed=Cargo.toml\n"); 25 | } 26 | -------------------------------------------------------------------------------- /relay-server/src/endpoints/batch_metrics.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::response::IntoResponse; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::extractors::{ReceivedAt, SignedBytes}; 6 | use crate::service::ServiceState; 7 | use crate::services::processor::{BucketSource, ProcessBatchedMetrics}; 8 | 9 | #[derive(Debug, Serialize, Deserialize)] 10 | struct SendMetricsResponse {} 11 | 12 | pub async fn handle( 13 | state: ServiceState, 14 | ReceivedAt(received_at): ReceivedAt, 15 | body: SignedBytes, 16 | ) -> impl IntoResponse { 17 | if !body.relay.internal { 18 | return StatusCode::FORBIDDEN.into_response(); 19 | } 20 | 21 | state.processor().send(ProcessBatchedMetrics { 22 | payload: body.body, 23 | source: BucketSource::Internal, 24 | received_at, 25 | sent_at: None, 26 | }); 27 | 28 | (StatusCode::ACCEPTED, axum::Json(SendMetricsResponse {})).into_response() 29 | } 30 | -------------------------------------------------------------------------------- /relay-server/src/endpoints/batch_outcomes.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::response::IntoResponse; 3 | use relay_config::EmitOutcomes; 4 | 5 | use crate::extractors::SignedJson; 6 | use crate::service::ServiceState; 7 | use crate::services::outcome::{SendOutcomes, SendOutcomesResponse}; 8 | 9 | pub async fn handle(state: ServiceState, body: SignedJson<SendOutcomes>) -> impl IntoResponse { 10 | if !body.relay.internal || state.config().emit_outcomes() != EmitOutcomes::AsOutcomes { 11 | return StatusCode::FORBIDDEN.into_response(); 12 | } 13 | 14 | let producer = &state.outcome_producer(); 15 | for outcome in body.inner.outcomes { 16 | producer.send(outcome); 17 | } 18 | 19 | (StatusCode::ACCEPTED, axum::Json(SendOutcomesResponse {})).into_response() 20 | } 21 | -------------------------------------------------------------------------------- /relay-server/src/endpoints/events.rs: -------------------------------------------------------------------------------- 1 | //! Returns captured events. 2 | 3 | use axum::extract::Path; 4 | use axum::http::{StatusCode, header}; 5 | use axum::response::IntoResponse; 6 | use relay_event_schema::protocol::EventId; 7 | 8 | use crate::endpoints::common::ServiceUnavailable; 9 | use crate::envelope; 10 | use crate::service::ServiceState; 11 | use crate::services::test_store::GetCapturedEnvelope; 12 | 13 | pub async fn handle( 14 | state: ServiceState, 15 | Path(event_id): Path<EventId>, 16 | ) -> Result<impl IntoResponse, ServiceUnavailable> { 17 | let envelope_opt = state 18 | .test_store() 19 | .send(GetCapturedEnvelope { event_id }) 20 | .await?; 21 | 22 | Ok(match envelope_opt { 23 | Some(Ok(envelope)) => { 24 | let headers = [(header::CONTENT_TYPE, envelope::CONTENT_TYPE)]; 25 | (StatusCode::OK, headers, envelope.to_vec().unwrap()).into_response() 26 | } 27 | Some(Err(error)) => (StatusCode::BAD_REQUEST, error).into_response(), 28 | None => StatusCode::NOT_FOUND.into_response(), 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /relay-server/src/endpoints/health_check.rs: -------------------------------------------------------------------------------- 1 | //! A simple health check endpoint for the relay. 2 | 3 | use axum::extract::Path; 4 | use axum::http::StatusCode; 5 | use axum::response::IntoResponse; 6 | use serde::Serialize; 7 | 8 | use crate::service::ServiceState; 9 | use crate::services::health_check::{IsHealthy, Status as HealthStatus}; 10 | 11 | #[derive(Serialize)] 12 | struct Status { 13 | is_healthy: bool, 14 | } 15 | 16 | pub async fn handle(state: ServiceState, Path(kind): Path<IsHealthy>) -> impl IntoResponse { 17 | match state.health_check().send(kind).await { 18 | Ok(HealthStatus::Healthy) => (StatusCode::OK, axum::Json(Status { is_healthy: true })), 19 | _ => ( 20 | StatusCode::SERVICE_UNAVAILABLE, 21 | axum::Json(Status { is_healthy: false }), 22 | ), 23 | } 24 | } 25 | 26 | pub async fn handle_live(state: ServiceState) -> impl IntoResponse { 27 | handle(state, Path(IsHealthy::Liveness)).await 28 | } 29 | -------------------------------------------------------------------------------- /relay-server/src/endpoints/statics.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::response::IntoResponse; 3 | 4 | /// An endpoint function that always responds with `404 Not Found`. 5 | pub async fn not_found() -> impl IntoResponse { 6 | StatusCode::NOT_FOUND 7 | } 8 | -------------------------------------------------------------------------------- /relay-server/src/extractors/content_type.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | use std::fmt; 3 | 4 | use axum::extract::FromRequestParts; 5 | use axum::http::header; 6 | use axum::http::request::Parts; 7 | 8 | #[derive(Clone, Debug, PartialEq, Eq)] 9 | pub struct RawContentType(String); 10 | 11 | impl fmt::Display for RawContentType { 12 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 13 | self.0.fmt(f) 14 | } 15 | } 16 | 17 | impl AsRef<str> for RawContentType { 18 | fn as_ref(&self) -> &str { 19 | &self.0 20 | } 21 | } 22 | 23 | impl<S: Send + Sync> FromRequestParts<S> for RawContentType { 24 | type Rejection = Infallible; 25 | 26 | async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> { 27 | let mime = parts 28 | .headers 29 | .get(header::CONTENT_TYPE) 30 | .and_then(|v| v.to_str().ok()) 31 | .unwrap_or("") 32 | .to_owned(); 33 | 34 | Ok(Self(mime)) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /relay-server/src/extractors/mod.rs: -------------------------------------------------------------------------------- 1 | mod content_type; 2 | mod forwarded_for; 3 | mod mime; 4 | mod received_at; 5 | mod remote; 6 | mod request_meta; 7 | mod signed_json; 8 | 9 | pub use self::content_type::*; 10 | pub use self::forwarded_for::*; 11 | pub use self::mime::*; 12 | pub use self::received_at::*; 13 | pub use self::remote::*; 14 | pub use self::request_meta::*; 15 | pub use self::signed_json::*; 16 | -------------------------------------------------------------------------------- /relay-server/src/extractors/received_at.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | 3 | use axum::Extension; 4 | use axum::extract::FromRequestParts; 5 | use axum::http::request::Parts; 6 | use chrono::{DateTime, Utc}; 7 | 8 | /// The time at which the request started. 9 | #[derive(Clone, Copy, Debug)] 10 | pub struct ReceivedAt(pub DateTime<Utc>); 11 | 12 | impl ReceivedAt { 13 | pub fn now() -> Self { 14 | Self(Utc::now()) 15 | } 16 | } 17 | 18 | impl<S> FromRequestParts<S> for ReceivedAt 19 | where 20 | S: Send + Sync, 21 | { 22 | type Rejection = Infallible; 23 | 24 | async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { 25 | let Extension(start_time) = Extension::from_request_parts(parts, state) 26 | .await 27 | .expect("ReceivedAt middleware is not configured"); 28 | 29 | Ok(start_time) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /relay-server/src/metrics/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "processing")] 2 | mod bucket_encoding; 3 | mod metric_stats; 4 | mod minimal; 5 | mod outcomes; 6 | mod rate_limits; 7 | 8 | #[cfg(feature = "processing")] 9 | pub use self::bucket_encoding::*; 10 | pub use self::metric_stats::*; 11 | pub use self::minimal::*; 12 | pub use self::outcomes::*; 13 | pub use self::rate_limits::*; 14 | -------------------------------------------------------------------------------- /relay-server/src/metrics_extraction/mod.rs: -------------------------------------------------------------------------------- 1 | use relay_common::time::UnixTimestamp; 2 | use relay_metrics::Bucket; 3 | 4 | pub mod event; 5 | pub mod generic; 6 | pub mod sessions; 7 | pub mod transactions; 8 | 9 | pub trait IntoMetric { 10 | fn into_metric(self, timestamp: UnixTimestamp) -> Bucket; 11 | } 12 | -------------------------------------------------------------------------------- /relay-server/src/middlewares/decompression.rs: -------------------------------------------------------------------------------- 1 | use axum::extract::Request; 2 | use axum::http::header; 3 | pub use tower_http::decompression::RequestDecompressionLayer; 4 | 5 | /// Map request middleware that removes empty content encoding headers. 6 | /// 7 | /// This is to be used along with the [`RequestDecompressionLayer`]. 8 | pub fn remove_empty_encoding(mut request: Request) -> Request { 9 | if let header::Entry::Occupied(entry) = request.headers_mut().entry(header::CONTENT_ENCODING) { 10 | if should_ignore_encoding(entry.get().as_bytes()) { 11 | entry.remove(); 12 | } 13 | } 14 | 15 | request 16 | } 17 | 18 | /// Returns `true` if this content-encoding value should be ignored. 19 | fn should_ignore_encoding(value: &[u8]) -> bool { 20 | // sentry-ruby/5.x sends an empty string 21 | // sentry.java.android/2.0.0 sends "UTF-8" 22 | value == b"" || value.eq_ignore_ascii_case(b"utf-8") 23 | } 24 | -------------------------------------------------------------------------------- /relay-server/src/middlewares/handle_panic.rs: -------------------------------------------------------------------------------- 1 | use std::any::Any; 2 | 3 | use axum::http::StatusCode; 4 | use axum::response::{IntoResponse, Response}; 5 | pub use tower_http::catch_panic::CatchPanicLayer; 6 | 7 | use crate::utils::ApiErrorResponse; 8 | 9 | /// Handler function for the [`CatchPanicLayer`] middleware. 10 | pub fn handle_panic(err: Box<dyn Any + Send + 'static>) -> Response { 11 | let detail = if let Some(s) = err.downcast_ref::<String>() { 12 | s.as_str() 13 | } else if let Some(s) = err.downcast_ref::<&str>() { 14 | s 15 | } else { 16 | "no error details" 17 | }; 18 | 19 | relay_log::error!("panic in web handler: {detail}"); 20 | 21 | let response = ( 22 | StatusCode::INTERNAL_SERVER_ERROR, 23 | ApiErrorResponse::with_detail(detail), 24 | ); 25 | 26 | response.into_response() 27 | } 28 | -------------------------------------------------------------------------------- /relay-server/src/middlewares/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middlewares for the HTTP server. 2 | //! 3 | //! This module exposes tower [layers](tower::Layer) and related utilities to configure the 4 | //! axum/hyper HTTP server. Most of the middlewares should be registered as a layer on the 5 | //! [`Router`](axum::Router). 6 | //! 7 | //! See the server startup in [`HttpServer`](crate::services::server::HttpServer) for where these 8 | //! middlewares are registered. 9 | 10 | mod cors; 11 | mod decompression; 12 | mod handle_panic; 13 | mod metrics; 14 | mod normalize_path; 15 | mod trace; 16 | 17 | mod body_timing; 18 | 19 | pub use self::body_timing::*; 20 | pub use self::cors::*; 21 | pub use self::decompression::*; 22 | pub use self::handle_panic::*; 23 | pub use self::metrics::*; 24 | pub use self::normalize_path::*; 25 | pub use self::trace::*; 26 | -------------------------------------------------------------------------------- /relay-server/src/middlewares/trace.rs: -------------------------------------------------------------------------------- 1 | use relay_log::Level; 2 | use tower_http::classify::{ServerErrorsAsFailures, SharedClassifier}; 3 | use tower_http::trace::{DefaultOnFailure, TraceLayer}; 4 | 5 | pub fn trace_http_layer() -> TraceLayer<SharedClassifier<ServerErrorsAsFailures>> { 6 | TraceLayer::new_for_http().on_failure(DefaultOnFailure::new().level(Level::DEBUG)) 7 | } 8 | -------------------------------------------------------------------------------- /relay-server/src/services/buffer/envelope_stack/memory.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | 3 | use chrono::{DateTime, Utc}; 4 | 5 | use crate::Envelope; 6 | 7 | use super::EnvelopeStack; 8 | 9 | #[derive(Debug)] 10 | pub struct MemoryEnvelopeStack(#[allow(clippy::vec_box)] Vec<Box<Envelope>>); 11 | 12 | impl MemoryEnvelopeStack { 13 | pub fn new() -> Self { 14 | Self(vec![]) 15 | } 16 | } 17 | 18 | impl EnvelopeStack for MemoryEnvelopeStack { 19 | type Error = Infallible; 20 | 21 | async fn push(&mut self, envelope: Box<Envelope>) -> Result<(), Self::Error> { 22 | self.0.push(envelope); 23 | Ok(()) 24 | } 25 | 26 | async fn peek(&mut self) -> Result<Option<DateTime<Utc>>, Self::Error> { 27 | Ok(self.0.last().map(|e| e.received_at())) 28 | } 29 | 30 | async fn pop(&mut self) -> Result<Option<Box<Envelope>>, Self::Error> { 31 | Ok(self.0.pop()) 32 | } 33 | 34 | async fn flush(self) {} 35 | } 36 | -------------------------------------------------------------------------------- /relay-server/src/services/buffer/envelope_stack/mod.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | use chrono::{DateTime, Utc}; 4 | 5 | use crate::envelope::Envelope; 6 | 7 | pub mod caching; 8 | pub mod memory; 9 | pub mod sqlite; 10 | 11 | /// A stack-like data structure that holds [`Envelope`]s. 12 | pub trait EnvelopeStack: Send + std::fmt::Debug { 13 | /// The error type that is returned when an error is encountered during reading or writing the 14 | /// [`EnvelopeStack`]. 15 | type Error: std::fmt::Debug + std::error::Error; 16 | 17 | /// Pushes an [`Envelope`] on top of the stack. 18 | fn push(&mut self, envelope: Box<Envelope>) -> impl Future<Output = Result<(), Self::Error>>; 19 | 20 | /// Peeks the [`Envelope`] on top of the stack. 21 | fn peek(&mut self) -> impl Future<Output = Result<Option<DateTime<Utc>>, Self::Error>>; 22 | 23 | /// Pops the [`Envelope`] on top of the stack. 24 | fn pop(&mut self) -> impl Future<Output = Result<Option<Box<Envelope>>, Self::Error>>; 25 | 26 | /// Persists all envelopes in the [`EnvelopeStack`]s to external storage, if possible, 27 | /// and consumes the stack provider. 28 | fn flush(self) -> impl Future<Output = ()>; 29 | } 30 | -------------------------------------------------------------------------------- /relay-server/src/services/buffer/envelope_store/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod sqlite; 2 | -------------------------------------------------------------------------------- /relay-server/src/services/metrics/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::aggregator::*; 2 | pub use self::router::*; 3 | 4 | mod aggregator; 5 | mod router; 6 | -------------------------------------------------------------------------------- /relay-server/src/services/processor/standalone.rs: -------------------------------------------------------------------------------- 1 | use crate::envelope::ItemType; 2 | use crate::services::processor::StandaloneGroup; 3 | use crate::utils::{ItemAction, TypedEnvelope}; 4 | 5 | /// Processes a standalone envelope by removing unnecessary items. 6 | /// 7 | /// This function removes form data items from the envelope since they are not allowed in 8 | /// standalone processing. 9 | pub fn process(managed_envelope: &mut TypedEnvelope<StandaloneGroup>) { 10 | managed_envelope.retain_items(|i| match i.ty() { 11 | ItemType::FormData => ItemAction::DropSilently, 12 | _ => ItemAction::Keep, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /relay-server/src/services/processor/transaction.rs: -------------------------------------------------------------------------------- 1 | //! Processing logic specific to transaction envelopes. 2 | 3 | use relay_dynamic_config::GlobalConfig; 4 | 5 | use crate::envelope::ItemType; 6 | use crate::services::outcome::{DiscardReason, Outcome}; 7 | use crate::utils::{ItemAction, ManagedEnvelope}; 8 | 9 | /// Drops attachments in transaction envelopes. 10 | pub fn drop_invalid_items(envelope: &mut ManagedEnvelope, global_config: &GlobalConfig) { 11 | if global_config.options.drop_transaction_attachments { 12 | envelope.retain_items(|item| match item.ty() { 13 | &ItemType::Attachment => { 14 | ItemAction::Drop(Outcome::Invalid(DiscardReason::TransactionAttachment)) 15 | } 16 | _ => ItemAction::Keep, 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /relay-server/src/services/projects/cache/mod.rs: -------------------------------------------------------------------------------- 1 | mod handle; 2 | mod project; 3 | mod service; 4 | mod state; 5 | 6 | pub use self::handle::ProjectCacheHandle; 7 | pub use self::project::{CheckedEnvelope, Project}; 8 | pub use self::service::{ProjectCache, ProjectCacheService, ProjectChange}; 9 | -------------------------------------------------------------------------------- /relay-server/src/services/projects/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cache; 2 | pub mod project; 3 | pub mod source; 4 | -------------------------------------------------------------------------------- /relay-server/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | mod api; 2 | mod dynamic_sampling; 3 | mod managed_envelope; 4 | mod multipart; 5 | mod param_parser; 6 | mod pick; 7 | mod rate_limits; 8 | mod retry; 9 | mod scheduled; 10 | mod sizes; 11 | mod sleep_handle; 12 | mod split_off; 13 | mod statsd; 14 | mod thread_pool; 15 | 16 | mod memory; 17 | #[cfg(feature = "processing")] 18 | mod native; 19 | mod serde; 20 | #[cfg(feature = "processing")] 21 | mod unreal; 22 | 23 | pub use self::api::*; 24 | pub use self::dynamic_sampling::*; 25 | pub use self::managed_envelope::*; 26 | pub use self::memory::*; 27 | pub use self::multipart::*; 28 | #[cfg(feature = "processing")] 29 | pub use self::native::*; 30 | pub use self::param_parser::*; 31 | pub use self::pick::*; 32 | pub use self::rate_limits::*; 33 | pub use self::retry::*; 34 | pub use self::scheduled::*; 35 | pub use self::serde::*; 36 | pub use self::sizes::*; 37 | pub use self::sleep_handle::*; 38 | pub use self::split_off::*; 39 | pub use self::statsd::*; 40 | pub use self::thread_pool::*; 41 | #[cfg(feature = "processing")] 42 | pub use self::unreal::*; 43 | -------------------------------------------------------------------------------- /relay-server/src/utils/scheduled/mod.rs: -------------------------------------------------------------------------------- 1 | mod futures; 2 | mod queue; 3 | 4 | pub use self::futures::FuturesScheduled; 5 | pub use self::queue::{ScheduledQueue, UniqueScheduledQueue}; 6 | -------------------------------------------------------------------------------- /relay-server/src/utils/serde.rs: -------------------------------------------------------------------------------- 1 | use serde::de::IgnoredAny; 2 | use serde::{Deserialize, Deserializer, de}; 3 | 4 | /// Deserializes only the count of a sequence ignoring all individual items. 5 | #[derive(Clone, Copy, Debug, Default)] 6 | pub struct SeqCount(pub usize); 7 | 8 | impl<'de> Deserialize<'de> for SeqCount { 9 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 10 | where 11 | D: Deserializer<'de>, 12 | { 13 | struct Visitor; 14 | 15 | impl<'a> de::Visitor<'a> for Visitor { 16 | type Value = SeqCount; 17 | 18 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 19 | formatter.write_str("a sequence") 20 | } 21 | 22 | fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> 23 | where 24 | A: de::SeqAccess<'a>, 25 | { 26 | let mut count = 0; 27 | while seq.next_element::<IgnoredAny>()?.is_some() { 28 | count += 1; 29 | } 30 | 31 | Ok(SeqCount(count)) 32 | } 33 | } 34 | 35 | deserializer.deserialize_seq(Visitor) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /relay-server/src/utils/snapshots/relay_server__utils__unreal__tests__merge_unreal_logs.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: relay-server/src/utils/unreal.rs 3 | expression: "Annotated::new(event).to_json_pretty().unwrap()" 4 | --- 5 | { 6 | "breadcrumbs": { 7 | "values": [ 8 | { 9 | "timestamp": 1540832198.0, 10 | "category": "LogGameplayTags", 11 | "message": "Display: UGameplayTagsManager::DoneAddingNativeTags. DelegateIsBound: 0" 12 | }, 13 | { 14 | "timestamp": 1540832199.0, 15 | "category": "LogStats", 16 | "message": "UGameplayTagsManager::ConstructGameplayTagTree: ImportINI prefixes - 0.000 s" 17 | }, 18 | { 19 | "timestamp": 1540832200.0, 20 | "category": "LogStats", 21 | "message": "UGameplayTagsManager::ConstructGameplayTagTree: Construct from data asset - 0.000 s" 22 | }, 23 | { 24 | "timestamp": 1540832201.0, 25 | "category": "LogStats", 26 | "message": "UGameplayTagsManager::ConstructGameplayTagTree: ImportINI - 0.000 s" 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /relay-spans/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-spans" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Event normalization and processing" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | chrono = { workspace = true } 17 | hex = { workspace = true } 18 | once_cell = { workspace = true } 19 | opentelemetry-proto = { workspace = true, features = [ 20 | "gen-tonic", 21 | "with-serde", 22 | "trace", 23 | ] } 24 | relay-event-schema = { workspace = true } 25 | relay-protocol = { workspace = true } 26 | serde_json = { workspace = true } 27 | 28 | [dev-dependencies] 29 | insta = { workspace = true } 30 | -------------------------------------------------------------------------------- /relay-spans/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Structs and functions needed to ingest OpenTelemetry spans. 2 | 3 | #![warn(missing_docs)] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png", 6 | html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png" 7 | )] 8 | 9 | pub use crate::otel_to_sentry::otel_to_sentry_span; 10 | pub use crate::v2_to_v1::span_v2_to_span_v1; 11 | 12 | pub use opentelemetry_proto::tonic::trace::v1 as otel_trace; 13 | 14 | mod otel_to_sentry; 15 | mod otel_to_sentry_v2; 16 | mod status_codes; 17 | mod v2_to_v1; 18 | -------------------------------------------------------------------------------- /relay-statsd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-statsd" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "High-level StatsD metric client for internal measurements" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | cadence = { workspace = true } 17 | crossbeam-channel = { workspace = true } 18 | parking_lot = { workspace = true } 19 | rand = { workspace = true } 20 | relay-log = { workspace = true } 21 | statsdproxy = { workspace = true, features = ["cadence"] } 22 | 23 | [features] 24 | default = [] 25 | test = [] 26 | -------------------------------------------------------------------------------- /relay-system/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-system" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Foundational system components for Relay's services" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [features] 16 | test = [] 17 | 18 | [dependencies] 19 | futures = { workspace = true } 20 | once_cell = { workspace = true } 21 | relay-log = { workspace = true } 22 | relay-statsd = { workspace = true } 23 | tokio = { workspace = true, features = ["rt", "signal", "macros", "sync", "time", "rt-multi-thread"] } 24 | pin-project-lite = { workspace = true } 25 | 26 | 27 | [dev-dependencies] 28 | insta = { workspace = true } 29 | relay-statsd = { workspace = true, features = ["test"] } 30 | tokio = { workspace = true, features = ["test-util"] } 31 | futures = { workspace = true, features = ["async-await"] } 32 | -------------------------------------------------------------------------------- /relay-system/src/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | mod handle; 2 | mod metrics; 3 | #[expect( 4 | clippy::module_inception, 5 | reason = "contains the Runtime struct, follows tokio" 6 | )] 7 | mod runtime; 8 | mod spawn; 9 | 10 | pub use self::handle::{Handle, ServiceSet}; 11 | pub use self::metrics::RuntimeMetrics; 12 | pub use self::runtime::{Builder, Runtime}; 13 | pub use self::spawn::{TaskId, spawn, spawn_in}; 14 | -------------------------------------------------------------------------------- /relay-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-test" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Test utilities for Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | relay-log = { workspace = true, features = ["test"] } 17 | relay-system = { workspace = true } 18 | tokio = { workspace = true } 19 | -------------------------------------------------------------------------------- /relay-threading/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-threading" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Threading code that is used by Relay" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [dependencies] 13 | flume = { workspace = true, features = ["async"] } 14 | futures = { workspace = true } 15 | tokio = { workspace = true } 16 | pin-project-lite = { workspace = true } 17 | 18 | relay-system = { workspace = true } 19 | 20 | [dev-dependencies] 21 | criterion = { workspace = true, features = ["async_tokio"] } 22 | futures = { workspace = true, features = ["executor"] } 23 | tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time", "sync", "macros"] } 24 | 25 | [[bench]] 26 | name = "pool" 27 | harness = false -------------------------------------------------------------------------------- /relay-ua/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-ua" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "User agent parser with built-in rules" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [lints] 13 | workspace = true 14 | 15 | [dependencies] 16 | once_cell = { workspace = true } 17 | uaparser = { workspace = true } 18 | 19 | [features] 20 | default = [] 21 | -------------------------------------------------------------------------------- /relay/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "The Relay binary, a proxy server for Sentry" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "25.5.1" 8 | edition = "2024" 9 | license-file = "../LICENSE.md" 10 | publish = false 11 | 12 | [features] 13 | default = [] 14 | processing = ["relay-server/processing", "dep:relay-kafka"] 15 | crash-handler = ["relay-log/crash-handler"] 16 | 17 | [lints] 18 | workspace = true 19 | 20 | # Direct dependencies of the main application in `src/` 21 | [dependencies] 22 | anyhow = { workspace = true } 23 | clap = { workspace = true, features = ["env", "wrap_help"] } 24 | clap_complete = { workspace = true } 25 | dialoguer = { workspace = true } 26 | hostname = { workspace = true } 27 | once_cell = { workspace = true } 28 | relay-config = { workspace = true } 29 | relay-log = { workspace = true, features = ["init"] } 30 | relay-server = { workspace = true } 31 | relay-statsd = { workspace = true } 32 | relay-kafka = { workspace = true, optional = true } 33 | uuid = { workspace = true } 34 | 35 | [target.'cfg(target_os = "linux")'.dependencies] 36 | tikv-jemallocator = { workspace = true, features = ["background_threads"] } 37 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | --index-url https://pypi.devinfra.sentry.io/simple 2 | 3 | # Dependencies and their versions must be listed in the Sentry package index. 4 | # See https://github.com/getsentry/pypi#readme 5 | 6 | black==24.3.0 7 | blinker==1.8.2 8 | click==8.1.7 9 | devservices==1.1.5 10 | flake8==7.0.0 11 | confluent-kafka==2.1.1 12 | flask==3.0.3 13 | msgpack==1.1.0 14 | opentelemetry-proto==1.32.1 15 | pytest-localserver==0.8.1 16 | pytest-sentry==0.3.0 17 | pytest-xdist==3.5.0 18 | pytest==7.4.3 19 | PyYAML==6.0.2 20 | redis==4.5.4 21 | requests==2.32.2 22 | sentry_sdk==2.10.0 23 | setuptools==70.0.0 24 | werkzeug==3.0.6 25 | zstandard==0.18.0 26 | sentry_protos==0.2.0 27 | 28 | # typing things 29 | mypy==1.10.0 30 | types-pyyaml==6.0.12.10 31 | types-redis==4.5.1.3 32 | types-requests==2.30.0.0 33 | types-setuptools==69.0.0.0 34 | types-protobuf==5.27.0.20240626 35 | -------------------------------------------------------------------------------- /scripts/bump-library.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | cd $SCRIPT_DIR/.. 6 | 7 | OLD_VERSION="${1}" 8 | NEW_VERSION="${2}" 9 | 10 | echo "Current version: ${OLD_VERSION}" 11 | echo "Bumping version: ${NEW_VERSION}" 12 | 13 | perl -pi -e "s/^version = .*\$/version = \"$NEW_VERSION\"/" relay-cabi/Cargo.toml 14 | 15 | cargo update -p relay-cabi 16 | -------------------------------------------------------------------------------- /scripts/bump-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | if [ "$(uname -s)" != "Linux" ]; then 5 | echo "Relay can only be released on Linux!" 6 | echo "Please use the GitHub Action instead." 7 | exit 1 8 | fi 9 | 10 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 11 | cd $SCRIPT_DIR/.. 12 | 13 | OLD_VERSION="${1}" 14 | NEW_VERSION="${2}" 15 | 16 | echo "Current version: ${OLD_VERSION}" 17 | echo "Bumping version: ${NEW_VERSION}" 18 | 19 | TOML_FILES="$(git ls-files 'relay*/Cargo.toml' | grep -v cabi)" 20 | perl -pi -e "s/^version = .*\$/version = \"$NEW_VERSION\"/" $TOML_FILES 21 | 22 | cargo update -p relay 23 | -------------------------------------------------------------------------------- /scripts/docker-manylinux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | if [ -z "$TARGET" ]; then 5 | echo "TARGET is not set" 6 | exit 1 7 | fi 8 | 9 | TARGET_LINKER="CARGO_TARGET_$(echo $TARGET | tr '[:lower:]' '[:upper:]')_UNKNOWN_LINUX_GNU_LINKER" 10 | 11 | # Build docker image with all dependencies for cross compilation 12 | BUILDER_NAME="${BUILDER_NAME:-relay-cabi-builder-${TARGET}}" 13 | docker build --build-arg TARGET=${TARGET} -t ${BUILDER_NAME} py/ 14 | 15 | # run the cross compilation 16 | docker run \ 17 | --rm \ 18 | -w "/work" \ 19 | -v "$(pwd):/work" \ 20 | -e $TARGET_LINKER \ 21 | -e CARGO_BUILD_TARGET \ 22 | ${BUILDER_NAME} \ 23 | bash -c 'cargo build -p relay-cabi --profile release-cabi' 24 | 25 | # create a wheel for the correct architecture 26 | docker run \ 27 | --rm \ 28 | -w /work/py \ 29 | -v "$(pwd):/work" \ 30 | -e SKIP_RELAY_LIB_BUILD=1 \ 31 | -e CARGO_BUILD_TARGET \ 32 | quay.io/pypa/manylinux_2_28_${TARGET} \ 33 | sh manylinux.sh 34 | 35 | # Fix permissions for shared directories 36 | USER_ID=$(id -u) 37 | GROUP_ID=$(id -g) 38 | sudo chown -R ${USER_ID}:${GROUP_ID} target/ 39 | -------------------------------------------------------------------------------- /scripts/get-sentry-release-name: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script: get the Sentry release name (e.g. "relay@1.0.0+1234abcd...") 4 | # 5 | # Positional arguments: 6 | # $1: Release version (commit SHA) 7 | # $2: Name of the release (default: relay) 8 | set -eu 9 | 10 | REVISION="${1:-}" 11 | NAME="${2:-relay}" 12 | 13 | if [ -z "${REVISION}" ]; then 14 | echo 'No revision specified' && exit 1 15 | fi 16 | 17 | # Don't fail if the release name doesn't exist (e.g. if the release hasn't been created yet) 18 | RELEASE=$(gsutil cat "gs://dicd-team-devinfra-cd--relay/deployment-assets/${REVISION}/${NAME}/release-name") || true 19 | 20 | echo "${RELEASE}" 21 | -------------------------------------------------------------------------------- /tests/fixtures/GeoIP2-Enterprise-Test.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/fixtures/GeoIP2-Enterprise-Test.mmdb -------------------------------------------------------------------------------- /tests/fixtures/basic-event-input.json: -------------------------------------------------------------------------------- 1 | {"message": "Hello World!", "fingerprint":[42]} 2 | -------------------------------------------------------------------------------- /tests/fixtures/basic-event-output.json: -------------------------------------------------------------------------------- 1 | {"fingerprint":["42"],"logentry":{"formatted":"Hello World!"}} 2 | -------------------------------------------------------------------------------- /tests/fixtures/linux.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/fixtures/linux.dmp -------------------------------------------------------------------------------- /tests/fixtures/macos.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/fixtures/macos.dmp -------------------------------------------------------------------------------- /tests/fixtures/replay_missing_user.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "replay_event", 3 | "replay_id": "d2132d31b39445f1938d7e21b6bf0ec4", 4 | "event_id": "123", 5 | "segment_id": 0, 6 | "timestamp": 1597977777.6189718, 7 | "replay_start_timestamp": 1597976392.6542819, 8 | "urls": [ 9 | "sentry.io" 10 | ], 11 | "error_ids": [ 12 | "1", 13 | "2" 14 | ], 15 | "trace_ids": [ 16 | "3", 17 | "4" 18 | ], 19 | "dist": "1.12", 20 | "platform": "javascript", 21 | "environment": "production", 22 | "release": "version@1.3", 23 | "tags": { 24 | "transaction": "/organizations/:orgId/performance/:eventSlug/" 25 | }, 26 | "sdk": { 27 | "name": "name", 28 | "version": "veresion" 29 | }, 30 | "request": { 31 | "url": null, 32 | "headers": { 33 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15" 34 | } 35 | }, 36 | "contexts": { 37 | "trace": { 38 | "trace_id": "4C79F60C11214EB38604F4AE0781BFB2", 39 | "span_id": "FA90FDEAD5F74052", 40 | "type": "trace" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/replay_no_requests.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "replay_event", 3 | "replay_id": "d2132d31b39445f1938d7e21b6bf0ec4", 4 | "event_id": "123", 5 | "segment_id": 0, 6 | "timestamp": 1597977777.6189718, 7 | "replay_start_timestamp": 1597976392.6542819, 8 | "urls": [ 9 | "sentry.io" 10 | ], 11 | "error_ids": [ 12 | "1", 13 | "2" 14 | ], 15 | "trace_ids": [ 16 | "3", 17 | "4" 18 | ], 19 | "dist": "1.12", 20 | "platform": "Python", 21 | "environment": "production", 22 | "release": "version@1.3", 23 | "tags": { 24 | "transaction": "/organizations/:orgId/performance/:eventSlug/" 25 | }, 26 | "sdk": { 27 | "name": "name", 28 | "version": "veresion" 29 | }, 30 | "user": { 31 | "id": "123", 32 | "username": "user", 33 | "email": "user@site.com", 34 | "ip_address": "192.168.11.12" 35 | }, 36 | "contexts": { 37 | "trace": { 38 | "trace_id": "4C79F60C11214EB38604F4AE0781BFB2", 39 | "span_id": "FA90FDEAD5F74052", 40 | "type": "trace" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/fixtures/windows.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/fixtures/windows.dmp -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/integration/asserts/__init__.py: -------------------------------------------------------------------------------- 1 | from .time import time_after, time_within, time_within_delta 2 | 3 | __all__ = ["time_after", "time_within", "time_within_delta"] 4 | -------------------------------------------------------------------------------- /tests/integration/consts.py: -------------------------------------------------------------------------------- 1 | # Minimum supported version for metric transaction by Relay. 2 | TRANSACTION_EXTRACT_MIN_SUPPORTED_VERSION = 3 3 | # Minimum supported version for generic metrics extraction by Relay. 4 | METRICS_EXTRACTION_MIN_SUPPORTED_VERSION = 4 5 | # Maximum supported version for metric transaction by Relay. 6 | TRANSACTION_EXTRACT_MAX_SUPPORTED_VERSION = 6 7 | -------------------------------------------------------------------------------- /tests/integration/fixtures/10GB.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/10GB.gz -------------------------------------------------------------------------------- /tests/integration/fixtures/native/.gitattributes: -------------------------------------------------------------------------------- 1 | *.dmp binary 2 | unreal_crash binary 3 | unreal_crash_apple binary 4 | -------------------------------------------------------------------------------- /tests/integration/fixtures/native/annotations.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/annotations.dmp -------------------------------------------------------------------------------- /tests/integration/fixtures/native/bad_electron_simple.dmp: -------------------------------------------------------------------------------- 1 | --0eede1e790b8498a 2 | Content-Disposition: form-data; name="pid" 3 | 4 | 22385 5 | --0eede1e790b8498a 6 | Content-Disposition: form-data; name="platform" 7 | 8 | linux 9 | --0eede1e790b8498a 10 | Content-Disposition: form-data; name="process_type" 11 | 12 | browser 13 | --0eede1e790b8498a 14 | Content-Disposition: form-data; name="upload_file_minidump"; filename="dump" 15 | Content-Type: application/octet-stream 16 | 17 | BAD_START_MDMP00000-317792f80000 rw-p 00000000 00:00 0 18 | --0eede1e790b8498a-- 19 | -------------------------------------------------------------------------------- /tests/integration/fixtures/native/electron.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/electron.dmp -------------------------------------------------------------------------------- /tests/integration/fixtures/native/electron_simple.dmp: -------------------------------------------------------------------------------- 1 | --0eede1e790b8498a 2 | Content-Disposition: form-data; name="pid" 3 | 4 | 22385 5 | --0eede1e790b8498a 6 | Content-Disposition: form-data; name="platform" 7 | 8 | linux 9 | --0eede1e790b8498a 10 | Content-Disposition: form-data; name="process_type" 11 | 12 | browser 13 | --0eede1e790b8498a 14 | Content-Disposition: form-data; name="upload_file_minidump"; filename="dump" 15 | Content-Type: application/octet-stream 16 | 17 | MDMP00000-317792f80000 rw-p 00000000 00:00 0 18 | --0eede1e790b8498a-- 19 | -------------------------------------------------------------------------------- /tests/integration/fixtures/native/minidump.dmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/minidump.dmp -------------------------------------------------------------------------------- /tests/integration/fixtures/native/minidump.dmp.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/minidump.dmp.bz2 -------------------------------------------------------------------------------- /tests/integration/fixtures/native/minidump.dmp.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/minidump.dmp.gz -------------------------------------------------------------------------------- /tests/integration/fixtures/native/minidump.dmp.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/minidump.dmp.xz -------------------------------------------------------------------------------- /tests/integration/fixtures/native/minidump.dmp.zst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/minidump.dmp.zst -------------------------------------------------------------------------------- /tests/integration/fixtures/native/nnswitch_dying_message_zstandard.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/nnswitch_dying_message_zstandard.dat -------------------------------------------------------------------------------- /tests/integration/fixtures/native/playstation.prosperodmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/playstation.prosperodmp -------------------------------------------------------------------------------- /tests/integration/fixtures/native/unreal_crash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/unreal_crash -------------------------------------------------------------------------------- /tests/integration/fixtures/native/unreal_crash_apple: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/unreal_crash_apple -------------------------------------------------------------------------------- /tests/integration/fixtures/native/unreal_crash_with_config: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/unreal_crash_with_config -------------------------------------------------------------------------------- /tests/integration/fixtures/native/user_data.prosperodmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/relay/7f4b354ebb99286dd20ee34c1da4540f7e1135bd/tests/integration/fixtures/native/user_data.prosperodmp -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/csp.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "csp-report": { 3 | "document-uri": "https://example.com/foo/bar", 4 | "referrer": "https://www.google.com/", 5 | "violated-directive": "default-src self", 6 | "original-policy": "default-src self; report-uri /csp-hotline.php", 7 | "blocked-uri": "http://evilhackerscripts.com" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/csp_chrome.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "csp-report": { 3 | "document-uri": "http://localhost:8000/", 4 | "referrer": "", 5 | "violated-directive": "style-src cdn.example.com", 6 | "effective-directive": "style-src", 7 | "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri http://requestb.in/1im8m061", 8 | "blocked-uri": "http://localhost:8000/lol.css", 9 | "status-code": 200 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/csp_chrome_blocked_asset.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "csp-report": { 3 | "document-uri": "http://notlocalhost:8000/", 4 | "referrer": "", 5 | "violated-directive": "style-src cdn.example.com", 6 | "effective-directive": "style-src", 7 | "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri http://requestb.in/1im8m061", 8 | "blocked-uri": "http://notlocalhost:8000/lol.css", 9 | "status-code": 200 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/csp_firefox_blocked_asset.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "csp-report": { 3 | "blocked-uri": "http://notlocalhost:8000/lol.css", 4 | "document-uri": "http://notlocalhost:8000/", 5 | "original-policy": "default-src 'none'; style-src http://cdn.example.com; report-uri http://requestb.in/1im8m061", 6 | "referrer": "", 7 | "violated-directive": "style-src http://cdn.example.com" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/expect_ct.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "expect-ct-report": { 3 | "date-time": "2014-04-06T13:00:50Z", 4 | "hostname": "www.example.com", 5 | "port": 443, 6 | "effective-expiration-date": "2014-05-01T12:40:50Z", 7 | "served-certificate-chain": [ 8 | "-----BEGIN CERTIFICATE-----\nABC\n-----END CERTIFICATE-----" 9 | ], 10 | "validated-certificate-chain": [ 11 | "-----BEGIN CERTIFICATE-----\nCDE\n-----END CERTIFICATE-----" 12 | ], 13 | "scts": [ 14 | { 15 | "version": 1, 16 | "status": "invalid", 17 | "source": "embedded", 18 | "serialized_sct": "ABCD==" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/expect_staple.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "expect-staple-report": { 3 | "date-time": "2014-04-06T13:00:50Z", 4 | "hostname": "www.example.com", 5 | "port": 443, 6 | "response-status": "ERROR_RESPONSE", 7 | "cert-status": "REVOKED", 8 | "effective-expiration-date": "2014-05-01T12:40:50Z", 9 | "served-certificate-chain": [ 10 | "-----BEGIN CERTIFICATE-----\nABC\n-----END CERTIFICATE-----" 11 | ], 12 | "validated-certificate-chain": [ 13 | "-----BEGIN CERTIFICATE-----\nCDE\n-----END CERTIFICATE-----" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/integration/fixtures/security_report/hpkp.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "date-time": "2014-04-06T13:00:50Z", 3 | "hostname": "www.example.com", 4 | "port": 443, 5 | "effective-expiration-date": "2014-05-01T12:40:50Z", 6 | "include-subdomains": false, 7 | "served-certificate-chain": [ 8 | "-----BEGIN CERTIFICATE-----\n MIIEBDCCAuygBQUAMEIxCzAJBgNVBAYTAlVT\n -----END CERTIFICATE-----" 9 | ], 10 | "validated-certificate-chain": [ 11 | "-----BEGIN CERTIFICATE-----\n MIIEBDCCAuygAwIBAgIDCzAJBgNVBAYTAlVT\n -----END CERTIFICATE-----" 12 | ], 13 | "known-pins": [ 14 | "pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"", 15 | "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tests/integration/test_ingest_path.py: -------------------------------------------------------------------------------- 1 | def test_ingest_path(mini_sentry, relay, relay_with_processing, latest_relay_version): 2 | internal_relay = relay_with_processing() 3 | internal_keys = list(internal_relay.iter_public_keys()) 4 | relay = relay(relay(relay(mini_sentry))) 5 | project_id = 42 6 | project_config = mini_sentry.add_basic_project_config(project_id) 7 | external_keys = [ 8 | key for key in relay.iter_public_keys() if key not in internal_keys 9 | ] 10 | project_config["config"]["trustedRelays"] = list(external_keys) 11 | 12 | relay.send_event(project_id) 13 | event = mini_sentry.captured_events.get(timeout=1).get_event() 14 | assert event["ingest_path"] == [ 15 | {"version": latest_relay_version, "public_key": key} for key in external_keys 16 | ] 17 | -------------------------------------------------------------------------------- /tests/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --tb=native --durations 5 -ra 3 | markers = 4 | extra_failure_checks: Marker which can add additional failure checks to 5 | a test. It accepts the keyword argument `checks` which should be a 6 | list of functions to call after the test finished executing. These 7 | functions can fail the test by calling `pytest.fail()`. 8 | -------------------------------------------------------------------------------- /tests/test_pii_docs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_pii_docs" 3 | version = "0.1.0" 4 | edition = "2024" 5 | -------------------------------------------------------------------------------- /tests/test_pii_docs/src/anothermod.rs: -------------------------------------------------------------------------------- 1 | pub struct FooBar { 2 | #[metastructure(pii = "false")] 3 | not_sensitive: u32, 4 | } 5 | 6 | pub struct BarFoo; 7 | 8 | pub struct WeirdTypes<'a> { 9 | reference: &'a WeirdType, 10 | tuple: (WeirdType, u32), 11 | ptr: *const WeirdType, 12 | slice: [WeirdType], 13 | func: fn(WeirdType), 14 | } 15 | 16 | pub struct WeirdType { 17 | #[metastructure(pii = "true")] 18 | pii_true: u32, 19 | } 20 | 21 | pub struct TruthTableTest { 22 | #[metastructure(pii = "truth_table_test", retain = "true", additional_properties)] 23 | foo: u32, 24 | #[metastructure(pii = "truth_table_test", additional_properties)] 25 | bar: u32, 26 | #[metastructure(pii = "truth_table_test", retain = "true")] 27 | baz: u32, 28 | #[metastructure(pii = "truth_table_test")] 29 | qux: u32, 30 | } 31 | -------------------------------------------------------------------------------- /tests/test_pii_docs/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | 5 | pub mod anothermod; 6 | 7 | use crate::anothermod::{BarFoo, FooBar, WeirdTypes}; 8 | 9 | struct MyStruct { 10 | #[metastructure(foo = "bar", pii = "true")] 11 | foo: String, 12 | sub_struct: SubStruct, 13 | } 14 | 15 | struct SubStruct { 16 | field1: String, 17 | #[metastructure(pii = "true")] 18 | field2: FooBar, 19 | // Checks that it goes spearately into both HasGeneric and InnerGeneric to check for pii fields. 20 | mystery_field: HasGeneric<InnerGeneric>, 21 | } 22 | 23 | struct HasGeneric<T> { 24 | inner_generic: T, 25 | #[metastructure(pii = "maybe", apple = "oranges")] 26 | maybe_sensitive_stuff: u32, 27 | } 28 | 29 | struct InnerGeneric { 30 | #[metastructure(pii = "true")] 31 | bitcoin_wallet_key: String, 32 | } 33 | 34 | struct SelfReferential { 35 | #[metastructure(pii = "true")] 36 | pretty_sensitive: String, 37 | // Tests that it doesn't get stuck in an infinite loop. 38 | oh_no_its_self_referential: Box<SelfReferential>, 39 | } 40 | -------------------------------------------------------------------------------- /tools/bench-buffer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bench-buffer" 3 | version = "0.1.0" 4 | authors = ["Sentry <oss@sentry.io>"] 5 | description = "Generates documentation for metrics" 6 | homepage = "https://getsentry.github.io/relay/" 7 | repository = "https://github.com/getsentry/relay" 8 | edition = "2024" 9 | publish = false 10 | 11 | [dependencies] 12 | bytes = { workspace = true } 13 | clap = { workspace = true, features = ["derive"] } 14 | rand = { workspace = true } 15 | relay-config = { path = "../../relay-config" } 16 | relay-log = { path = "../../relay-log" } 17 | relay-server = { path = "../../relay-server" } 18 | serde_json = { workspace = true } 19 | tempfile = { workspace = true } 20 | tokio = { workspace = true } 21 | chrono = { workspace = true } 22 | -------------------------------------------------------------------------------- /tools/document-metrics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "document-metrics" 3 | version = "0.1.0" 4 | authors = ["Sentry <oss@sentry.io>"] 5 | description = "Generates documentation for metrics" 6 | homepage = "https://getsentry.github.io/relay/" 7 | repository = "https://github.com/getsentry/relay" 8 | edition = "2024" 9 | publish = false 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = ["derive"] } 14 | serde = { workspace = true } 15 | serde_json = { workspace = true } 16 | serde_yaml = { workspace = true } 17 | syn = { workspace = true, features = ["full"] } 18 | 19 | [dev-dependencies] 20 | insta = { workspace = true } 21 | -------------------------------------------------------------------------------- /tools/document-pii/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "document-pii" 3 | version = "0.1.0" 4 | authors = ["Sentry <oss@sentry.io>"] 5 | description = "Generates documentation for which fields are datascrubbed" 6 | homepage = "https://getsentry.github.io/relay/" 7 | repository = "https://github.com/getsentry/relay" 8 | edition = "2024" 9 | publish = false 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = ["derive"] } 14 | path-slash = { workspace = true } 15 | proc-macro2 = { workspace = true } 16 | quote = { workspace = true } 17 | serde = { workspace = true } 18 | serde_json = { workspace = true } 19 | syn = { workspace = true, features = ["visit", "full", "extra-traits"] } 20 | walkdir = { workspace = true } 21 | 22 | [dev-dependencies] 23 | insta = { workspace = true } 24 | -------------------------------------------------------------------------------- /tools/document-pii/src/snapshots/document_pii__tests__find_rs_files.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tools/document-pii/src/main.rs 3 | expression: rust_file_paths 4 | --- 5 | [ 6 | "../../tests/test_pii_docs/src/anothermod.rs", 7 | "../../tests/test_pii_docs/src/main.rs", 8 | ] 9 | -------------------------------------------------------------------------------- /tools/document-pii/src/snapshots/document_pii__tests__pii_false.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tools/document-pii/src/main.rs 3 | expression: output 4 | --- 5 | [ 6 | Output { 7 | path: "FooBar.not_sensitive", 8 | additional_properties: false, 9 | }, 10 | ] 11 | -------------------------------------------------------------------------------- /tools/document-pii/src/snapshots/document_pii__tests__pii_retain_additional_properties_truth_table.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tools/document-pii/src/main.rs 3 | expression: output 4 | --- 5 | [ 6 | Output { 7 | path: "TruthTableTest", 8 | additional_properties: true, 9 | }, 10 | Output { 11 | path: "TruthTableTest.baz", 12 | additional_properties: false, 13 | }, 14 | Output { 15 | path: "TruthTableTest.qux", 16 | additional_properties: false, 17 | }, 18 | ] 19 | -------------------------------------------------------------------------------- /tools/document-pii/src/snapshots/document_pii__tests__scoped_paths.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tools/document-pii/src/main.rs 3 | expression: scoped_paths 4 | --- 5 | { 6 | "test_pii_docs": { 7 | "test_pii_docs::HasGeneric", 8 | "test_pii_docs::InnerGeneric", 9 | "test_pii_docs::MyStruct", 10 | "test_pii_docs::SelfReferential", 11 | "test_pii_docs::SubStruct", 12 | }, 13 | "test_pii_docs::anothermod": { 14 | "test_pii_docs::anothermod::BarFoo", 15 | "test_pii_docs::anothermod::FooBar", 16 | "test_pii_docs::anothermod::TruthTableTest", 17 | "test_pii_docs::anothermod::WeirdType", 18 | "test_pii_docs::anothermod::WeirdTypes", 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /tools/document-pii/src/snapshots/document_pii__tests__single_type.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tools/document-pii/src/main.rs 3 | expression: output 4 | --- 5 | [ 6 | Output { 7 | path: "SubStruct.field2", 8 | additional_properties: false, 9 | }, 10 | Output { 11 | path: "SubStruct.mystery_field.bitcoin_wallet_key", 12 | additional_properties: false, 13 | }, 14 | ] 15 | -------------------------------------------------------------------------------- /tools/process-event/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "process-event" 3 | version = "0.1.0" 4 | authors = ["Sentry <oss@sentry.io>"] 5 | description = "Process a Sentry event payload" 6 | homepage = "https://getsentry.github.io/relay/" 7 | repository = "https://github.com/getsentry/relay" 8 | edition = "2024" 9 | publish = false 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | anyhow = { workspace = true } 15 | clap = { workspace = true, features = ["derive"] } 16 | relay-event-schema = { workspace = true } 17 | relay-pii = { workspace = true } 18 | relay-protocol = { workspace = true } 19 | relay-event-normalization = { workspace = true } 20 | serde_json = { workspace = true } 21 | -------------------------------------------------------------------------------- /tools/scrub-minidump/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scrub-minidump" 3 | authors = ["Sentry <oss@sentry.io>"] 4 | description = "Scrubs PII from a Minidump file" 5 | homepage = "https://getsentry.github.io/relay/" 6 | repository = "https://github.com/getsentry/relay" 7 | version = "20.8.0" 8 | edition = "2024" 9 | publish = false 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | clap = { workspace = true, features = ["derive"] } 14 | relay-pii = { workspace = true } 15 | serde_json = { workspace = true } 16 | --------------------------------------------------------------------------------