feat(server): implement remaining performance item types
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 8/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- rust
- Domain
- backend, observability
Research direction
This is an umbrella epic covering nine envelope item types, so there is no single starting edit. Begin by reading the EnvelopeItemKind enum and the handling of the Other catch-all where unknown item types are ignored, then pick one item type and open a dedicated sub-issue for it. Done means that one type is parsed, stored and queryable, with its own tests, and the epic's checklist is updated.
Written by the indexing model from the issue text.
Description
Overview
Rustrak currently handles 5 EnvelopeItemKind variants (Event, Transaction, Session, Sessions, Other catch-all). Relay supports 21+ ItemType variants across multiple processing pipelines. This issue tracks all the remaining performance-related envelope item types that Rustrak silently ignores.
Current behavior: Every unrecognized item type lands in EnvelopeItemKind::Other and is discarded with log::debug!("envelope item '{}' ignored"). No error, no storage, no processing.
Item types to implement
1. Standalone Span items (ItemType::Span)
What they are: OTel-style spans that are NOT attached to a parent transaction. These arrive as standalone items in envelopes, each representing a distributed tracing span. Relay has a dedicated SpansProcessor pipeline.
Relay pipeline:
- SpansProcessor: validate → DSC presence check → expand → normalize → filter → rate limit → store
- DataCategories: Span, SpanIndexed
- Schema: SpanV2 with segment_id, is_segment
- Kafka topic: SnubaSpan
SDKs that send them:
- OpenTelemetry SDKs (via OTel-to-Sentry bridge)
- Sentry SDKs in standalone-span mode (e.g. serverless functions, background jobs)
- SDK integration items (content_type determines routing)
Implementation scope:
- New EnvelopeItemKind variant
- New SpansProcessor in digest/processors/spans.rs
- New spans table with fields: span_id, trace_id, parent_span_id, segment_id, op, description, status, start_timestamp, timestamp, tags, data
- Separate rate limiting per DataCategory::Span / SpanIndexed
- GET /api/projects/{id}/spans — list spans filterable by trace_id, op
- GET /api/projects/{id}/traces/{trace_id} — trace assembly (correlate spans + transactions)
Reference: relay-server/src/processing/spans/mod.rs
2. Profile items (ItemType::Profile)
What they are: Continuous profiling data linked to a transaction. Arrives in the same envelope as its parent transaction. Relay extracts it during TransactionProcessor.process_profile().
Relay pipeline:
- ProfilesProcessor: expand → parse JSON → validate schema → rate limit
- DataCategories: Profile, ProfileIndexed, ProfileBackend, ProfileUi
- Kafka topic: Profiles
- Key detail: Profile travels with its Transaction item until split
SDKs that send them:
- sentry-python with profiling enabled
- sentry-rust with profiling enabled
- Any SDK that sets profiles_sample_rate > 0
Implementation scope:
- New EnvelopeItemKind variant
- Link to parent transaction (same envelope, share trace_id)
- New profiles table with fields: profile_id, transaction_id, trace_id, platform, profile_type, data (JSONB), sampled (bool)
- Store with transaction or as separate row
- GET /api/projects/{id}/profiles/{transaction_id}
Reference: relay-server/src/processing/profiles/mod.rs
3. ProfileChunk items (ItemType::ProfileChunk)
What they are: Standalone continuous profiling chunks NOT linked to a specific transaction. Used primarily by Android SDKs for continuous profiling sessions.
Relay pipeline:
- ProfileChunksProcessor: platform check → rate limit
- DataCategories: ProfileChunk (backend) or ProfileChunkUi (UI)
- Alias: profile_chunk_ui for Android SDK 8.10-8.11 compat
SDKs that send them:
- sentry-android with continuous profiling
Implementation scope:
- New EnvelopeItemKind variant
- Separate storage from transaction profiles
- Platform-aware storage (different ProfileType per platform)
Reference: relay-server/src/processing/profile_chunks/mod.rs
4. CheckIn items (ItemType::CheckIn)
What they are: Cron monitoring heartbeats. SDKs send CheckIn items at the start and end of cron job executions. Relay validates and forwards to the Monitors system.
Relay pipeline:
- CheckInsProcessor: normalize → rate limit
- DataCategories: Monitor
- Kafka topic: Monitors
- Simplest processor — just validation + forwarding
SDKs that send them:
- sentry-python with cron monitoring
- sentry-javascript with cron monitoring
Implementation scope:
- New EnvelopeItemKind variant
- New check_ins table: monitor_slug, status (in_progress/ok/error/missed), duration, environment, release, started_at, timestamp
- GET /api/projects/{id}/monitors — list monitors with last check-in status
- GET /api/projects/{id}/monitors/{slug}/checkins — list check-ins for a monitor
- No issue/grouping — standalone feature
Reference: relay-server/src/processing/check_ins/mod.rs
5. Replay items (ItemType::ReplayEvent, ItemType::ReplayRecording, ItemType::ReplayVideo)
What they are: Session replay data. Three item types share one workflow:
- ReplayEvent: Metadata JSON (breadcrumbs, URLs, user interactions)
- ReplayRecording: Compressed recording binary (RRWeb)
- ReplayVideo: Video recording (mobile replay)
Relay pipeline:
- ReplaysProcessor: expand → validate → filter → PII scrub → rate limit → store
- All three share DataCategory::Replay (single counter)
- Maximum size configurable for recordings
- Valid combinations: (1,1,0), (0,1,0), (0,0,1)
Implementation scope:
- Three new EnvelopeItemKind variants (or one Replay with sub-type)
- ReplayEvent table: replay_id, event payload (breadcrumbs, urls, user), trace_ids[], started_at, timestamp
- Recording storage: file/blob storage (can be large)
- PII scrubbing on replay events
- GET /api/projects/{id}/replays — list sessions filterable by user, url, browser
Reference: relay-server/src/processing/replays/mod.rs
6. Metric items (ItemType::Statsd, ItemType::MetricBuckets)
What they are: Custom metrics sent by SDKs. Statsd is text-encoded individual metrics. MetricBuckets is pre-aggregated JSON arrays. These feed into Relay's internal metrics aggregator.
Relay pipeline:
- Inline in processor.rs (no dedicated Processor struct)
- Statsd: parse individually, discard invalid entries
- MetricBuckets: parse JSON array, validate
- Both go to internal aggregator → Kafka topic MetricsGeneric
- NOT rate limited by DataCategory (no category)
- SourceQuantities tracks what they derived from (events, transactions, spans, etc.)
Implementation scope:
- New EnvelopeItemKind variants
- Metrics aggregator (in-memory time-bucketed counters)
- Metrics table: project_id, metric_name, metric_type (counter/distribution/set/gauge), tags (JSONB), value, timestamp, bucketed_at
- GET /api/projects/{id}/metrics — query metrics by name, tags, time range
- Statsd parsing library or custom parser
Reference: relay-server/src/ (inline in processor.rs around line 693-750)
7. Log items (ItemType::Log)
What they are: Standalone logs sent via Sentry SDKs. Not exceptions — structured log messages with severity, trace_id, span_id.
Relay pipeline:
- LogsProcessor: validate (DSC presence) → filter (size, fast) → expand (parse OurLog) → normalize → rate limit
- DataCategories: LogByte, LogItem
- Schema: OurLog with trace_id, span_id
- Kafka topic: TraceItemType::Log
- Max size configurable
Implementation scope:
- New EnvelopeItemKind variant
- LogsProcessor
- Logs table: message, severity, timestamp, trace_id, span_id, logger_name, extra (JSONB)
- Rate limiting (separate from errors/transactions)
- GET /api/projects/{id}/logs — filter by severity, trace_id, logger_name
Reference: relay-server/src/processing/logs/mod.rs
8. TraceMetric items (ItemType::TraceMetric)
What they are: Trace-level metrics with trace_id and span_id. Represent aggregated metrics at the trace level.
Relay pipeline: Inline in processor.rs (no dedicated Processor struct yet)
Schema: TraceMetric with trace_id, span_id, numeric metrics
DataCategories: TraceMetricByte, TraceMetric
Implementation scope: Minimal — store as-is with trace_id/span_id indexing.
9. Integration items (ItemType::Integration)
What they are: Generic integration items routed by content_type. OTel integration sends OTel logs/spans that get converted to native items. Content_type determines processor: OTel logs → LogsProcessor, OTel spans → SpansProcessor.
Key properties:
- is_internal() returns true — cannot be forwarded to other Relays without conversion
- Must be converted before storage
Reference: relay-server/src/envelope/item.rs (ItemType::Integration)
Implementation priority suggestions
| Priority | Item Type | Complexity | SDK reach |
|---|---|---|---|
| P0 | Span (standalone) | High | OTel, serverless, background jobs |
| P1 | Profile | Medium | Python, Rust, JS profiling users |
| P1 | CheckIn | Low | Simple structure, cron users |
| P2 | Replay | High | RRWeb, large binary storage |
| P2 | Metrics (Statsd/Buckets) | Medium | Custom metrics users |
| P3 | Log | Medium | Growing use case |
| P3 | TraceMetric | Low | Emerging spec |
| P3 | Integration | Medium | OTel bridge |
Shared infrastructure needed
Several of these items share common needs:
- Rate limiting by DataCategory: extend rate limit service to support per-category counters (currently only global + per-project)
- DynamicSamplingContext parsing: DSC is required for Span and Log items. Need to parse trace from envelope headers and validate.
- File/blob storage for large items: Replay recordings and profiles can be large — need efficient storage strategy
- Separate indexing strategy: Each item type needs different query patterns — avoid overloading a single events table
References
- Full item type enum: relay-server/src/envelope/item.rs (21+ variants)
- Processing pipeline registry: relay-server/src/services/processor.rs
- Complete gap analysis: _bmad/_memory/agent-rusty/BOND.md (updated 2026-06-23)
- Dominant language
- TypeScript
- Stars
- 170
- Forks
- 25
- Avg merge
- 17h 40m
- Merged PRs (30d)
- 49
Getting set up
- Ships a Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rustrak/rustrak
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
rustrak/rustrak#389 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 22/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 38/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
polarsource/polar#15580 ·
Maintainers usually reply within 1 day
-
accepted bug via-triage
Difficulty 2/5 1-3 hours Newbie friendliness 69/100
pingdotgg/t3code#20931 · 1 comment ·
Maintainers usually reply within 1 day
-
bug/1-unconfirmed kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 83/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
ranxianglei/billion-context#3583 ·
Maintainers usually reply within 1 day