-
Notifications
You must be signed in to change notification settings - Fork 2.2k
fix(new_relic sink): Multiple fixes related to metrics #18151
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
Merged
Merged
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
05025b1
Convert tags into attributes.
asllop 4cdef4e
Merge branch 'vectordotdev:master' into master
asllop 087d4bf
Decompose metric into parts to reuse tags instead of cloning.
asllop 2dd2668
Remove unnecessary blocks.
asllop 6020efb
Set metric type.
asllop 9e7d57c
Fix field name typo.
asllop 567f236
Remove unnecessary brackets.
asllop c3b4784
Merge branch 'master' into master
asllop b755769
Cargo fmt.
asllop 67943c9
Merge branch 'master' of https://github.com/asllop/vector
asllop 48f16d8
Update src/sinks/new_relic/model.rs
asllop af14a7d
Update src/sinks/new_relic/model.rs
asllop 137943c
Fix typo.
asllop 2a2282c
Add tests for newly supported metrics.
asllop b72faed
Simplify metric type cases.
asllop 84a8d61
Merge branch 'vectordotdev:master' into master
asllop 41b41ab
Cargo fmt.
asllop f247c95
Merge remote-tracking branch 'origin/master' into asllop/master
jszwedko 62addd3
Update to handle new tag model
jszwedko 1f2bc83
PR feedback
jszwedko f256b33
refactor
dsmith3197 0ecfa81
add dropped event metrics
dsmith3197 c3769db
track unsupported metric types as well
dsmith3197 494b12e
merge master
dsmith3197 c11c958
feedback
dsmith3197 4e4943f
more feedback
dsmith3197 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,16 @@ | ||
| use std::{collections::HashMap, convert::TryFrom, fmt::Debug, time::SystemTime}; | ||
| use std::{ | ||
| collections::{BTreeMap, HashMap}, | ||
| convert::TryFrom, | ||
| fmt::Debug, | ||
| time::SystemTime, | ||
| }; | ||
|
|
||
| use chrono::{DateTime, Utc}; | ||
| use ordered_float::NotNan; | ||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| use super::NewRelicSinkError; | ||
| use crate::event::{Event, MetricValue, Value}; | ||
| use crate::event::{Event, MetricKind, MetricValue, Value}; | ||
|
|
||
| #[derive(Debug)] | ||
| pub enum NewRelicApiModel { | ||
|
|
@@ -21,30 +26,9 @@ type DataStore = HashMap<String, Vec<KeyValData>>; | |
| pub struct MetricsApiModel(pub Vec<DataStore>); | ||
|
|
||
| impl MetricsApiModel { | ||
| pub fn new(metric_array: Vec<(Value, Value, Value)>) -> Self { | ||
| let mut metric_data_array = vec![]; | ||
| for (m_name, m_value, m_timestamp) in metric_array { | ||
| let mut metric_data = KeyValData::new(); | ||
| metric_data.insert("name".to_owned(), m_name); | ||
| metric_data.insert("value".to_owned(), m_value); | ||
| match m_timestamp { | ||
| Value::Timestamp(ts) => { | ||
| metric_data.insert("timestamp".to_owned(), Value::from(ts.timestamp())); | ||
| } | ||
| Value::Integer(i) => { | ||
| metric_data.insert("timestamp".to_owned(), Value::from(i)); | ||
| } | ||
| _ => { | ||
| metric_data.insert( | ||
| "timestamp".to_owned(), | ||
| Value::from(DateTime::<Utc>::from(SystemTime::now()).timestamp()), | ||
| ); | ||
| } | ||
| } | ||
| metric_data_array.push(metric_data); | ||
| } | ||
| pub fn new(metric_array: Vec<KeyValData>) -> Self { | ||
| let mut metric_store = DataStore::new(); | ||
| metric_store.insert("metrics".to_owned(), metric_data_array); | ||
| metric_store.insert("metrics".to_owned(), metric_array); | ||
| Self(vec![metric_store]) | ||
| } | ||
| } | ||
|
|
@@ -57,39 +41,88 @@ impl TryFrom<Vec<Event>> for MetricsApiModel { | |
|
|
||
| for buf_event in buf_events { | ||
| if let Event::Metric(metric) = buf_event { | ||
| // Future improvement: put metric type. If type = count, NR metric model requires an interval.ms field, that is not provided by the Vector Metric model. | ||
| match metric.value() { | ||
| MetricValue::Gauge { value } => { | ||
| metric_array.push(( | ||
| Value::from(metric.name().to_owned()), | ||
| Value::from( | ||
| NotNan::new(*value).map_err(|_| { | ||
| NewRelicSinkError::new("NaN value not supported") | ||
| })?, | ||
| ), | ||
| Value::from(metric.timestamp()), | ||
| )); | ||
| // Generate Value::Object() from BTreeMap<String, String> | ||
| let (series, data, _) = metric.into_parts(); | ||
|
|
||
| // We only handle gauge and counter metrics | ||
| if let MetricValue::Gauge { value } | MetricValue::Counter { value } = data.value { | ||
| let mut metric_data = KeyValData::new(); | ||
|
|
||
| // Set type and type related attributes | ||
| if let (MetricValue::Counter { .. }, MetricKind::Incremental) = | ||
| (&data.value, &data.kind) | ||
| { | ||
| if let Some(interval_ms) = data.time.interval_ms { | ||
| metric_data.insert( | ||
| "interval.ms".to_owned(), | ||
| Value::from(interval_ms.get() as i64), | ||
| ); | ||
| } else { | ||
| // Incremental counter without an interval is worthless, skip this metric | ||
| continue; | ||
| } | ||
| metric_data.insert("type".to_owned(), Value::from("count")); | ||
| } else { | ||
| // Anything that's not an incremental counter is considered a gauge, that is gauge and absolute counters metrics. | ||
| metric_data.insert("type".to_owned(), Value::from("gauge")); | ||
| } | ||
|
dsmith3197 marked this conversation as resolved.
Outdated
|
||
| MetricValue::Counter { value } => { | ||
| metric_array.push(( | ||
| Value::from(metric.name().to_owned()), | ||
|
|
||
| // Set name, value, and timestamp | ||
| metric_data.insert("name".to_owned(), Value::from(series.name.name)); | ||
| metric_data.insert( | ||
| "value".to_owned(), | ||
| Value::from( | ||
| NotNan::new(value) | ||
| .map_err(|_| NewRelicSinkError::new("NaN value not supported"))?, | ||
| ), | ||
| ); | ||
| metric_data.insert( | ||
| "timestamp".to_owned(), | ||
| Value::from( | ||
| data.time | ||
| .timestamp | ||
| .unwrap_or_else(|| DateTime::<Utc>::from(SystemTime::now())) | ||
| .timestamp(), | ||
| ), | ||
| ); | ||
|
|
||
| if let Some(tags) = series.tags { | ||
| metric_data.insert( | ||
| "attributes".to_owned(), | ||
| Value::from( | ||
| NotNan::new(*value).map_err(|_| { | ||
| NewRelicSinkError::new("NaN value not supported") | ||
| })?, | ||
| tags.iter_single() | ||
| .map(|(key, value)| (key.to_string(), Value::from(value))) | ||
| .collect::<BTreeMap<_, _>>(), | ||
| ), | ||
| Value::from(metric.timestamp()), | ||
| )); | ||
| ); | ||
| } | ||
| _ => { | ||
| // Unrecognized metric type | ||
|
|
||
| // Set type and type related attributes | ||
| if let (MetricValue::Counter { .. }, MetricKind::Incremental) = | ||
| (data.value, data.kind) | ||
| { | ||
| if let Some(interval_ms) = data.time.interval_ms { | ||
| metric_data.insert( | ||
| "interval.ms".to_owned(), | ||
| Value::from(interval_ms.get() as i64), | ||
| ); | ||
| } else { | ||
| // Incremental counter without an interval is worthless, skip this metric | ||
| continue; | ||
| } | ||
| metric_data.insert("type".to_owned(), Value::from("count")); | ||
| } else { | ||
| // Anything that's not an incremental counter is considered a gauge, that is gauge and absolute counters metrics. | ||
| metric_data.insert("type".to_owned(), Value::from("gauge")); | ||
|
dsmith3197 marked this conversation as resolved.
Outdated
|
||
| } | ||
|
dsmith3197 marked this conversation as resolved.
Outdated
|
||
|
|
||
| metric_array.push(metric_data); | ||
|
dsmith3197 marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+116
to
139
Contributor
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. Here and elsewhere, I'm not a fan of emitting these events within a |
||
|
|
||
| if !metric_array.is_empty() { | ||
| Ok(MetricsApiModel::new(metric_array)) | ||
| Ok(Self::new(metric_array)) | ||
| } else { | ||
| Err(NewRelicSinkError::new("No valid metrics to generate")) | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 think we should track the number of events dropped here (and in the encapsulating if statement) with
component_discarded_events_total. What do you think?Are we concerned that this might create a regression, given that we were not previously dropping this? I'm unclear about how often this scenario might occur, but an alternative would be to report these as gauges, which is the default value.
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.
On further investigation, the New Relic docs state that cumulative counters can be given the
cumulativeCounttype and will be incrementalized on the server side.