/*
* 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.flink.runtime.metrics.groups;
import org.apache.flink.configuration.ConfigConstants;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.MetricOptions;
import org.apache.flink.metrics.CharacterFilter;
import org.apache.flink.metrics.Metric;
import org.apache.flink.metrics.MetricGroup;
import org.apache.flink.metrics.reporter.MetricReporter;
import org.apache.flink.runtime.metrics.MetricRegistry;
import org.apache.flink.runtime.metrics.MetricRegistryConfiguration;
import org.apache.flink.runtime.metrics.dump.QueryScopeInfo;
import org.apache.flink.runtime.metrics.util.TestReporter;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class AbstractMetricGroupTest {
/**
* Verifies that no {@link NullPointerException} is thrown when {@link AbstractMetricGroup#getAllVariables()} is
* called and the parent is null.
*/
@Test
public void testGetAllVariables() {
MetricRegistry registry = new MetricRegistry(MetricRegistryConfiguration.defaultMetricRegistryConfiguration());
AbstractMetricGroup group = new AbstractMetricGroup<AbstractMetricGroup<?>>(registry, new String[0], null) {
@Override
protected QueryScopeInfo createQueryServiceMetricInfo(CharacterFilter filter) {
return null;
}
@Override
protected String getGroupName(CharacterFilter filter) {
return "";
}
};
assertTrue(group.getAllVariables().isEmpty());
registry.shutdown();
}
// ========================================================================
// Scope Caching
// ========================================================================
private static final CharacterFilter FILTER_C = new CharacterFilter() {
@Override
public String filterCharacters(String input) {
return input.replace("C", "X");
}
};
private static final CharacterFilter FILTER_B = new CharacterFilter() {
@Override
public String filterCharacters(String input) {
return input.replace("B", "X");
}
};
@Test
public void testScopeCachingForMultipleReporters() throws Exception {
Configuration config = new Configuration();
config.setString(MetricOptions.SCOPE_NAMING_TM, "A.B.C.D");
config.setString(MetricOptions.REPORTERS_LIST, "test1,test2");
config.setString(ConfigConstants.METRICS_REPORTER_PREFIX + "test1." + ConfigConstants.METRICS_REPORTER_CLASS_SUFFIX, TestReporter1.class.getName());
config.setString(ConfigConstants.METRICS_REPORTER_PREFIX + "test1." + ConfigConstants.METRICS_REPORTER_SCOPE_DELIMITER, "-");
config.setString(ConfigConstants.METRICS_REPORTER_PREFIX + "test2." + ConfigConstants.METRICS_REPORTER_CLASS_SUFFIX, TestReporter2.class.getName());
config.setString(ConfigConstants.METRICS_REPORTER_PREFIX + "test2." + ConfigConstants.METRICS_REPORTER_SCOPE_DELIMITER, "!");
MetricRegistry testRegistry = new MetricRegistry(MetricRegistryConfiguration.fromConfiguration(config));
try {
MetricGroup tmGroup = new TaskManagerMetricGroup(testRegistry, "host", "id");
tmGroup.counter("1");
assertEquals("Reporters were not properly instantiated", 2, testRegistry.getReporters().size());
for (MetricReporter reporter : testRegistry.getReporters()) {
ScopeCheckingTestReporter typedReporter = (ScopeCheckingTestReporter) reporter;
if (typedReporter.failureCause != null) {
throw typedReporter.failureCause;
}
}
} finally {
testRegistry.shutdown();
}
}
private abstract static class ScopeCheckingTestReporter extends TestReporter {
protected Exception failureCause;
@Override
public void notifyOfAddedMetric(Metric metric, String metricName, MetricGroup group) {
try {
checkScopes(metric, metricName, group);
} catch (Exception e) {
if (failureCause == null) {
failureCause = e;
}
}
}
public abstract void checkScopes(Metric metric, String metricName, MetricGroup group);
}
public static class TestReporter1 extends ScopeCheckingTestReporter {
@Override
public String filterCharacters(String input) {
return FILTER_B.filterCharacters(input);
}
@Override
public void checkScopes(Metric metric, String metricName, MetricGroup group) {
// the first call determines which filter is applied to all future calls; in this case no filter is used at all
assertEquals("A-B-C-D-1", group.getMetricIdentifier(metricName));
// from now on the scope string is cached and should not be reliant on the given filter
assertEquals("A-B-C-D-1", group.getMetricIdentifier(metricName, FILTER_C));
assertEquals("A-B-C-D-1", group.getMetricIdentifier(metricName, this));
// the metric name however is still affected by the filter as it is not cached
assertEquals("A-B-C-D-4", group.getMetricIdentifier(metricName, new CharacterFilter() {
@Override
public String filterCharacters(String input) {
return input.replace("B", "X").replace("1", "4");
}
}));
}
}
public static class TestReporter2 extends ScopeCheckingTestReporter {
@Override
public String filterCharacters(String input) {
return FILTER_C.filterCharacters(input);
}
@Override
public void checkScopes(Metric metric, String metricName, MetricGroup group) {
// the first call determines which filter is applied to all future calls
assertEquals("A!B!X!D!1", group.getMetricIdentifier(metricName, this));
// from now on the scope string is cached and should not be reliant on the given filter
assertEquals("A!B!X!D!1", group.getMetricIdentifier(metricName));
assertEquals("A!B!X!D!1", group.getMetricIdentifier(metricName, FILTER_C));
// the metric name however is still affected by the filter as it is not cached
assertEquals("A!B!X!D!3", group.getMetricIdentifier(metricName, new CharacterFilter() {
@Override
public String filterCharacters(String input) {
return input.replace("A", "X").replace("1", "3");
}
}));
}
}
@Test
public void testScopeGenerationWithoutReporters() {
Configuration config = new Configuration();
config.setString(MetricOptions.SCOPE_NAMING_TM, "A.B.C.D");
MetricRegistry testRegistry = new MetricRegistry(MetricRegistryConfiguration.fromConfiguration(config));
try {
TaskManagerMetricGroup group = new TaskManagerMetricGroup(testRegistry, "host", "id");
assertEquals("MetricReporters list should be empty", 0, testRegistry.getReporters().size());
// default delimiter should be used
assertEquals("A.B.X.D.1", group.getMetricIdentifier("1", FILTER_C));
// no caching should occur
assertEquals("A.X.C.D.1", group.getMetricIdentifier("1", FILTER_B));
// invalid reporter indices do not throw errors
assertEquals("A.X.C.D.1", group.getMetricIdentifier("1", FILTER_B, -1));
assertEquals("A.X.C.D.1", group.getMetricIdentifier("1", FILTER_B, 2));
} finally {
testRegistry.shutdown();
}
}
}