Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poznachowski/0bfc5ab19bb8e29e6a60e77a8c22c533 to your computer and use it in GitHub Desktop.
Save poznachowski/0bfc5ab19bb8e29e6a60e77a8c22c533 to your computer and use it in GitHub Desktop.
ContentFilteringSlf4jEventSender
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.ext.logging.event.LogEvent;
import org.apache.cxf.ext.logging.slf4j.Slf4jEventSender;
import org.apache.cxf.ext.logging.slf4j.Slf4jVerboseEventSender;
import org.slf4j.event.Level;
import javax.xml.namespace.QName;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Based on {@link Slf4jVerboseEventSender} and
* https://stackoverflow.com/questions/23212313/cxf-logging-request-response-with-content-filtering-or-masking-soap-fields
*/
public class ContentFilteringSlf4jEventSender extends Slf4jEventSender {
private static final String MASK_PATTERN = "<\\s*{}\\s*>(.*)</\\s*{}\\s*>|<\\s*name\\s*>\\s*{}\\s*</\\s*name\\s*>\\s*<\\s*value\\s*>(.*)<";
private final Pattern pattern;
public static ContentFilteringSlf4jEventSender of(Level loggingLevel, Set<String> sensitiveFields) {
return new ContentFilteringSlf4jEventSender(loggingLevel, sensitiveFields);
}
private ContentFilteringSlf4jEventSender(Level loggingLevel, Set<String> sensitiveFields) {
super.setLoggingLevel(loggingLevel);
var patternBuilder = new StringBuilder();
sensitiveFields.forEach(field -> {
patternBuilder.append(MASK_PATTERN.replace("{}", field));
patternBuilder.append("|");
});
patternBuilder.setLength(patternBuilder.length() - 1);
pattern = Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
}
@Override
protected String getLogMessage(LogEvent event) {
var b = new StringBuilder();
// Start from the next line to have the output well-aligned
b.append(event.getType()).append('\n');
write(b, "Address", event.getAddress());
write(b, "HttpMethod", event.getHttpMethod());
write(b, "Content-Type", event.getContentType());
write(b, "ResponseCode", event.getResponseCode());
write(b, "ExchangeId", event.getExchangeId());
if (event.getServiceName() != null) {
write(b, "ServiceName", localPart(event.getServiceName()));
write(b, "PortName", localPart(event.getPortName()));
write(b, "PortTypeName", localPart(event.getPortTypeName()));
}
if (event.getFullContentFile() != null) {
write(b, "FullContentFile", event.getFullContentFile().getAbsolutePath());
}
write(b, "Headers", event.getHeaders().toString());
if (!StringUtils.isEmpty(event.getPayload())) {
writePayload(b, event.getPayload());
}
return b.toString();
}
private void writePayload(StringBuilder b, String payload) {
b.append('\n');
var matcher = pattern.matcher(payload);
var builder = new StringBuilder(payload);
while (matcher.find()) {
int group = 1;
while (group <= matcher.groupCount()) {
if (matcher.group(group) != null) {
for (int i = matcher.start(group); i < matcher.end(group); i++) {
builder.setCharAt(i, '*');
}
}
group++;
}
}
b.append(builder.toString());
}
private static String localPart(QName name) {
return name == null ? null : name.getLocalPart();
}
private static void write(StringBuilder b, String key, String value) {
if (value != null) {
b.append(" ").append(key).append(": ").append(value).append('\n');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment