hm.binkley.util.logging.MatchConverter Maven / Gradle / Ivy
/*
* This is free and unencumbered software released into the public domain.
*
* Please see https://github.com/binkley/binkley/blob/master/LICENSE.md.
*/
package hm.binkley.util.logging;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.boolex.EvaluationException;
import ch.qos.logback.core.boolex.EventEvaluator;
import ch.qos.logback.core.status.ErrorStatus;
import javax.annotation.Nonnull;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static ch.qos.logback.core.CoreConstants.EVALUATOR_MAP;
import static java.util.Collections.emptyMap;
/**
* {@code MarkedConverter} provides alternate conversions based on conditions. Enable with:
*
* <conversionRule
* conversionWord="match"
* converterClass="hm.binkley.util.logging.MatchConverter"/>
Use as:
*
* <pattern>%match{cond1,patt1,...,fallback}</pattern>
Example:
*
* <evaluator name="WITH_MARKER">
* <expression>null != marker ∓∓ "ALERT".equals(marker.getName())</expression>
* </evaluator>
* <pattern>%match(WITH_MARKER,%marker/%level,%level)</pattern>
will log
* "ALERT/ERROR" when marker is "ALERT" and level is "ERROR", otherwise just "ERROR".
*
* @author B. K. Oxley (binkley)
* @todo Fix error reporting - logback swallows
*/
public final class MatchConverter
extends ClassicConverter {
private static final int MAX_ERROR_COUNT = 4;
private Map conditions;
private String unmatched;
private Map> evaluators;
private int errors;
@SuppressWarnings("unchecked")
@Override
public void start() {
final List options = getOptionList();
if (null == options || 2 > options.size()) {
addError("Missing options for %match - " + (null == options ? "missing options"
: options));
conditions = emptyMap();
unmatched = "";
return;
}
conditions = new LinkedHashMap<>();
for (int i = 0; i < options.size() - 1; i += 2)
conditions.put(options.get(i), options.get(i + 1));
unmatched = 0 == options.size() % 2 ? "" : options.get(options.size() - 1);
evaluators = (Map>) getContext()
.getObject(EVALUATOR_MAP);
super.start();
}
@Nonnull
@Override
public String convert(@Nonnull final ILoggingEvent event) {
for (final Map.Entry entry : conditions.entrySet())
if (evaluate(entry.getKey(), event))
return relayout(entry.getValue(), event);
return relayout(unmatched, event);
}
private boolean evaluate(final String name, final ILoggingEvent event) {
final EventEvaluator evaluator = evaluators.get(name);
try {
return null != evaluator && evaluator.evaluate(event);
} catch (final EvaluationException e) {
errors++;
if (MAX_ERROR_COUNT > errors) {
addError("Exception thrown for evaluator named [" + evaluator.getName() + "]", e);
} else if (MAX_ERROR_COUNT == errors) {
final ErrorStatus errorStatus = new ErrorStatus(
"Exception thrown for evaluator named [" + evaluator.getName() + "].", this,
e);
errorStatus.add(new ErrorStatus(
"This was the last warning about this evaluator's errors."
+ "We don't want the StatusManager to get flooded.", this));
addStatus(errorStatus);
}
return false;
}
}
private String relayout(final String pattern, final ILoggingEvent event) {
final PatternLayout layout = new PatternLayout();
layout.setContext(getContext());
layout.setPattern(pattern);
layout.start();
return layout.doLayout(event);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy