| /* |
| * 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.tools; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.nio.charset.Charset; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Locale; |
| |
| import javax.tools.Diagnostic; |
| import javax.tools.DiagnosticCollector; |
| import javax.tools.JavaCompiler; |
| import javax.tools.JavaFileObject; |
| import javax.tools.StandardJavaFileManager; |
| import javax.tools.ToolProvider; |
| |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Marker; |
| import org.apache.logging.log4j.message.Message; |
| import org.apache.logging.log4j.message.MessageFactory; |
| import org.apache.logging.log4j.spi.ExtendedLogger; |
| import org.apache.logging.log4j.test.TestLogger; |
| import org.apache.logging.log4j.util.MessageSupplier; |
| import org.apache.logging.log4j.util.Supplier; |
| import org.junit.jupiter.api.AfterAll; |
| import org.junit.jupiter.api.BeforeAll; |
| import org.junit.jupiter.api.Tag; |
| import org.junit.jupiter.api.Test; |
| |
| import static org.junit.jupiter.api.Assertions.*; |
| |
| @Tag("functional") |
| public class GenerateExtendedLoggerTest { |
| |
| private static final String TEST_SOURCE = "target/test-classes/org/apache/logging/log4j/core/MyExtendedLogger.java"; |
| |
| @BeforeAll |
| public static void beforeClass() { |
| System.setProperty("log4j2.loggerContextFactory", "org.apache.logging.log4j.test.TestLoggerContextFactory"); |
| } |
| |
| @AfterAll |
| public static void afterClass() { |
| File file = new File(TEST_SOURCE); |
| File parent = file.getParentFile(); |
| if (file.exists()) { |
| file.delete(); |
| } |
| file = new File(parent, "MyExtendedLogger.class"); |
| if (file.exists()) { |
| file.delete(); |
| } |
| } |
| |
| @Test |
| public void testGenerateSource() throws Exception { |
| final String CLASSNAME = "org.apache.logging.log4j.core.MyExtendedLogger"; |
| |
| // generate custom logger source |
| final List<String> values = Arrays.asList("DIAG=350 NOTICE=450 VERBOSE=550".split(" ")); |
| final List<Generate.LevelInfo> levels = Generate.LevelInfo.parse(values, Generate.ExtendedLogger.class); |
| final String src = Generate.generateSource(CLASSNAME, levels, Generate.Type.EXTEND); |
| final File f = new File(TEST_SOURCE); |
| f.getParentFile().mkdirs(); |
| try (final FileOutputStream out = new FileOutputStream(f)) { |
| out.write(src.getBytes(Charset.defaultCharset())); |
| } |
| |
| final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); |
| final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); |
| final List<String> errors = new ArrayList<>(); |
| try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) { |
| final Iterable<? extends JavaFileObject> compilationUnits = fileManager |
| .getJavaFileObjectsFromFiles(Collections.singletonList(f)); |
| |
| List<String> optionList = |
| new ArrayList<>(Arrays.asList("-classpath", System.getProperty("jdk.module.path"))); |
| // compile generated source |
| compiler.getTask(null, fileManager, diagnostics, optionList, null, compilationUnits).call(); |
| |
| // check we don't have any compilation errors |
| for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { |
| if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { |
| errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault()))); |
| } |
| } |
| } |
| assertTrue(errors.isEmpty(), errors.toString()); |
| |
| // load the compiled class |
| final Class<?> cls = Class.forName(CLASSNAME); |
| |
| // check that all factory methods exist and are static |
| assertTrue(Modifier.isStatic(cls.getDeclaredMethod("create").getModifiers())); |
| assertTrue(Modifier.isStatic(cls.getDeclaredMethod("create", Class.class).getModifiers())); |
| assertTrue(Modifier.isStatic(cls.getDeclaredMethod("create", Object.class).getModifiers())); |
| assertTrue(Modifier.isStatic(cls.getDeclaredMethod("create", String.class).getModifiers())); |
| assertTrue(Modifier.isStatic(cls.getDeclaredMethod("create", Class.class, MessageFactory.class).getModifiers())); |
| assertTrue(Modifier |
| .isStatic(cls.getDeclaredMethod("create", Object.class, MessageFactory.class).getModifiers())); |
| assertTrue(Modifier |
| .isStatic(cls.getDeclaredMethod("create", String.class, MessageFactory.class).getModifiers())); |
| |
| // check that the extended log methods exist |
| final String[] extendedMethods = { "diag", "notice", "verbose" }; |
| for (final String name : extendedMethods) { |
| assertDoesNotThrow(() -> { |
| cls.getDeclaredMethod(name, Marker.class, Message.class, Throwable.class); |
| cls.getDeclaredMethod(name, Marker.class, Object.class, Throwable.class); |
| cls.getDeclaredMethod(name, Marker.class, String.class, Throwable.class); |
| cls.getDeclaredMethod(name, Marker.class, Message.class); |
| cls.getDeclaredMethod(name, Marker.class, Object.class); |
| cls.getDeclaredMethod(name, Marker.class, String.class); |
| cls.getDeclaredMethod(name, Message.class); |
| cls.getDeclaredMethod(name, Object.class); |
| cls.getDeclaredMethod(name, String.class); |
| cls.getDeclaredMethod(name, Message.class, Throwable.class); |
| cls.getDeclaredMethod(name, Object.class, Throwable.class); |
| cls.getDeclaredMethod(name, String.class, Throwable.class); |
| cls.getDeclaredMethod(name, String.class, Object[].class); |
| cls.getDeclaredMethod(name, Marker.class, String.class, Object[].class); |
| |
| // 2.4 lambda support |
| cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class); |
| cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class, Throwable.class); |
| cls.getDeclaredMethod(name, Marker.class, String.class, Supplier[].class); |
| cls.getDeclaredMethod(name, Marker.class, Supplier.class); |
| cls.getDeclaredMethod(name, Marker.class, Supplier.class, Throwable.class); |
| cls.getDeclaredMethod(name, MessageSupplier.class); |
| cls.getDeclaredMethod(name, MessageSupplier.class, Throwable.class); |
| cls.getDeclaredMethod(name, String.class, Supplier[].class); |
| cls.getDeclaredMethod(name, Supplier.class); |
| cls.getDeclaredMethod(name, Supplier.class, Throwable.class); |
| }); |
| } |
| |
| // now see if it actually works... |
| final Method create = cls.getDeclaredMethod("create", String.class); |
| final Object extendedLogger = create.invoke(null, "X.Y.Z"); |
| int n = 0; |
| for (final String name : extendedMethods) { |
| final Method method = cls.getDeclaredMethod(name, String.class); |
| method.invoke(extendedLogger, "This is message " + n++); |
| } |
| |
| // This logger extends o.a.l.log4j.spi.ExtendedLogger, |
| // so all the standard logging methods can be used as well |
| final ExtendedLogger logger = (ExtendedLogger) extendedLogger; |
| logger.trace("trace message"); |
| logger.debug("debug message"); |
| logger.info("info message"); |
| logger.warn("warn message"); |
| logger.error("error message"); |
| logger.fatal("fatal message"); |
| |
| final TestLogger underlying = (TestLogger) LogManager.getLogger("X.Y.Z"); |
| final List<String> lines = underlying.getEntries(); |
| for (int i = 0; i < lines.size() - 6; i++) { |
| assertEquals(" " + levels.get(i).name + " This is message " + i, lines.get(i)); |
| } |
| |
| // test that the standard logging methods still work |
| int i = lines.size() - 6; |
| assertEquals(" TRACE trace message", lines.get(i++)); |
| assertEquals(" DEBUG debug message", lines.get(i++)); |
| assertEquals(" INFO info message", lines.get(i++)); |
| assertEquals(" WARN warn message", lines.get(i++)); |
| assertEquals(" ERROR error message", lines.get(i++)); |
| assertEquals(" FATAL fatal message", lines.get(i++)); |
| } |
| } |