You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/03/15 07:25:44 UTC
[2/2] logging-log4j2 git commit: LOG4J2-1295 Added automated GC-free
test. Still @Ignored as of now because the API creates vararg arrays so the
test fails.
LOG4J2-1295 Added automated GC-free test. Still @Ignored as of now because the API creates vararg arrays so the test fails.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/52d04e07
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/52d04e07
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/52d04e07
Branch: refs/heads/master
Commit: 52d04e0779eef09d0826c800cdc0874eea4960e5
Parents: 575cd5b
Author: rpopma <rp...@apache.org>
Authored: Tue Mar 15 17:25:40 2016 +1100
Committer: rpopma <rp...@apache.org>
Committed: Tue Mar 15 17:25:40 2016 +1100
----------------------------------------------------------------------
.../logging/log4j/core/GcFreeLoggingTest.java | 131 +++++++++++++++++++
1 file changed, 131 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/52d04e07/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTest.java
new file mode 100644
index 0000000..2cca348
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.logging.log4j.core;
+
+import java.io.File;
+import java.net.URL;
+import java.nio.file.Files;
+
+import com.google.monitoring.runtime.instrumentation.AllocationRecorder;
+import com.google.monitoring.runtime.instrumentation.Sampler;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
+import org.apache.logging.log4j.core.util.Constants;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Verifies steady state logging is GC-free.
+ *
+ * @see <a href="https://github.com/google/allocation-instrumenter">https://github.com/google/allocation-instrumenter</a>
+ */
+public class GcFreeLoggingTest {
+
+ // ignored: test still fails because of vararg arrays
+ @Ignore
+ @Test
+ public void testNoAllocationDuringSteadyStateLogging() throws Throwable {
+ final String javaHome = System.getProperty("java.home");
+ final String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
+ final String classpath = System.getProperty("java.class.path");
+ final String javaagent = "-javaagent:" + agentJar();
+
+ final File tempFile = File.createTempFile("allocations", ".txt");
+ tempFile.deleteOnExit();
+
+ final ProcessBuilder builder = new ProcessBuilder( //
+ javaBin, javaagent, "-cp", classpath, GcFreeLoggingTest.class.getName());
+ builder.redirectError(ProcessBuilder.Redirect.to(tempFile));
+ builder.redirectOutput(ProcessBuilder.Redirect.to(tempFile));
+ final Process process = builder.start();
+ process.waitFor();
+ process.exitValue();
+
+ final String output = new String(Files.readAllBytes(tempFile.toPath()));
+ assertEquals("", output);
+ }
+
+ /**
+ * This code runs in a separate process, instrumented with the Google Allocation Instrumenter.
+ */
+ public static void main(String[] args) throws Exception {
+ System.setProperty("log4j2.enable.threadlocals", "true");
+ System.setProperty("log4j2.is.webapp", "false");
+ System.setProperty("log4j.configurationFile", "perf3PlainNoLoc.xml");
+ System.setProperty("Log4jContextSelector", AsyncLoggerContextSelector.class.getName());
+
+ assertTrue("Constants.ENABLE_THREADLOCALS", Constants.ENABLE_THREADLOCALS);
+ assertFalse("Constants.IS_WEB_APP", Constants.IS_WEB_APP);
+
+ // initialize LoggerContext etc.
+ // This is not steady-state logging and will allocate objects.
+ final Logger logger = LogManager.getLogger(GcFreeLoggingTest.class.getName());
+ logger.debug("debug not set");
+ logger.error("Sample error message");
+ logger.error("Test parameterized message {}", "param");
+
+ // BlockingWaitStrategy uses ReentrantLock which allocates Node objects. Ignore this.
+ final String[] exclude = new String[] {
+ "java/util/concurrent/locks/AbstractQueuedSynchronizer$Node", //
+ "com/google/monitoring/runtime/instrumentation/Sampler", //
+ };
+ final Sampler sampler = new Sampler() {
+ public void sampleAllocation(int count, String desc, Object newObj, long size) {
+ for (int i = 0; i < exclude.length; i++) {
+ if (exclude[i].equals(desc)) {
+ return; // exclude
+ }
+ }
+ System.out.println("I just allocated the object " + newObj +
+ " of type " + desc + " whose size is " + size);
+ if (count != -1) {
+ System.out.println("It's an array of size " + count);
+ }
+
+ // uncomment to get a stack trace and see which line caused allocation
+ //new RuntimeException().printStackTrace();
+ }
+ };
+ Thread.sleep(500);
+ AllocationRecorder.addSampler(sampler);
+
+ // now do some steady-state logging
+ final int ITERATIONS = 5;
+ for (int i = 0; i < ITERATIONS; i++) {
+ logger.error("Test message");
+ logger.error("Test parameterized message {}", "param");
+ logger.error("Test parameterized message {}{}", "param", "param2");
+ logger.error("Test parameterized message {}{}{}", "param", "param2", "abc");
+ }
+ AllocationRecorder.removeSampler(sampler);
+ Thread.sleep(50);
+ }
+
+ private static File agentJar() {
+ final String name = AllocationRecorder.class.getName();
+ final URL url = AllocationRecorder.class.getResource("/" + name.replace('.', '/').concat(".class"));
+ if (url == null) {
+ throw new IllegalStateException("Could not find url for " + name);
+ }
+ final String temp = url.toString();
+ final String path = temp.substring("jar:file:/".length(), temp.indexOf('!'));
+ return new File(path);
+ }
+}