-
Notifications
You must be signed in to change notification settings - Fork 331
SAMZA-1733 New metric type Listgauge #541
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
Changes from 5 commits
5ae1df9
5a3ef7b
75ef5d2
1efed5a
d2922c5
1f08eae
6f19ba0
4f08cd1
bdc85d4
5c1ed0a
c1884e4
c7821ba
9ba8e5b
fd77c53
cc4d881
863d850
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 |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF 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.apache.samza.metrics; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
|
|
||
|
|
||
| /** | ||
| * A {@link ListGauge} is a {@link org.apache.samza.metrics.Metric} that buffers multiple instances of a type T in a list. | ||
| * {@link ListGauge}s are useful for maintaining, recording, or collecting values over time. | ||
| * For example, a set of specific logging-events (e.g., errors). | ||
| * | ||
| * Eviction from list is either done by consuming-code using the remove APIs or by specifying an eviction policy | ||
|
||
| * at creation time. | ||
| * | ||
| * All public methods are thread-safe. | ||
| * | ||
| */ | ||
| public class ListGauge<T> implements Metric { | ||
| private final String name; | ||
| private final List<T> metricList; | ||
|
||
| private ListGaugeEvictionPolicy<T> listGaugeEvictionPolicy; | ||
|
|
||
| private final static int DEFAULT_POLICY_NUM_RETAIN = 60; | ||
|
|
||
| /** | ||
| * Create a new {@link ListGauge} with no auto eviction, callers can add/remove items as desired. | ||
| * @param name Name to be assigned | ||
| */ | ||
| public ListGauge(String name) { | ||
| this.name = name; | ||
| this.metricList = new ArrayList<T>(DEFAULT_POLICY_NUM_RETAIN); | ||
| this.listGaugeEvictionPolicy = new RetainLastNPolicy<T>(this, DEFAULT_POLICY_NUM_RETAIN); | ||
| } | ||
|
|
||
| /** | ||
| * Get the name assigned to this {@link ListGauge} | ||
| * @return the assigned name | ||
| */ | ||
| public String getName() { | ||
| return this.name; | ||
| } | ||
|
|
||
| /** | ||
| * Get the Collection of Gauge values currently in the list, used when serializing this Gauge. | ||
|
||
| * @return the collection of gauge values | ||
| */ | ||
| public synchronized Collection<T> getValue() { | ||
|
||
| return Collections.unmodifiableList(this.metricList); | ||
| } | ||
|
|
||
| /** | ||
| * Package-private method to change the eviction policy | ||
| * @param listGaugeEvictionPolicy | ||
| */ | ||
| synchronized void setEvictionPolicy(ListGaugeEvictionPolicy<T> listGaugeEvictionPolicy) { | ||
|
||
| this.listGaugeEvictionPolicy = listGaugeEvictionPolicy; | ||
| } | ||
|
|
||
| /** | ||
| * Add a gauge to the list | ||
| * @param value The Gauge value to be added | ||
| */ | ||
| public synchronized void add(T value) { | ||
| this.metricList.add(value); | ||
|
|
||
| // notify the policy object (if one is present), for performing any eviction that may be needed. | ||
| // note: monitor is being held | ||
| if (this.listGaugeEvictionPolicy != null) { | ||
| this.listGaugeEvictionPolicy.elementAddedCallback(); | ||
| } | ||
| } | ||
|
|
||
| public synchronized boolean remove(T value) { | ||
|
||
| return this.metricList.remove(value); | ||
| } | ||
|
|
||
| /** | ||
| * {@inheritDoc} | ||
| */ | ||
| @Override | ||
| public synchronized void visit(MetricsVisitor visitor) { | ||
|
||
| visitor.listGauge(this); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF 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.apache.samza.metrics; | ||
|
|
||
| public interface ListGaugeEvictionPolicy<T> { | ||
|
||
| void elementAddedCallback(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF 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.apache.samza.metrics; | ||
|
|
||
| import java.util.Collection; | ||
| import java.util.Iterator; | ||
|
|
||
|
|
||
| public class RetainLastNPolicy<T> implements ListGaugeEvictionPolicy<T> { | ||
|
|
||
| private final ListGauge<T> listGauge; | ||
| private final int nItems; | ||
|
|
||
| public RetainLastNPolicy(ListGauge<T> listGauge, int numItems) { | ||
| this.listGauge = listGauge; | ||
| this.nItems = numItems; | ||
| } | ||
|
|
||
| @Override | ||
| public void elementAddedCallback() { | ||
| // get a snapshot of the list | ||
| Collection<T> listGaugeCollection = this.listGauge.getValue(); | ||
| int numToEvict = listGaugeCollection.size() - nItems; | ||
| Iterator<T> iterator = listGaugeCollection.iterator(); | ||
| while (numToEvict > 0 && iterator.hasNext()) { | ||
| // Remove in FIFO order to retain the last nItems | ||
| listGauge.remove(iterator.next()); | ||
|
||
| numToEvict--; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF 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.apache.samza.metrics; | ||
|
|
||
| import java.time.Duration; | ||
| import java.util.Collection; | ||
| import java.util.Iterator; | ||
| import org.junit.Assert; | ||
| import org.junit.Test; | ||
|
|
||
|
|
||
| /** | ||
| * Class to encapsulate test-cases for {@link org.apache.samza.metrics.ListGauge} | ||
| */ | ||
| public class TestListGauge { | ||
|
|
||
| private final static Duration THREAD_TEST_TIMEOUT = Duration.ofSeconds(10); | ||
|
|
||
| @Test | ||
| public void basicTest() { | ||
| ListGauge<String> listGauge = new ListGauge<String>("sampleListGauge"); | ||
| listGauge.add("sampleValue"); | ||
| Assert.assertEquals("Names should be the same", listGauge.getName(), "sampleListGauge"); | ||
| Assert.assertEquals("List sizes should match", listGauge.getValue().size(), 1); | ||
| Assert.assertEquals("ListGauge should contain sampleGauge", listGauge.getValue().contains("sampleValue"), true); | ||
| } | ||
|
|
||
| @Test | ||
| public void testSizeEnforcement() { | ||
| ListGauge listGauge = new ListGauge<String>("listGauge"); | ||
| listGauge.setEvictionPolicy(new RetainLastNPolicy(listGauge, 10)); | ||
| for (int i = 15; i > 0; i--) { | ||
| listGauge.add("v" + i); | ||
| } | ||
| Assert.assertEquals("List sizes should be as configured at creation time", listGauge.getValue().size(), 10); | ||
|
|
||
| int valueIndex = 10; | ||
| Collection<String> currentList = listGauge.getValue(); | ||
| Iterator iterator = currentList.iterator(); | ||
| while (iterator.hasNext()) { | ||
| String gaugeValue = (String) iterator.next(); | ||
| Assert.assertTrue(gaugeValue.equals("v" + valueIndex)); | ||
| valueIndex--; | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testThreadSafety() throws InterruptedException { | ||
| ListGauge<Integer> listGauge = new ListGauge<Integer>("listGauge"); | ||
| listGauge.setEvictionPolicy(new RetainLastNPolicy(listGauge, 20)); | ||
|
|
||
| Thread thread1 = new Thread(new Runnable() { | ||
| @Override | ||
| public void run() { | ||
| for (int i = 1; i <= 100; i++) { | ||
| listGauge.add(i); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| Thread thread2 = new Thread(new Runnable() { | ||
| @Override | ||
| public void run() { | ||
| for (int i = 1; i <= 100; i++) { | ||
| listGauge.add(i); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| thread1.start(); | ||
| thread2.start(); | ||
|
|
||
| thread1.join(THREAD_TEST_TIMEOUT.toMillis()); | ||
| thread2.join(THREAD_TEST_TIMEOUT.toMillis()); | ||
|
|
||
| Assert.assertTrue("ListGauge should have the last 20 values", listGauge.getValue().size() == 20); | ||
| for (Integer gaugeValue : listGauge.getValue()) { | ||
| Assert.assertTrue("Values should have the last 20 range", gaugeValue <= 100 && gaugeValue > 80); | ||
| } | ||
| } | ||
| } |
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.
minor: Do you need the fully qualified name "{@link org.apache.samza.metrics.Metric}" here? it seems like you should be able to use {@link Metric}