使用LogstashLayout输出日志的时候遇到标题中的错误,上面的错误还只是冰山一角,整段启动日志中出现的所有的错误:
2020-05-08 00:19:24,187 main DEBUG PluginManager 'Level' found 0 plugins
2020-05-08 00:19:24,190 main ERROR Error processing element EventTemplateAdditionalFields ([LogstashLayout: null]): CLASS_NOT_FOUND
2020-05-08 00:19:24,194 main DEBUG Building Plugin[name=property, class=org.apache.logging.log4j.core.config.Property].
2020-05-08 00:19:24,204 main TRACE TypeConverterRegistry initializing.
2020-05-08 00:19:24,251 main ERROR Kafka contains an invalid element or attribute "LogstashLayout"
2020-05-08 00:19:24,251 main ERROR No layout provided for KafkaAppender
2020-05-08 00:19:24,282 main DEBUG Building Plugin[name=appenders, class=org.apache.logging.log4j.core.config.AppendersPlugin].
2020-05-08 00:19:24,282 main ERROR Null object returned for Kafka in Appenders.
2020-05-08 00:19:24,282 main DEBUG createAppenders(={CONSOLE, , FILE, failover primary=null, failover={FILE}})
2020-05-08 00:19:24,332 main DEBUG LoggerContext[name=70dea4e, org.apache.logging.log4j.core.LoggerContext@367ffa75] started OK.
2020-05-08 00:19:24,368 main ERROR Attempted to append to non-started appender failover
2020-05-08 00:19:24,369 main ERROR FailoverAppender failover did not start successfully
2020-05-08 00:19:24,374 main DEBUG Using configurationFactory org.apache.logging.log4j.core.config.ConfigurationFactory$Factory@6bedbc4d
2020-05-08 00:19:24,375 main DEBUG Closing JarURLInputStream sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@d29f28
2020-05-08 00:19:24,544 main ERROR Attempted to append to non-started appender failover
2020-05-08 00:19:24,544 main ERROR FailoverAppender failover did not start successfully
上面是我启动服务的时候,启动日志中所有的报错日志的片段,分析上面的错误日志,其根本原因是LogstashLayout这个layout 获取失败导致的。这也是从第一段报错日志中获取到的信息,那么,这个类为啥找不到呢?
关于这个标签引用的地方如下
<Kafka name="kafka" topic="log-collect" ignoreExceptions="false">
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<LogstashLayout dateTimeFormatPattern="yyyy-MM-dd'T'HH:mm:ss.SSSZZZ"
eventTemplateUri="classpath:LogstashJsonEventLayoutV1.json"
prettyPrintEnabled="true"
stackTraceEnabled="true"
locationInfoEnabled="true">
<EventTemplateAdditionalFields>
<KeyValuePair key="appName" value="${log.name}"/>
<KeyValuePair key="env" value="${profileActive}"/>
<KeyValuePair key="git" value="${git.commit.id.abbrev}"/>
</EventTemplateAdditionalFields>
</LogstashLayout>
<Property name="bootstrap.servers">${kafka.servers}</Property>
<Property name="request.timeout.ms">5000</Property>
<Property name="transaction.timeout.ms">5000</Property>
<Property name="max.block.ms">3000</Property>
</Kafka>
引用logstashLayout的目的是为了往kafka中添加日志的时候,在日志模版中增加几个默认字段。logstashLayout我这里引入的依赖版本是
<dependency>
<groupId>com.vlkan.log4j2</groupId>
<artifactId>log4j2-logstash-layout</artifactId>
<version>0.21</version>
</dependency>
然后查看引用的依赖的根路径下,发现是可以找到对应上面配置的classpath:LogstashJsonEventLayoutV1.json文件的
image.png
在项目中查看kafka append源码,找到了报错代码的位置:
image.png
跟踪layout的来源
public Layout<? extends Serializable> getOrCreateLayout() {
return (Layout)(this.layout == null ? PatternLayout.createDefaultLayout() : this.layout);
}
public static PatternLayout createDefaultLayout() {
return newBuilder().build();
}
public PatternLayout build() {
if (this.configuration == null) {
this.configuration = new DefaultConfiguration();
}
return new PatternLayout(this.configuration, this.regexReplacement, this.pattern, this.patternSelector, this.charset, this.alwaysWriteExceptions, this.disableAnsi, this.noConsoleNoAnsi, this.header, this.footer);
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.logging.log4j.core.layout;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.impl.LocationAware;
import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer2;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternFormatter;
import org.apache.logging.log4j.core.pattern.PatternParser;
import org.apache.logging.log4j.core.pattern.RegexReplacement;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.Strings;
@Plugin(
name = "PatternLayout",
category = "Core",
elementType = "layout",
printObject = true
)
public final class PatternLayout extends AbstractStringLayout {
public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
public static final String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %notEmpty{%x }- %m%n";
public static final String SIMPLE_CONVERSION_PATTERN = "%d [%t] %p %c - %m%n";
public static final String KEY = "Converter";
private final String conversionPattern;
private final PatternSelector patternSelector;
private final Serializer eventSerializer;
private PatternLayout(Configuration config, RegexReplacement replace, String eventPattern, PatternSelector patternSelector, Charset charset, boolean alwaysWriteExceptions, boolean disableAnsi, boolean noConsoleNoAnsi, String headerPattern, String footerPattern) {
super(config, charset, newSerializerBuilder().setConfiguration(config).setReplace(replace).setPatternSelector(patternSelector).setAlwaysWriteExceptions(alwaysWriteExceptions).setDisableAnsi(disableAnsi).setNoConsoleNoAnsi(noConsoleNoAnsi).setPattern(headerPattern).build(), newSerializerBuilder().setConfiguration(config).setReplace(replace).setPatternSelector(patternSelector).setAlwaysWriteExceptions(alwaysWriteExceptions).setDisableAnsi(disableAnsi).setNoConsoleNoAnsi(noConsoleNoAnsi).setPattern(footerPattern).build());
this.conversionPattern = eventPattern;
this.patternSelector = patternSelector;
this.eventSerializer = newSerializerBuilder().setConfiguration(config).setReplace(replace).setPatternSelector(patternSelector).setAlwaysWriteExceptions(alwaysWriteExceptions).setDisableAnsi(disableAnsi).setNoConsoleNoAnsi(noConsoleNoAnsi).setPattern(eventPattern).setDefaultPattern("%m%n").build();
}
public static PatternLayout.SerializerBuilder newSerializerBuilder() {
return new PatternLayout.SerializerBuilder();
}
public boolean requiresLocation() {
return this.eventSerializer instanceof LocationAware && ((LocationAware)this.eventSerializer).requiresLocation();
}
/** @deprecated */
@Deprecated
public static Serializer createSerializer(Configuration configuration, RegexReplacement replace, String pattern, String defaultPattern, PatternSelector patternSelector, boolean alwaysWriteExceptions, boolean noConsoleNoAnsi) {
PatternLayout.SerializerBuilder builder = newSerializerBuilder();
builder.setAlwaysWriteExceptions(alwaysWriteExceptions);
builder.setConfiguration(configuration);
builder.setDefaultPattern(defaultPattern);
builder.setNoConsoleNoAnsi(noConsoleNoAnsi);
builder.setPattern(pattern);
builder.setPatternSelector(patternSelector);
builder.setReplace(replace);
return builder.build();
}
public String getConversionPattern() {
return this.conversionPattern;
}
public Map<String, String> getContentFormat() {
Map<String, String> result = new HashMap();
result.put("structured", "false");
result.put("formatType", "conversion");
result.put("format", this.conversionPattern);
return result;
}
public String toSerializable(LogEvent event) {
return this.eventSerializer.toSerializable(event);
}
public void encode(LogEvent event, ByteBufferDestination destination) {
if (!(this.eventSerializer instanceof Serializer2)) {
super.encode(event, destination);
} else {
StringBuilder text = this.toText((Serializer2)this.eventSerializer, event, getStringBuilder());
Encoder<StringBuilder> encoder = this.getStringBuilderEncoder();
encoder.encode(text, destination);
trimToMaxSize(text);
}
}
private StringBuilder toText(Serializer2 serializer, LogEvent event, StringBuilder destination) {
return serializer.toSerializable(event, destination);
}
public static PatternParser createPatternParser(Configuration config) {
if (config == null) {
return new PatternParser(config, "Converter", LogEventPatternConverter.class);
} else {
PatternParser parser = (PatternParser)config.getComponent("Converter");
if (parser == null) {
parser = new PatternParser(config, "Converter", LogEventPatternConverter.class);
config.addComponent("Converter", parser);
parser = (PatternParser)config.getComponent("Converter");
}
return parser;
}
}
public String toString() {
return this.patternSelector == null ? this.conversionPattern : this.patternSelector.toString();
}
/** @deprecated */
@PluginFactory
@Deprecated
public static PatternLayout createLayout(@PluginAttribute(value = "pattern",defaultString = "%m%n") String pattern, @PluginElement("PatternSelector") PatternSelector patternSelector, @PluginConfiguration Configuration config, @PluginElement("Replace") RegexReplacement replace, @PluginAttribute("charset") Charset charset, @PluginAttribute(value = "alwaysWriteExceptions",defaultBoolean = true) boolean alwaysWriteExceptions, @PluginAttribute("noConsoleNoAnsi") boolean noConsoleNoAnsi, @PluginAttribute("header") String headerPattern, @PluginAttribute("footer") String footerPattern) {
return newBuilder().withPattern(pattern).withPatternSelector(patternSelector).withConfiguration(config).withRegexReplacement(replace).withCharset(charset).withAlwaysWriteExceptions(alwaysWriteExceptions).withNoConsoleNoAnsi(noConsoleNoAnsi).withHeader(headerPattern).withFooter(footerPattern).build();
}
public static PatternLayout createDefaultLayout() {
return newBuilder().build();
}
public static PatternLayout createDefaultLayout(Configuration configuration) {
return newBuilder().withConfiguration(configuration).build();
}
@PluginBuilderFactory
public static PatternLayout.Builder newBuilder() {
return new PatternLayout.Builder();
}
public Serializer getEventSerializer() {
return this.eventSerializer;
}
public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> {
@PluginBuilderAttribute
private String pattern;
@PluginElement("PatternSelector")
private PatternSelector patternSelector;
@PluginConfiguration
private Configuration configuration;
@PluginElement("Replace")
private RegexReplacement regexReplacement;
@PluginBuilderAttribute
private Charset charset;
@PluginBuilderAttribute
private boolean alwaysWriteExceptions;
@PluginBuilderAttribute
private boolean disableAnsi;
@PluginBuilderAttribute
private boolean noConsoleNoAnsi;
@PluginBuilderAttribute
private String header;
@PluginBuilderAttribute
private String footer;
private Builder() {
this.pattern = "%m%n";
this.charset = Charset.defaultCharset();
this.alwaysWriteExceptions = true;
this.disableAnsi = !this.useAnsiEscapeCodes();
}
private boolean useAnsiEscapeCodes() {
PropertiesUtil propertiesUtil = PropertiesUtil.getProperties();
boolean isPlatformSupportsAnsi = !propertiesUtil.isOsWindows();
boolean isJansiRequested = !propertiesUtil.getBooleanProperty("log4j.skipJansi", true);
return isPlatformSupportsAnsi || isJansiRequested;
}
public PatternLayout.Builder withPattern(String pattern) {
this.pattern = pattern;
return this;
}
public PatternLayout.Builder withPatternSelector(PatternSelector patternSelector) {
this.patternSelector = patternSelector;
return this;
}
public PatternLayout.Builder withConfiguration(Configuration configuration) {
this.configuration = configuration;
return this;
}
public PatternLayout.Builder withRegexReplacement(RegexReplacement regexReplacement) {
this.regexReplacement = regexReplacement;
return this;
}
public PatternLayout.Builder withCharset(Charset charset) {
if (charset != null) {
this.charset = charset;
}
return this;
}
public PatternLayout.Builder withAlwaysWriteExceptions(boolean alwaysWriteExceptions) {
this.alwaysWriteExceptions = alwaysWriteExceptions;
return this;
}
public PatternLayout.Builder withDisableAnsi(boolean disableAnsi) {
this.disableAnsi = disableAnsi;
return this;
}
public PatternLayout.Builder withNoConsoleNoAnsi(boolean noConsoleNoAnsi) {
this.noConsoleNoAnsi = noConsoleNoAnsi;
return this;
}
public PatternLayout.Builder withHeader(String header) {
this.header = header;
return this;
}
public PatternLayout.Builder withFooter(String footer) {
this.footer = footer;
return this;
}
public PatternLayout build() {
if (this.configuration == null) {
this.configuration = new DefaultConfiguration();
}
return new PatternLayout(this.configuration, this.regexReplacement, this.pattern, this.patternSelector, this.charset, this.alwaysWriteExceptions, this.disableAnsi, this.noConsoleNoAnsi, this.header, this.footer);
}
}
private static class PatternSelectorSerializer implements Serializer, Serializer2, LocationAware {
private final PatternSelector patternSelector;
private final RegexReplacement replace;
private PatternSelectorSerializer(PatternSelector patternSelector, RegexReplacement replace) {
this.patternSelector = patternSelector;
this.replace = replace;
}
public String toSerializable(LogEvent event) {
StringBuilder sb = AbstractStringLayout.getStringBuilder();
String var3;
try {
var3 = this.toSerializable(event, sb).toString();
} finally {
AbstractStringLayout.trimToMaxSize(sb);
}
return var3;
}
public StringBuilder toSerializable(LogEvent event, StringBuilder buffer) {
PatternFormatter[] formatters = this.patternSelector.getFormatters(event);
int len = formatters.length;
for(int i = 0; i < len; ++i) {
formatters[i].format(event, buffer);
}
if (this.replace != null) {
String str = buffer.toString();
str = this.replace.format(str);
buffer.setLength(0);
buffer.append(str);
}
return buffer;
}
public boolean requiresLocation() {
return this.patternSelector instanceof LocationAware && ((LocationAware)this.patternSelector).requiresLocation();
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(super.toString());
builder.append("[patternSelector=");
builder.append(this.patternSelector);
builder.append(", replace=");
builder.append(this.replace);
builder.append("]");
return builder.toString();
}
}
public static class SerializerBuilder implements org.apache.logging.log4j.core.util.Builder<Serializer> {
private Configuration configuration;
private RegexReplacement replace;
private String pattern;
private String defaultPattern;
private PatternSelector patternSelector;
private boolean alwaysWriteExceptions;
private boolean disableAnsi;
private boolean noConsoleNoAnsi;
public SerializerBuilder() {
}
public Serializer build() {
if (Strings.isEmpty(this.pattern) && Strings.isEmpty(this.defaultPattern)) {
return null;
} else if (this.patternSelector == null) {
try {
PatternParser parser = PatternLayout.createPatternParser(this.configuration);
List<PatternFormatter> list = parser.parse(this.pattern == null ? this.defaultPattern : this.pattern, this.alwaysWriteExceptions, this.disableAnsi, this.noConsoleNoAnsi);
PatternFormatter[] formatters = (PatternFormatter[])list.toArray(new PatternFormatter[0]);
return new PatternLayout.PatternSerializer(formatters, this.replace);
} catch (RuntimeException var4) {
throw new IllegalArgumentException("Cannot parse pattern '" + this.pattern + "'", var4);
}
} else {
return new PatternLayout.PatternSelectorSerializer(this.patternSelector, this.replace);
}
}
public PatternLayout.SerializerBuilder setConfiguration(Configuration configuration) {
this.configuration = configuration;
return this;
}
public PatternLayout.SerializerBuilder setReplace(RegexReplacement replace) {
this.replace = replace;
return this;
}
public PatternLayout.SerializerBuilder setPattern(String pattern) {
this.pattern = pattern;
return this;
}
public PatternLayout.SerializerBuilder setDefaultPattern(String defaultPattern) {
this.defaultPattern = defaultPattern;
return this;
}
public PatternLayout.SerializerBuilder setPatternSelector(PatternSelector patternSelector) {
this.patternSelector = patternSelector;
return this;
}
public PatternLayout.SerializerBuilder setAlwaysWriteExceptions(boolean alwaysWriteExceptions) {
this.alwaysWriteExceptions = alwaysWriteExceptions;
return this;
}
public PatternLayout.SerializerBuilder setDisableAnsi(boolean disableAnsi) {
this.disableAnsi = disableAnsi;
return this;
}
public PatternLayout.SerializerBuilder setNoConsoleNoAnsi(boolean noConsoleNoAnsi) {
this.noConsoleNoAnsi = noConsoleNoAnsi;
return this;
}
}
private static class PatternSerializer implements Serializer, Serializer2, LocationAware {
private final PatternFormatter[] formatters;
private final RegexReplacement replace;
private PatternSerializer(PatternFormatter[] formatters, RegexReplacement replace) {
this.formatters = formatters;
this.replace = replace;
}
public String toSerializable(LogEvent event) {
StringBuilder sb = AbstractStringLayout.getStringBuilder();
String var3;
try {
var3 = this.toSerializable(event, sb).toString();
} finally {
AbstractStringLayout.trimToMaxSize(sb);
}
return var3;
}
public StringBuilder toSerializable(LogEvent event, StringBuilder buffer) {
int len = this.formatters.length;
for(int i = 0; i < len; ++i) {
this.formatters[i].format(event, buffer);
}
if (this.replace != null) {
String str = buffer.toString();
str = this.replace.format(str);
buffer.setLength(0);
buffer.append(str);
}
return buffer;
}
public boolean requiresLocation() {
PatternFormatter[] var1 = this.formatters;
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
PatternFormatter formatter = var1[var3];
if (formatter.requiresLocation()) {
return true;
}
}
return false;
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(super.toString());
builder.append("[formatters=");
builder.append(Arrays.toString(this.formatters));
builder.append(", replace=");
builder.append(this.replace);
builder.append("]");
return builder.toString();
}
}
}
根据上面源码知,如果传入的layout为空,那么就会默认的创建一个PatternLayout类型的layout,否则取传入的layout,对于我的上面的程序,我这里应该是传入layout有值的,只是解析它的时候报错了,class not found。
发现新现象
超过半天的探索,发现同样的程序,在idea中执行,是OK的,但是打包之后,发现会出现上面的错误,搜噶,原来是打包的原因,但是我的maven打包程序是没有发现异常,而且将jar包解压之后,发现可以在对应的路径下找到logstashLayout 的相关依赖。又卡住了。
问题解决
最后在log4j2.xml的配置文件中,手动引入packages,如下,问题得到解决
<Configuration status="trace" packages="com.vlkan.log4j2.logstash.layout">
其中packages的内容是logstashLayout所在的包
网友评论