|
@@ -0,0 +1,194 @@
|
|
|
+import {Outcome} from 'sentry/types';
|
|
|
+
|
|
|
+// List of Relay's current invalid reasons - https://github.com/getsentry/relay/blob/89a8dd7caaad1f126e1cacced0d73bb50fcd4f5a/relay-server/src/services/outcome.rs#L333
|
|
|
+enum DiscardReason {
|
|
|
+ DUPLICATE = 'duplicate',
|
|
|
+ PROJECT_ID = 'project_id',
|
|
|
+ AUTH_VERSION = 'auth_version',
|
|
|
+ AUTH_CLIENT = 'auth_client',
|
|
|
+ NO_DATA = 'no_data',
|
|
|
+ DISALLOWED_METHOD = 'disallowed_method',
|
|
|
+ CONTENT_TYPE = 'content_type',
|
|
|
+ INVALID_MULTIPART = 'invalid_multipart',
|
|
|
+ INVALID_MSGPACK = 'invalid_msgpack',
|
|
|
+ INVALID_JSON = 'invalid_json',
|
|
|
+ INVALID_ENVELOPE = 'invalid_envelope',
|
|
|
+ TIMESTAMP = 'timestamp',
|
|
|
+ DUPLICATE_ITEM = 'duplicate_item',
|
|
|
+ INVALID_TRANSACTION = 'invalid_transaction',
|
|
|
+ INVALID_SPAN = 'invalid_span',
|
|
|
+ INVALID_REPLAY = 'invalid_replay',
|
|
|
+ INVALID_REPLAY_RECORDING = 'invalid_replay_recording',
|
|
|
+ INVALID_REPLAY_VIDEO = 'invalid_replay_video',
|
|
|
+ PAYLOAD = 'payload',
|
|
|
+ INVALID_COMPRESSION = 'invalid_compression',
|
|
|
+ TOO_LARGE = 'too_large',
|
|
|
+ MISSING_MINIDUMP_UPLOAD = 'missing_minidump_upload',
|
|
|
+ INVALID_MINIDUMP = 'invalid_minidump',
|
|
|
+ SECURITY_REPORT = 'security_report',
|
|
|
+ SECURITY_REPORT_TYPE = 'security_report_type',
|
|
|
+ PROCESS_UNREAL = 'process_unreal',
|
|
|
+ CORS = 'cors',
|
|
|
+ NO_EVENT_PAYLOAD = 'no_event_payload',
|
|
|
+ EMPTY_ENVELOPE = 'empty_envelope',
|
|
|
+ INVALID_REPLAY_NO_PAYLOAD = 'invalid_replay_no_payload',
|
|
|
+ TRANSACTION_SAMPLED = 'transaction_sampled',
|
|
|
+ INTERNAL = 'internal',
|
|
|
+ MULTI_PROJECT_ID = 'multi_project_id',
|
|
|
+ PROJECT_STATE = 'project_state',
|
|
|
+ PROJECT_STATE_PII = 'project_state_pii',
|
|
|
+ INVALID_REPLAY_PII_SCRUBBER_FAILED = 'invalid_replay_pii_scrubber_failed',
|
|
|
+ FEATURE_DISABLED = 'feature_disabled',
|
|
|
+}
|
|
|
+
|
|
|
+// List of Relay's current filtered reasons - https://github.com/getsentry/relay/blob/ce5520b4a3bea022808982a52a66bfddacc70ac0/relay-filter/src/common.rs#L11
|
|
|
+enum FilteredReason {
|
|
|
+ BROWSER_EXTENSION = 'browser-extensions',
|
|
|
+ DENIED_NAME = 'denied-name',
|
|
|
+ DISABLED_NAMESPACE = 'disabled-namespace',
|
|
|
+ ERROR_MESSAGE = 'error-message',
|
|
|
+ FILTERED_TRANSACTION = 'filtered-transaction',
|
|
|
+ INVALID_CSP = 'invalid-csp',
|
|
|
+ IP_ADDRESS = 'ip-address',
|
|
|
+ LEGACY_BROWSER = 'legacy-browsers',
|
|
|
+ LOCALHOST = 'localhost',
|
|
|
+ RELEASE_VERSION = 'release-version',
|
|
|
+ WEB_CRAWLER = 'web-crawlers',
|
|
|
+}
|
|
|
+
|
|
|
+// List of Client Discard Reason according to the Client Report's doc - https://develop.sentry.dev/sdk/client-reports/#envelope-item-payload
|
|
|
+enum ClientDiscardReason {
|
|
|
+ QUEUE_OVERFLOW = 'queue_overflow',
|
|
|
+ CACHE_OVERFLOW = 'cache_overflow',
|
|
|
+ RATELIMIT_BACKOFF = 'ratelimit_backoff',
|
|
|
+ NETWORK_ERROR = 'network_error',
|
|
|
+ SAMPLE_RATE = 'sample_rate',
|
|
|
+ BEFORE_SEND = 'before_send',
|
|
|
+ EVENT_PROCESSSOR = 'event_processor',
|
|
|
+ SEND_ERROR = 'send_error',
|
|
|
+ INTERNAL_SDK_ERROR = 'internal_sdk_error',
|
|
|
+ INSUFFICIENT_DATA = 'insufficient_data',
|
|
|
+ BACKPRESSURE = 'backpressure',
|
|
|
+}
|
|
|
+
|
|
|
+enum RateLimitedReason {
|
|
|
+ KEY_QUOTA = 'key_quota',
|
|
|
+ SPIKE_PROTECTION = 'spike_protection',
|
|
|
+ SMART_RATE_LIMIT = 'smart_rate_limit',
|
|
|
+}
|
|
|
+
|
|
|
+// Invalid reasons should not be exposed directly, but instead in the following groups:
|
|
|
+const invalidReasonsGroup: Record<string, DiscardReason[]> = {
|
|
|
+ duplicate: [DiscardReason.DUPLICATE],
|
|
|
+ project_missing: [DiscardReason.PROJECT_ID],
|
|
|
+ invalid_request: [
|
|
|
+ DiscardReason.AUTH_VERSION,
|
|
|
+ DiscardReason.AUTH_CLIENT,
|
|
|
+ DiscardReason.NO_DATA,
|
|
|
+ DiscardReason.DISALLOWED_METHOD,
|
|
|
+ DiscardReason.CONTENT_TYPE,
|
|
|
+ DiscardReason.INVALID_MULTIPART,
|
|
|
+ DiscardReason.INVALID_MSGPACK,
|
|
|
+ DiscardReason.INVALID_JSON,
|
|
|
+ DiscardReason.INVALID_ENVELOPE,
|
|
|
+ DiscardReason.TIMESTAMP,
|
|
|
+ DiscardReason.DUPLICATE_ITEM,
|
|
|
+ ],
|
|
|
+ invalid_data: [
|
|
|
+ DiscardReason.INVALID_TRANSACTION,
|
|
|
+ DiscardReason.INVALID_SPAN,
|
|
|
+ DiscardReason.INVALID_REPLAY,
|
|
|
+ DiscardReason.INVALID_REPLAY_RECORDING,
|
|
|
+ DiscardReason.INVALID_REPLAY_VIDEO,
|
|
|
+ ],
|
|
|
+ payload: [DiscardReason.PAYLOAD, DiscardReason.INVALID_COMPRESSION],
|
|
|
+ too_large: [DiscardReason.TOO_LARGE],
|
|
|
+ minidump: [DiscardReason.MISSING_MINIDUMP_UPLOAD, DiscardReason.INVALID_MINIDUMP],
|
|
|
+ security_report: [DiscardReason.SECURITY_REPORT, DiscardReason.SECURITY_REPORT_TYPE],
|
|
|
+ unreal: [DiscardReason.PROCESS_UNREAL],
|
|
|
+ cors: [DiscardReason.CORS],
|
|
|
+ empty: [
|
|
|
+ DiscardReason.NO_EVENT_PAYLOAD,
|
|
|
+ DiscardReason.EMPTY_ENVELOPE,
|
|
|
+ DiscardReason.INVALID_REPLAY_NO_PAYLOAD,
|
|
|
+ ],
|
|
|
+ sampling: [DiscardReason.TRANSACTION_SAMPLED],
|
|
|
+};
|
|
|
+
|
|
|
+function getInvalidReasonGroupName(reason: DiscardReason): string {
|
|
|
+ for (const [group, reasons] of Object.entries(invalidReasonsGroup)) {
|
|
|
+ if (reasons.includes(reason)) {
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 'internal';
|
|
|
+}
|
|
|
+
|
|
|
+function getRateLimitedReasonGroupName(reason: RateLimitedReason | string): string {
|
|
|
+ if (reason.endsWith('_usage_exceeded')) {
|
|
|
+ return 'quota';
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (reason) {
|
|
|
+ case RateLimitedReason.KEY_QUOTA:
|
|
|
+ return 'key limit';
|
|
|
+ case RateLimitedReason.SPIKE_PROTECTION:
|
|
|
+ case RateLimitedReason.SMART_RATE_LIMIT:
|
|
|
+ return 'spike protection';
|
|
|
+ default:
|
|
|
+ return 'internal';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function getFilteredReasonGroupName(reason: FilteredReason): string {
|
|
|
+ switch (reason) {
|
|
|
+ case FilteredReason.BROWSER_EXTENSION:
|
|
|
+ case FilteredReason.ERROR_MESSAGE:
|
|
|
+ case FilteredReason.FILTERED_TRANSACTION:
|
|
|
+ case FilteredReason.INVALID_CSP:
|
|
|
+ case FilteredReason.IP_ADDRESS:
|
|
|
+ case FilteredReason.LEGACY_BROWSER:
|
|
|
+ case FilteredReason.LOCALHOST:
|
|
|
+ case FilteredReason.RELEASE_VERSION:
|
|
|
+ case FilteredReason.WEB_CRAWLER:
|
|
|
+ return reason;
|
|
|
+ default:
|
|
|
+ return 'other';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function getClientDiscardReasonGroupName(reason: ClientDiscardReason): string {
|
|
|
+ switch (reason) {
|
|
|
+ case ClientDiscardReason.QUEUE_OVERFLOW:
|
|
|
+ case ClientDiscardReason.CACHE_OVERFLOW:
|
|
|
+ case ClientDiscardReason.RATELIMIT_BACKOFF:
|
|
|
+ case ClientDiscardReason.NETWORK_ERROR:
|
|
|
+ case ClientDiscardReason.SAMPLE_RATE:
|
|
|
+ case ClientDiscardReason.BEFORE_SEND:
|
|
|
+ case ClientDiscardReason.EVENT_PROCESSSOR:
|
|
|
+ case ClientDiscardReason.SEND_ERROR:
|
|
|
+ case ClientDiscardReason.INTERNAL_SDK_ERROR:
|
|
|
+ case ClientDiscardReason.INSUFFICIENT_DATA:
|
|
|
+ case ClientDiscardReason.BACKPRESSURE:
|
|
|
+ return reason;
|
|
|
+ default:
|
|
|
+ return 'other';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function getReasonGroupName(outcome: string | number, reason: string): string {
|
|
|
+ switch (outcome) {
|
|
|
+ case Outcome.INVALID:
|
|
|
+ return getInvalidReasonGroupName(reason as DiscardReason);
|
|
|
+ case Outcome.CARDINALITY_LIMITED:
|
|
|
+ case Outcome.RATE_LIMITED:
|
|
|
+ case Outcome.ABUSE:
|
|
|
+ return getRateLimitedReasonGroupName(reason as RateLimitedReason);
|
|
|
+ case Outcome.FILTERED:
|
|
|
+ return getFilteredReasonGroupName(reason as FilteredReason);
|
|
|
+ case Outcome.CLIENT_DISCARD:
|
|
|
+ return getClientDiscardReasonGroupName(reason as ClientDiscardReason);
|
|
|
+ default:
|
|
|
+ return String(reason);
|
|
|
+ }
|
|
|
+}
|