package com.blazemeter.jmeter.debugger.logging; import com.blazemeter.jmeter.debugger.gui.LoggerPanelWrapping; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.StringLayout; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.layout.PatternLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @Plugin(name = "Logger", category = "Core", elementType = "appender", printObject = true) public class LoggerPanelAppender extends AbstractAppender { private static final Logger log = LoggerFactory.getLogger(LoggerPanelAppender.class); public static final String DEFAULT_PATTERN = "%d %p %c{1.}: %m%n"; private final LoggerPanelWrapping panelWrapping; private Method processLogEventMethod; private Constructor logEventObjectConstructor; public LoggerPanelAppender(String name, LoggerPanelWrapping panelWrapping) { super(name, null, PatternLayout.newBuilder().withPattern(DEFAULT_PATTERN).build()); start(); Configuration configuration = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); configuration.getRootLogger().addAppender(this, Level.INFO, null); this.panelWrapping = panelWrapping; initializeProcessLogEventMethod(); initializeLogEventObjectConstructor(); } private void initializeProcessLogEventMethod() { try { Method[] methods = panelWrapping.getClass().getSuperclass().getMethods(); for (Method method : methods) { if ("processLogEvent".equals(method.getName())) { processLogEventMethod = method; break; } } } catch (Throwable ex) { log.error("Cannot find 'processLogEventMethod' method for initialize logging panel", ex); } } private void initializeLogEventObjectConstructor() { try { Class cls = Class.forName("org.apache.jmeter.gui.logging.LogEventObject"); logEventObjectConstructor = cls.getConstructor(Object.class, String.class); } catch (Throwable ex) { log.error("Cannot find constructor for class 'LogEventObject'", ex); } } @Override public void append(LogEvent logEvent) { if (processLogEventMethod != null && logEventObjectConstructor != null) { final String serializedString = getStringLayout().toSerializable(logEvent); if (serializedString != null && !serializedString.isEmpty()) { postLogEventObject(logEvent, serializedString); } } } private void postLogEventObject(LogEvent logEvent, String serializedString) { Object logEventObject = createLogEventObject(logEvent, serializedString); if (logEventObject != null) { try { processLogEventMethod.invoke(panelWrapping, logEventObject); } catch (Throwable ex) { log.error("Cannot post logEventObject", ex); } } } private Object createLogEventObject(LogEvent logEvent, String serializedString) { try { return logEventObjectConstructor.newInstance(logEvent, serializedString); } catch (Throwable ex) { log.error("Cannot create instance of class 'LogEventObject'", ex); return null; } } public StringLayout getStringLayout() { return (StringLayout) getLayout(); } }