/** * Copyright 2013 Netflix, Inc. * <p/> * Licensed 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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 com.netflix.servo.publish; import com.netflix.servo.BasicMonitorRegistry; import com.netflix.servo.Metric; import com.netflix.servo.MonitorRegistry; import com.netflix.servo.annotations.DataSourceType; import com.netflix.servo.monitor.AbstractMonitor; import com.netflix.servo.monitor.Counter; import com.netflix.servo.monitor.MonitorConfig; import com.netflix.servo.monitor.Monitors; import org.testng.annotations.Test; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.concurrent.atomic.AtomicLong; import static com.netflix.servo.publish.BasicMetricFilter.MATCH_ALL; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; public class MonitorRegistryMetricPollerTest { private static final long TEN_SECONDS = 10 * 1000; private static final long ONE_MINUTE = 60 * 1000; private static final long ONE_HOUR = 60 * ONE_MINUTE; @Test public void testBasic() throws Exception { MonitorRegistry registry = new BasicMonitorRegistry(); registry.register(Monitors.newCounter("test")); MetricPoller poller = new MonitorRegistryMetricPoller(registry); Metric metric = poller.poll(MATCH_ALL).get(0); MonitorConfig expected = MonitorConfig.builder("test") .withTag(DataSourceType.COUNTER) .build(); assertEquals(metric.getConfig(), expected); } @Test public void testSlowMonitor() throws Exception { MonitorRegistry registry = new BasicMonitorRegistry(); registry.register(new SlowCounter("slow")); registry.register(Monitors.newCounter("test")); MetricPoller poller = new MonitorRegistryMetricPoller(registry); long start = System.currentTimeMillis(); Metric metric = poller.poll(MATCH_ALL).get(0); long end = System.currentTimeMillis(); // Verify we didn't wait too long, we should only wait 1 second but allow up to // 10 to make it less likely to have spurious test failures assertTrue(end - start < TEN_SECONDS); MonitorConfig expected = MonitorConfig.builder("test") .withTag(DataSourceType.COUNTER) .build(); assertEquals(metric.getConfig(), expected); } @Test(enabled = false) public void testShutdown() throws Exception { MonitorRegistry registry = new BasicMonitorRegistry(); registry.register(Monitors.newCounter("test")); final String threadPrefix = "ServoMonitorGetValueLimiter"; Thread.sleep(1000); int baseCount = countThreadsWithName(threadPrefix); MonitorRegistryMetricPoller[] pollers = new MonitorRegistryMetricPoller[10]; for (int i = 0; i < pollers.length; ++i) { pollers[i] = new MonitorRegistryMetricPoller(registry); pollers[i].poll(MATCH_ALL); } int retries = 0; for (; retries < 10; ++retries) { int currentThreads = countThreadsWithName(threadPrefix); if (currentThreads >= 10 + baseCount) { break; } System.err.println(String.format("currentThreads: %d/%d", currentThreads, baseCount)); Thread.sleep(200); } assertTrue(retries < 10); for (MonitorRegistryMetricPoller poller : pollers) { poller.shutdown(); } Thread.sleep(1000); assertTrue(countThreadsWithName(threadPrefix) <= baseCount); // Verify threads will be cleanup up by gc /*System.err.println("pre-gc: " + countThreadsWithName("ServoMonitorGetValueLimiter")); for (int i = 0; i < pollers.length; ++i) { pollers[i] = null; } System.gc(); Thread.sleep(1000); System.err.println("post-gc: " + countThreadsWithName("ServoMonitorGetValueLimiter"));*/ } private int countThreadsWithName(String prefix) { final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); final long[] ids = bean.getAllThreadIds(); final ThreadInfo[] infos = bean.getThreadInfo(ids); int count = 0; for (ThreadInfo info : infos) { if (info != null && info.getThreadName().startsWith(prefix)) { ++count; } } return count; } private static class SlowCounter extends AbstractMonitor<Number> implements Counter { private final AtomicLong count = new AtomicLong(); public SlowCounter(String name) { super(MonitorConfig.builder(name).withTag(DataSourceType.COUNTER).build()); } @Override public void increment() { count.incrementAndGet(); } @Override public void increment(long amount) { count.getAndAdd(amount); } @Override public Number getValue(int pollerIndex) { try { Thread.sleep(ONE_HOUR); } catch (Exception e) { System.err.println("Ignoring exception " + e.getMessage()); } return count.get(); } } }