Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

- Apply timestamp validations to transaction spans. ([#6005](https://github.com/getsentry/relay/pull/6005))
- Obtain PII values for `SpanData` fields from `sentry-conventions`. ([#5997](https://github.com/getsentry/relay/pull/5997))
- Add `sentry.dsc.transaction` and `sentry.dsc.trace_id` to all spans. ([#6001](https://github.com/getsentry/relay/pull/6001), [#6004](https://github.com/getsentry/relay/pull/6004), [#6008](https://github.com/getsentry/relay/pull/6008))
- Add `sentry.dsc.transaction`, `sentry.dsc.trace_id`, and `sentry.dsc.project_id` to all spans. ([#6001](https://github.com/getsentry/relay/pull/6001), [#6004](https://github.com/getsentry/relay/pull/6004), [#6008](https://github.com/getsentry/relay/pull/6008), [#6011](https://github.com/getsentry/relay/pull/6011))

## 26.5.0

Expand Down
1 change: 1 addition & 0 deletions relay-cabi/src/processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ pub unsafe extern "C" fn relay_store_normalizer_normalize_event(
performance_issues_spans: Default::default(),
derive_trace_id: Default::default(),
dsc: None,
sampling_project_id: None,
};
normalize_event(&mut event, &normalization_config);

Expand Down
59 changes: 47 additions & 12 deletions relay-event-normalization/src/eap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use relay_conventions::attributes::*;
use relay_conventions::{AttributeInfo, WriteBehavior};
use relay_event_schema::protocol::{AttributeType, Attributes, BrowserContext, Geo};
use relay_protocol::{Annotated, ErrorKind, Meta, Remark, RemarkType, Value};
use relay_sampling::DynamicSamplingContext;
use relay_spans::derive_op_for_v2_span;

use crate::span::TABLE_NAME_REGEX;
Expand All @@ -20,7 +19,7 @@ use crate::span::tag_extraction::{
domain_from_scrubbed_http, domain_from_server_address, span_op_to_category,
sql_action_from_query, sql_tables_from_query,
};
use crate::{ClientHints, FromUserAgentInfo as _, RawUserAgentInfo};
use crate::{ClientHints, DscNormalizationCommonProps, FromUserAgentInfo as _, RawUserAgentInfo};

mod ai;
mod mobile;
Expand Down Expand Up @@ -346,17 +345,17 @@ pub fn normalize_user_geo(
attributes.insert_if_missing(USER__GEO__REGION, || geo.region);
}

/// Normalizes the [DSC](DynamicSamplingContext) into [`Attributes`].
/// Normalizes the dynamic sampling context into [`Attributes`].
///
/// If `is_segment` is set to `false`, the function will only add select attributes that are
/// necessary on every span - both segment and non-segment - for dynamic sampling to work. More
/// attributes are added when `is_segment` is set to `true`.
pub fn normalize_dsc(
attributes: &mut Annotated<Attributes>,
is_segment: &Annotated<bool>,
dsc: Option<&DynamicSamplingContext>,
props: &DscNormalizationCommonProps,
) {
let Some(dsc) = dsc else { return };
let Some(dsc) = props.dsc else { return };

let attributes = attributes.get_or_insert_with(Default::default);

Expand All @@ -369,6 +368,9 @@ pub fn normalize_dsc(
if let Some(transaction) = &dsc.transaction {
attributes.insert(SENTRY__DSC__TRANSACTION, transaction.clone());
}
if let Some(project_id) = props.sampling_project_id {
attributes.insert(SENTRY__DSC__PROJECT_ID, project_id.to_string());
}

if is_segment.value().is_some_and(|is_segment| *is_segment) {
attributes.insert(SENTRY__DSC__PUBLIC_KEY, dsc.public_key.to_string());
Expand Down Expand Up @@ -730,7 +732,9 @@ pub fn write_legacy_attributes(attributes: &mut Annotated<Attributes>) {

#[cfg(test)]
mod tests {
use relay_base_schema::project::ProjectId;
use relay_protocol::{Empty, SerializableAnnotated, assert_annotated_snapshot};
use relay_sampling::DynamicSamplingContext;

use super::*;

Expand All @@ -752,17 +756,30 @@ mod tests {
#[test]
fn test_normalize_dsc_child_span_no_dsc() {
let mut attributes = Annotated::empty();
normalize_dsc(&mut attributes, &Annotated::new(false), None);
normalize_dsc(
&mut attributes,
&Annotated::new(false),
&DscNormalizationCommonProps::new(None, None),
);
assert!(attributes.value().is_none());
}

#[test]
fn test_normalize_dsc_child_span_no_transaction() {
let mut attributes = Annotated::empty();
let dsc = mock_dsc(None);
normalize_dsc(&mut attributes, &Annotated::new(false), Some(&dsc));
let dsc = &mock_dsc(None);
let sampling_project_id = ProjectId::new(42);
normalize_dsc(
&mut attributes,
&Annotated::new(false),
&DscNormalizationCommonProps::new(Some(dsc), Some(sampling_project_id)),
);
assert_annotated_snapshot!(attributes, @r#"
{
"sentry.dsc.project_id": {
"type": "string",
"value": 42
},
"sentry.dsc.trace_id": {
"type": "string",
"value": "67e5504410b1426f9247bb680e5fe0c8"
Expand All @@ -774,10 +791,19 @@ mod tests {
#[test]
fn test_normalize_dsc_child_span() {
let mut attributes = Annotated::empty();
let dsc = mock_dsc(Some("/some/endpoint"));
normalize_dsc(&mut attributes, &Annotated::new(false), Some(&dsc));
let dsc = &mock_dsc(Some("/some/endpoint"));
let sampling_project_id = ProjectId::new(42);
normalize_dsc(
&mut attributes,
&Annotated::new(false),
&DscNormalizationCommonProps::new(Some(dsc), Some(sampling_project_id)),
);
assert_annotated_snapshot!(attributes, @r#"
{
"sentry.dsc.project_id": {
"type": "string",
"value": 42
},
"sentry.dsc.trace_id": {
"type": "string",
"value": "67e5504410b1426f9247bb680e5fe0c8"
Expand All @@ -793,10 +819,19 @@ mod tests {
#[test]
fn test_normalize_dsc_segment() {
let mut attributes = Annotated::empty();
let dsc = mock_dsc(Some("/some/endpoint"));
normalize_dsc(&mut attributes, &Annotated::new(true), Some(&dsc));
let dsc = &mock_dsc(Some("/some/endpoint"));
let sampling_project_id = ProjectId::new(42);
normalize_dsc(
&mut attributes,
&Annotated::new(true),
&DscNormalizationCommonProps::new(Some(dsc), Some(sampling_project_id)),
);
assert_annotated_snapshot!(attributes, @r#"
{
"sentry.dsc.project_id": {
"type": "string",
"value": 42
},
"sentry.dsc.public_key": {
"type": "string",
"value": "12345678901234567890123456789012"
Expand Down
22 changes: 14 additions & 8 deletions relay-event-normalization/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use regex::Regex;
use relay_base_schema::metrics::{
DurationUnit, FractionUnit, MetricUnit, can_be_valid_metric_name,
};
use relay_base_schema::project::ProjectId;
use relay_conventions::attributes::{
APP__VITALS__START__COLD__VALUE, APP__VITALS__START__SCREEN, APP__VITALS__START__TYPE,
APP__VITALS__START__VALUE, APP__VITALS__START__WARM__VALUE, SCORE__TOTAL,
Expand Down Expand Up @@ -42,10 +43,10 @@ use crate::span::ai::enrich_ai_event_data;
use crate::span::tag_extraction::{extract_segment_name_from_event, extract_span_tags_from_event};
use crate::utils::{self, MAX_DURATION_MOBILE_MS, get_event_user_tag};
use crate::{
BorrowedSpanOpDefaults, BreakdownsConfig, CombinedMeasurementsConfig, GeoIpLookup, MaxChars,
ModelMetadata, PerformanceScoreConfig, RawUserAgentInfo, SpanDescriptionRule,
TransactionNameConfig, breakdowns, event_error, legacy, mechanism, remove_other, schema, span,
stacktrace, transactions, trimming, user_agent,
BorrowedSpanOpDefaults, BreakdownsConfig, CombinedMeasurementsConfig,
DscNormalizationCommonProps, GeoIpLookup, MaxChars, ModelMetadata, PerformanceScoreConfig,
RawUserAgentInfo, SpanDescriptionRule, TransactionNameConfig, breakdowns, event_error, legacy,
mechanism, remove_other, schema, span, stacktrace, transactions, trimming, user_agent,
};

/// Configuration for [`normalize_event`].
Expand Down Expand Up @@ -141,7 +142,7 @@ pub struct NormalizationConfig<'a> {
/// This is similar to `transaction_name_config`, but applies to span descriptions.
pub span_description_rules: Option<&'a Vec<SpanDescriptionRule>>,

/// Configuration for generating performance score measurements for web vitals
/// Configuration for generating performance score measurements for web vitals.
pub performance_score: Option<&'a PerformanceScoreConfig>,

/// Metadata for AI models including costs and context size.
Expand All @@ -165,7 +166,7 @@ pub struct NormalizationConfig<'a> {
/// It is persisted into the event payload for correlation.
pub replay_id: Option<Uuid>,

/// Controls list of hosts to be excluded from scrubbing
/// Controls list of hosts to be excluded from scrubbing.
pub span_allowed_hosts: &'a [String],

/// Rules to infer `span.op` from other span fields.
Expand All @@ -177,8 +178,11 @@ pub struct NormalizationConfig<'a> {
/// Should add a random trace ID to events that lack one.
pub derive_trace_id: bool,

/// Dynamic sampling context
/// Dynamic sampling context.
pub dsc: Option<&'a DynamicSamplingContext>,

/// The identifier of the project where the trace originated.
pub sampling_project_id: Option<ProjectId>,
}

impl Default for NormalizationConfig<'_> {
Expand Down Expand Up @@ -215,6 +219,7 @@ impl Default for NormalizationConfig<'_> {
performance_issues_spans: Default::default(),
derive_trace_id: Default::default(),
dsc: None,
sampling_project_id: None,
}
}
}
Expand Down Expand Up @@ -346,8 +351,9 @@ fn normalize(event: &mut Event, meta: &mut Meta, config: &NormalizationConfig) {
normalize_contexts(&mut event.contexts, event_id, config);

if config.normalize_spans && event.ty.value() == Some(&EventType::Transaction) {
let dsc_props = DscNormalizationCommonProps::new(config.dsc, config.sampling_project_id);
span::normalize_dsc_for_event_spans(event, &dsc_props);
span::normalize_app_start_spans(event);
span::normalize_dsc_for_event_spans(event, config.dsc);
span::exclusive_time::compute_span_exclusive_time(event);
}

Expand Down
23 changes: 23 additions & 0 deletions relay-event-normalization/src/normalize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use std::{collections::HashMap, sync::LazyLock};

use regex::Regex;
use relay_base_schema::metrics::MetricUnit;
use relay_base_schema::project::ProjectId;
use relay_event_schema::protocol::VALID_PLATFORMS;
use relay_pattern::Pattern;
use relay_protocol::{FiniteF64, RuleCondition};
use relay_sampling::DynamicSamplingContext;
use serde::{Deserialize, Serialize};

pub mod breakdowns;
Expand Down Expand Up @@ -364,6 +366,27 @@ pub struct ModelMetadataEntry {
pub context_size: Option<u64>,
}

/// Parameters shared across dsc normalization functions.
pub struct DscNormalizationCommonProps<'a> {
/// Dynamic sampling context containing the trace id and root transaction that started the trace.
pub dsc: Option<&'a DynamicSamplingContext>,
/// Id of the project where the trace originated.
pub sampling_project_id: Option<ProjectId>,
}

impl<'a> DscNormalizationCommonProps<'a> {
/// Creates a new [`DscNormalizationCommonProps`].
pub fn new(
dsc: Option<&'a DynamicSamplingContext>,
sampling_project_id: Option<ProjectId>,
) -> Self {
DscNormalizationCommonProps {
dsc,
sampling_project_id,
}
}
}

#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
Expand Down
21 changes: 14 additions & 7 deletions relay-event-normalization/src/normalize/span/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
//! Span normalization logic.

use regex::Regex;
use relay_conventions::attributes::{SENTRY__DSC__TRACE_ID, SENTRY__DSC__TRANSACTION};
use relay_conventions::attributes::*;
use relay_event_schema::protocol::{Event, SpanData, TraceContext};
use relay_protocol::{Annotated, Value};
use relay_sampling::DynamicSamplingContext;
use std::sync::LazyLock;

use crate::DscNormalizationCommonProps;

pub mod ai;
pub mod country_subregion;
pub mod description;
Expand Down Expand Up @@ -61,14 +62,14 @@ pub fn normalize_app_start_spans(event: &mut Event) {
///
/// If `sentry.dsc.trace_id` is already present in a span's `data`, the function does nothing for
/// that span.
pub fn normalize_dsc_for_event_spans(event: &mut Event, dsc: Option<&DynamicSamplingContext>) {
pub fn normalize_dsc_for_event_spans(event: &mut Event, props: &DscNormalizationCommonProps) {
if let Some(ctx) = event.context_mut::<TraceContext>() {
normalize_dsc_for_span_data(&mut ctx.data, dsc);
normalize_dsc_for_span_data(&mut ctx.data, props);
}
if let Some(spans) = event.spans.value_mut() {
for span in spans {
if let Some(span) = span.value_mut() {
normalize_dsc_for_span_data(&mut span.data, dsc);
normalize_dsc_for_span_data(&mut span.data, props);
}
}
}
Expand All @@ -79,9 +80,9 @@ pub fn normalize_dsc_for_event_spans(event: &mut Event, dsc: Option<&DynamicSamp
/// If `sentry.dsc.trace_id` is already present in `span_data`, the function does nothing.
pub fn normalize_dsc_for_span_data(
span_data: &mut Annotated<SpanData>,
dsc: Option<&DynamicSamplingContext>,
props: &DscNormalizationCommonProps,
) {
Comment thread
elramen marked this conversation as resolved.
Outdated
let Some(dsc) = dsc else { return };
let Some(dsc) = props.dsc else { return };

let data = span_data.get_or_insert_with(SpanData::default);
if data.other.contains_key(SENTRY__DSC__TRACE_ID) {
Expand All @@ -98,4 +99,10 @@ pub fn normalize_dsc_for_span_data(
Annotated::new(Value::String(transaction.clone())),
);
}
if let Some(project_id) = props.sampling_project_id {
data.other.insert(
SENTRY__DSC__PROJECT_ID.to_owned(),
Annotated::new(Value::String(project_id.to_string())),
);
}
Comment thread
elramen marked this conversation as resolved.
Outdated
}
9 changes: 8 additions & 1 deletion relay-server/src/processing/legacy_spans/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use crate::services::processor::ProcessingError;
use chrono::{DateTime, Utc};
use relay_base_schema::project::ProjectId;
use relay_event_normalization::DscNormalizationCommonProps;
use relay_event_normalization::span::{self, ai};
use relay_event_normalization::{
BorrowedSpanOpDefaults, ClientHints, CombinedMeasurementsConfig, FromUserAgentInfo,
Expand Down Expand Up @@ -58,6 +60,8 @@ pub struct NormalizeSpanConfig<'a> {
pub span_op_defaults: BorrowedSpanOpDefaults<'a>,
/// Dynamic sampling context from the envelope headers.
pub dsc: Option<&'a DynamicSamplingContext>,
/// Project ID of the project that started the trace.
pub sampling_project_id: Option<ProjectId>,
}

fn set_segment_attributes(span: &mut Annotated<Span>) {
Expand Down Expand Up @@ -112,6 +116,7 @@ pub fn normalize(
geo_lookup,
span_op_defaults,
dsc,
sampling_project_id,
} = config;

set_segment_attributes(annotated_span);
Expand Down Expand Up @@ -211,7 +216,8 @@ pub fn normalize(

normalize_performance_score(span, *performance_score);

span::normalize_dsc_for_span_data(&mut span.data, *dsc);
let dsc_normalization_props = &DscNormalizationCommonProps::new(*dsc, *sampling_project_id);
span::normalize_dsc_for_span_data(&mut span.data, dsc_normalization_props);

ai::enrich_ai_span(span, *ai_model_metadata);

Expand Down Expand Up @@ -555,6 +561,7 @@ mod tests {
geo_lookup: &GEO_LOOKUP,
span_op_defaults: Default::default(),
dsc: None,
sampling_project_id: None,
}
}

Expand Down
1 change: 1 addition & 0 deletions relay-server/src/processing/legacy_spans/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub fn normalize(
geo_lookup,
span_op_defaults: ctx.global_config.span_op_defaults.borrow(),
dsc: dsc.as_ref(),
sampling_project_id: ctx.sampling_project_info.and_then(|p| p.project_id),
};

spans.retain(
Expand Down
Loading
Loading