/* * 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 gobblin.metrics; import java.io.IOException; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.Timer; import static gobblin.metrics.test.TestConstants.*; import gobblin.metrics.reporter.ContextAwareScheduledReporter; /** * Unit tests for {@link MetricContext}. * * <p> * This test class also tests classes {@link ContextAwareCounter}, {@link ContextAwareMeter}, * {@link ContextAwareHistogram}, {@link ContextAwareTimer}, {@link ContextAwareGauge}, * {@link gobblin.metrics.reporter.ContextAwareScheduledReporter}, and {@link TagBasedMetricFilter}. * </p> * * @author Yinan Li */ @Test(groups = {"gobblin.metrics"}) public class MetricContextTest { private static final String CHILD_CONTEXT_NAME = "TestChildContext"; private static final String JOB_ID_KEY = "job.id"; private static final String JOB_ID_PREFIX = "TestJob-"; private static final String TASK_ID_KEY = "task.id"; private static final String TASK_ID_PREFIX = "TestTask-"; private static final String METRIC_GROUP_KEY = "metric.group"; private static final String INPUT_RECORDS_GROUP = "INPUT_RECORDS"; private static final String TEST_REPORTER_NAME = TestContextAwareScheduledReporter.class.getName(); private MetricContext context; private MetricContext childContext; @BeforeClass public void setUp() { String contextName = CONTEXT_NAME + "_" + UUID.randomUUID().toString(); this.context = MetricContext.builder(contextName) .addTag(new Tag<String>(JOB_ID_KEY, JOB_ID_PREFIX + 0)) .build(); Assert.assertEquals(this.context.getName(), contextName); Assert.assertTrue(this.context.getParent().isPresent()); Assert.assertEquals(this.context.getParent().get(), RootMetricContext.get()); Assert.assertEquals(this.context.getTags().size(), 3); // uuid and name tag gets added automatically Assert.assertEquals(this.context.getTags().get(0).getKey(), JOB_ID_KEY); Assert.assertEquals(this.context.getTags().get(0).getValue(), JOB_ID_PREFIX + 0); // Second tag should be uuid Assert.assertTrue(this.context.getTags().get(1).getValue().toString() .matches("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}")); } @Test public void testChildContext() { this.childContext = this.context.childBuilder(CHILD_CONTEXT_NAME) .addTag(new Tag<String>(TASK_ID_KEY, TASK_ID_PREFIX + 0)) .build(); Assert.assertEquals(this.childContext.getName(), CHILD_CONTEXT_NAME); Assert.assertTrue(this.childContext.getParent().isPresent()); Assert.assertEquals(this.childContext.getParent().get(), this.context); Assert.assertEquals(this.childContext.getTags().size(), 4); Assert.assertEquals(this.childContext.getTags().get(0).getKey(), JOB_ID_KEY); Assert.assertEquals(this.childContext.getTags().get(0).getValue(), JOB_ID_PREFIX + 0); Assert.assertEquals(this.childContext.getTags().get(1).getKey(), MetricContext.METRIC_CONTEXT_ID_TAG_NAME); Assert.assertEquals(this.childContext.getTags().get(2).getKey(), MetricContext.METRIC_CONTEXT_NAME_TAG_NAME); Assert.assertEquals(this.childContext.getTags().get(3).getKey(), TASK_ID_KEY); Assert.assertEquals(this.childContext.getTags().get(3).getValue(), TASK_ID_PREFIX + 0); } @Test(dependsOnMethods = "testChildContext") public void testContextAwareCounter() { ContextAwareCounter jobRecordsProcessed = this.context.contextAwareCounter(RECORDS_PROCESSED); Assert.assertEquals(this.context.getCounters().get(jobRecordsProcessed.getName()), jobRecordsProcessed.getInnerMetric()); Assert.assertEquals(jobRecordsProcessed.getContext(), this.context); Assert.assertEquals(jobRecordsProcessed.getName(), RECORDS_PROCESSED); jobRecordsProcessed.inc(); Assert.assertEquals(jobRecordsProcessed.getCount(), 1l); jobRecordsProcessed.inc(5); Assert.assertEquals(jobRecordsProcessed.getCount(), 6l); jobRecordsProcessed.dec(); Assert.assertEquals(jobRecordsProcessed.getCount(), 5l); jobRecordsProcessed.dec(3); Assert.assertEquals(jobRecordsProcessed.getCount(), 2l); ContextAwareCounter taskRecordsProcessed = this.childContext.contextAwareCounter(RECORDS_PROCESSED); Assert.assertEquals(this.childContext.getCounters() .get(taskRecordsProcessed.getName()), taskRecordsProcessed.getInnerMetric()); Assert.assertEquals(taskRecordsProcessed.getContext(), this.childContext); Assert.assertEquals(taskRecordsProcessed.getName(), RECORDS_PROCESSED); taskRecordsProcessed.inc(); Assert.assertEquals(taskRecordsProcessed.getCount(), 1l); Assert.assertEquals(jobRecordsProcessed.getCount(), 3l); taskRecordsProcessed.inc(3); Assert.assertEquals(taskRecordsProcessed.getCount(), 4l); Assert.assertEquals(jobRecordsProcessed.getCount(), 6l); taskRecordsProcessed.dec(4); Assert.assertEquals(taskRecordsProcessed.getCount(), 0l); Assert.assertEquals(jobRecordsProcessed.getCount(), 2l); } @Test(dependsOnMethods = "testChildContext") public void testContextAwareMeter() { ContextAwareMeter jobRecordsProcessRate = this.context.contextAwareMeter(RECORD_PROCESS_RATE); Assert.assertEquals(this.context.getMeters() .get(jobRecordsProcessRate.getName()), jobRecordsProcessRate.getInnerMetric()); Assert.assertEquals(jobRecordsProcessRate.getContext(), this.context); Assert.assertEquals(jobRecordsProcessRate.getName(), RECORD_PROCESS_RATE); jobRecordsProcessRate.mark(); jobRecordsProcessRate.mark(3); Assert.assertEquals(jobRecordsProcessRate.getCount(), 4l); ContextAwareMeter taskRecordsProcessRate = this.childContext.contextAwareMeter(RECORD_PROCESS_RATE); Assert.assertEquals(this.childContext.getMeters() .get(taskRecordsProcessRate.getName()), taskRecordsProcessRate.getInnerMetric()); Assert.assertEquals(taskRecordsProcessRate.getContext(), this.childContext); Assert.assertEquals(taskRecordsProcessRate.getName(), RECORD_PROCESS_RATE); taskRecordsProcessRate.mark(2); Assert.assertEquals(taskRecordsProcessRate.getCount(), 2l); Assert.assertEquals(jobRecordsProcessRate.getCount(), 6l); taskRecordsProcessRate.mark(5); Assert.assertEquals(taskRecordsProcessRate.getCount(), 7l); Assert.assertEquals(jobRecordsProcessRate.getCount(), 11l); } @Test(dependsOnMethods = "testChildContext") public void testContextAwareHistogram() { ContextAwareHistogram jobRecordSizeDist = this.context.contextAwareHistogram(RECORD_SIZE_DISTRIBUTION); Assert.assertEquals( this.context.getHistograms().get( jobRecordSizeDist.getName()), jobRecordSizeDist.getInnerMetric()); Assert.assertEquals(jobRecordSizeDist.getContext(), this.context); Assert.assertEquals(jobRecordSizeDist.getName(), RECORD_SIZE_DISTRIBUTION); jobRecordSizeDist.update(2); jobRecordSizeDist.update(4); jobRecordSizeDist.update(7); Assert.assertEquals(jobRecordSizeDist.getCount(), 3l); Assert.assertEquals(jobRecordSizeDist.getSnapshot().getMin(), 2l); Assert.assertEquals(jobRecordSizeDist.getSnapshot().getMax(), 7l); ContextAwareHistogram taskRecordSizeDist = this.childContext.contextAwareHistogram(RECORD_SIZE_DISTRIBUTION); Assert.assertEquals(this.childContext.getHistograms().get(taskRecordSizeDist.getName()), taskRecordSizeDist.getInnerMetric()); Assert.assertEquals(taskRecordSizeDist.getContext(), this.childContext); Assert.assertEquals(taskRecordSizeDist.getName(), RECORD_SIZE_DISTRIBUTION); taskRecordSizeDist.update(3); taskRecordSizeDist.update(14); taskRecordSizeDist.update(11); Assert.assertEquals(taskRecordSizeDist.getCount(), 3l); Assert.assertEquals(taskRecordSizeDist.getSnapshot().getMin(), 3l); Assert.assertEquals(taskRecordSizeDist.getSnapshot().getMax(), 14l); Assert.assertEquals(jobRecordSizeDist.getCount(), 6l); Assert.assertEquals(jobRecordSizeDist.getSnapshot().getMin(), 2l); Assert.assertEquals(jobRecordSizeDist.getSnapshot().getMax(), 14l); } @Test public void testContextAwareTimer() { ContextAwareTimer jobTotalDuration = this.context.contextAwareTimer(TOTAL_DURATION); Assert.assertEquals(this.context.getTimers().get(jobTotalDuration.getName()), jobTotalDuration.getInnerMetric()); Assert.assertEquals(jobTotalDuration.getContext(), this.context); Assert.assertEquals(jobTotalDuration.getName(), TOTAL_DURATION); jobTotalDuration.update(50, TimeUnit.SECONDS); jobTotalDuration.update(100, TimeUnit.SECONDS); jobTotalDuration.update(150, TimeUnit.SECONDS); Assert.assertEquals(jobTotalDuration.getCount(), 3l); Assert.assertEquals(jobTotalDuration.getSnapshot().getMin(), TimeUnit.SECONDS.toNanos(50l)); Assert.assertEquals(jobTotalDuration.getSnapshot().getMax(), TimeUnit.SECONDS.toNanos(150l)); Assert.assertTrue(jobTotalDuration.time().stop() >= 0l); } @Test public void testTaggableGauge() { ContextAwareGauge<Long> queueSize = this.context.newContextAwareGauge( QUEUE_SIZE, new Gauge<Long>() { @Override public Long getValue() { return 1000l; } }); this.context.register(QUEUE_SIZE, queueSize); Assert.assertEquals(queueSize.getValue().longValue(), 1000l); Assert.assertEquals( this.context.getGauges().get(queueSize.getName()), queueSize.getInnerMetric()); Assert.assertEquals(queueSize.getContext(), this.context); Assert.assertEquals(queueSize.getName(), QUEUE_SIZE); } @Test(dependsOnMethods = { "testContextAwareCounter", "testContextAwareMeter", "testContextAwareHistogram", "testContextAwareTimer", "testTaggableGauge" }) public void testGetMetrics() { SortedSet<String> names = this.context.getNames(); Assert.assertEquals(names.size(), 6); Assert.assertTrue(names.contains(RECORDS_PROCESSED)); Assert.assertTrue(names.contains(RECORD_PROCESS_RATE)); Assert.assertTrue( names.contains(RECORD_SIZE_DISTRIBUTION)); Assert.assertTrue(names.contains(TOTAL_DURATION)); Assert.assertTrue(names.contains(QUEUE_SIZE)); SortedSet<String> childNames = this.childContext.getNames(); Assert.assertEquals(childNames.size(), 4); Assert.assertTrue( childNames.contains(RECORDS_PROCESSED)); Assert.assertTrue( childNames.contains(RECORD_PROCESS_RATE)); Assert.assertTrue( childNames.contains(RECORD_SIZE_DISTRIBUTION)); Map<String, Metric> metrics = this.context.getMetrics(); Assert.assertEquals(metrics.size(), 6); Assert.assertTrue( metrics.containsKey(RECORDS_PROCESSED)); Assert.assertTrue( metrics.containsKey(RECORD_PROCESS_RATE)); Assert.assertTrue( metrics.containsKey(RECORD_SIZE_DISTRIBUTION)); Assert.assertTrue(metrics.containsKey(TOTAL_DURATION)); Assert.assertTrue(metrics.containsKey(QUEUE_SIZE)); Map<String, Counter> counters = this.context.getCounters(); Assert.assertEquals(counters.size(), 1); Assert.assertTrue( counters.containsKey(RECORDS_PROCESSED)); Map<String, Meter> meters = this.context.getMeters(); Assert.assertEquals(meters.size(), 1); Assert.assertTrue( meters.containsKey(RECORD_PROCESS_RATE)); Map<String, Histogram> histograms = this.context.getHistograms(); Assert.assertEquals(histograms.size(), 1); Assert.assertTrue( histograms.containsKey(RECORD_SIZE_DISTRIBUTION)); Map<String, Timer> timers = this.context.getTimers(); Assert.assertEquals(timers.size(), 2); Assert.assertTrue(timers.containsKey(TOTAL_DURATION)); Map<String, Gauge> gauges = this.context.getGauges(); Assert.assertEquals(gauges.size(), 1); Assert.assertTrue(gauges.containsKey(QUEUE_SIZE)); } @Test(dependsOnMethods = "testGetMetrics") @SuppressWarnings("unchecked") public void testGetMetricsWithFilter() { MetricFilter filter = new MetricFilter() { @Override public boolean matches(String name, Metric metric) { return !name.equals(MetricContext.GOBBLIN_METRICS_NOTIFICATIONS_TIMER_NAME); } }; Map<String, Counter> counters = this.context.getCounters(filter); Assert.assertEquals(counters.size(), 1); Assert.assertTrue( counters.containsKey(RECORDS_PROCESSED)); Map<String, Meter> meters = this.context.getMeters(filter); Assert.assertEquals(meters.size(), 1); Assert.assertTrue( meters.containsKey(RECORD_PROCESS_RATE)); Map<String, Histogram> histograms = this.context.getHistograms(filter); Assert.assertEquals(histograms.size(), 1); Assert.assertTrue( histograms.containsKey(RECORD_SIZE_DISTRIBUTION)); Map<String, Timer> timers = this.context.getTimers(filter); Assert.assertEquals(timers.size(), 1); Assert.assertTrue(timers.containsKey(TOTAL_DURATION)); Map<String, Gauge> gauges = this.context.getGauges(filter); Assert.assertEquals(gauges.size(), 1); Assert.assertTrue(gauges.containsKey(QUEUE_SIZE)); } @Test(dependsOnMethods = { "testGetMetricsWithFilter" }) public void testRemoveMetrics() { Assert.assertTrue(this.childContext.remove(RECORDS_PROCESSED)); Assert.assertTrue(this.childContext.getCounters().isEmpty()); Assert.assertTrue(this.childContext.remove(RECORD_PROCESS_RATE)); Assert.assertTrue(this.childContext.getMeters().isEmpty()); Assert.assertTrue(this.childContext.remove(RECORD_SIZE_DISTRIBUTION)); Assert.assertTrue(this.childContext.getHistograms().isEmpty()); Assert.assertEquals(this.childContext.getNames().size(), 1); } @AfterClass public void tearDown() throws IOException { if (this.context != null) { this.context.close(); } } private static class TestContextAwareScheduledReporter extends ContextAwareScheduledReporter { protected TestContextAwareScheduledReporter(MetricContext context, String name, MetricFilter filter, TimeUnit rateUnit, TimeUnit durationUnit) { super(context, name, filter, rateUnit, durationUnit); } @Override protected void reportInContext(MetricContext context, SortedMap<String, Gauge> gauges, SortedMap<String, Counter> counters, SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters, SortedMap<String, Timer> timers) { Assert.assertEquals(context.getName(), CONTEXT_NAME); Assert.assertEquals(gauges.size(), 1); Assert.assertTrue(gauges.containsKey(QUEUE_SIZE)); Assert.assertEquals(counters.size(), 1); Assert.assertTrue(counters.containsKey(RECORDS_PROCESSED)); Assert.assertEquals(histograms.size(), 1); Assert.assertTrue( histograms.containsKey(RECORD_SIZE_DISTRIBUTION)); Assert.assertEquals(meters.size(), 1); Assert.assertTrue(meters.containsKey(RECORD_PROCESS_RATE)); Assert.assertEquals(timers.size(), 2); Assert.assertTrue(timers.containsKey(TOTAL_DURATION)); } private static class TestContextAwareScheduledReporterBuilder extends Builder { public TestContextAwareScheduledReporterBuilder(String name) { super(name); } @Override public ContextAwareScheduledReporter build(MetricContext context) { return new MetricContextTest.TestContextAwareScheduledReporter( context, this.name, this.filter, this.rateUnit, this.durationUnit); } } } }