Skip to content

Commit 7f8435c

Browse files
authored
feat(store): Introduce a sample rate to rollout json spans (#5101)
Adds two options that allow to completely override what's set in `produce_json` and `produce_protobuf`. The rollout forces JSON and disables protobuf. Closes STREAM-413
1 parent 022d4f5 commit 7f8435c

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

relay-config/src/config.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,14 @@ impl Default for Processing {
11971197
#[derive(Debug, Serialize, Deserialize)]
11981198
#[serde(default)]
11991199
pub struct SpanProducers {
1200+
/// Random sample of organizations to produce json and no protobuf.
1201+
///
1202+
/// Overrides both `produce_json` and `produce_protobuf` for matching orgs.
1203+
pub produce_json_sample_rate: Option<f32>,
1204+
/// List of organization IDs to produce JSON spans for.
1205+
///
1206+
/// Overrides both `produce_json` and `produce_protobuf` for matching orgs.
1207+
pub produce_json_orgs: Vec<u64>,
12001208
/// Send JSON spans to `ingest-spans`.
12011209
pub produce_json: bool,
12021210
/// Send Protobuf (TraceItem) to `snuba-items`.
@@ -1206,6 +1214,8 @@ pub struct SpanProducers {
12061214
impl Default for SpanProducers {
12071215
fn default() -> Self {
12081216
Self {
1217+
produce_json_sample_rate: None,
1218+
produce_json_orgs: vec![],
12091219
produce_json: false,
12101220
produce_protobuf: true,
12111221
}
@@ -2614,14 +2624,9 @@ impl Config {
26142624
forward.unwrap_or_else(|| !self.processing_enabled())
26152625
}
26162626

2617-
/// Returns `true` if we should produce TraceItem spans on `snuba-items`.
2618-
pub fn produce_protobuf_spans(&self) -> bool {
2619-
self.values.processing.span_producers.produce_protobuf
2620-
}
2621-
2622-
/// Returns `true` if we should produce JSON spans on `ingest-spans`.
2623-
pub fn produce_json_spans(&self) -> bool {
2624-
self.values.processing.span_producers.produce_json
2627+
/// Returns the configuration for span producers.
2628+
pub fn span_producers(&self) -> &SpanProducers {
2629+
&self.values.processing.span_producers
26252630
}
26262631
}
26272632

relay-server/src/services/store.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::services::global_config::GlobalConfigHandle;
4545
use crate::services::outcome::{DiscardItemType, DiscardReason, Outcome, TrackOutcome};
4646
use crate::services::processor::Processed;
4747
use crate::statsd::{RelayCounters, RelayGauges, RelayTimers};
48-
use crate::utils::FormDataIter;
48+
use crate::utils::{self, FormDataIter, PickResult};
4949

5050
/// Fallback name used for attachment items without a `filename` header.
5151
const UNNAMED_ATTACHMENT: &str = "Unnamed Attachment";
@@ -1055,7 +1055,8 @@ impl StoreService {
10551055
span.start_timestamp_ms = (span.start_timestamp_precise * 1e3) as u64;
10561056
span.key_id = scoping.key_id;
10571057

1058-
if self.config.produce_protobuf_spans() {
1058+
let spans_target = self.spans_target(span.organization_id);
1059+
if spans_target.is_protobuf() {
10591060
self.inner_produce_protobuf_span(
10601061
scoping,
10611062
received_at,
@@ -1075,13 +1076,32 @@ impl StoreService {
10751076
});
10761077
}
10771078

1078-
if self.config.produce_json_spans() {
1079+
if spans_target.is_json() {
10791080
self.inner_produce_json_span(scoping, span)?;
10801081
}
10811082

10821083
Ok(())
10831084
}
10841085

1086+
fn spans_target(&self, org_id: u64) -> SpansTarget {
1087+
let config = self.config.span_producers();
1088+
if config.produce_json_orgs.contains(&org_id) {
1089+
return SpansTarget::Json;
1090+
} else if let Some(rate) = config.produce_json_sample_rate {
1091+
return match utils::is_rolled_out(org_id, rate) {
1092+
PickResult::Keep => SpansTarget::Json,
1093+
PickResult::Discard => SpansTarget::Protobuf,
1094+
};
1095+
}
1096+
1097+
match (config.produce_json, config.produce_protobuf) {
1098+
(true, true) => SpansTarget::Both,
1099+
(true, false) => SpansTarget::Json,
1100+
(false, true) => SpansTarget::Protobuf,
1101+
(false, false) => SpansTarget::default(),
1102+
}
1103+
}
1104+
10851105
fn inner_produce_json_span(
10861106
&self,
10871107
scoping: Scoping,
@@ -2005,6 +2025,24 @@ fn safe_timestamp(timestamp: DateTime<Utc>) -> u64 {
20052025
Utc::now().timestamp() as u64
20062026
}
20072027

2028+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2029+
enum SpansTarget {
2030+
#[default]
2031+
Protobuf,
2032+
Json,
2033+
Both,
2034+
}
2035+
2036+
impl SpansTarget {
2037+
fn is_protobuf(&self) -> bool {
2038+
matches!(self, SpansTarget::Protobuf | SpansTarget::Both)
2039+
}
2040+
2041+
fn is_json(&self) -> bool {
2042+
matches!(self, SpansTarget::Json | SpansTarget::Both)
2043+
}
2044+
}
2045+
20082046
#[cfg(test)]
20092047
mod tests {
20102048

0 commit comments

Comments
 (0)