yvasyliev opened a new issue, #2026:
URL: https://github.com/apache/logging-log4j2/issues/2026
# Description
In `log4j2` (ver `2.21.1`), we can create custom appender plugins with
nested elements.
Let's say we have the following `log4j2.xml` configuration:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<MyAppender name="myAppender">
<MessageTemplate prefix="Hello, " suffix="!"/>
</MyAppender>
</Appenders>
<Loggers>
<Root level="ALL">
<AppenderRef ref="myAppender"/>
</Root>
</Loggers>
</Configuration>
```
`MyAppender` is a custom appender and `MessageTemplate` is a custom nested
element.
A source code of `MyAppender` class:
```java
@Plugin(name = "MyAppender", category = Core.CATEGORY_NAME, elementType =
Appender.ELEMENT_TYPE)
public class MyAppender extends AbstractAppender {
private final MessageTemplate messageTemplate;
public MyAppender(String name, MessageTemplate messageTemplate) {
super(name, null, PatternLayout.createDefaultLayout(), true,
Property.EMPTY_ARRAY);
this.messageTemplate = messageTemplate;
}
@PluginFactory
public static MyAppender createAppender(@PluginAttribute("name") String
name,
@PluginElement("MessageTemplate") MessageTemplate messageTemplate) {
return new MyAppender(name, messageTemplate);
}
@Override
public void append(LogEvent event) {
var prefix = messageTemplate.getPrefix();
var formattedMessage = event.getMessage().getFormattedMessage();
var suffix = messageTemplate.getSuffix();
var text = prefix + formattedMessage + suffix;
System.out.println(text);
}
}
```
A source code of `MessageTemplate` class:
```java
@Plugin(name = "MessageTemplate", category = Core.CATEGORY_NAME, elementType
= Appender.ELEMENT_TYPE)
public class MessageTemplate {
private final String prefix;
private final String suffix;
public MessageTemplate(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
@PluginFactory
public static MessageTemplate createAppender(@PluginAttribute("prefix")
String prefix,
@PluginAttribute("suffix")
String suffix) {
return new MessageTemplate(prefix, suffix);
}
public String getPrefix() {
return prefix;
}
public String getSuffix() {
return suffix;
}
}
```
Let's create a main class:
```java
public class Log4j2Demo {
private static final Logger LOGGER =
LoggerFactory.getLogger(Log4j2Demo.class);
public static void main(String[] args) {
LOGGER.info("World");
}
}
```
If we run the code above, we'll get the following output:
```
Hello, World!
```
# Problem
If the project is developed with Java 17, you may think of making
`MessageTemplate` a record:
```java
@Plugin(name = "MessageTemplate", category = Core.CATEGORY_NAME, elementType
= Appender.ELEMENT_TYPE)
public record MessageTemplate(String prefix, String suffix) {
@PluginFactory
public static MessageTemplate createAppender(@PluginAttribute("prefix")
String prefix,
@PluginAttribute("suffix")
String suffix) {
return new MessageTemplate(prefix, suffix);
}
}
```
Now the code extremely clean.
But if we run it now, we'll get the following error:
```
ERROR StatusConsoleListener MyAppender contains an invalid element or
attribute "MessageTemplate"
ERROR StatusConsoleListener An exception occurred processing Appender
myAppender
java.lang.NullPointerException: Cannot invoke
"com.github.yvasyliev.log4j2.appenders.MessageTemplate.prefix()" because
"this.messageTemplate" is null
at
com.github.yvasyliev.log4j2.appenders.MyAppender.append(MyAppender.java:31)
at
org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:161)
at
org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:134)
at
org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:125)
at
org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:89)
at
org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:686)
at
org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:644)
at
org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:620)
at
org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:556)
at
org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:81)
at org.apache.logging.log4j.core.Logger.log(Logger.java:163)
at
org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2165)
at
org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2119)
at
org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2102)
at
org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1982)
at
org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1835)
at org.apache.logging.slf4j.Log4jLogger.info(Log4jLogger.java:174)
at com.github.yvasyliev.log4j2.Log4j2Demo.main(Log4j2Demo.java:10)
```
# Suggestion
My suggestion is to add support of Java records to Log4j 2 annotations so we
can create clean plugin code.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]