├── .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 |
5 |
6 |
7 |
8 |
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 ",
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 "]
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 "]
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::()
31 | .unwrap_or_default()
32 | .into()
33 | }
34 |
--------------------------------------------------------------------------------
/relay-cardinality/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "relay-cardinality"
3 | authors = ["Sentry "]
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 = std::result::Result;
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;
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 "]
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>>);
8 |
9 | impl TestRecorder {
10 | /// Returns the recorded measurements.
11 | pub fn measurements(&self) -> Vec {
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 "]
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 "]
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 "]
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 "]
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
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 "]
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(&self, f: F) -> syn::Result
7 | where
8 | F: FnMut(&VariantInfo<'_>) -> syn::Result,
9 | R: ToTokens;
10 | }
11 |
12 | impl SynstructureExt for Structure<'_> {
13 | fn try_each_variant(&self, mut f: F) -> syn::Result
14 | where
15 | F: FnMut(&VariantInfo<'_>) -> syn::Result,
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 = 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,
11 |
12 | /// Public key of the Relay.
13 | #[metastructure(required = false, max_chars = 256, max_chars_allowance = 20)]
14 | pub public_key: Annotated,
15 |
16 | /// Additional arbitrary fields for forwards compatibility.
17 | #[metastructure(additional_properties)]
18 | pub other: Object,
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
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 "]
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 "]
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 "]
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 "]
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 "]
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 "]
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 "]
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 "]
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
6 | #[derive(Default, Debug, Serialize, Deserialize, Clone)]
7 | pub struct DebugMeta {
8 | pub(crate) images: Vec,
9 | }
10 |
11 | /// This is a serde-friendly version of
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 "]
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 "]
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(&self, f: F) -> syn::Result
7 | where
8 | F: FnMut(&VariantInfo<'_>) -> syn::Result,
9 | R: ToTokens;
10 | }
11 |
12 | impl SynstructureExt for Structure<'_> {
13 | fn try_each_variant(&self, mut f: F) -> syn::Result
14 | where
15 | F: FnMut(&VariantInfo<'_>) -> syn::Result,
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 "]
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 "]
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 "]
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 "]
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 "]
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) -> 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,
16 | ) -> Result {
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) -> 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 for RawContentType {
18 | fn as_ref(&self) -> &str {
19 | &self.0
20 | }
21 | }
22 |
23 | impl FromRequestParts for RawContentType {
24 | type Rejection = Infallible;
25 |
26 | async fn from_request_parts(parts: &mut Parts, _: &S) -> Result {
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);
11 |
12 | impl ReceivedAt {
13 | pub fn now() -> Self {
14 | Self(Utc::now())
15 | }
16 | }
17 |
18 | impl FromRequestParts 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 {
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) -> Response {
11 | let detail = if let Some(s) = err.downcast_ref::() {
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> {
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>);
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) -> Result<(), Self::Error> {
22 | self.0.push(envelope);
23 | Ok(())
24 | }
25 |
26 | async fn peek(&mut self) -> Result