Skip to content

Instantly share code, notes, and snippets.

@vicly
Last active June 27, 2018 02:48
Show Gist options
  • Save vicly/0afb7fd36b602badfb74ac0a02777b37 to your computer and use it in GitHub Desktop.
Save vicly/0afb7fd36b602badfb74ac0a02777b37 to your computer and use it in GitHub Desktop.
[Change log message in Dropwizard] #Java #Dropwizard
import java.util.function.Predicate;
import ch.qos.logback.access.spi.IAccessEvent;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.spi.DeferredProcessingAware;
class AbstractMaskPredicate<E extends DeferredProcessingAware>
implements Predicate<E>
{
@Override
public boolean test(E e)
{
if (e == null)
{
return false;
}
else if (e instanceof IAccessEvent)
{
return needMask((IAccessEvent) e);
}
else if (e instanceof ILoggingEvent)
{
return needMask((ILoggingEvent) e);
}
else
{
return false;
}
}
/**
* override if need to handle logback access event.
*
* @param event event
* @return true if need to mask.
*/
protected boolean needMask(IAccessEvent event)
{
return false;
}
/**
* override if need to handle logback log event.
*
* @param event event
* @return true if need to mask.
*/
protected boolean needMask(ILoggingEvent event)
{
return false;
}
}

Expose PCIConsoleAppenderFactory to dropwizard

Under resources/, create file META-INF/services/io.dropwizard.logging.AppenderFactory with content

the.package.PCIConsoleAppenderFactory

Reference it in server.yml

server:
  applicationConnectors:
  - type: http
    port: ${PORT:-8080}
  adminConnectors:
  - type: http
    port: ${ADMIN_PORT:-8081}
  requestLog:
    appenders:
    - type: console-pci # Apply to jetty http log events


logging:
  level: ${LOG_LEVEL:-WARN}
  appenders:
    - type: console-pci # apply to application log event
      logFormat: "%d %r %p [%t] %c - %m%n"
  loggers:
    "io.dropwizard":
      level: INFO
import java.util.Set;
import com.google.common.collect.Sets;
import ch.qos.logback.classic.spi.ILoggingEvent;
class LoggerNamePredicate
extends AbstractMaskPredicate
{
private static final Set<String> LOGGER_NAMES = Sets.newHashSet(
"http.request", // dropwizard jettery http log
"app.logger.name");
@Override
protected boolean needMask(ILoggingEvent event)
{
String loggerName = event.getLoggerName();
return LOGGER_NAMES.contains(loggerName);
}
}
import java.util.Map;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.common.annotations.VisibleForTesting;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.pattern.PatternLayoutBase;
import ch.qos.logback.core.spi.DeferredProcessingAware;
import io.dropwizard.logging.ConsoleAppenderFactory;
import io.dropwizard.logging.layout.LayoutFactory;
// expose type, used in server.yml
@JsonTypeName("console-pci")
public class PCIConsoleAppenderFactory<E extends DeferredProcessingAware>
extends ConsoleAppenderFactory<E>
{
/* Mask "cvv" */
private static final Pattern PAYMENT_API_CVV = Pattern.compile("(\"cvv\"\\s*:\\s*)\".*?\"");
private Predicate<E> maskPredicate = new LoggerNamePredicate().or(new RestEndpointPredicate());
@VisibleForTesting
static String mask(String str)
{
return str == null ? null : PAYMENT_API_CVV.matcher(str).replaceAll("$1\"***\"");
}
// Leverage buildLayout to overwrite log event message.
@Override
protected PatternLayoutBase<E> buildLayout(LoggerContext context, LayoutFactory<E> layoutFactory)
{
PatternLayoutBase<E> layout = super.buildLayout(context, layoutFactory);
return new PatternLayoutBase<E>()
{
@Override
public String doLayout(E event)
{
String eventString = layout.doLayout(event);
if (maskPredicate.test(event))
{
return eventString == null ? null : mask(eventString);
}
else
{
return eventString;
}
}
@Override
public Map<String, String> getDefaultConverterMap()
{
return layout.getDefaultConverterMap();
}
};
}
}
import com.google.common.base.Strings;
import ch.qos.logback.access.spi.IAccessEvent;
class RestEndpointPredicate
extends AbstractMaskPredicate
{
@Override
protected boolean needMask(IAccessEvent event)
{
String method = event.getMethod();
String requestURI = Strings.nullToEmpty(event.getRequestURI());
boolean postSessionMatched = "POST".equalsIgnoreCase(method) && requestURI.contains("/my-path");
return postSessionMatched;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment