Home / cs-notes / Architecture / Components / Log / Log4j2 / 日志格式是如何解析的
log4j-core-2.6.2.jar
PatternLayout
org.apache.logging.log4j.core.layout
public static Serializer createSerializer(final Configuration configuration, final RegexReplacement replace,
final String pattern, final String defaultPattern, final PatternSelector patternSelector,
final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi) {
if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) {
return null;
}
if (patternSelector == null) {
try {
final PatternParser parser = createPatternParser(configuration);
final List<PatternFormatter> list = parser.parse(pattern == null ? defaultPattern : pattern,
alwaysWriteExceptions, noConsoleNoAnsi);
final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
return new PatternSerializer(formatters, replace);
} catch (final RuntimeException ex) {
throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
}
}
return new PatternSelectorSerializer(patternSelector, replace);
}
PatternParser
public List<PatternFormatter> parse(final String pattern) {
return parse(pattern, false, false);
}
public List<PatternFormatter> parse(final String pattern, final boolean alwaysWriteExceptions,
final boolean noConsoleNoAnsi) {
final List<PatternFormatter> list = new ArrayList<>();
final List<PatternConverter> converters = new ArrayList<>();
final List<FormattingInfo> fields = new ArrayList<>();
parse(pattern, converters, fields, noConsoleNoAnsi, true);
final Iterator<FormattingInfo> fieldIter = fields.iterator();
boolean handlesThrowable = false;
for (final PatternConverter converter : converters) {
if (converter instanceof NanoTimePatternConverter) {
// LOG4J2-1074 Switch to actual clock if nanosecond timestamps are required in config.
// LOG4J2-1248 set config nanoclock
if (config != null) {
config.setNanoClock(new SystemNanoClock());
}
}
LogEventPatternConverter pc;
if (converter instanceof LogEventPatternConverter) {
pc = (LogEventPatternConverter) converter;
handlesThrowable |= pc.handlesThrowable();
} else {
pc = new LiteralPatternConverter(config, Strings.EMPTY, true);
}
FormattingInfo field;
if (fieldIter.hasNext()) {
field = fieldIter.next();
} else {
field = FormattingInfo.getDefault();
}
list.add(new PatternFormatter(pc, field));
}
if (alwaysWriteExceptions && !handlesThrowable) {
final LogEventPatternConverter pc = ExtendedThrowablePatternConverter.newInstance(null);
list.add(new PatternFormatter(pc, FormattingInfo.getDefault()));
}
return list;
}
/**
* Parse a format specifier.
*
* @param pattern
* pattern to parse.
* @param patternConverters
* list to receive pattern converters.
* @param formattingInfos
* list to receive field specifiers corresponding to pattern converters.
* @param noConsoleNoAnsi
* TODO
* @param convertBackslashes if {@code true}, backslash characters are treated as escape characters and character
* sequences like "\" followed by "t" (backslash+t) are converted to special characters like '\t' (tab).
*/
public void parse(final String pattern, final List<PatternConverter> patternConverters,
final List<FormattingInfo> formattingInfos, final boolean noConsoleNoAnsi,
final boolean convertBackslashes) {
Objects.requireNonNull(pattern, "pattern");
final StringBuilder currentLiteral = new StringBuilder(BUF_SIZE);
final int patternLength = pattern.length();
ParserState state = ParserState.LITERAL_STATE;
char c;
int i = 0;
FormattingInfo formattingInfo = FormattingInfo.getDefault();
while (i < patternLength) {
c = pattern.charAt(i++);
switch (state) {
case LITERAL_STATE:
// In literal state, the last char is always a literal.
if (i == patternLength) {
currentLiteral.append(c);
continue;
}
if (c == ESCAPE_CHAR) {
// peek at the next char.
switch (pattern.charAt(i)) {
case ESCAPE_CHAR:
currentLiteral.append(c);
i++; // move pointer
break;
default:
if (currentLiteral.length() != 0) {
patternConverters.add(new LiteralPatternConverter(config, currentLiteral.toString(),
convertBackslashes));
formattingInfos.add(FormattingInfo.getDefault());
}
currentLiteral.setLength(0);
currentLiteral.append(c); // append %
state = ParserState.CONVERTER_STATE;
formattingInfo = FormattingInfo.getDefault();
}
} else {
currentLiteral.append(c);
}
break;
case CONVERTER_STATE:
currentLiteral.append(c);
switch (c) {
case '-':
formattingInfo = new FormattingInfo(true, formattingInfo.getMinLength(),
formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
break;
case '.':
state = ParserState.DOT_STATE;
break;
default:
if (c >= '0' && c <= '9') {
formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), c - '0',
formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
state = ParserState.MIN_STATE;
} else {
i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo, converterRules,
patternConverters, formattingInfos, noConsoleNoAnsi, convertBackslashes);
// Next pattern is assumed to be a literal.
state = ParserState.LITERAL_STATE;
formattingInfo = FormattingInfo.getDefault();
currentLiteral.setLength(0);
}
} // switch
break;
case MIN_STATE:
currentLiteral.append(c);
if (c >= '0' && c <= '9') {
// Multiply the existing value and add the value of the number just encountered.
formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength()
* DECIMAL + c - '0', formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
} else if (c == '.') {
state = ParserState.DOT_STATE;
} else {
i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo, converterRules,
patternConverters, formattingInfos, noConsoleNoAnsi, convertBackslashes);
state = ParserState.LITERAL_STATE;
formattingInfo = FormattingInfo.getDefault();
currentLiteral.setLength(0);
}
break;
case DOT_STATE:
currentLiteral.append(c);
switch (c) {
case '-':
formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
formattingInfo.getMaxLength(),false);
break;
default:
if (c >= '0' && c <= '9') {
formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
c - '0', formattingInfo.isLeftTruncate());
state = ParserState.MAX_STATE;
} else {
LOGGER.error("Error occurred in position " + i + ".\n Was expecting digit, instead got char \"" + c
+ "\".");
state = ParserState.LITERAL_STATE;
}
}
break;
case MAX_STATE:
currentLiteral.append(c);
if (c >= '0' && c <= '9') {
// Multiply the existing value and add the value of the number just encountered.
formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
formattingInfo.getMaxLength() * DECIMAL + c - '0', formattingInfo.isLeftTruncate());
} else {
i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo, converterRules,
patternConverters, formattingInfos, noConsoleNoAnsi, convertBackslashes);
state = ParserState.LITERAL_STATE;
formattingInfo = FormattingInfo.getDefault();
currentLiteral.setLength(0);
}
break;
} // switch
}
// while
if (currentLiteral.length() != 0) {
patternConverters.add(new LiteralPatternConverter(config, currentLiteral.toString(), convertBackslashes));
formattingInfos.add(FormattingInfo.getDefault());
}
}