Skip to content

Commit

Permalink
feat(server): Extrapolate sampled metrics numbers (#3753)
Browse files Browse the repository at this point in the history
Extrapolates numbers tracked as metrics after extraction from spans.
This allows to view the original order of magnitude before client
sampling and should remove jumps resulting from changes in sample rates.

Extrapolation is part of metric extraction in Relay and controlled via a
project config field. In addition to that, there is a global threshold
for the maximum duplication factor for expansion of distribution
metrics.
  • Loading branch information
jan-auer authored Jun 28, 2024
1 parent 707aa92 commit af43172
Show file tree
Hide file tree
Showing 7 changed files with 427 additions and 61 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
- Fixes metrics dropped due to missing project state. ([#3553](https://github.com/getsentry/relay/issues/3553))
- Report outcomes for spans when transactions are rate limited. ([#3749](https://github.com/getsentry/relay/pull/3749))


**Internal**:

- Aggregate metrics before rate limiting. ([#3746](https://github.com/getsentry/relay/pull/3746))
- Make sure outcomes for dropped profiles are consistent between indexed and non-indexed categories. ([#3767](https://github.com/getsentry/relay/pull/3767))
- Add web vitals support for mobile browsers. ([#3762](https://github.com/getsentry/relay/pull/3762))
- Accept profiler_id in the profile context. ([#3714](https://github.com/getsentry/relay/pull/3714))
- Support extrapolation of metrics extracted from sampled data, as long as the sample rate is set in the DynamicSamplingContext. ([#3753](https://github.com/getsentry/relay/pull/3753))

## 24.6.0

Expand Down
13 changes: 13 additions & 0 deletions relay-dynamic-config/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ pub struct Options {
)]
pub processing_disable_normalization: bool,

/// The maximum duplication factor used to extrapolate distribution metrics from sampled data.
///
/// This applies as long as Relay duplicates distribution values to extrapolate. The default is
/// `0`, which disables extrapolation of distributions completely. This option does not apply to
/// any other metric types.
#[serde(
default,
rename = "sentry-metrics.extrapolation.duplication-limit",
deserialize_with = "default_on_error",
skip_serializing_if = "is_default"
)]
pub extrapolation_duplication_limit: usize,

/// All other unknown options.
#[serde(flatten)]
other: HashMap<String, Value>,
Expand Down
59 changes: 58 additions & 1 deletion relay-dynamic-config/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ pub struct MetricExtractionConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<TagMapping>,

/// Extrapolation for metrics extracted from sampled data.
#[serde(default, skip_serializing_if = "ExtrapolationConfig::is_empty")]
pub extrapolate: ExtrapolationConfig,

/// This config has been extended with fields from `conditional_tagging`.
///
/// At the moment, Relay will parse `conditional_tagging` rules and insert them into the `tags`
Expand Down Expand Up @@ -339,6 +343,7 @@ impl MetricExtractionConfig {
global_groups: BTreeMap::new(),
metrics: Default::default(),
tags: Default::default(),
extrapolate: Default::default(),
_conditional_tags_extended: false,
_span_metrics_extended: false,
}
Expand Down Expand Up @@ -566,7 +571,7 @@ impl Tag {

/// Intermediate result of the tag spec builder.
///
/// Can be transformed into `[TagSpec]`.
/// Can be transformed into [`TagSpec`].
pub struct TagWithSource {
key: String,
field: Option<String>,
Expand Down Expand Up @@ -638,6 +643,39 @@ pub fn convert_conditional_tagging(project_config: &mut ProjectConfig) {
}
}

/// Configuration for metric extrapolation from sampled data.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExtrapolationConfig {
/// A list of MRI glob patterns to include in extrapolation.
#[serde(default)]
pub include: Vec<LazyGlob>,

/// A list of MRI glob patterns to exclude from extrapolation, overriding inclusion.
#[serde(default)]
pub exclude: Vec<LazyGlob>,
}

impl ExtrapolationConfig {
/// Returns `true` if this config is empty.
pub fn is_empty(&self) -> bool {
self.include.is_empty()
}

/// Returns `true` if the given metric resource identifier matches the include and exclude
/// patterns.
pub fn matches(&self, mri: &str) -> bool {
!self
.exclude
.iter()
.any(|glob| glob.compiled().is_match(mri))
&& self
.include
.iter()
.any(|glob| glob.compiled().is_match(mri))
}
}

struct TaggingRuleConverter<I: Iterator<Item = TaggingRule>> {
rules: std::iter::Peekable<I>,
tags: Vec<TagSpec>,
Expand Down Expand Up @@ -816,4 +854,23 @@ mod tests {
vec!["tag1"]
);
}

#[test]
fn test_extrapolation() {
let json = serde_json::json!({
"version": 1,
"extrapolate": {
"include": ["?:transactions/*", "?:spans/*", "?:custom/*"],
"exclude": ["c:spans/usage@none", "c:transactions/usage@none", "c:transactions/count_per_root_project@none"]
}
});

let config: MetricExtractionConfig = serde_json::from_value(json).unwrap();
let extrapolate = config.extrapolate;

assert!(!extrapolate.is_empty());
assert!(extrapolate.matches("d:custom/foo@none"));
assert!(extrapolate.matches("d:spans/foo@none"));
assert!(!extrapolate.matches("c:spans/usage@none"));
}
}
5 changes: 5 additions & 0 deletions relay-metrics/src/finite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ impl FiniteF64 {
Self((self.0 * other.0).clamp(f64::MIN, f64::MAX))
}

/// Divides two numbers, saturating at the maximum and minimum representable values.
pub fn saturating_div(self, other: Self) -> Self {
Self((self.0 / other.0).clamp(f64::MIN, f64::MAX))
}

// NB: There is no saturating_div, since 0/0 is NaN, which is not finite.
}

Expand Down
Loading

0 comments on commit af43172

Please sign in to comment.