Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(outcomes): Emit outcomes as client reports [INGEST-247] #1119

Merged
merged 40 commits into from
Nov 18, 2021

Conversation

jjbayer
Copy link
Member

@jjbayer jjbayer commented Nov 9, 2021

Add the option to emit outcomes as client reports. This allows external relays to emit outcomes.

Main feature of this PR:

  1. The emit_outcomes config flag can now have three states: true, false, or "client reports".
  2. Every created TrackOutcome is now sent to the outcome aggregator instead of the outcome producer.
  3. If configured to emit outcomes as client reports, the outcome aggregator erases event_id and remote_addr from the outcome.
  4. If an outcome still has an event_id after step 3, it is forwarded to the configured producer without aggregating.
  5. Else, the outcome is aggregated as in Feat(outcomes): Aggregate client reports [INGEST-247] #1118.
  6. Finally, the outcome producer converts the aggregated outcome to a client report and sends it to the upstream as an envelope.

Also in this PR:

  • Dynamic sampling config is now propagated to untrusted relays, allowing them to apply sampling rules.

@jjbayer jjbayer changed the title feat(outcomes): Emit outcomes as client reports feat(outcomes): Emit outcomes as client reports [INGEST-247] Nov 12, 2021
@jjbayer jjbayer marked this pull request as ready for review November 15, 2021 09:17
@jjbayer jjbayer requested review from a team and untitaker November 15, 2021 09:17
Outcome::RateLimited(_) => &mut client_report._server_rate_limited_events,
_ => {
// Cannot convert this outcome to a client report.
return Ok(());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that only these three outcome types will be emitted. Everything else is silently dropped.

relay-server/src/actors/outcome.rs Outdated Show resolved Hide resolved

// TODO: timestamp validation? (min, max)
let offset = timestamp.timestamp() as u64 / self.bucket_interval;
let offset = msg.timestamp.timestamp() as u64 / self.bucket_interval;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that we do not need to validate the timestamp here, because

  • outcomes coming in via client reports have their own validation,
  • all other outcomes are created by trusted relays.

@@ -121,6 +121,7 @@ pub struct LimitedProjectConfig {
pub trusted_relays: Vec<PublicKey>,
pub pii_config: Option<PiiConfig>,
pub datascrubbing_settings: DataScrubbingConfig,
pub dynamic_sampling: Option<SamplingConfig>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change enables dynamic sampling in external relays.

relay-server/src/actors/outcome.rs Show resolved Hide resolved
relay-config/src/config.rs Outdated Show resolved Hide resolved
relay-config/src/config.rs Outdated Show resolved Hide resolved
relay-general/src/protocol/client_report.rs Outdated Show resolved Hide resolved
relay-server/src/actors/envelopes.rs Outdated Show resolved Hide resolved
relay-server/src/actors/outcome.rs Outdated Show resolved Hide resolved
relay-server/src/actors/outcome.rs Outdated Show resolved Hide resolved
relay-general/benches/benchmarks.rs Outdated Show resolved Hide resolved
relay-metrics/benches/aggregator.rs Show resolved Hide resolved
type Result = Result<(), ()>;
}

impl Handler<SendClientReport> for EnvelopeManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since SendEnvelope is pub now, can't this live in the outcome actor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that (that's why SendEnvelope is public) but bumped into an issue I cannot remember. Is it OK if we keep it here to keep SendClientReport consistent with SendMetrics, and refactor both at a later time?

relay-server/src/actors/outcome.rs Show resolved Hide resolved
relay-server/src/actors/outcome.rs Outdated Show resolved Hide resolved
Comment on lines +772 to +775
pub struct NonProcessingOutcomeProducer {
producer: Option<Recipient<TrackOutcome>>,
raw_producer: Option<Recipient<TrackRawOutcome>>,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to replace this with

pub enum NonProcessingOutcomeProducer {
    AsClientReports(Addr<ClientReportOutcomeProducer>),
    AsOutcomes(Addr<HttpOutcomeProducer>),
    Disabled,
}

and remove impl Handler<TrackOutcome> for HttpProducer>

alternatively we could fold all three actors into one

relay-config/src/config.rs Outdated Show resolved Hide resolved
relay-general/benches/benchmarks.rs Outdated Show resolved Hide resolved
relay-metrics/benches/aggregator.rs Show resolved Hide resolved
type Result = Result<(), ()>;
}

impl Handler<SendClientReport> for EnvelopeManager {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that (that's why SendEnvelope is public) but bumped into an issue I cannot remember. Is it OK if we keep it here to keep SendClientReport consistent with SendMetrics, and refactor both at a later time?

type Context = Context<Self>;

fn started(&mut self, ctx: &mut Self::Context) {
ctx.run_interval(self.flush_interval, Self::flush);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@untitaker In the end I decided to use run_interval here. The outcomes for ClientReportOutcomeProducer always come from the aggregator in predictable intervals, so I suppose there is no need for "flush when batch is full or too much time has passed" logic. Instead, just flush with the same interval as the aggregator.

@@ -1008,7 +1090,7 @@ pub struct Outcomes {
impl Default for Outcomes {
fn default() -> Self {
Outcomes {
emit_outcomes: false,
emit_outcomes: EmitOutcomes::None,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we set the default to EmitOutcomes::AsClientReports?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so, in that case we should write some warnings into the changelog imo

relay-config/src/config.rs Outdated Show resolved Hide resolved
relay-config/src/config.rs Outdated Show resolved Hide resolved
relay-config/src/config.rs Outdated Show resolved Hide resolved
@@ -1008,7 +1090,7 @@ pub struct Outcomes {
impl Default for Outcomes {
fn default() -> Self {
Outcomes {
emit_outcomes: false,
emit_outcomes: EmitOutcomes::None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so, in that case we should write some warnings into the changelog imo

if self.processing_enabled() {
return EmitOutcomes::AsOutcomes;
}
self.values.outcomes.emit_outcomes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jjbayer this makes me think, maybe we should make the field in the config Option<EmitOutcomes> so explicitly setting the value to anything takes precedence over this. but not entirely sure. can leave it out for now

@@ -162,6 +162,26 @@ impl fmt::Display for FilterStatKey {
}
}

impl<'a> TryFrom<&'a str> for FilterStatKey {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have a macro for this? maybe just for serde impl

relay-metrics/benches/aggregator.rs Show resolved Hide resolved
relay-server/src/actors/outcome.rs Show resolved Hide resolved
Copy link
Member

@untitaker untitaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should flip the default before we merge this, because people are not going to enable this explicitly. All other comments are optional.

@jjbayer jjbayer merged commit d242158 into master Nov 18, 2021
@jjbayer jjbayer deleted the feat/outcomes-as-client-reports-original branch November 18, 2021 10:21
jan-auer added a commit that referenced this pull request Nov 24, 2021
* master:
  test(outcomes): Fix sort order in flaky test (#1135)
  feat(outcomes): Aggregate more outcomes (#1134)
  ref(outcomes): Fold processing vs non-processing into single actor (#1133)
  build: Update symbolic to support UE5 (#1132)
  feat(metrics): Extract measurement ratings, port from frontend (#1130)
  feat(metrics): Another statsd metric to measure bucket duplication (#1128)
  feat(outcomes): Emit outcomes as client reports (#1119)
  fix: Move changelog line to right version (#1129)
  fix(dangerjs): Do not suggest to add JIRA ticket to changelog (#1125)
  feat(metrics): Tag metrics by transaction name [INGEST-542] (#1126)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants