Handle regex parsing errors in Gsub and Grok Processors

Currently, both Gsub and Grok parse regex strings during
Pipeline creation. Thrown parsing exceptions were leaking out, this
commit wraps those exceptions in ElasticsearchParseExceptions.
This commit is contained in:
Tal Levy 2016-03-22 14:28:24 -07:00
parent f8e84f0bbb
commit 534caa8927
4 changed files with 64 additions and 5 deletions

View File

@ -19,6 +19,7 @@
package org.elasticsearch.ingest.processor; package org.elasticsearch.ingest.processor;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.ingest.core.AbstractProcessor; import org.elasticsearch.ingest.core.AbstractProcessor;
import org.elasticsearch.ingest.core.AbstractProcessorFactory; import org.elasticsearch.ingest.core.AbstractProcessorFactory;
import org.elasticsearch.ingest.core.IngestDocument; import org.elasticsearch.ingest.core.IngestDocument;
@ -28,6 +29,9 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static org.elasticsearch.ingest.core.ConfigurationUtils.newConfigurationException;
import static org.elasticsearch.ingest.core.ConfigurationUtils.readStringProperty;
/** /**
* Processor that allows to search for patterns in field content and replace them with corresponding string replacement. * Processor that allows to search for patterns in field content and replace them with corresponding string replacement.
* Support fields of string type only, throws exception if a field is of a different type. * Support fields of string type only, throws exception if a field is of a different type.
@ -79,10 +83,15 @@ public final class GsubProcessor extends AbstractProcessor {
public static final class Factory extends AbstractProcessorFactory<GsubProcessor> { public static final class Factory extends AbstractProcessorFactory<GsubProcessor> {
@Override @Override
public GsubProcessor doCreate(String processorTag, Map<String, Object> config) throws Exception { public GsubProcessor doCreate(String processorTag, Map<String, Object> config) throws Exception {
String field = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "field"); String field = readStringProperty(TYPE, processorTag, config, "field");
String pattern = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "pattern"); String pattern = readStringProperty(TYPE, processorTag, config, "pattern");
String replacement = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "replacement"); String replacement = readStringProperty(TYPE, processorTag, config, "replacement");
Pattern searchPattern = Pattern.compile(pattern); Pattern searchPattern;
try {
searchPattern = Pattern.compile(pattern);
} catch (Exception e) {
throw newConfigurationException(TYPE, processorTag, "pattern", "Invalid regex pattern. " + e.getMessage());
}
return new GsubProcessor(processorTag, field, searchPattern, replacement); return new GsubProcessor(processorTag, field, searchPattern, replacement);
} }
} }

View File

@ -84,4 +84,18 @@ public class GsubProcessorFactoryTests extends ESTestCase {
assertThat(e.getMessage(), equalTo("[replacement] required property is missing")); assertThat(e.getMessage(), equalTo("[replacement] required property is missing"));
} }
} }
public void testCreateInvalidPattern() throws Exception {
GsubProcessor.Factory factory = new GsubProcessor.Factory();
Map<String, Object> config = new HashMap<>();
config.put("field", "field1");
config.put("pattern", "[");
config.put("replacement", "-");
try {
factory.create(config);
fail("factory create should have failed");
} catch(ElasticsearchParseException e) {
assertThat(e.getMessage(), equalTo("[pattern] Invalid regex pattern. Unclosed character class near index 0\n[\n^"));
}
}
} }

View File

@ -27,6 +27,8 @@ import org.elasticsearch.ingest.core.IngestDocument;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.ingest.core.ConfigurationUtils.newConfigurationException;
public final class GrokProcessor extends AbstractProcessor { public final class GrokProcessor extends AbstractProcessor {
public static final String TYPE = "grok"; public static final String TYPE = "grok";
@ -82,7 +84,12 @@ public final class GrokProcessor extends AbstractProcessor {
patternBank.putAll(customPatternBank); patternBank.putAll(customPatternBank);
} }
Grok grok = new Grok(patternBank, matchPattern); Grok grok;
try {
grok = new Grok(patternBank, matchPattern);
} catch (Exception e) {
throw newConfigurationException(TYPE, processorTag, "pattern", "Invalid regex pattern. " + e.getMessage());
}
return new GrokProcessor(processorTag, grok, matchField); return new GrokProcessor(processorTag, grok, matchField);
} }

View File

@ -84,4 +84,33 @@ public class GrokProcessorFactoryTests extends ESTestCase {
assertThat(processor.getGrok(), notNullValue()); assertThat(processor.getGrok(), notNullValue());
assertThat(processor.getGrok().match("foo!"), equalTo(true)); assertThat(processor.getGrok().match("foo!"), equalTo(true));
} }
public void testCreateWithInvalidPattern() throws Exception {
GrokProcessor.Factory factory = new GrokProcessor.Factory(Collections.emptyMap());
Map<String, Object> config = new HashMap<>();
config.put("field", "_field");
config.put("pattern", "[");
try {
factory.create(config);
fail("should fail");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), equalTo("[pattern] Invalid regex pattern. premature end of char-class"));
}
}
public void testCreateWithInvalidPatternDefinition() throws Exception {
GrokProcessor.Factory factory = new GrokProcessor.Factory(Collections.emptyMap());
Map<String, Object> config = new HashMap<>();
config.put("field", "_field");
config.put("pattern", "%{MY_PATTERN:name}!");
config.put("pattern_definitions", Collections.singletonMap("MY_PATTERN", "["));
try {
factory.create(config);
fail("should fail");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), equalTo("[pattern] Invalid regex pattern. premature end of char-class"));
}
}
} }