diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtFormatter.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtFormatter.java index 5b052f07e30f8..6de80b0ec9d19 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtFormatter.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtFormatter.java @@ -19,6 +19,9 @@ package org.jboss.logmanager; +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import java.util.logging.Formatter; import java.util.logging.LogRecord; @@ -35,10 +38,40 @@ public final String format(final LogRecord record) { /** * Format a message using an extended log record. * - * @param extLogRecord the log record + * @param record the log record * @return the formatted message */ - public abstract String format(final ExtLogRecord extLogRecord); + public abstract String format(ExtLogRecord record); + + @Override + public String formatMessage(LogRecord record) { + final ResourceBundle bundle = record.getResourceBundle(); + String msg = record.getMessage(); + if (msg == null) { + return null; + } + if (bundle != null) { + try { + msg = bundle.getString(msg); + } catch (MissingResourceException ex) { + // ignore + } + } + final Object[] parameters = record.getParameters(); + if (parameters == null || parameters.length == 0) { + return formatMessageNone(record); + } + if (record instanceof ExtLogRecord) { + final ExtLogRecord extLogRecord = (ExtLogRecord) record; + final ExtLogRecord.FormatStyle formatStyle = extLogRecord.getFormatStyle(); + if (formatStyle == ExtLogRecord.FormatStyle.PRINTF) { + return formatMessagePrintf(record); + } else if (formatStyle == ExtLogRecord.FormatStyle.NO_FORMAT) { + return formatMessageNone(record); + } + } + return msg.indexOf('{') >= 0 ? formatMessageLegacy(record) : formatMessageNone(record); + } /** * Determines whether or not this formatter will require caller, source level, information when a log record is @@ -54,4 +87,37 @@ public final String format(final LogRecord record) { public boolean isCallerCalculationRequired() { return true; } -} + + /** + * Format the message text as if there are no parameters. The default implementation delegates to + * {@link LogRecord#getMessage() record.getMessage()}. + * + * @param record the record to format + * @return the formatted string + */ + protected String formatMessageNone(LogRecord record) { + return record.getMessage(); + } + + /** + * Format the message text as if there are no parameters. The default implementation delegates to + * {@link MessageFormat#format(String, Object[]) MessageFormat.format(record.getMessage(),record.getParameters())}. + * + * @param record the record to format + * @return the formatted string + */ + protected String formatMessageLegacy(LogRecord record) { + return MessageFormat.format(record.getMessage(), record.getParameters()); + } + + /** + * Format the message text as if there are no parameters. The default implementation delegates to + * {@link String#format(String, Object[]) String.format(record.getMessage(),record.getParameters())}. + * + * @param record the record to format + * @return the formatted string + */ + protected String formatMessagePrintf(LogRecord record) { + return String.format(record.getMessage(), record.getParameters()); + } +} \ No newline at end of file diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtHandler.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtHandler.java index c45791f6278f2..f8a4968060a05 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtHandler.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtHandler.java @@ -46,7 +46,7 @@ public abstract class ExtHandler extends Handler implements FlushableCloseable { * The sub-handlers for this handler. May only be updated using the {@link #handlersUpdater} atomic updater. The array * instance should not be modified (treat as immutable). */ - @SuppressWarnings({ "UnusedDeclaration" }) + @SuppressWarnings("unused") protected volatile Handler[] handlers; /** @@ -296,9 +296,12 @@ public boolean isCallerCalculationRequired() { Formatter formatter = getFormatter(); if (formatterRequiresCallerCalculation(formatter)) { return true; - } else { - final Handler[] handlers = getHandlers(); - for (Handler handler : handlers) { + } else for (Handler handler : getHandlers()) { + if (handler instanceof ExtHandler) { + if (((ExtHandler) handler).isCallerCalculationRequired()) { + return true; + } + } else { formatter = handler.getFormatter(); if (formatterRequiresCallerCalculation(formatter)) { return true; diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtLogRecord.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtLogRecord.java index 739f16d78f28e..345d28a408a38 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtLogRecord.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/ExtLogRecord.java @@ -118,8 +118,6 @@ public ExtLogRecord(final ExtLogRecord original) { ndc = original.ndc; loggerClassName = original.loggerClassName; threadName = original.threadName; - resourceKey = original.resourceKey; - formattedMessage = original.formattedMessage; hostName = original.hostName; processName = original.processName; processId = original.processId; @@ -150,8 +148,6 @@ public static ExtLogRecord wrap(LogRecord rec) { private FastCopyHashMap mdcCopy; private int sourceLineNumber = -1; private String sourceFileName; - private String resourceKey; - private String formattedMessage; private String threadName; private String hostName; private String processName; @@ -172,8 +168,6 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound mdcCopy = (FastCopyHashMap) fields.get("mdcCopy", new FastCopyHashMap<>()); sourceLineNumber = fields.get("sourceLineNumber", -1); sourceFileName = (String) fields.get("sourceFileName", null); - resourceKey = (String) fields.get("resourceKey", null); - formattedMessage = (String) fields.get("formattedMessage", null); threadName = (String) fields.get("threadName", null); hostName = (String) fields.get("hostName", null); processName = (String) fields.get("processName", null); @@ -199,7 +193,6 @@ public void disableCallerCalculation() { public void copyAll() { copyMdc(); calculateCaller(); - getFormattedMessage(); } /** @@ -462,36 +455,17 @@ public void setSourceModuleVersion(final String sourceModuleVersion) { * Get the fully formatted log record, with resources resolved and parameters applied. * * @return the formatted log record + * @deprecated The formatter should normally be used to format the message contents. */ + @Deprecated public String getFormattedMessage() { - if (formattedMessage == null) { - formattedMessage = formatRecord(); - } - return formattedMessage; - } - - /** - * Get the resource key, if any. If the log message is not localized, then the key is {@code null}. - * - * @return the resource key - */ - public String getResourceKey() { - if (formattedMessage == null) { - formatRecord(); - } - return resourceKey; - } - - private String formatRecord() { final ResourceBundle bundle = getResourceBundle(); String msg = getMessage(); if (msg == null) return null; if (bundle != null) { try { - String locMsg = bundle.getString(msg); - resourceKey = msg; - msg = locMsg; + msg = bundle.getString(msg); } catch (MissingResourceException ex) { // ignore } @@ -512,6 +486,18 @@ private String formatRecord() { return msg; } + /** + * Get the resource key, if any. If the log message is not localized, then the key is {@code null}. + * + * @return the resource key + */ + public String getResourceKey() { + final String msg = getMessage(); + if (msg == null) return null; + if (getResourceBundleName() == null && getResourceBundle() == null) return null; + return msg; + } + /** * Get the thread name of this logging event. * @@ -603,7 +589,6 @@ public void setMessage(final String message) { */ public void setMessage(final String message, final FormatStyle formatStyle) { this.formatStyle = formatStyle == null ? FormatStyle.MESSAGE_FORMAT : formatStyle; - formattedMessage = null; super.setMessage(message); } @@ -613,7 +598,6 @@ public void setMessage(final String message, final FormatStyle formatStyle) { * @param parameters the log message parameters. (may be null) */ public void setParameters(final Object[] parameters) { - formattedMessage = null; super.setParameters(parameters); } @@ -623,7 +607,6 @@ public void setParameters(final Object[] parameters) { * @param bundle localization bundle (may be null) */ public void setResourceBundle(final ResourceBundle bundle) { - formattedMessage = null; super.setResourceBundle(bundle); } @@ -633,7 +616,6 @@ public void setResourceBundle(final ResourceBundle bundle) { * @param name localization bundle name (may be null) */ public void setResourceBundleName(final String name) { - formattedMessage = null; super.setResourceBundleName(name); } } diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/RegexFilter.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/RegexFilter.java index 60b7d2673f84f..3b88d3fad5671 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/RegexFilter.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/RegexFilter.java @@ -24,8 +24,6 @@ import java.util.logging.Filter; -import org.jboss.logmanager.ExtLogRecord; - /** * A regular-expression-based filter. Used to exclude log records which match or don't match the expression. The * regular expression is checked against the raw (unformatted) message. @@ -59,12 +57,6 @@ public RegexFilter(final String patternString) { */ @Override public boolean isLoggable(final LogRecord record) { - final String msg; - if (record instanceof ExtLogRecord) { - msg = ((ExtLogRecord) record).getFormattedMessage(); - } else { - msg = record.getMessage(); - } - return pattern.matcher(String.valueOf(msg)).find(); + return record != null && pattern.matcher(String.valueOf(record.getMessage())).find(); } } diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/SubstituteFilter.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/SubstituteFilter.java index 98b5a61706c1a..ff01b19644fdb 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/SubstituteFilter.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/filters/SubstituteFilter.java @@ -19,6 +19,7 @@ package org.jboss.logmanager.filters; +import java.text.MessageFormat; import java.util.logging.LogRecord; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -77,7 +78,7 @@ public boolean isLoggable(final LogRecord record) { if (record instanceof ExtLogRecord) { currentMsg = ((ExtLogRecord) record).getFormattedMessage(); } else { - currentMsg = record.getMessage(); + currentMsg = MessageFormat.format(record.getMessage(), record.getParameters()); } final Matcher matcher = pattern.matcher(String.valueOf(currentMsg)); final String msg; diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPatternFormatter.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPatternFormatter.java new file mode 100644 index 0000000000000..1833172bc6647 --- /dev/null +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPatternFormatter.java @@ -0,0 +1,232 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed 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.jboss.logmanager.formatters; + +import static java.lang.Math.abs; + +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import org.jboss.logmanager.ExtLogRecord; +import org.jboss.logmanager.Level; +import org.wildfly.common.format.Printf; + +/** + * A pattern formatter that colorizes the pattern in a fixed manner. + */ +public class ColorPatternFormatter extends PatternFormatter { + + private final Printf printf = new ColorPrintf(); + + public ColorPatternFormatter() { + } + + public ColorPatternFormatter(final String pattern) { + super(); + setPattern(pattern); + } + + static final boolean trueColor = determineTrueColor(); + + static boolean determineTrueColor() { + final String colorterm = System.getenv("COLORTERM"); + return (colorterm != null && (colorterm.contains("truecolor") || colorterm.contains("24bit"))); + } + + static boolean isTrueColor() { + return trueColor; + } + + public void setSteps(final FormatStep[] steps) { + FormatStep[] colorSteps = new FormatStep[steps.length]; + for (int i = 0; i < steps.length; i++) { + colorSteps[i] = colorize(steps[i]); + } + super.setSteps(colorSteps); + } + + private FormatStep colorize(final FormatStep step) { + switch (step.getItemType()) { + case LEVEL: + return new LevelColorStep(step); + case SOURCE_CLASS_NAME: + return new ColorStep(step, 0xff, 0xff, 0xdd); + case DATE: + return new ColorStep(step, 0xc0, 0xc0, 0xc0); + case SOURCE_FILE_NAME: + return new ColorStep(step, 0xff, 0xff, 0xdd); + case HOST_NAME: + return new ColorStep(step, 0xdd, 0xff, 0xdd); + case SOURCE_LINE_NUMBER: + return new ColorStep(step, 0xff, 0xff, 0xdd); + case LINE_SEPARATOR: + return step; + case CATEGORY: + return new ColorStep(step, 0xdd, 0xdd, 0xff); + case MDC: + return new ColorStep(step, 0xdd, 0xff, 0xaa); + case MESSAGE: + return new ColorStep(step, 0xff, 0xff, 0xff); + case EXCEPTION_TRACE: + return new ColorStep(step, 0xff, 0xdd, 0xdd); + case SOURCE_METHOD_NAME: + return new ColorStep(step, 0xff, 0xff, 0xdd); + case SOURCE_MODULE_NAME: + return new ColorStep(step, 0x88, 0xff, 0xdd); + case SOURCE_MODULE_VERSION: + return new ColorStep(step, 0xdd, 0xff, 0xdd); + case NDC: + return new ColorStep(step, 0xdd, 0xff, 0xaa); + case PROCESS_ID: + return new ColorStep(step, 0xff, 0xdd, 0xff); + case PROCESS_NAME: + return new ColorStep(step, 0xff, 0xdd, 0xff); + case RELATIVE_TIME: + return new ColorStep(step, 0xc0, 0xc0, 0xc0); + case RESOURCE_KEY: + return new ColorStep(step, 0xdd, 0xff, 0xdd); + case SYSTEM_PROPERTY: + return new ColorStep(step, 0x88, 0x88, 0x00); + case TEXT: + return new ColorStep(step, 0xdd, 0xdd, 0xdd); + case THREAD_ID: + return new ColorStep(step, 0xdd, 0x88, 0xdd); + case THREAD_NAME: + return new ColorStep(step, 0xdd, 0x88, 0xdd); + case COMPOUND: + case GENERIC: + default: + return new ColorStep(step, 0xc0, 0xc0, 0xc0); + } + } + + private String colorizePlain(final String str) { + return ColorUtil.endFgColor(ColorUtil.startFgColor(new StringBuilder(), isTrueColor(), 0xff, 0xff, 0xff).append(str)).toString(); + } + + public String formatMessage(final LogRecord logRecord) { + if (logRecord instanceof ExtLogRecord) { + final ExtLogRecord record = (ExtLogRecord) logRecord; + if (record.getFormatStyle() != ExtLogRecord.FormatStyle.PRINTF || record.getParameters() == null || record.getParameters().length == 0) { + return colorizePlain(super.formatMessage(record)); + } + return printf.format(record.getMessage(), record.getParameters()); + } else { + return colorizePlain(super.formatMessage(logRecord)); + } + } + + static final class ColorStep implements FormatStep { + private final int r, g, b; + private final FormatStep delegate; + + ColorStep(final FormatStep delegate, final int r, final int g, final int b) { + this.r = r; + this.g = g; + this.b = b; + this.delegate = delegate; + } + + public void render(final Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { + ColorUtil.startFgColor(builder, isTrueColor(), r, g, b); + delegate.render(formatter, builder, record); + ColorUtil.endFgColor(builder); + } + + public void render(final StringBuilder builder, final ExtLogRecord record) { + render(null, builder, record); + } + + public int estimateLength() { + return delegate.estimateLength() + 30; + } + + public boolean isCallerInformationRequired() { + return delegate.isCallerInformationRequired(); + } + + public FormatStep[] childSteps() { + return delegate.childSteps(); + } + + public int childStepCount() { + return delegate.childStepCount(); + } + + public FormatStep getChildStep(final int idx) { + return delegate.getChildStep(idx); + } + + public ItemType getItemType() { + return delegate.getItemType(); + } + } + + static final class LevelColorStep implements FormatStep { + private static final int LARGEST_LEVEL = Level.ERROR.intValue(); + private static final int SMALLEST_LEVEL = Level.TRACE.intValue(); + private static final int SATURATION = 128; + private final FormatStep delegate; + + LevelColorStep(final FormatStep delegate) { + this.delegate = delegate; + } + + public void render(final Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { + final int level = Math.max(Math.min(record.getLevel().intValue(), LARGEST_LEVEL), SMALLEST_LEVEL) - SMALLEST_LEVEL; + // really crappy linear interpolation + int r = (level < 200 ? 0 : (level - 200) * (255 - SATURATION) / 400) + SATURATION; + int g = (300 - abs(level - 300)) * (255 - SATURATION) / 300 + SATURATION; + int b = (level > 400 ? 0 : level * (255 - SATURATION - 1) / 400) + SATURATION; + ColorUtil.startFgColor(builder, isTrueColor(), r, g, b); + delegate.render(formatter, builder, record); + ColorUtil.endFgColor(builder); + } + + public void render(final StringBuilder builder, final ExtLogRecord record) { + render(null, builder, record); + } + + public int estimateLength() { + return delegate.estimateLength() + 30; + } + } +} + +// delayed init on native image +final class TrueColorHolder { + private TrueColorHolder() {} + + static final boolean trueColor = ColorPatternFormatter.determineTrueColor(); +} + +@TargetClass(ColorPatternFormatter.class) +final class Target_ColorPatternFormatter { + + @Delete + static final boolean trueColor = false; + + @Substitute + static boolean isTrueColor() { + return TrueColorHolder.trueColor; + } +} \ No newline at end of file diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPrintf.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPrintf.java new file mode 100644 index 0000000000000..c580fd9f25872 --- /dev/null +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorPrintf.java @@ -0,0 +1,129 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed 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.jboss.logmanager.formatters; + +import static org.jboss.logmanager.formatters.ColorPatternFormatter.isTrueColor; + +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.util.Formattable; +import java.util.Locale; +import java.util.UUID; + +import org.wildfly.common.format.GeneralFlags; +import org.wildfly.common.format.NumericFlags; +import org.wildfly.common.format.Printf; + +/** + */ +class ColorPrintf extends Printf { + ColorPrintf() { + super(Locale.getDefault()); + } + + public StringBuilder formatDirect(final StringBuilder destination, final String format, final Object... params) { + restoreColor(destination); + super.formatDirect(destination, format, params); + ColorUtil.endFgColor(destination); + return destination; + } + + private static void restoreColor(final StringBuilder destination) { + ColorUtil.startFgColor(destination, isTrueColor(), 0xff, 0xff, 0xff); + } + + protected void formatTimeTextField(final StringBuilder target, final TemporalAccessor ta, final TemporalField field, final String[] symbols, final GeneralFlags genFlags, final int width) { + super.formatTimeTextField(target, ta, field, symbols, genFlags, width); + } + + protected void formatTimeZoneId(final StringBuilder target, final TemporalAccessor ta, final GeneralFlags genFlags, final int width) { + super.formatTimeZoneId(target, ta, genFlags, width); + } + + protected void formatTimeZoneOffset(final StringBuilder target, final TemporalAccessor ta, final GeneralFlags genFlags, final int width) { + super.formatTimeZoneOffset(target, ta, genFlags, width); + } + + protected void formatTimeField(final StringBuilder target, final TemporalAccessor ta, final TemporalField field, final GeneralFlags genFlags, final int width, final int zeroPad) { + super.formatTimeField(target, ta, field, genFlags, width, zeroPad); + } + + + protected void formatPercent(final StringBuilder target) { + super.formatPercent(target); + } + + protected void formatLineSeparator(final StringBuilder target) { + super.formatLineSeparator(target); + } + + protected void formatFormattableString(final StringBuilder target, final Formattable formattable, final GeneralFlags genFlags, final int width, final int precision) { + super.formatFormattableString(target, formattable, genFlags, width, precision); + } + + protected void formatPlainString(final StringBuilder target, final Object item, final GeneralFlags genFlags, final int width, final int precision) { + if (item instanceof Class || item instanceof Executable || item instanceof Field) { + ColorUtil.startFgColor(target, isTrueColor(), 0xff, 0xff, 0xdd); + } else if (item instanceof UUID) { + ColorUtil.startFgColor(target, isTrueColor(), 0xdd, 0xff, 0xdd); + } else { + ColorUtil.startFgColor(target, isTrueColor(), 0xdd, 0xdd, 0xdd); + } + super.formatPlainString(target, item, genFlags, width, precision); + restoreColor(target); + } + + protected void formatBoolean(final StringBuilder target, final Object item, final GeneralFlags genFlags, final int width, final int precision) { + super.formatBoolean(target, item, genFlags, width, precision); + } + + protected void formatHashCode(final StringBuilder target, final Object item, final GeneralFlags genFlags, final int width, final int precision) { + super.formatHashCode(target, item, genFlags, width, precision); + } + + protected void formatCharacter(final StringBuilder target, final int codePoint, final GeneralFlags genFlags, final int width, final int precision) { + super.formatCharacter(target, codePoint, genFlags, width, precision); + } + + protected void formatDecimalInteger(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width) { + super.formatDecimalInteger(target, item, genFlags, numFlags, width); + } + + protected void formatOctalInteger(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width) { + super.formatOctalInteger(target, item, genFlags, numFlags, width); + } + + protected void formatHexInteger(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width) { + super.formatHexInteger(target, item, genFlags, numFlags, width); + } + + protected void formatFloatingPointSci(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width, final int precision) { + super.formatFloatingPointSci(target, item, genFlags, numFlags, width, precision); + } + + protected void formatFloatingPointDecimal(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width, final int precision) { + super.formatFloatingPointDecimal(target, item, genFlags, numFlags, width, precision); + } + + protected void formatFloatingPointGeneral(final StringBuilder target, final Number item, final GeneralFlags genFlags, final NumericFlags numFlags, final int width, final int precision) { + super.formatFloatingPointGeneral(target, item, genFlags, numFlags, width, precision); + } +} diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorUtil.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorUtil.java new file mode 100644 index 0000000000000..be14ea88a5a98 --- /dev/null +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/ColorUtil.java @@ -0,0 +1,62 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed 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.jboss.logmanager.formatters; + +/** + * This is a throwaway temp class. + */ +final class ColorUtil { + private ColorUtil() {} + + static StringBuilder startFgColor(StringBuilder target, boolean trueColor, int r, int g, int b) { + return startColor(target, 38, trueColor, r, g, b); + } + + static StringBuilder startBgColor(StringBuilder target, boolean trueColor, int r, int g, int b) { + return startColor(target, 48, trueColor, r, g, b); + } + + static StringBuilder startColor(StringBuilder target, int mode, boolean trueColor, int r, int g, int b) { + if (trueColor) { + return target.appendCodePoint(27).append('[').append(mode).append(';').append(2).append(';').append(clip(r)).append(';').append(clip(g)).append(';').append(clip(b)).append('m'); + } else { + int ar = (5 * clip(r)) / 255; + int ag = (5 * clip(g)) / 255; + int ab = (5 * clip(b)) / 255; + int col = 16 + 36 * ar + 6 * ag + ab; + return target.appendCodePoint(27).append('[').append(mode).append(';').append('5').append(';').append(col).append('m'); + } + } + + private static int clip(int color) { + return Math.min(Math.max(0, color), 255); + } + + static StringBuilder endFgColor(StringBuilder target) { + return endColor(target, 39); + } + + static StringBuilder endBgColor(StringBuilder target) { + return endColor(target, 49); + } + + static StringBuilder endColor(StringBuilder target, int mode) { + return target.appendCodePoint(27).append('[').append(mode).append('m'); + } +} diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/CompoundFormatStep.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/CompoundFormatStep.java new file mode 100644 index 0000000000000..794ba50c1130b --- /dev/null +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/CompoundFormatStep.java @@ -0,0 +1,71 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed 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.jboss.logmanager.formatters; + +import org.jboss.logmanager.ExtLogRecord; + +/** + * A compound format step. Create via {@link FormatStep#createCompoundStep(FormatStep...)}. + */ +public class CompoundFormatStep implements FormatStep { + private final FormatStep[] steps; + + protected CompoundFormatStep(final FormatStep[] clonedSteps) { + this.steps = clonedSteps; + } + + public void render(final StringBuilder builder, final ExtLogRecord record) { + for (FormatStep step : steps) { + step.render(builder, record); + } + } + + public int estimateLength() { + int est = 0; + for (FormatStep step : steps) { + est += step.estimateLength(); + } + return est; + } + + public boolean isCallerInformationRequired() { + for (FormatStep step : steps) { + if (step.isCallerInformationRequired()) { + return true; + } + } + return false; + } + + public ItemType getItemType() { + return ItemType.COMPOUND; + } + + public int childStepCount() { + return steps.length; + } + + public FormatStep getChildStep(final int idx) { + return steps[idx]; + } + + public FormatStep[] childSteps() { + return steps.clone(); + } +} diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/FormatStep.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/FormatStep.java index 7c610da03c1be..9f03fce6dd217 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/FormatStep.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/FormatStep.java @@ -21,10 +21,34 @@ import org.jboss.logmanager.ExtLogRecord; +import java.util.logging.Formatter; + /** * A single format step which handles some part of rendering a log record. */ public interface FormatStep { + /** + * An array of no steps. + */ + FormatStep[] NO_STEPS = new FormatStep[0]; + + FormatStep NULL_STEP = new FormatStep() { + public void render(final StringBuilder builder, final ExtLogRecord record) { + } + + public int estimateLength() { + return 0; + } + }; + + static FormatStep createCompoundStep(final FormatStep... steps) { + final FormatStep[] clonedSteps = steps.clone(); + if (clonedSteps.length == 0) { + return NULL_STEP; + } else if (clonedSteps.length == 1) { + return clonedSteps[0]; + } else return new CompoundFormatStep(clonedSteps); + } /** * Render a part of the log record. @@ -34,6 +58,17 @@ public interface FormatStep { */ void render(StringBuilder builder, ExtLogRecord record); + /** + * Render a part of the log record to the given formatter. + * + * @param formatter the formatter to render to + * @param builder the string builder to append to + * @param record the record being rendered + */ + default void render(Formatter formatter, StringBuilder builder, ExtLogRecord record) { + render(builder, record); + } + /** * Emit an estimate of the length of data which this step will produce. The more accurate the estimate, the * more likely the format operation will be performant. @@ -50,4 +85,75 @@ public interface FormatStep { default boolean isCallerInformationRequired() { return false; } + + /** + * Get child steps that compose this step. + * + * @return the child steps (not {@code null}) + */ + default FormatStep[] childSteps() { + return NO_STEPS; + } + + default int childStepCount() { + return 0; + } + + default FormatStep getChildStep(int idx) { + throw new IndexOutOfBoundsException(); + } + + /** + * Get the item type of this step. + * + * @return the item type + */ + default ItemType getItemType() { + return ItemType.GENERIC; + } + + /** + * An enumeration of the types of items that can be rendered. Note that this enumeration may be expanded + * in the future, so unknown values should be handled gracefully as if {@link #GENERIC} were used. + */ + enum ItemType { + /** An item of unknown kind. */ + GENERIC, + + /** A compound step. */ + COMPOUND, + + // == // == // + + /** A log level. */ + LEVEL, + + // == // == // + + SOURCE_CLASS_NAME, + DATE, + SOURCE_FILE_NAME, + HOST_NAME, + SOURCE_LINE_NUMBER, + LINE_SEPARATOR, + CATEGORY, + MDC, + /** + * The log message without the exception trace. + */ + MESSAGE, + EXCEPTION_TRACE, + SOURCE_METHOD_NAME, + SOURCE_MODULE_NAME, + SOURCE_MODULE_VERSION, + NDC, + PROCESS_ID, + PROCESS_NAME, + RELATIVE_TIME, + RESOURCE_KEY, + SYSTEM_PROPERTY, + TEXT, + THREAD_ID, + THREAD_NAME, + } } diff --git a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/Formatters.java b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/Formatters.java index a07e402724c8b..fa27ec40aa6f9 100644 --- a/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/Formatters.java +++ b/jboss-logmanager-embedded/src/main/java/org/jboss/logmanager/formatters/Formatters.java @@ -40,6 +40,7 @@ import java.util.logging.LogRecord; import java.util.regex.Pattern; +import org.jboss.logmanager.ExtFormatter; import org.jboss.logmanager.ExtLogRecord; /** @@ -87,6 +88,10 @@ public void render(final StringBuilder builder, final ExtLogRecord record) { public int estimateLength() { return string.length(); } + + public ItemType getItemType() { + return ItemType.TEXT; + } }; } @@ -187,13 +192,17 @@ protected JustifyingFormatStep(final boolean leftJustify, final int minimumWidth } public void render(final StringBuilder builder, final ExtLogRecord record) { + render(null, builder, record); + } + + public void render(Formatter formatter, StringBuilder builder, ExtLogRecord record) { final int minimumWidth = this.minimumWidth; final int maximumWidth = this.maximumWidth; final boolean leftJustify = this.leftJustify; if (leftJustify) { // no copy necessary for left justification final int oldLen = builder.length(); - renderRaw(builder, record); + renderRaw(formatter, builder, record); final int newLen = builder.length(); // if we exceeded the max width, chop it off final int writtenLen = newLen - oldLen; @@ -212,7 +221,7 @@ public void render(final StringBuilder builder, final ExtLogRecord record) { } else { // only copy the data if we're right justified final StringBuilder subBuilder = new StringBuilder(); - renderRaw(subBuilder, record); + renderRaw(formatter, subBuilder, record); final int len = subBuilder.length(); if (len > maximumWidth) { if (truncateBeginning) { @@ -241,7 +250,7 @@ public int estimateLength() { } } - public abstract void renderRaw(final StringBuilder builder, final ExtLogRecord record); + public abstract void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record); } private abstract static class SegmentedFormatStep extends JustifyingFormatStep { @@ -260,7 +269,7 @@ protected SegmentedFormatStep(final boolean leftJustify, final int minimumWidth, this.precision = precision; } - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { if (precision == null) { builder.append(applySegments(count, getSegmentedSubject(record))); } else { @@ -298,6 +307,10 @@ public static FormatStep loggerNameFormatStep(final boolean leftJustify, final i */ public static FormatStep loggerNameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth, final String precision) { return new SegmentedFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth, precision) { + public ItemType getItemType() { + return ItemType.CATEGORY; + } + public String getSegmentedSubject(final ExtLogRecord record) { return record.getLoggerName(); } @@ -341,6 +354,10 @@ public String getSegmentedSubject(final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_CLASS_NAME; + } }; } @@ -381,6 +398,10 @@ public String getSegmentedSubject(final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_MODULE_NAME; + } }; } @@ -406,6 +427,10 @@ public String getSegmentedSubject(final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_MODULE_VERSION; + } }; } @@ -438,6 +463,10 @@ public static FormatStep dateFormatStep(final TimeZone timeZone, final String fo public static FormatStep dateFormatStep(final TimeZone timeZone, final String formatString, final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { + public ItemType getItemType() { + return ItemType.DATE; + } + private final ThreadLocal holder = new ThreadLocal() { protected SimpleDateFormat initialValue() { final SimpleDateFormat dateFormat = new SimpleDateFormat(formatString == null ? "yyyy-MM-dd HH:mm:ss,SSS" : formatString); @@ -446,7 +475,7 @@ protected SimpleDateFormat initialValue() { } }; - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(holder.get().format(new Date(record.getMillis()))); } }; @@ -490,7 +519,7 @@ public static FormatStep fileNameFormatStep(final boolean leftJustify, final int */ public static FormatStep fileNameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getSourceFileName()); } @@ -498,6 +527,10 @@ public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_FILE_NAME; + } }; } @@ -512,7 +545,11 @@ public boolean isCallerInformationRequired() { */ public static FormatStep processNameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.PROCESS_NAME; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getProcessName()); } }; @@ -530,7 +567,11 @@ public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { */ public static FormatStep processIdFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.PROCESS_ID; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getProcessId()); } }; @@ -548,6 +589,10 @@ public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { */ public static FormatStep hostnameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth, final boolean qualified) { return new SegmentedFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth, null) { + public ItemType getItemType() { + return ItemType.HOST_NAME; + } + public String getSegmentedSubject(final ExtLogRecord record) { final String hostName = record.getHostName(); final int idx = hostName.indexOf('.'); @@ -568,6 +613,10 @@ public String getSegmentedSubject(final ExtLogRecord record) { */ public static FormatStep hostnameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth, final String precision) { return new SegmentedFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth, precision) { + public ItemType getItemType() { + return ItemType.HOST_NAME; + } + public String getSegmentedSubject(final ExtLogRecord record) { return record.getHostName(); } @@ -599,7 +648,7 @@ public static FormatStep locationInformationFormatStep(final boolean leftJustify */ public static FormatStep locationInformationFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { final String fileName = record.getSourceFileName(); final int lineNumber = record.getSourceLineNumber(); final String className = record.getSourceClassName(); @@ -644,7 +693,7 @@ public static FormatStep lineNumberFormatStep(final boolean leftJustify, final i */ public static FormatStep lineNumberFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getSourceLineNumber()); } @@ -652,6 +701,10 @@ public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_LINE_NUMBER; + } }; } @@ -678,14 +731,25 @@ public static FormatStep messageFormatStep(final boolean leftJustify, final int */ public static FormatStep messageFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { - builder.append(record.getFormattedMessage()); + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { + String formatted; + if (formatter == null || record.getFormatStyle() == ExtLogRecord.FormatStyle.PRINTF && ! (formatter instanceof ExtFormatter)) { + formatted = record.getFormattedMessage(); + } else { + formatted = formatter.formatMessage(record); + } + builder.append(formatted); final Throwable t = record.getThrown(); if (t != null) { builder.append(": "); t.printStackTrace(new PrintWriter(new StringBuilderWriter(builder))); } } + + // not really correct but doesn't matter for now + public ItemType getItemType() { + return ItemType.MESSAGE; + } }; } @@ -712,8 +776,14 @@ public static FormatStep simpleMessageFormatStep(final boolean leftJustify, fina */ public static FormatStep simpleMessageFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { - builder.append(record.getFormattedMessage()); + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { + String formatted; + if (formatter == null || record.getFormatStyle() == ExtLogRecord.FormatStyle.PRINTF && ! (formatter instanceof ExtFormatter)) { + formatted = record.getFormattedMessage(); + } else { + formatted = formatter.formatMessage(record); + } + builder.append(formatted); } }; } @@ -742,7 +812,12 @@ public static FormatStep exceptionFormatStep(final boolean leftJustify, final in */ public static FormatStep exceptionFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth, final String argument) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + // not really correct but doesn't matter for now + public ItemType getItemType() { + return ItemType.EXCEPTION_TRACE; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { doPrivileged(new PrivilegedAction() { public Void run() { final Throwable t = record.getThrown(); @@ -786,7 +861,11 @@ public static FormatStep resourceKeyFormatStep(final boolean leftJustify, final */ public static FormatStep resourceKeyFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.RESOURCE_KEY; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { final String key = record.getResourceKey(); if (key != null) builder.append(key); } @@ -818,7 +897,7 @@ public static FormatStep methodNameFormatStep(final boolean leftJustify, final i */ public static FormatStep methodNameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getSourceMethodName()); } @@ -826,6 +905,10 @@ public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { public boolean isCallerInformationRequired() { return true; } + + public ItemType getItemType() { + return ItemType.SOURCE_METHOD_NAME; + } }; } @@ -862,7 +945,11 @@ public static FormatStep lineSeparatorFormatStep(final boolean leftJustify, fina */ public static FormatStep lineSeparatorFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.SOURCE_LINE_NUMBER; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(separatorString); } }; @@ -891,7 +978,11 @@ public static FormatStep levelFormatStep(final boolean leftJustify, final int mi */ public static FormatStep levelFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.LEVEL; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { final Level level = record.getLevel(); builder.append(level.getName()); } @@ -921,7 +1012,11 @@ public static FormatStep localizedLevelFormatStep(final boolean leftJustify, fin */ public static FormatStep localizedLevelFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.LEVEL; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { final Level level = record.getLevel(); builder.append(level.getResourceBundleName() != null ? level.getLocalizedName() : level.getName()); } @@ -953,7 +1048,11 @@ public static FormatStep relativeTimeFormatStep(final long baseTime, final boole */ public static FormatStep relativeTimeFormatStep(final long baseTime, final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.RELATIVE_TIME; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getMillis() - baseTime); } }; @@ -990,7 +1089,11 @@ public static FormatStep threadFormatStep(final String argument, final boolean l */ public static FormatStep threadIdFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.THREAD_ID; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getThreadID()); } }; @@ -1019,7 +1122,11 @@ public static FormatStep threadNameFormatStep(final boolean leftJustify, final i */ public static FormatStep threadNameFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.THREAD_NAME; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { builder.append(record.getThreadName()); } }; @@ -1049,6 +1156,10 @@ public static FormatStep ndcFormatStep(final boolean leftJustify, final int mini */ public static FormatStep ndcFormatStep(final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth, final int count) { return new SegmentedFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth, count) { + public ItemType getItemType() { + return ItemType.NDC; + } + public String getSegmentedSubject(final ExtLogRecord record) { return record.getNdc(); } @@ -1078,7 +1189,11 @@ public static FormatStep mdcFormatStep(final String key, final boolean leftJusti */ public static FormatStep mdcFormatStep(final String key, final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.MDC; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { if (key == null) { builder.append(new TreeMap<>(record.getMdcCopy())); } else { @@ -1129,7 +1244,11 @@ public static FormatStep systemPropertyFormatStep(final String argument, final b throw new IllegalArgumentException("System property requires a key for the lookup"); } return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { - public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { + public ItemType getItemType() { + return ItemType.SYSTEM_PROPERTY; + } + + public void renderRaw(Formatter formatter, final StringBuilder builder, final ExtLogRecord record) { // Check for a default value final String[] parts = argument.split("(?1.2.16 2.0 1.7.25 - 1.5.0.Alpha1 + 1.5.0.Alpha1-format-002 1.8.0.Final ${env.GRAALVM_HOME}