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:
parent
f9004eed31
commit
8d71337be5
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue