Added a "logging" action

Mainly useful for testing & debugging, but might be even useful as an actual action in production.

(for now, we won't document it)

Original commit: elastic/x-pack-elasticsearch@726049cece
This commit is contained in:
uboness 2015-04-06 23:18:04 +02:00
parent f9004eed31
commit 8d71337be5
9 changed files with 837 additions and 55 deletions

View File

@ -7,8 +7,10 @@ package org.elasticsearch.watcher.actions;
import org.elasticsearch.watcher.actions.email.EmailAction;
import org.elasticsearch.watcher.actions.index.IndexAction;
import org.elasticsearch.watcher.actions.logging.LoggingAction;
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
import org.elasticsearch.watcher.support.http.TemplatedHttpRequest;
import org.elasticsearch.watcher.support.template.Template;
/**
*
@ -30,4 +32,12 @@ public final class ActionBuilders {
return new WebhookAction.SourceBuilder(id, httpRequest);
}
public static LoggingAction.SourceBuilder loggingAction(String id, String text) {
return new LoggingAction.SourceBuilder(id).text(text);
}
public static LoggingAction.SourceBuilder loggingAction(String id, Template.SourceBuilder text) {
return new LoggingAction.SourceBuilder(id).text(text);
}
}

View File

@ -11,6 +11,7 @@ import org.elasticsearch.watcher.actions.email.EmailAction;
import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
import org.elasticsearch.watcher.actions.index.IndexAction;
import org.elasticsearch.watcher.actions.logging.LoggingAction;
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
import java.util.HashMap;
@ -39,6 +40,9 @@ public class ActionModule extends AbstractModule {
bind(IndexAction.Parser.class).asEagerSingleton();
parsersBinder.addBinding(IndexAction.TYPE).to(IndexAction.Parser.class);
bind(LoggingAction.Parser.class).asEagerSingleton();
parsersBinder.addBinding(LoggingAction.TYPE).to(LoggingAction.Parser.class);
for (Map.Entry<String, Class<? extends Action.Parser>> entry : parsers.entrySet()) {
bind(entry.getValue()).asEagerSingleton();
parsersBinder.addBinding(entry.getKey()).to(entry.getValue());

View File

@ -0,0 +1,335 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.actions.logging;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.support.Variables;
import org.elasticsearch.watcher.support.template.ScriptTemplate;
import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.WatchExecutionContext;
import java.io.IOException;
import java.util.Locale;
/**
*
*/
public class LoggingAction extends Action<LoggingAction.Result> {
public static final String TYPE = "logging";
private final String category;
private final LoggingLevel level;
private final Template template;
private final ESLogger actionLogger;
public LoggingAction(ESLogger logger, ESLogger actionLogger, @Nullable String category, LoggingLevel level, Template template) {
super(logger);
this.category = category;
this.level = level;
this.template = template;
this.actionLogger = actionLogger;
}
@Override
public String type() {
return TYPE;
}
String category() {
return category;
}
LoggingLevel level() {
return level;
}
Template template() {
return template;
}
ESLogger logger() {
return actionLogger;
}
@Override
protected LoggingAction.Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws IOException {
try {
String text = template.render(Variables.createCtxModel(ctx, payload));
level.log(actionLogger, text);
return new Result.Success(text);
} catch (Exception e) {
return new Result.Failure("failed to execute log action: " + e.getMessage());
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (category != null) {
builder.field(Parser.CATEGORY_FIELD.getPreferredName(), category);
}
builder.field(Parser.LEVEL_FIELD.getPreferredName(), level);
builder.field(Parser.TEXT_FIELD.getPreferredName(), template);
return builder.endObject();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoggingAction action = (LoggingAction) o;
if (category != null ? !category.equals(action.category) : action.category != null) return false;
if (level != action.level) return false;
return template.equals(action.template);
}
@Override
public int hashCode() {
int result = category != null ? category.hashCode() : 0;
result = 31 * result + level.hashCode();
result = 31 * result + template.hashCode();
return result;
}
public static abstract class Result extends Action.Result {
protected Result(boolean success) {
super(TYPE, success);
}
public static class Success extends Result {
private final String loggedText;
public Success(String loggedText) {
super(true);
this.loggedText = loggedText;
}
public String loggedText() {
return loggedText;
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Parser.LOGGED_TEXT_FIELD.getPreferredName(), loggedText);
}
}
public static class Failure extends Result {
private final String reason;
public Failure(String reason) {
super(false);
this.reason = reason;
}
public String reason() {
return reason;
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Parser.REASON_FIELD.getPreferredName(), reason);
}
}
}
public static class Parser implements Action.Parser<LoggingAction.Result, LoggingAction> {
static final ParseField CATEGORY_FIELD = new ParseField("category");
static final ParseField LEVEL_FIELD = new ParseField("level");
static final ParseField TEXT_FIELD = new ParseField("text");
static final ParseField LOGGED_TEXT_FIELD = new ParseField("logged_text");
static final ParseField REASON_FIELD = new ParseField("reason");
private final Settings settings;
private final Template.Parser templateParser;
private final ESLogger logger;
@Inject
public Parser(Settings settings, Template.Parser templateParser) {
this.settings = settings;
this.logger = Loggers.getLogger(LoggingAction.class, settings);
this.templateParser = templateParser;
}
@Override
public String type() {
return TYPE;
}
@Override
public LoggingAction parse(XContentParser parser) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
String category = null;
LoggingLevel level = LoggingLevel.INFO;
Template text = null;
String currentFieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.VALUE_STRING) {
if (CATEGORY_FIELD.match(currentFieldName)) {
category = parser.text();
} else if (LEVEL_FIELD.match(currentFieldName)) {
try {
level = LoggingLevel.valueOf(parser.text().toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException iae) {
throw new ActionSettingsException("failed to parse logging action. unknown logging level [" + parser.text() + "]");
}
} else if (TEXT_FIELD.match(currentFieldName)) {
try {
text = templateParser.parse(parser);
} catch (Template.Parser.ParseException pe) {
throw new ActionSettingsException("failed to parse logging action. failed to parse text template", pe);
}
} else {
throw new ActionSettingsException("failed to parse logging action. unexpected string field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (TEXT_FIELD.match(currentFieldName)) {
try {
text = templateParser.parse(parser);
} catch (Template.Parser.ParseException pe) {
throw new ActionSettingsException("failed to parse logging action. failed to parse text template", pe);
}
} else {
throw new ActionSettingsException("failed to parse logging action. unexpected object field [" + currentFieldName + "]");
}
} else {
throw new ActionSettingsException("failed to parse logging action. unexpected token [" + token + "]");
}
}
if (text == null) {
throw new ActionSettingsException("failed to parse logging action. missing [text] field");
}
ESLogger actionLogger = category != null ? Loggers.getLogger(category, settings) : logger;
return new LoggingAction(logger, actionLogger, category, level, text);
}
@Override
public LoggingAction.Result parseResult(XContentParser parser) throws IOException {
Boolean success = null;
String loggedText = null;
String reason = null;
XContentParser.Token token;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.VALUE_STRING) {
if (LOGGED_TEXT_FIELD.match(currentFieldName)) {
loggedText = parser.text();
} else if (REASON_FIELD.match(currentFieldName)) {
reason = parser.text();
} else {
throw new ActionException("could not parse index result. unexpected string field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
if (Action.Result.SUCCESS_FIELD.match(currentFieldName)) {
success = parser.booleanValue();
} else {
throw new ActionException("could not parse index result. unexpected boolean field [" + currentFieldName + "]");
}
} else {
throw new ActionException("could not parse index result. unexpected token [" + token + "]");
}
}
if (success == null) {
throw new ActionException("could not parse index result. expected boolean field [success]");
}
if (success) {
if (loggedText == null) {
throw new ActionException("could not parse successful index result. expected string field [logged_text]");
}
return new Result.Success(loggedText);
}
if (reason == null) {
throw new ActionException("could not parse failed index result. expected string field [reason]");
}
return new Result.Failure(reason);
}
}
public static class SourceBuilder extends Action.SourceBuilder<SourceBuilder> {
private Template.SourceBuilder text;
private String category;
private LoggingLevel level;
public SourceBuilder(String id) {
super(id);
}
@Override
public String type() {
return TYPE;
}
public SourceBuilder text(String text) {
return text(new ScriptTemplate.SourceBuilder(text));
}
public SourceBuilder text(Template.SourceBuilder text) {
this.text = text;
return this;
}
public SourceBuilder category(String category) {
this.category = category;
return this;
}
public SourceBuilder level(LoggingLevel level) {
this.level = level;
return this;
}
@Override
protected XContentBuilder actionXContent(XContentBuilder builder, Params params) throws IOException {
if (text == null) {
throw new ActionException("could not build logging action source. [text] must be defined");
}
builder.startObject();
builder.field(Parser.TEXT_FIELD.getPreferredName(), text);
if (category != null) {
builder.field(Parser.CATEGORY_FIELD.getPreferredName(), category);
}
if (level != null) {
builder.field(Parser.LEVEL_FIELD.getPreferredName(), level);
}
return builder.endObject();
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.actions.logging;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Locale;
/**
*
*/
public enum LoggingLevel implements ToXContent {
ERROR() {
@Override
void log(ESLogger logger, String text) {
logger.error(text);
}
},
WARN() {
@Override
void log(ESLogger logger, String text) {
logger.warn(text);
}
},
INFO() {
@Override
void log(ESLogger logger, String text) {
logger.info(text);
}
},
DEBUG() {
@Override
void log(ESLogger logger, String text) {
logger.debug(text);
}
},
TRACE() {
@Override
void log(ESLogger logger, String text) {
logger.trace(text);
}
};
abstract void log(ESLogger logger, String text);
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.value(name().toLowerCase(Locale.ROOT));
}
}

View File

@ -24,7 +24,7 @@ public interface Template extends ToXContent {
T parse(XContentParser parser) throws IOException, ParseException;
public static class ParseException extends WatcherException {
class ParseException extends WatcherException {
public ParseException(String msg) {
super(msg);

View File

@ -0,0 +1,335 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.actions.logging;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.email.service.Attachment;
import org.elasticsearch.watcher.support.template.ValueTemplate;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.watch.WatchExecutionContext;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import static org.elasticsearch.common.joda.time.DateTimeZone.UTC;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.watcher.actions.ActionBuilders.loggingAction;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.*;
/**
*/
public class LoggingActionTests extends ElasticsearchTestCase {
private ESLogger actionLogger;
private LoggingLevel level;
@Before
public void init() throws IOException {
actionLogger = mock(ESLogger.class);
level = randomFrom(LoggingLevel.values());
}
@Test @Repeat(iterations = 30)
public void testExecute() throws Exception {
final DateTime now = DateTime.now(UTC);
final Map<String, Object> expectedModel = ImmutableMap.<String, Object>builder()
.put("ctx", ImmutableMap.builder()
.put("execution_time", now)
.put("watch_name", "_watch_name")
.put("payload", ImmutableMap.of())
.put("trigger", ImmutableMap.builder()
.put("scheduled_time", now)
.put("triggered_time", now)
.build())
.build())
.build();
String text = randomAsciiOfLength(10);
LoggingAction action = new LoggingAction(logger, actionLogger, "_category", level, new ValueTemplate(text) {
@Override
public String render(Map<String, Object> model) {
assertThat(model, equalTo((Object) expectedModel));
return super.render(model);
}
});
Watch watch = mock(Watch.class);
when(watch.name()).thenReturn("_watch_name");
WatchExecutionContext ctx = new WatchExecutionContext("_ctx_id", watch, now, new ScheduleTriggerEvent(now, now));
LoggingAction.Result result = action.execute("_id", ctx, new Payload.Simple());
verifyLogger(actionLogger, level, text);
assertThat(result, notNullValue());
assertThat(result.success(), is(true));
assertThat(result, instanceOf(LoggingAction.Result.Success.class));
assertThat(((LoggingAction.Result.Success) result).loggedText(), is(text));
}
@Test @Repeat(iterations = 10)
public void testParser() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject();
builder.field("text", new ValueTemplate(text));
String category = null;
if (randomBoolean()) {
category = randomAsciiOfLength(10);
builder.field("category", category);
}
LoggingLevel level = null;
if (randomBoolean()) {
level = randomFrom(LoggingLevel.values());
builder.field("level", level);
}
builder.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
LoggingAction action = parser.parse(xContentParser);
assertThat(action, notNullValue());
assertThat(action.category(), is(category));
assertThat(action.level(), level == null ? is(LoggingLevel.INFO) : is(level));
assertThat(action.logger(), notNullValue());
assertThat(action.template(), notNullValue());
assertThat(action.template().render(Collections.<String, Object>emptyMap()), is(text));
}
@Test @Repeat(iterations = 10)
public void testParser_SelfGenerated() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
String category = randomAsciiOfLength(10);
LoggingAction action = new LoggingAction(logger, actionLogger, category, level, new ValueTemplate(text));
XContentBuilder builder = jsonBuilder();
action.toXContent(builder, Attachment.XContent.EMPTY_PARAMS);
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
LoggingAction parsedAction = parser.parse(xContentParser);
assertThat(parsedAction, equalTo(action));
}
@Test @Repeat(iterations = 10)
public void testParser_SourceBuilder() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
LoggingAction.SourceBuilder sourceBuilder = loggingAction("_id", new ValueTemplate.SourceBuilder(text));
String category = null;
if (randomBoolean()) {
category = randomAsciiOfLength(10);
sourceBuilder.category(category);
}
LoggingLevel level = null;
if (randomBoolean()) {
level = randomFrom(LoggingLevel.values());
sourceBuilder.level(level);
}
XContentBuilder builder = jsonBuilder();
sourceBuilder.toXContent(builder, Attachment.XContent.EMPTY_PARAMS);
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
assertThat(xContentParser.nextToken(), is(XContentParser.Token.START_OBJECT));
assertThat(xContentParser.nextToken(), is(XContentParser.Token.FIELD_NAME));
assertThat(xContentParser.currentName(), is(LoggingAction.TYPE));
assertThat(xContentParser.nextToken(), is(XContentParser.Token.START_OBJECT));
LoggingAction action = parser.parse(xContentParser);
assertThat(action, notNullValue());
assertThat(action.category(), is(category));
assertThat(action.level(), level == null ? is(LoggingLevel.INFO) : is(level));
assertThat(action.logger(), notNullValue());
assertThat(action.template(), notNullValue());
assertThat(action.template(), Matchers.instanceOf(ValueTemplate.class));
assertThat(action.template().render(Collections.<String, Object>emptyMap()), is(text));
}
@Test(expected = ActionException.class)
public void testParser_Failure() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
XContentBuilder builder = jsonBuilder()
.startObject().endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as there's no text
parser.parse(xContentParser);
}
@Test @Repeat(iterations = 30)
public void testParser_Result_Success() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject()
.field("success", true)
.field("logged_text", text)
.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as there's no text
LoggingAction.Result result = parser.parseResult(xContentParser);
assertThat(result, Matchers.notNullValue());
assertThat(result.success(), is(true));
assertThat(result, Matchers.instanceOf(LoggingAction.Result.Success.class));
assertThat(((LoggingAction.Result.Success) result).loggedText(), is(text));
}
@Test @Repeat(iterations = 30)
public void testParser_Result_Failure() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String reason = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject()
.field("success", false)
.field("reason", reason)
.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as there's no text
LoggingAction.Result result = parser.parseResult(xContentParser);
assertThat(result, Matchers.notNullValue());
assertThat(result.success(), is(false));
assertThat(result, Matchers.instanceOf(LoggingAction.Result.Failure.class));
assertThat(((LoggingAction.Result.Failure) result).reason(), is(reason));
}
@Test(expected = ActionException.class)
public void testParser_Result_MissingSuccessField() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject()
.field("logged_text", text)
.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as there's no success boolean field
parser.parseResult(xContentParser);
}
@Test(expected = ActionException.class)
public void testParser_Result_Failure_WithoutReason() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject()
.field("success", false);
if (randomBoolean()) {
builder.field("logged_text", text);
}
builder.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as the reason field is missing for the failure result
parser.parseResult(xContentParser);
}
@Test(expected = ActionException.class)
public void testParser_Result_Success_WithoutLoggedText() throws Exception {
Settings settings = ImmutableSettings.EMPTY;
ValueTemplate.Parser templateParser = new ValueTemplate.Parser();
LoggingAction.Parser parser = new LoggingAction.Parser(settings, templateParser);
String text = randomAsciiOfLength(10);
XContentBuilder builder = jsonBuilder().startObject()
.field("success", true);
if (randomBoolean()) {
builder.field("reason", text);
}
builder.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
xContentParser.nextToken();
// will fail as the logged_text field is missing for the successful result
parser.parseResult(xContentParser);
}
static void verifyLogger(ESLogger logger, LoggingLevel level, String text) {
switch (level) {
case ERROR:
verify(logger, times(1)).error(text);
break;
case WARN:
verify(logger, times(1)).warn(text);
break;
case INFO:
verify(logger, times(1)).info(text);
break;
case DEBUG:
verify(logger, times(1)).debug(text);
break;
case TRACE:
verify(logger, times(1)).trace(text);
break;
default:
fail("unhandled logging level [" + level.name() + "]");
}
}
}

View File

@ -16,8 +16,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.InputBuilders;
@ -28,6 +28,7 @@ import org.elasticsearch.watcher.support.http.auth.BasicAuth;
import org.elasticsearch.watcher.support.http.auth.HttpAuth;
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.support.template.ValueTemplate;
import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
@ -39,7 +40,6 @@ import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
@ -61,7 +61,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
@Before
public void init() throws Exception {
httpClient = mock(HttpClient.class);
Template.Parser templateParser = new MockTemplate.Parser();
Template.Parser templateParser = new ValueTemplate.Parser();
HttpAuthRegistry registry = new HttpAuthRegistry(ImmutableMap.of("basic", new BasicAuth.Parser()));
httpParser = new HttpInput.Parser(
ImmutableSettings.EMPTY, httpClient, new HttpRequest.Parser(registry), new TemplatedHttpRequest.Parser(templateParser, registry)
@ -120,7 +120,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
.setScheme(scheme)
.setMethod(httpMethod)
.setPath(pathTemplate)
.setBody(body != null ? new MockTemplate(body) : null)
.setBody(body != null ? new ValueTemplate(body) : null)
.setAuth(auth);
if (params != null) {
@ -176,7 +176,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
.setMethod(httpMethod)
.setHost("_host")
.setPort(123)
.setBody(new MockTemplate(body))
.setBody(new ValueTemplate(body))
.setHeaders(headers);
Map<String, Object> payload = MapBuilder.<String, Object>newMapBuilder().put("x", "y").map();
@ -202,56 +202,11 @@ public class HttpInputTests extends ElasticsearchTestCase {
}
private static Template mockTemplate(String value) {
return new MockTemplate(value);
return new ValueTemplate(value);
}
private static Template.SourceBuilder mockTemplateSourceBuilder(String value) {
return new Template.InstanceSourceBuilder(new MockTemplate(value));
}
private static class MockTemplate implements Template {
private final String value;
private MockTemplate(String value) {
this.value = value;
}
@Override
public String render(Map<String, Object> model) {
return value;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.value(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MockTemplate that = (MockTemplate) o;
if (!value.equals(that.value)) return false;
return true;
}
@Override
public int hashCode() {
return value.hashCode();
}
static class Parser implements Template.Parser {
@Override
public Template parse(XContentParser parser) throws IOException, ParseException {
String value = parser.text();
return new MockTemplate(value);
}
}
return new Template.InstanceSourceBuilder(new ValueTemplate(value));
}
static MockTemplateMatcher isTemplate(String value) {
@ -268,7 +223,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
@Override
public boolean matches(Object item) {
return item instanceof MockTemplate && ((MockTemplate) item).value.equals(value);
return item instanceof ValueTemplate && ((ValueTemplate) item).value().equals(value);
}
@Override

View File

@ -0,0 +1,79 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.support.template;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Map;
/**
*
*/
public class ValueTemplate implements Template {
private final String value;
public ValueTemplate(String value) {
this.value = value;
}
public String value() {
return value;
}
@Override
public String render(Map<String, Object> model) {
return value;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.value(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ValueTemplate that = (ValueTemplate) o;
if (!value.equals(that.value)) return false;
return true;
}
@Override
public int hashCode() {
return value.hashCode();
}
public static class Parser implements Template.Parser {
@Override
public Template parse(XContentParser parser) throws IOException, ParseException {
String value = parser.text();
return new ValueTemplate(value);
}
}
public static class SourceBuilder implements Template.SourceBuilder {
private final String value;
public SourceBuilder(String value) {
this.value = value;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.value(value);
}
}
}

View File

@ -35,6 +35,7 @@ import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.actions.ActionBuilders.loggingAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
import static org.elasticsearch.watcher.input.InputBuilders.searchInput;
@ -59,7 +60,12 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
.source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest))
.condition(scriptCondition("ctx.payload.hits.total == 1")))
.condition(scriptCondition("ctx.payload.hits.total == 1"))
.addAction(loggingAction("_logger",
"\n\n************\n" +
"total hits: {{ctx.payload.hits.total}}\n" +
"************\n")
.category("_category")))
.get();
if (timeWarped()) {