/*
* ============LICENSE_START=======================================================
* Integrity Audit
* ================================================================================
* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
* ================================================================================
* 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.
* ============LICENSE_END=========================================================
*/
package org.onap.policy.common.utils.test.log.logback;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
/**
* This is an appender that is intended for use by JUnit tests that wish to
* capture logged messages. The appender takes an optional list of regular
* expressions that are used to identify and extract data of interest.
*
* If no patterns are provided, then every logged message is recorded. However,
* if patterns are provided, then only messages that match one of the patterns
* are recorded. In addition, if the pattern contains a capture group that is
* non-null, only the captured group is recorded. Otherwise, the entire portion
* of the message that matches the pattern is recorded.
*
* All operations are thread-safe.
*/
public class ExtractAppender extends AppenderBase {
/**
* Extracted text is placed here.
*/
private final Queue extracted;
/**
* Regular expressions/Patterns to be used to extract text. Uses a
* LinkedHashMap so that order is preserved.
*/
private final LinkedHashMap patterns;
/**
* Records every message that is logged.
*/
public ExtractAppender() {
this(new LinkedList<>());
}
/**
* Records portions of messages that match one of the regular expressions.
*
* @param regex
* regular expression (i.e., {@link Pattern}) to match
*/
public ExtractAppender(String... regex) {
this(new LinkedList<>(), regex);
}
/**
* Rather than allocating an internal queue to store matched messages,
* messages are recorded in the specified target queue using the
* {@link Queue#offer(Object)} method. Note: whenever the queue is used, it
* will be synchronized to prevent simultaneous accesses.
*
* @param target
* @param regex
* regular expression (i.e., {@link Pattern}) to match
*/
public ExtractAppender(Queue target, String... regex) {
extracted = target;
patterns = new LinkedHashMap<>(regex.length);
for (String re : regex) {
patterns.put(re, Pattern.compile(re));
}
}
/*
* (non-Javadoc)
*
* @see ch.qos.logback.core.AppenderBase#append(Object)
*/
@Override
protected void append(ILoggingEvent event) {
String msg = event.getMessage();
synchronized (patterns) {
if (patterns.isEmpty()) {
addExtraction(msg);
return;
}
for (Pattern p : patterns.values()) {
Matcher m = p.matcher(msg);
if (m.find()) {
addGroupMatch(m);
break;
}
}
}
}
/**
* Adds the first match group to {@link #extracted}.
*
* @param mat
* the matcher containing the groups
* @return {@code true} if a group was found, {@code false} otherwise
*/
private void addGroupMatch(Matcher mat) {
int ngroups = mat.groupCount();
for (int x = 1; x <= ngroups; ++x) {
String txt = mat.group(x);
if (txt != null) {
addExtraction(txt);
return;
}
}
addExtraction(mat.group());
}
/**
* Adds an item to {@link #extracted}, in a thread-safe manner. It uses the
* queue's offer() method so that the queue can discard the item if
* it so chooses, without generating an exception.
*
* @param txt
* text to be added
*/
private void addExtraction(String txt) {
synchronized (extracted) {
extracted.offer(txt);
}
}
/**
* Gets the text that has been extracted.
*
* @return a copy of the text that has been extracted
*/
public List getExtracted() {
synchronized (extracted) {
return new ArrayList<>(extracted);
}
}
/**
* Clears the list of extracted text.
*/
public void clearExtractions() {
synchronized (extracted) {
extracted.clear();
}
}
/**
* Adds a pattern to be matched by this appender.
*
* @param regex
* regular expression (i.e., {@link Pattern}) to match
*/
public void setPattern(String regex) {
synchronized (patterns) {
patterns.put(regex, Pattern.compile(regex));
}
}
}