package org.jboss.windup.config.operation; import java.util.Set; import org.ocpsoft.logging.Logger; import org.ocpsoft.logging.Logger.Level; import org.ocpsoft.rewrite.config.DefaultOperationBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; import org.ocpsoft.rewrite.event.Rewrite; import org.ocpsoft.rewrite.param.ParameterStore; import org.ocpsoft.rewrite.param.Parameterized; import org.ocpsoft.rewrite.param.ParameterizedPattern; import org.ocpsoft.rewrite.param.RegexParameterizedPatternBuilder; /** * Logging utility class. Usage: * <code> * Log.message(Level.INFO, "Client requested path: {p}") * </code> * * @see {@link Log#message(Level, String)} */ public class Log extends DefaultOperationBuilder implements Parameterized { private final Logger log; private final Level level; private final RegexParameterizedPatternBuilder messageBuilder; private Log(Logger log, Level level, String message) { Class<?> caller = findClassCaller(); if (caller == null) caller = Log.class; log = Logger.getLogger(caller); if (level == null) level = Level.INFO; if (message == null) message = "(null)"; this.log = log; this.level = level; this.messageBuilder = new RegexParameterizedPatternBuilder(message); } private Log(Level level, String message) { this(null, level, message); } /** * Log a message at the given {@link Level}. * <p> * The message may be parameterized: * <p> * For example, assuming a given {@link Condition} has been configured to use a parameter "p"}: * <p> * <code> * Path.matches("/{p}") * </code> * <p> * The parameter "p" may be referenced in the log message: * <p> * <code> * Log.message(Level.INFO, "Client requested path: {p}") * </code> * <p> * * @param level the log {@link Level} to which the message be written * @param message {@link ParameterizedPattern} to be written to the log. * * @see {@link ConfigurationRuleParameterBuilder#where(String)} */ public static Log message(Level level, String message) { return new Log(level, message); } public static Log message(Class<?> cls, Level level, String message) { return new Log(Logger.getLogger(cls), level, message); } @Override public void perform(Rewrite event, EvaluationContext context) { // Quite verbose. TODO: ... See https://github.com/ocpsoft/logging/issues/1 switch (level) { case TRACE: if (log.isTraceEnabled()) log.trace(messageBuilder.build(event, context)); break; case DEBUG: if (log.isDebugEnabled()) log.debug(messageBuilder.build(event, context)); break; case INFO: if (log.isInfoEnabled()) log.info(messageBuilder.build(event, context)); break; case WARN: if (log.isWarnEnabled()) log.warn(messageBuilder.build(event, context)); break; case ERROR: if (log.isErrorEnabled()) log.error(messageBuilder.build(event, context)); break; } } @Override public Set<String> getRequiredParameterNames() { return messageBuilder.getRequiredParameterNames(); } @Override public void setParameterStore(ParameterStore store) { messageBuilder.setParameterStore(store); } @Override public String toString() { return "LOG[" + level + ", " + messageBuilder.toString() + "]"; } /** * Finds the calling class - looks for most recent call outside of this class (and descendants). */ private static Class<? extends StackTraceElement> findClassCaller() { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); for( int i = 2; i < stackTrace.length; i++ ) { StackTraceElement call = stackTrace[i]; if (!Log.class.isAssignableFrom(call.getClass())) return call.getClass(); } return null; } }