-
Notifications
You must be signed in to change notification settings - Fork 119
Streamify log expansion (for discussion, not review) #6266
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |
| use crate::envelope::{ContainerItems, EnvelopeHeaders, Item, WithHeader}; | ||
| use crate::integrations::{Integration, LogsIntegration}; | ||
| use crate::managed::RecordKeeper; | ||
| use crate::processing::logs::Settings; | ||
| use crate::processing::logs::{Result, Settings}; | ||
|
|
||
| mod nel; | ||
| mod otel; | ||
|
|
@@ -17,6 +17,7 @@ | |
| item: Item, | ||
| records: &mut RecordKeeper<'_>, | ||
| headers: &EnvelopeHeaders, | ||
| max_expanded_log_count: usize, | ||
| ) -> Option<(Settings, ContainerItems<OurLog>)> { | ||
| let integration = match item.integration() { | ||
| Some(Integration::Logs(integration)) => integration, | ||
|
|
@@ -26,37 +27,49 @@ | |
| } | ||
| }; | ||
|
|
||
| let mut logs = Vec::new(); | ||
| let produce = |log: OurLog| { | ||
| let byte_size = relay_ourlogs::calculate_size(&log); | ||
|
|
||
| records.modify_by(DataCategory::LogItem, 1); | ||
| records.modify_by(DataCategory::LogByte, byte_size as isize); | ||
| let payload = item.payload(); | ||
|
|
||
| logs.push(WithHeader { | ||
| header: Some(OurLogHeader { | ||
| byte_size: Some(byte_size), | ||
| other: Default::default(), | ||
| }), | ||
| value: log.into(), | ||
| }); | ||
| let log_stream: Result<Box<dyn Iterator<Item = OurLog>>> = match integration { | ||
| LogsIntegration::Nel => nel::expand2(&payload, headers), | ||
| LogsIntegration::OtelV1 { format } => otel::expand2(format, &payload), | ||
|
Check warning on line 34 in relay-server/src/processing/logs/integrations/mod.rs
|
||
|
Comment on lines
+32
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OTel log expansion panics on malformed input instead of returning an error
Evidence
Also found at 2 additional locations
Identified by Warden · wrdn-dos-review · RMP-KHP |
||
| LogsIntegration::VercelDrainLog { format } => vercel::expand2(format, &payload), | ||
| }; | ||
|
|
||
| let payload = item.payload(); | ||
|
|
||
| let settings = match integration { | ||
| LogsIntegration::Nel => nel::expand(&payload, headers, produce), | ||
| LogsIntegration::OtelV1 { format } => otel::expand(format, &payload, produce), | ||
| LogsIntegration::VercelDrainLog { format } => vercel::expand(format, &payload, produce), | ||
| LogsIntegration::Nel => Settings { | ||
| infer_user_agent: true, | ||
| infer_ip: false, | ||
| }, | ||
| LogsIntegration::OtelV1 { format: _ } => Settings::default(), | ||
| LogsIntegration::VercelDrainLog { format: _ } => Settings::default(), | ||
| }; | ||
| let settings = match settings { | ||
| Ok(settings) => settings, | ||
|
|
||
| let (log_stream, settings) = match log_stream { | ||
| Ok(log_stream) => (log_stream, settings), | ||
| Err(err) => { | ||
| let _ = records.reject_err(err, &item); | ||
| return None; | ||
| } | ||
| }; | ||
|
|
||
| let logs = log_stream | ||
| .take(max_expanded_log_count) | ||
| .map(|log| { | ||
| let byte_size = relay_ourlogs::calculate_size(&log); | ||
|
|
||
| records.modify_by(DataCategory::LogItem, 1); | ||
| records.modify_by(DataCategory::LogByte, byte_size as isize); | ||
|
|
||
| WithHeader { | ||
| header: Some(OurLogHeader { | ||
| byte_size: Some(byte_size), | ||
| other: Default::default(), | ||
| }), | ||
| value: log.into(), | ||
| } | ||
| }) | ||
| .collect(); | ||
|
|
||
| // Undo all the base item quantities, as they will be completely taken over by the parsed | ||
| // contents, which contains an arbitrary amount of items (even 0). | ||
| for (category, quantity) in item.quantities() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,33 @@ | ||
| use std::ops::Deref; | ||
|
|
||
| use opentelemetry_proto::tonic::logs::v1::LogsData; | ||
| use prost::Message as _; | ||
| use relay_event_schema::protocol::OurLog; | ||
|
|
||
| use crate::integrations::OtelFormat; | ||
| use crate::processing::logs::{Error, Result, Settings}; | ||
| use crate::processing::logs::{Error, Result}; | ||
| use crate::services::outcome::DiscardReason; | ||
|
|
||
| /// Expands OTeL logs into the [`OurLog`] format. | ||
| pub fn expand<F>(format: OtelFormat, payload: &[u8], mut produce: F) -> Result<Settings> | ||
| where | ||
| F: FnMut(OurLog), | ||
| { | ||
| let logs = parse_logs_data(format, payload)?; | ||
|
|
||
| for resource_logs in logs.resource_logs { | ||
| let resource = resource_logs.resource.as_ref(); | ||
| for scope_logs in resource_logs.scope_logs { | ||
| let scope = scope_logs.scope.as_ref(); | ||
| for log_record in scope_logs.log_records { | ||
| let log = relay_ourlogs::otel_to_sentry_log(log_record, resource, scope); | ||
| produce(log); | ||
| } | ||
| } | ||
| } | ||
| pub fn expand2(format: OtelFormat, payload: &[u8]) -> Result<Box<dyn Iterator<Item = OurLog>>> { | ||
| let logs: LogsData = parse_logs_data(format, payload).unwrap(); | ||
|
Check warning on line 13 in relay-server/src/processing/logs/integrations/otel.rs
|
||
|
|
||
| Ok(Settings::default()) | ||
| Ok(Box::new(logs.resource_logs.into_iter().flat_map( | ||
| |resource_logs| { | ||
| let resource = std::cell::RefCell::new(resource_logs.resource); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this This entire stream may be easier expressed if you build up a stream of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's because of all the nesting--that |
||
| resource_logs | ||
| .scope_logs | ||
| .into_iter() | ||
| .flat_map(move |scope_logs| { | ||
| let scope = scope_logs.scope; | ||
| let r = resource.clone(); | ||
| scope_logs.log_records.into_iter().map(move |log_record| { | ||
| let b = r.borrow(); | ||
| relay_ourlogs::otel_to_sentry_log(log_record, b.deref(), &scope) | ||
| }) | ||
| }) | ||
| }, | ||
| ))) | ||
| } | ||
|
|
||
| fn parse_logs_data(format: OtelFormat, payload: &[u8]) -> Result<LogsData, Error> { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,6 +55,9 @@ | |
| /// The log is invalid. | ||
| #[error("invalid: {0}")] | ||
| Invalid(DiscardReason), | ||
| // The expanded logs exceed the maximum number allowed. | ||
| // #[error("expanded logs exeeds limit")] | ||
| // TooManyExpandedLogs, | ||
| } | ||
|
|
||
| impl OutcomeError for Error { | ||
|
|
@@ -74,6 +77,8 @@ | |
| } | ||
| Self::ProcessingFailed(_) => Some(Outcome::Invalid(DiscardReason::Internal)), | ||
| Self::Invalid(reason) => Some(Outcome::Invalid(*reason)), | ||
| // TODO: Or should this be abuse? Or should this be filtered, or rate-limited? | ||
| // Self::TooManyExpandedLogs => Some(Outcome::Invalid(DiscardReason::InvalidLog)), | ||
| }; | ||
|
|
||
| (outcome, self) | ||
|
|
@@ -153,7 +158,7 @@ | |
| // Fast filters, which do not need expanded logs. | ||
| filter::feature_flag(ctx).reject(&logs)?; | ||
|
|
||
| let mut logs = process::expand(logs)?; | ||
| let mut logs = process::expand(logs, ctx.config.max_expanded_log_count())?; | ||
|
Check warning on line 161 in relay-server/src/processing/logs/mod.rs
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. max_expanded_log_count cap is post-materialization for integrations and skipped for containers The Evidence
Identified by Warden · wrdn-dos-review · HQH-YVE |
||
|
|
||
| validate::size(&mut logs, ctx); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,10 @@ | |
| /// Parses all serialized logs into their [`ExpandedLogs`] representation. | ||
| /// | ||
| /// Individual, invalid logs will be discarded. | ||
| pub fn expand(logs: Managed<SerializedLogs>) -> Result<Managed<ExpandedLogs>, Rejected<Error>> { | ||
| pub fn expand( | ||
| logs: Managed<SerializedLogs>, | ||
| max_expanded_log_count: usize, | ||
| ) -> Result<Managed<ExpandedLogs>, Rejected<Error>> { | ||
| let trust = logs.headers.meta().request_trust(); | ||
|
|
||
| logs.try_map(|logs, records| { | ||
|
|
@@ -44,7 +47,8 @@ | |
| let (settings, logs) = match items { | ||
| LogItems::Container(item) => expand_log_container(&item, trust)?, | ||
| LogItems::Integration(item) => { | ||
|
Comment on lines
48
to
49
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could also be streamed, then the question arises if the stream shouldn't be consumed here? |
||
| logs::integrations::expand(item, records, &headers).unwrap_or_default() | ||
| logs::integrations::expand(item, records, &headers, max_expanded_log_count) | ||
| .unwrap_or_default() | ||
|
Check warning on line 51 in relay-server/src/processing/logs/process.rs
|
||
| } | ||
| }; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we can derive this from the total size, so we don't have to derive a count when we already have a size.