| /* |
| * |
| * 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.cassandra.metrics; |
| |
| import java.lang.management.ManagementFactory; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.concurrent.TimeUnit; |
| import java.util.stream.Collectors; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import com.codahale.metrics.Meter; |
| import com.codahale.metrics.Metric; |
| import com.codahale.metrics.Timer; |
| import com.codahale.metrics.jvm.BufferPoolMetricSet; |
| import com.codahale.metrics.jvm.GarbageCollectorMetricSet; |
| import com.codahale.metrics.jvm.MemoryUsageGaugeSet; |
| import org.apache.cassandra.metrics.CassandraMetricsRegistry.MetricName; |
| import org.apache.cassandra.utils.EstimatedHistogram; |
| |
| import static com.codahale.metrics.MetricRegistry.name; |
| import static org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName; |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| |
| public class CassandraMetricsRegistryTest |
| { |
| // A class with a name ending in '$' |
| private static class StrangeName$ |
| { |
| } |
| |
| @Before |
| public void prepare() |
| { |
| CassandraMetricsRegistry.Metrics.getNames().forEach(CassandraMetricsRegistry.Metrics::remove); |
| } |
| |
| @Test |
| public void testChooseType() |
| { |
| assertEquals("StrangeName", MetricName.chooseType(null, StrangeName$.class)); |
| assertEquals("StrangeName", MetricName.chooseType("", StrangeName$.class)); |
| assertEquals("String", MetricName.chooseType(null, String.class)); |
| assertEquals("String", MetricName.chooseType("", String.class)); |
| |
| assertEquals("a", MetricName.chooseType("a", StrangeName$.class)); |
| assertEquals("b", MetricName.chooseType("b", String.class)); |
| } |
| |
| @Test |
| public void testMetricName() |
| { |
| MetricName name = new MetricName(StrangeName$.class, "NaMe", "ScOpE"); |
| assertEquals("StrangeName", name.getType()); |
| } |
| |
| @Test |
| public void testJvmMetricsRegistration() |
| { |
| CassandraMetricsRegistry registry = CassandraMetricsRegistry.Metrics; |
| |
| // Same registration as CassandraDaemon |
| registry.register("jvm.buffers", new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer())); |
| registry.register("jvm.gc", new GarbageCollectorMetricSet()); |
| registry.register("jvm.memory", new MemoryUsageGaugeSet()); |
| |
| Collection<String> names = registry.getNames(); |
| |
| // No metric with ".." in name |
| assertTrue(names.stream() |
| .filter(name -> name.contains("..")) |
| .count() |
| == 0); |
| |
| // There should be several metrics within each category |
| for (String category : new String[]{"jvm.buffers","jvm.gc","jvm.memory"}) |
| { |
| assertTrue(names.stream() |
| .filter(name -> name.startsWith(category+'.')) |
| .count() > 1); |
| } |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void testMetricSetRegistration() |
| { |
| CassandraMetricsRegistry registry = CassandraMetricsRegistry.Metrics; |
| DefaultNameFactory factory = new DefaultNameFactory("ThreadPools", "TestMetricSetRegistration"); |
| registry.register(factory.createMetricName("jvm.buffers"), new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer())); |
| } |
| |
| @Test |
| public void testDeltaBaseCase() |
| { |
| long[] last = new long[10]; |
| long[] now = new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| // difference between all zeros and a value should be the value |
| assertArrayEquals(now, CassandraMetricsRegistry.delta(now, last)); |
| // the difference between itself should be all 0s |
| assertArrayEquals(last, CassandraMetricsRegistry.delta(now, now)); |
| // verifying each value is calculated |
| assertArrayEquals(new long[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
| CassandraMetricsRegistry.delta(new long[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, now)); |
| } |
| |
| @Test |
| public void testDeltaHistogramSizeChange() |
| { |
| long[] count = new long[]{0, 1, 2, 3, 4, 5}; |
| assertArrayEquals(count, CassandraMetricsRegistry.delta(count, new long[3])); |
| assertArrayEquals(new long[6], CassandraMetricsRegistry.delta(count, new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); |
| } |
| |
| /** |
| * Test the updated timer values are estimated correctly (i.e., in the valid range, 1.2) in the micros based histogram. |
| */ |
| @Test |
| public void testTimer() |
| { |
| long[] offsets = EstimatedHistogram.newOffsets(DecayingEstimatedHistogramReservoir.LOW_BUCKET_COUNT, false); |
| Timer timer = new Timer(CassandraMetricsRegistry.createReservoir(TimeUnit.MICROSECONDS)); |
| timer.update(42, TimeUnit.NANOSECONDS); |
| timer.update(100, TimeUnit.NANOSECONDS); |
| timer.update(42, TimeUnit.MICROSECONDS); |
| timer.update(100, TimeUnit.MICROSECONDS); |
| timer.update(42, TimeUnit.MILLISECONDS); |
| timer.update(100, TimeUnit.MILLISECONDS); |
| timer.update(100, TimeUnit.SECONDS); |
| timer.update(100, TimeUnit.MINUTES); |
| int maxSeconds = 21356; |
| timer.update(maxSeconds, TimeUnit.SECONDS); |
| long[] counts = timer.getSnapshot().getValues(); |
| int expectedBucketsWithValues = 8; |
| int bucketsWithValues = 0; |
| for (int i = 0; i < counts.length; i++) |
| { |
| if (counts[i] != 0) |
| { |
| bucketsWithValues ++; |
| assertTrue( |
| inRange(offsets[i], TimeUnit.NANOSECONDS.toMicros(42), 1.2) |
| || inRange(offsets[i], TimeUnit.NANOSECONDS.toMicros(100), 1.2) |
| || inRange(offsets[i], TimeUnit.MICROSECONDS.toMicros(42), 1.2) |
| || inRange(offsets[i], TimeUnit.MICROSECONDS.toMicros(100), 1.2) |
| || inRange(offsets[i], TimeUnit.MILLISECONDS.toMicros(42), 1.2) |
| || inRange(offsets[i], TimeUnit.MILLISECONDS.toMicros(100), 1.2) |
| || inRange(offsets[i], TimeUnit.SECONDS.toMicros(100), 1.2) |
| || inRange(offsets[i], TimeUnit.MINUTES.toMicros(100), 1.2) |
| || inRange(offsets[i], TimeUnit.SECONDS.toMicros(maxSeconds), 1.2) |
| ); |
| } |
| } |
| assertEquals("42 and 100 nanos should both be put in the first bucket", |
| 2, counts[0]); |
| assertEquals(expectedBucketsWithValues, bucketsWithValues); |
| } |
| |
| @Test |
| public void testMetricAliasesRemoveByCondition() |
| { |
| LinkedList<MetricName> aliases = new LinkedList<>(); |
| int size = 10; |
| DefaultNameFactory factory = new DefaultNameFactory("Table", "FirstScope"); |
| DefaultNameFactory aliasFactory = new DefaultNameFactory("Table", "SecondScope"); |
| MetricName first = factory.createMetricName("FirstTestMetricAliasesOrder"); |
| for (int i = 0; i < size; i++) |
| aliases.add(aliasFactory.createMetricName("AliasFirstTestMetricAliasesOrder_" + UUID.randomUUID())); |
| |
| Meter metric = CassandraMetricsRegistry.Metrics.meter(first); |
| CassandraMetricsRegistry.Metrics.register(first, metric, aliases.toArray(new MetricName[size])); |
| List<String> all = CassandraMetricsRegistry.Metrics.getMetrics().keySet(). |
| stream() |
| .filter(m -> m.contains("FirstTestMetricAliasesOrder")) |
| .collect(Collectors.toList()); |
| |
| assertNotNull(all); |
| assertEquals(size + 1, all.size()); |
| |
| CassandraMetricsRegistry.Metrics.removeIfMatch(fullName -> |
| resolveShortMetricName(fullName, DefaultNameFactory.GROUP_NAME, "Table", null), |
| factory::createMetricName, |
| m -> {}); |
| Map<String, Metric> metrics = CassandraMetricsRegistry.Metrics.getMetrics(); |
| assertEquals(size, metrics.size()); |
| assertTrue(metrics.keySet().stream().allMatch(m -> m.startsWith(name(DefaultNameFactory.GROUP_NAME, "Table", "AliasFirstTestMetricAliasesOrder_")))); |
| |
| CassandraMetricsRegistry.Metrics.removeIfMatch(fullName -> |
| resolveShortMetricName(fullName, DefaultNameFactory.GROUP_NAME, "Table", null), |
| aliasFactory::createMetricName, |
| m -> {}); |
| assertTrue(CassandraMetricsRegistry.Metrics.getMetrics().isEmpty()); |
| } |
| |
| @Test |
| public void testMetricAliasesRegistration() |
| { |
| CassandraMetricsRegistry registry = CassandraMetricsRegistry.Metrics; |
| MetricNameFactory factory = new DefaultNameFactory("Table", "MetricsTestScope"); |
| MetricNameFactory aliasFactory = new DefaultNameFactory("Table", "MetricsTestAliasScope"); |
| |
| MetricName meter = factory.createMetricName("TestMeter"); |
| MetricName meterAlias = aliasFactory.createMetricName("TestMeterAlias"); |
| registry.meter(meter, meterAlias); |
| |
| MetricName histogram = factory.createMetricName("TestHistogram"); |
| MetricName histogramAlias = aliasFactory.createMetricName("TestHistogramAlias"); |
| registry.histogram(histogram, histogramAlias, false); |
| |
| MetricName counter = factory.createMetricName("TestCounter"); |
| MetricName counterAlias = aliasFactory.createMetricName("TestCounterAlias"); |
| registry.counter(counter, counterAlias); |
| |
| MetricName timer = factory.createMetricName("TestTimer"); |
| MetricName timerAlias = aliasFactory.createMetricName("TestTimerAlias"); |
| registry.timer(timer, timerAlias); |
| |
| Set<String> aliases = new HashSet<>(Arrays.asList(meter.getMetricName(), meterAlias.getMetricName(), |
| histogram.getMetricName(), histogramAlias.getMetricName(), |
| counter.getMetricName(), counterAlias.getMetricName(), |
| timer.getMetricName(), timerAlias.getMetricName())); |
| |
| assertTrue(registry.getMetrics().keySet().containsAll(aliases)); |
| assertTrue(registry.getNames().containsAll(aliases)); |
| } |
| |
| private boolean inRange(long anchor, long input, double range) |
| { |
| return input / ((double) anchor) < range; |
| } |
| } |