From 909d66c467cefea0d16d027a787f6656a36b8de1 Mon Sep 17 00:00:00 2001 From: kaisecheng <69120390+kaisecheng@users.noreply.github.com> Date: Mon, 23 Jun 2025 13:23:07 +0100 Subject: [PATCH] Added support for GAUGE_LIST metric type (#17721) * Added support for GAUGE_LIST metric type Prior to the changes, log emits a warning about an unknown gauge metric type when running pipeline-to-pipeline due to serialization of `{send_to:[pipeline_name]}`. This commit added support of List type to eliminate the warning. --- .../instrument/metrics/MetricType.java | 5 ++ .../metrics/gauge/LazyDelegatingGauge.java | 3 + .../instrument/metrics/gauge/ListGauge.java | 41 ++++++++++ .../instrument/metrics/MetricTypeTest.java | 1 + .../gauge/LazyDelegatingGaugeTest.java | 18 +++- .../metrics/gauge/ListGaugeTest.java | 82 +++++++++++++++++++ 6 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/ListGauge.java create mode 100644 logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/ListGaugeTest.java diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java index 6d813779d..0ca15cba3 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/MetricType.java @@ -68,6 +68,11 @@ public enum MetricType { */ GAUGE_RUBYTIMESTAMP("gauge/rubytimestamp"), + /** + * A gauge backed by a {@link java.util.List} type. + */ + GAUGE_LIST("gauge/list"), + /** * A flow-rate {@link FlowMetric}, instantiated with one or more backing {@link Metric}{@code }. */ diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java index 0afaea618..cf9f30ad8 100644 --- a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGauge.java @@ -27,6 +27,7 @@ import org.logstash.ext.JrubyTimestampExtLibrary.RubyTimestamp; import org.logstash.instrument.metrics.AbstractMetric; import org.logstash.instrument.metrics.MetricType; +import java.util.List; import java.util.Optional; /** @@ -117,6 +118,8 @@ public class LazyDelegatingGauge extends AbstractMetric implements Gauge lazyMetric = new RubyHashGauge(key, (RubyHash) value); } else if (value instanceof RubyTimestamp) { lazyMetric = new RubyTimeStampGauge(key, (RubyTimestamp) value); + } else if (value instanceof List) { + lazyMetric = new ListGauge(key, (List) value); } else { LOGGER.warn("A gauge metric of an unknown type ({}) has been created for key: {}. This may result in invalid serialization. It is recommended to " + "log an issue to the responsible developer/development team.", value.getClass().getCanonicalName(), key); diff --git a/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/ListGauge.java b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/ListGauge.java new file mode 100644 index 000000000..fc567ed7c --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/instrument/metrics/gauge/ListGauge.java @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +package org.logstash.instrument.metrics.gauge; + +import org.logstash.instrument.metrics.MetricType; + +import java.util.List; + +public class ListGauge extends AbstractGaugeMetric> { + + protected ListGauge(String name) { + super(name); + } + + protected ListGauge(String name, List initialValue) { + super(name, initialValue); + } + + public MetricType getType() { + return MetricType.GAUGE_LIST; + } + +} diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java index 941ffe87a..21c6a7faf 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/MetricTypeTest.java @@ -47,6 +47,7 @@ public class MetricTypeTest { nameMap.put(MetricType.GAUGE_TEXT, "gauge/text"); nameMap.put(MetricType.GAUGE_BOOLEAN, "gauge/boolean"); nameMap.put(MetricType.GAUGE_NUMBER, "gauge/number"); + nameMap.put(MetricType.GAUGE_LIST, "gauge/list"); nameMap.put(MetricType.GAUGE_UNKNOWN, "gauge/unknown"); nameMap.put(MetricType.GAUGE_RUBYHASH, "gauge/rubyhash"); nameMap.put(MetricType.GAUGE_RUBYTIMESTAMP, "gauge/rubytimestamp"); diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java index 0a5617877..fd00e7665 100644 --- a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/LazyDelegatingGaugeTest.java @@ -20,8 +20,6 @@ package org.logstash.instrument.metrics.gauge; -import java.net.URI; -import java.util.Collections; import org.jruby.RubyHash; import org.junit.Test; import org.logstash.RubyUtil; @@ -29,6 +27,10 @@ import org.logstash.Timestamp; import org.logstash.ext.JrubyTimestampExtLibrary; import org.logstash.instrument.metrics.MetricType; +import java.net.URI; +import java.util.Collections; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -91,6 +93,11 @@ public class LazyDelegatingGaugeTest { assertThat(gauge.get()).isNull(); assertThat(gauge.getType()).isNull(); + //List + gauge = new LazyDelegatingGauge("bar", List.of("one", "two")); + assertThat(gauge.getValue().toString()).isEqualTo("[one, two]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + assertThat(gauge.getName()).isNotEmpty(); } @@ -169,6 +176,13 @@ public class LazyDelegatingGaugeTest { gauge.set(null); assertThat(gauge.getValue()).isNull(); assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_TEXT); + + // List + gauge = new LazyDelegatingGauge("bar"); + gauge.set(List.of(1,2)); + assertThat(gauge.getValue().toString()).isEqualTo("[1, 2]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } } diff --git a/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/ListGaugeTest.java b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/ListGaugeTest.java new file mode 100644 index 000000000..b599c4c4e --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/instrument/metrics/gauge/ListGaugeTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +package org.logstash.instrument.metrics.gauge; + +import org.jruby.RubyHash; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Test; +import org.logstash.RubyUtil; +import org.logstash.instrument.metrics.MetricType; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link TextGauge} + */ +public class ListGaugeTest { + @Test + public void getSetStrings() { + ListGauge gauge = new ListGauge("bar"); + gauge.set(List.of("pipeline_name1", "pipeline_name2")); + assertThat(gauge.getValue().toString()).isEqualTo("[pipeline_name1, pipeline_name2]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } + + @Test + public void getSetNull() { + ListGauge gauge = new ListGauge("bar"); + gauge.set(null); + assertThat(gauge.getValue()).isNull(); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } + + @Test + public void getSetListOfNull() { + List nullList = new ArrayList<>(Collections.nCopies(2, null)); + ListGauge gauge = new ListGauge("bar"); + gauge.set(nullList); + assertThat(gauge.getValue().toString()).isEqualTo("[null, null]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } + + @Test + public void getSetHash() { + IRubyObject[] args = {RubyUtil.RUBY.newString("k"), RubyUtil.RUBY.newString("v")}; + RubyHash rubyHash = RubyHash.newHash(RubyUtil.RUBY, args[0], args[1]); + + ListGauge gauge = new ListGauge("bar"); + gauge.set(List.of(rubyHash)); + assertThat(gauge.getValue().toString()).isEqualTo("[{\"k\"=>\"v\"}]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } + + @Test + public void getSetNumber() { + ListGauge gauge = new ListGauge("bar"); + gauge.set(List.of(123, 456.7)); + assertThat(gauge.getValue().toString()).isEqualTo("[123, 456.7]"); + assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LIST); + } +}