From 686addb4b1751f5f7ccc4f93a2498b3d318156ad Mon Sep 17 00:00:00 2001 From: yew1eb Date: Wed, 6 Sep 2017 23:09:13 +0800 Subject: [PATCH 1/4] Implement a slf4j metric reporter --- flink-metrics/flink-metrics-slf4j/pom.xml | 65 +++++++++ .../flink/metrics/slf4j/Slf4jReporter.java | 135 ++++++++++++++++++ .../metrics/slf4j/Slf4jReporterTest.java | 128 +++++++++++++++++ .../apache/flink/metrics/slf4j/TestUtils.java | 86 +++++++++++ .../src/test/resources/log4j-test.properties | 24 ++++ flink-metrics/pom.xml | 1 + 6 files changed, 439 insertions(+) create mode 100644 flink-metrics/flink-metrics-slf4j/pom.xml create mode 100644 flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java create mode 100644 flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java create mode 100644 flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java create mode 100644 flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties diff --git a/flink-metrics/flink-metrics-slf4j/pom.xml b/flink-metrics/flink-metrics-slf4j/pom.xml new file mode 100644 index 0000000000000..efe909b553471 --- /dev/null +++ b/flink-metrics/flink-metrics-slf4j/pom.xml @@ -0,0 +1,65 @@ + + + + + 4.0.0 + + + org.apache.flink + flink-metrics + 1.4-SNAPSHOT + .. + + + flink-metrics-slf4j + flink-metrics-slf4j + + + + org.apache.flink + flink-annotations + ${project.version} + provided + + + org.apache.flink + flink-runtime_${scala.binary.version} + ${project.version} + provided + + + + org.apache.flink + flink-metrics-core + ${project.version} + provided + + + + + + org.apache.flink + flink-test-utils-junit + ${project.version} + + + + diff --git a/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java b/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java new file mode 100644 index 0000000000000..30a85cbb97824 --- /dev/null +++ b/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java @@ -0,0 +1,135 @@ +/* + * 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.metrics.slf4j; + +import org.apache.flink.annotation.VisibleForTesting; +import org.apache.flink.metrics.Counter; +import org.apache.flink.metrics.Gauge; +import org.apache.flink.metrics.Histogram; +import org.apache.flink.metrics.HistogramStatistics; +import org.apache.flink.metrics.Meter; +import org.apache.flink.metrics.Metric; +import org.apache.flink.metrics.MetricConfig; +import org.apache.flink.metrics.reporter.AbstractReporter; +import org.apache.flink.metrics.reporter.MetricReporter; +import org.apache.flink.metrics.reporter.Scheduled; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * {@link MetricReporter} that exports {@link Metric Metrics} via SLF4J {@link Logger}. + */ +public class Slf4jReporter extends AbstractReporter implements Scheduled { + private static final Logger LOG = LoggerFactory.getLogger(Slf4jReporter.class); + private static final String lineSeparator = System.lineSeparator(); + + @VisibleForTesting + public Map, String> getGauges() { + return gauges; + } + + @VisibleForTesting + public Map getCounters() { + return counters; + } + + @VisibleForTesting + public Map getHistograms() { + return histograms; + } + + @VisibleForTesting + public Map getMeters() { + return meters; + } + + @Override + public void open(MetricConfig metricConfig) { + + } + + @Override + public void close() { + + } + + @Override + public void report() { + StringBuilder builder = new StringBuilder(); + builder.append(lineSeparator).append("=========================== Starting metrics report ===========================").append(lineSeparator); + builder.append("-- Counters -------------------------------------------------------------------").append(lineSeparator); + for (Map.Entry metric : counters.entrySet()) { + builder.append(metric.getValue()).append(": count=").append(metric.getKey().getCount()).append(lineSeparator); + } + + builder.append(lineSeparator).append("-- Gauges ---------------------------------------------------------------------").append(lineSeparator); + for (Map.Entry, String> metric : gauges.entrySet()) { + builder.append(metric.getValue()).append(": value=").append(metric.getKey().getValue()).append(lineSeparator); + } + + builder.append(lineSeparator).append("-- Histograms -----------------------------------------------------------------").append(lineSeparator); + for (Map.Entry metric : histograms.entrySet()) { + HistogramStatistics stats = metric.getKey().getStatistics(); + builder.append(metric.getValue()).append(": count=").append(stats.size()) + .append(", min=").append(stats.getMin()).append(", max=").append(stats.getMax()) + .append(", mean=").append(stats.getMean()).append(", stddev=").append(stats.getStdDev()) + .append(", p50=").append(stats.getQuantile(0.50)).append(", p75=").append(stats.getQuantile(0.75)) + .append(", p95=").append(stats.getQuantile(0.95)).append(", p98=").append(stats.getQuantile(0.98)) + .append(", p99=").append(stats.getQuantile(0.99)).append(", p999=").append(stats.getQuantile(0.999)).append(lineSeparator); + } + + builder.append(lineSeparator).append("-- Meters ---------------------------------------------------------------------").append(lineSeparator); + for (Map.Entry metric : meters.entrySet()) { + builder.append(metric.getValue()).append(": rate=").append(metric.getKey().getRate()).append(lineSeparator); + } + + builder.append(lineSeparator).append("=========================== Finished metrics report ===========================").append(lineSeparator); + LOG.info(builder.toString()); + } + + @Override + public String filterCharacters(String input) { + char[] chars = null; + final int strLen = input.length(); + int pos = 0; + + for (int i = 0; i < strLen; i++) { + final char c = input.charAt(i); + switch (c) { + case ':': + if (chars == null) { + chars = input.toCharArray(); + } + chars[pos++] = '-'; + break; + + default: + if (chars != null) { + chars[pos] = c; + } + pos++; + } + } + + return chars == null ? input : new String(chars, 0, pos); + } +} diff --git a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java new file mode 100644 index 0000000000000..27c305cf9b3a7 --- /dev/null +++ b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java @@ -0,0 +1,128 @@ +/* + * 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.metrics.slf4j; + +import org.apache.flink.api.common.JobID; +import org.apache.flink.configuration.ConfigConstants; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.configuration.MetricOptions; +import org.apache.flink.metrics.Gauge; +import org.apache.flink.metrics.SimpleCounter; +import org.apache.flink.runtime.metrics.MetricRegistry; +import org.apache.flink.runtime.metrics.MetricRegistryConfiguration; +import org.apache.flink.runtime.metrics.groups.TaskManagerJobMetricGroup; +import org.apache.flink.runtime.metrics.groups.TaskManagerMetricGroup; +import org.apache.flink.runtime.metrics.groups.TaskMetricGroup; +import org.apache.flink.util.AbstractID; +import org.apache.flink.util.TestLogger; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * Test for {@link Slf4jReporter}. + */ + +public class Slf4jReporterTest extends TestLogger { + + private static final String HOST_NAME = "localhost"; + private static final String TASK_MANAGER_ID = "tm01"; + private static final String JOB_NAME = "jn01"; + private static final String TASK_NAME = "tn01"; + private static MetricRegistry registry; + private static char delimiter; + private static TaskMetricGroup taskMetricGroup; + private static Slf4jReporter reporter; + + @BeforeClass + public static void setUp() { + TestUtils.addTestAppenderForRootLogger(); + + Configuration configuration = new Configuration(); + configuration.setString(MetricOptions.REPORTERS_LIST, "slf4j"); + configuration.setString(ConfigConstants.METRICS_REPORTER_PREFIX + "slf4j." + + ConfigConstants.METRICS_REPORTER_CLASS_SUFFIX, Slf4jReporter.class.getName()); + configuration.setString(MetricOptions.SCOPE_NAMING_TASK, ".."); + + registry = new MetricRegistry(MetricRegistryConfiguration.fromConfiguration(configuration)); + delimiter = registry.getDelimiter(); + + TaskManagerMetricGroup tmMetricGroup = new TaskManagerMetricGroup(registry, HOST_NAME, TASK_MANAGER_ID); + TaskManagerJobMetricGroup tmJobMetricGroup = new TaskManagerJobMetricGroup(registry, tmMetricGroup, new JobID(), JOB_NAME); + taskMetricGroup = new TaskMetricGroup(registry, tmJobMetricGroup, new AbstractID(), new AbstractID(), TASK_NAME, 0, 0); + reporter = (Slf4jReporter) registry.getReporters().get(0); + } + + @AfterClass + public static void tearDown() { + registry.shutdown(); + } + + @Test + public void testAddCounter() throws Exception { + String myCounterName = "simpleCounter"; + + SimpleCounter simpleCounter = new SimpleCounter(); + taskMetricGroup.counter(myCounterName, simpleCounter); + + assertTrue(reporter.getCounters().containsKey(simpleCounter)); + + String expectedCounterName = reporter.filterCharacters(HOST_NAME) + delimiter + + reporter.filterCharacters(TASK_MANAGER_ID) + delimiter + reporter.filterCharacters(JOB_NAME) + delimiter + + reporter.filterCharacters(myCounterName); + + reporter.report(); + TestUtils.checkForLogString(expectedCounterName); + } + + @Test + public void testAddGague() throws Exception { + String myGagueName = "gague"; + + taskMetricGroup.gauge(myGagueName, null); + assertTrue(reporter.getGauges().isEmpty()); + + taskMetricGroup.gauge(myGagueName, new Gauge() { + @Override + public Long getValue() { + return null; + } + }); + String expectedTheGaugeReport = reporter.filterCharacters(HOST_NAME) + delimiter + + reporter.filterCharacters(TASK_MANAGER_ID) + delimiter + reporter.filterCharacters(JOB_NAME) + delimiter + + reporter.filterCharacters(myGagueName) + ": value=null"; + + reporter.report(); + TestUtils.checkForLogString(expectedTheGaugeReport); + } + + @Test + public void testFilterCharacters() throws Exception { + Slf4jReporter reporter = new Slf4jReporter(); + + assertThat(reporter.filterCharacters(""), equalTo("")); + assertThat(reporter.filterCharacters("abc"), equalTo("abc")); + assertThat(reporter.filterCharacters("a:b::"), equalTo("a-b--")); + } +} diff --git a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java new file mode 100644 index 0000000000000..b0a59174513c5 --- /dev/null +++ b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java @@ -0,0 +1,86 @@ +/* + * 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.metrics.slf4j; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test utilities. + */ +public class TestUtils { + private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class); + + private static TestAppender testAppender; + + public static void addTestAppenderForRootLogger() { + testAppender = new TestAppender(); + org.apache.log4j.Logger.getRootLogger().addAppender(testAppender); + } + + public static void checkForLogString(String expected) { + LoggingEvent found = getEventContainingString(expected); + if (found != null) { + LOG.info("Found expected string '" + expected + "' in log message " + found); + return; + } + Assert.fail("Unable to find expected string '" + expected + "' in log messages"); + } + + public static LoggingEvent getEventContainingString(String expected) { + if (testAppender == null) { + throw new NullPointerException("Initialize test appender first"); + } + LoggingEvent found = null; + // make sure that different threads are not logging while the logs are checked + synchronized (testAppender.events) { + for (LoggingEvent event : testAppender.events) { + if (event.getMessage().toString().contains(expected)) { + found = event; + break; + } + } + } + return found; + } + + private static class TestAppender extends AppenderSkeleton { + public final List events = new ArrayList<>(); + + public void close() { + } + + public boolean requiresLayout() { + return false; + } + + @Override + protected void append(LoggingEvent event) { + synchronized (events) { + events.add(event); + } + } + } +} diff --git a/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties b/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties new file mode 100644 index 0000000000000..7abf7dcec817e --- /dev/null +++ b/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +log4j.rootLogger=INFO, testlogger + +log4j.appender.testlogger=org.apache.log4j.ConsoleAppender +log4j.appender.testlogger.target=System.err +log4j.appender.testlogger.layout=org.apache.log4j.PatternLayout +log4j.appender.testlogger.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n diff --git a/flink-metrics/pom.xml b/flink-metrics/pom.xml index 5313498b64ccd..b7a16c3c300d4 100644 --- a/flink-metrics/pom.xml +++ b/flink-metrics/pom.xml @@ -42,6 +42,7 @@ under the License. flink-metrics-prometheus flink-metrics-statsd flink-metrics-datadog + flink-metrics-slf4j diff --git a/flink-dist/src/main/assemblies/opt.xml b/flink-dist/src/main/assemblies/opt.xml index ba32086abdcf9..c7627c15e8b0e 100644 --- a/flink-dist/src/main/assemblies/opt.xml +++ b/flink-dist/src/main/assemblies/opt.xml @@ -117,5 +117,12 @@ flink-metrics-datadog-${project.version}.jar 0644 + + + ../flink-metrics/flink-metrics-slf4j/target/flink-metrics-slf4j-${project.version}.jar + opt/ + flink-metrics-slf4j-${project.version}.jar + 0644 + From c86b223ca7a37ae9526547e3359c28963344130d Mon Sep 17 00:00:00 2001 From: yew1eb Date: Tue, 24 Oct 2017 20:50:50 +0800 Subject: [PATCH 4/4] fix --- flink-metrics/flink-metrics-slf4j/pom.xml | 17 +++++++++---- .../flink/metrics/slf4j/Slf4jReporter.java | 24 +------------------ .../metrics/slf4j/Slf4jReporterTest.java | 7 +++--- .../apache/flink/metrics/slf4j/TestUtils.java | 7 +++++- .../src/test/resources/log4j-test.properties | 12 ++++++---- 5 files changed, 30 insertions(+), 37 deletions(-) diff --git a/flink-metrics/flink-metrics-slf4j/pom.xml b/flink-metrics/flink-metrics-slf4j/pom.xml index efe909b553471..5e936b54e20e2 100644 --- a/flink-metrics/flink-metrics-slf4j/pom.xml +++ b/flink-metrics/flink-metrics-slf4j/pom.xml @@ -39,26 +39,35 @@ under the License. ${project.version} provided + org.apache.flink - flink-runtime_${scala.binary.version} + flink-metrics-core ${project.version} provided + + org.apache.flink - flink-metrics-core + flink-core ${project.version} - provided + test - + + org.apache.flink + flink-runtime_${scala.binary.version} + ${project.version} + test + org.apache.flink flink-test-utils-junit ${project.version} + test diff --git a/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java b/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java index 30a85cbb97824..c7f5bd9bb0517 100644 --- a/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java +++ b/flink-metrics/flink-metrics-slf4j/src/main/java/org/apache/flink/metrics/slf4j/Slf4jReporter.java @@ -108,28 +108,6 @@ public void report() { @Override public String filterCharacters(String input) { - char[] chars = null; - final int strLen = input.length(); - int pos = 0; - - for (int i = 0; i < strLen; i++) { - final char c = input.charAt(i); - switch (c) { - case ':': - if (chars == null) { - chars = input.toCharArray(); - } - chars[pos++] = '-'; - break; - - default: - if (chars != null) { - chars[pos] = c; - } - pos++; - } - } - - return chars == null ? input : new String(chars, 0, pos); + return input; } } diff --git a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java index 27c305cf9b3a7..504e28baaa36e 100644 --- a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java +++ b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/Slf4jReporterTest.java @@ -24,12 +24,12 @@ import org.apache.flink.configuration.MetricOptions; import org.apache.flink.metrics.Gauge; import org.apache.flink.metrics.SimpleCounter; +import org.apache.flink.runtime.jobgraph.JobVertexID; import org.apache.flink.runtime.metrics.MetricRegistry; import org.apache.flink.runtime.metrics.MetricRegistryConfiguration; import org.apache.flink.runtime.metrics.groups.TaskManagerJobMetricGroup; import org.apache.flink.runtime.metrics.groups.TaskManagerMetricGroup; import org.apache.flink.runtime.metrics.groups.TaskMetricGroup; -import org.apache.flink.util.AbstractID; import org.apache.flink.util.TestLogger; import org.junit.AfterClass; @@ -43,7 +43,6 @@ /** * Test for {@link Slf4jReporter}. */ - public class Slf4jReporterTest extends TestLogger { private static final String HOST_NAME = "localhost"; @@ -70,7 +69,7 @@ public static void setUp() { TaskManagerMetricGroup tmMetricGroup = new TaskManagerMetricGroup(registry, HOST_NAME, TASK_MANAGER_ID); TaskManagerJobMetricGroup tmJobMetricGroup = new TaskManagerJobMetricGroup(registry, tmMetricGroup, new JobID(), JOB_NAME); - taskMetricGroup = new TaskMetricGroup(registry, tmJobMetricGroup, new AbstractID(), new AbstractID(), TASK_NAME, 0, 0); + taskMetricGroup = new TaskMetricGroup(registry, tmJobMetricGroup, new JobVertexID(), new JobVertexID(), TASK_NAME, 0, 0); reporter = (Slf4jReporter) registry.getReporters().get(0); } @@ -123,6 +122,6 @@ public void testFilterCharacters() throws Exception { assertThat(reporter.filterCharacters(""), equalTo("")); assertThat(reporter.filterCharacters("abc"), equalTo("abc")); - assertThat(reporter.filterCharacters("a:b::"), equalTo("a-b--")); + assertThat(reporter.filterCharacters("a:b$%^::"), equalTo("a:b$%^::")); } } diff --git a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java index b0a59174513c5..30f3a87f3892f 100644 --- a/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java +++ b/flink-metrics/flink-metrics-slf4j/src/test/java/org/apache/flink/metrics/slf4j/TestUtils.java @@ -36,8 +36,13 @@ public class TestUtils { private static TestAppender testAppender; public static void addTestAppenderForRootLogger() { + org.apache.log4j.Logger.getRootLogger().removeAllAppenders(); + + org.apache.log4j.Logger logger = org.apache.log4j.LogManager.getLogger(Slf4jReporter.class); + logger.setLevel(org.apache.log4j.Level.INFO); + testAppender = new TestAppender(); - org.apache.log4j.Logger.getRootLogger().addAppender(testAppender); + logger.addAppender(testAppender); } public static void checkForLogString(String expected) { diff --git a/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties b/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties index 7abf7dcec817e..6f349fcea6f5d 100644 --- a/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties +++ b/flink-metrics/flink-metrics-slf4j/src/test/resources/log4j-test.properties @@ -16,9 +16,11 @@ # limitations under the License. # -log4j.rootLogger=INFO, testlogger +log4j.rootLogger=OFF, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.target=System.err +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n + -log4j.appender.testlogger=org.apache.log4j.ConsoleAppender -log4j.appender.testlogger.target=System.err -log4j.appender.testlogger.layout=org.apache.log4j.PatternLayout -log4j.appender.testlogger.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n