Skip to content

Commit 1f2369f

Browse files
authored
DEV-32671 Grok processing should fail faster on timeout interruption (#304)
1. Add interruption checks before each grok match, to fail processing faster in case of interruption. 2. Bump org.jruby.joni library version to gain some internal changes that will allow faster interruption of grok matching
1 parent ac5d4c9 commit 1f2369f

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<assertj.version>3.5.2</assertj.version>
5858
<logback.version>1.1.7</logback.version>
5959
<commonsIO.version>2.5</commonsIO.version>
60-
<jrubyJoni.version>2.1.16</jrubyJoni.version>
60+
<jrubyJoni.version>2.1.43</jrubyJoni.version>
6161
<wiremock.version>2.32.0</wiremock.version>
6262
<awaitility.version>4.2.0</awaitility.version>
6363
</properties>

sawmill-core/src/main/java/io/logz/sawmill/processors/KeyValueProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private Map<String,Object> parse(String message) throws InterruptedException {
172172
byte[] messageAsBytes = message.getBytes();
173173
Matcher matcher = pattern.matcher(messageAsBytes);
174174

175-
int result = matcher.search(0, messageAsBytes.length, Option.MULTILINE);
175+
int result = matcher.searchInterruptible(0, messageAsBytes.length, Option.MULTILINE);
176176

177177
while (result != -1 && matchesCounter < MAX_MATCHES) {
178178
Region region = matcher.getEagerRegion();
@@ -199,7 +199,7 @@ private Map<String,Object> parse(String message) throws InterruptedException {
199199
}
200200
}
201201
int endOfFullMatch = region.end[0];
202-
result = matcher.search(endOfFullMatch, messageAsBytes.length, Option.MULTILINE);
202+
result = matcher.searchInterruptible(endOfFullMatch, messageAsBytes.length, Option.MULTILINE);
203203

204204
matchesCounter++;
205205

sawmill-core/src/main/java/io/logz/sawmill/utilities/Grok.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@ private void addPattern(String patternName, String definition) {
9393
}
9494

9595
public List<Match> matches(String text) throws InterruptedException {
96+
if (Thread.interrupted()) {
97+
throw new InterruptedException();
98+
}
99+
96100
List<Match> matches = new ArrayList<>();
97101
byte[] textAsBytes = text.getBytes(StandardCharsets.UTF_8);
98102
Matcher matcher = compiledExpression.matcher(textAsBytes);
99-
int result = matcher.search(0, textAsBytes.length, Option.MULTILINE);
103+
int result = matcher.searchInterruptible(0, textAsBytes.length, Option.MULTILINE);
100104
boolean matchNotFound = result == -1;
101105
if (matchNotFound) {
102106
return null;

sawmill-core/src/test/java/io/logz/sawmill/processors/GrokProcessorTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
package io.logz.sawmill.processors;
22

3+
import com.google.common.collect.ImmutableMap;
34
import io.logz.sawmill.Doc;
45
import io.logz.sawmill.ProcessResult;
56
import io.logz.sawmill.exceptions.ProcessorConfigurationException;
7+
import org.apache.commons.lang3.RandomStringUtils;
68
import org.junit.BeforeClass;
79
import org.junit.Test;
810

911
import java.util.Arrays;
1012
import java.util.HashMap;
1113
import java.util.List;
1214
import java.util.Map;
15+
import java.util.concurrent.Executors;
16+
import java.util.concurrent.ScheduledExecutorService;
17+
import java.util.stream.Collectors;
18+
import java.util.stream.IntStream;
1319

1420
import static io.logz.sawmill.utils.DocUtils.createDoc;
1521
import static io.logz.sawmill.utils.FactoryUtils.createProcessor;
1622
import static io.logz.sawmill.utils.FactoryUtils.createProcessorFactory;
23+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
1724
import static org.assertj.core.api.Assertions.assertThat;
1825
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1926

@@ -308,4 +315,27 @@ public void testInvalidExpression() throws InterruptedException {
308315
public void testBadConfigs() {
309316
assertThatThrownBy(() -> createProcessor(GrokProcessor.class, "patterns", Arrays.asList("pattern"))).isInstanceOf(NullPointerException.class);
310317
}
318+
319+
@Test
320+
public void testInterruptStopsProcessor() {
321+
String field = "message";
322+
List<String> patterns = IntStream.range(1, 10000).mapToObj(i -> "%{COMBINEDAPACHELOG}").collect(Collectors.toList());
323+
Doc doc = createDoc(field, RandomStringUtils.randomAlphanumeric(100000));
324+
325+
Map<String,Object> config = ImmutableMap.of(
326+
"field", field,
327+
"patterns", patterns
328+
);
329+
GrokProcessor grokProcessor = factory.create(config);
330+
331+
interruptCurrentThreadIn(100);
332+
assertThatThrownBy(() -> grokProcessor.process(doc))
333+
.isInstanceOf(InterruptedException.class);
334+
}
335+
336+
private void interruptCurrentThreadIn(long millis) {
337+
Thread currentThread = Thread.currentThread();
338+
ScheduledExecutorService interrupter = Executors.newScheduledThreadPool(1);
339+
interrupter.schedule(currentThread::interrupt, millis, MILLISECONDS);
340+
}
311341
}

0 commit comments

Comments
 (0)