Skip to content

Commit b634432

Browse files
pabloemjszwedko
andauthored
fix(log_to_metric transform): set not working in log-to-metric transform when all_metrics=true (vectordotdev#20228)
* Fixing bug - set missing in log-to-metric transform * Adding a test case * Adding unit test * Create 20228_fix-log-to-metric-set-supported.fix.md * Update 20228_fix-log-to-metric-set-supported.fix.md * Update changelog.d/20228_fix-log-to-metric-set-supported.fix.md Co-authored-by: Jesse Szwedko <[email protected]> * Update changelog.d/20228_fix-log-to-metric-set-supported.fix.md Co-authored-by: Jesse Szwedko <[email protected]> * cargo fmt Signed-off-by: Jesse Szwedko <[email protected]> --------- Signed-off-by: Jesse Szwedko <[email protected]> Co-authored-by: Jesse Szwedko <[email protected]> Co-authored-by: Jesse Szwedko <[email protected]>
1 parent 0550286 commit b634432

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed an issue where the log_to_metric transform with all_metrics=true config failed to convert properly-formatted 'set'-type events into metrics.
2+
3+
authors: pabloem

src/transforms/log_to_metric.rs

+70
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,34 @@ fn get_gauge_value(log: &LogEvent) -> Result<MetricValue, TransformError> {
493493
})
494494
}
495495

496+
fn get_set_value(log: &LogEvent) -> Result<MetricValue, TransformError> {
497+
let set_values = log
498+
.get(event_path!("set", "values"))
499+
.ok_or_else(|| TransformError::PathNotFound {
500+
path: "set.values".to_string(),
501+
})?
502+
.as_array()
503+
.ok_or_else(|| TransformError::ParseError {
504+
path: "set.values".to_string(),
505+
kind: TransformParseErrorKind::ArrayError,
506+
})?;
507+
508+
let mut values: Vec<String> = Vec::new();
509+
for e_value in set_values {
510+
let value = e_value
511+
.as_bytes()
512+
.ok_or_else(|| TransformError::ParseError {
513+
path: "set.values".to_string(),
514+
kind: TransformParseErrorKind::ArrayError,
515+
})?;
516+
values.push(String::from_utf8_lossy(value).to_string());
517+
}
518+
519+
Ok(MetricValue::Set {
520+
values: values.into_iter().collect(),
521+
})
522+
}
523+
496524
fn get_distribution_value(log: &LogEvent) -> Result<MetricValue, TransformError> {
497525
let event_samples = log
498526
.get(event_path!("distribution", "samples"))
@@ -755,6 +783,7 @@ fn to_metrics(event: &Event) -> Result<Metric, TransformError> {
755783
"histogram" => Some(get_histogram_value(log)?),
756784
"summary" => Some(get_summary_value(log)?),
757785
"counter" => Some(get_counter_value(log)?),
786+
"set" => Some(get_set_value(log)?),
758787
_ => None,
759788
};
760789

@@ -1933,4 +1962,45 @@ mod tests {
19331962
.with_timestamp(Some(ts()))
19341963
);
19351964
}
1965+
1966+
#[tokio::test]
1967+
async fn transform_set() {
1968+
let config = parse_yaml_config(
1969+
r#"
1970+
metrics: []
1971+
all_metrics: true
1972+
"#,
1973+
);
1974+
1975+
let json_str = r#"{
1976+
"set": {
1977+
"values": ["990.0", "1234"]
1978+
},
1979+
"kind": "incremental",
1980+
"name": "test.transform.set",
1981+
"tags": {
1982+
"env": "test_env",
1983+
"host": "localhost"
1984+
}
1985+
}"#;
1986+
let log = create_log_event(json_str);
1987+
let metric = do_transform(config, log.clone()).await.unwrap();
1988+
assert_eq!(
1989+
*metric.as_metric(),
1990+
Metric::new_with_metadata(
1991+
"test.transform.set",
1992+
MetricKind::Incremental,
1993+
MetricValue::Set {
1994+
values: vec!["990.0".into(), "1234".into()].into_iter().collect()
1995+
},
1996+
metric.metadata().clone(),
1997+
)
1998+
.with_namespace(Some("test_namespace"))
1999+
.with_tags(Some(metric_tags!(
2000+
"env" => "test_env",
2001+
"host" => "localhost",
2002+
)))
2003+
.with_timestamp(Some(ts()))
2004+
);
2005+
}
19362006
}

testing/github-20228/config.toml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
[[tests]]
3+
name = "Test log_to_metric conversion of sets"
4+
5+
# The inputs for the test
6+
[[tests.inputs]]
7+
insert_at = "parse_json"
8+
type = "log"
9+
10+
[tests.inputs.log_fields]
11+
message = '{"name": "sample.set.metric", "tags": {"host": "my-host", "region": "us-west"}, "kind": "incremental", "values": [1, 2, 3, 4, 5]}'
12+
13+
[[tests.outputs]]
14+
extract_from = "convert_metrics"
15+
16+
# We just validate that the values are the same
17+
[[tests.outputs.conditions]]
18+
type = "vrl"
19+
source = '''
20+
assert!(.name == "sample.set.metric")
21+
assert!(.tags.host == "my-host")
22+
assert!(.tags.region == "us-west")
23+
assert!(.kind == "incremental")
24+
'''
25+
26+
[sources.stdin]
27+
type = "stdin"
28+
29+
[sinks.stdout]
30+
inputs = ["convert_metrics"]
31+
type = "console"
32+
encoding.codec = "json"
33+
34+
[transforms.parse_json]
35+
inputs = ["stdin"]
36+
type = "remap"
37+
source = '''
38+
. = parse_json!(.message)
39+
'''
40+
41+
[transforms.convert_metrics]
42+
inputs = ["parse_json"]
43+
type = "log_to_metric"
44+
all_metrics = true
45+
metrics = []
46+

0 commit comments

Comments
 (0)