De-normalize watch record format

Now that the watch record is write once and never read/parsed. We can de-normalize its format (the  structure of the `watch_record` document) such it'd be optimal for searching and aggregating.

- `execution_result` renamed to `result` (for minimal verbosity)

- the structure of `trigger_event` changed to:
 ```
 {
 	"trigger_event" : {
 		"type" : "<trigger_type>",
 		"triggered_time" : "<datetime>",
 		"<trigger_type>" : { // type specific data (optional) }
 	}
 }
 ```

- the structure of `input` results changed to:
 ```
 {
 	"result" : {
 		"input" : {
 			"type" : "<input_type>",
 			"payload" : { // the payload },
 			"<input_type>" : { // custom result fields per type (optional) }
 		},
 		...
 	}
 }
 ```

- the structure of `condition` results changed to:
 ```
 {
 	"result" : {
 	    ...
 		"condition" : {
 			"type" : "<condition_type>",
 			"met" : true | false,
 			"<condition_type>" : { // custom result fields per type (optional) }
 		},
 		...
 	}
 }
 ```

- the structure of `transform` results changed to:
 ```
 {
 	"result" : {
 	    ...
 		"transform" : {
 			"type" : "<transform_type>",
 			"payload" : { // the transformed payload }
 			"<transform_type>" : { // custom result fields per type (optional) }
 		},
 		...
 	}
 }
 ```

- the structure of `actions` results changed to:
 ```
 {
 	"result" : {
 	    ...
 		"actions" : [
 			{
 				"id" : "<action_id>"
 				"type" : "<action_type>",
 				"status" : "success" | "failure" | "simulated" | "throttled",
 				"reason" : "holds the reasoning if status is either success or throttled",
 				"transform" : { // action level transform result (if applicable)}
 				"<action_type>" : { // custom result fields per type (optional) }
 			},
 			...
 		]
 	}
 }
 ```

Original commit: elastic/x-pack-elasticsearch@98466d4b83
This commit is contained in:
uboness 2015-06-01 22:41:53 +02:00
parent 47247dc46a
commit 613ce8762c
46 changed files with 279 additions and 186 deletions

View File

@ -76,9 +76,12 @@
}
- match: { "watch_record.watch_id": "my_exe_watch" }
- match: { "watch_record.state": "executed" }
- match: { "watch_record.trigger_event.type": "manual" }
- match: { "watch_record.trigger_event.triggered_time": "2015-05-05T20:58:02.443Z" }
- match: { "watch_record.trigger_event.manual.schedule.scheduled_time": "2015-05-05T20:58:02.443Z" }
- match: { "watch_record.execution_result.condition.always": {} }
- match: { "watch_record.execution_result.input.simple.payload.foo": "bar" }
- match: { "watch_record.execution_result.actions.0.id" : "email_admin" }
- match: { "watch_record.execution_result.actions.0.email.status" : "simulated" }
- match: { "watch_record.execution_result.actions.0.email.email.subject" : "404 recently encountered" }
- match: { "watch_record.result.condition.met": true }
- match: { "watch_record.result.input.payload.foo": "bar" }
- match: { "watch_record.result.actions.0.id" : "email_admin" }
- match: { "watch_record.result.actions.0.status" : "simulated" }
- match: { "watch_record.result.actions.0.type" : "email" }
- match: { "watch_record.result.actions.0.email.email.subject" : "404 recently encountered" }

View File

@ -44,8 +44,9 @@
}
- match: { "watch_record.watch_id": "my_logging_watch" }
- match: { "watch_record.execution_result.condition.script.met": true }
- match: { "watch_record.state": "executed" }
- match: { "watch_record.execution_result.actions.0.id" : "logging" }
- match: { "watch_record.execution_result.actions.0.logging.status" : "success" }
- match: { "watch_record.execution_result.actions.0.logging.logged_text" : "foobar" }
- match: { "watch_record.result.condition.met": true }
- match: { "watch_record.result.actions.0.id" : "logging" }
- match: { "watch_record.result.actions.0.type" : "logging" }
- match: { "watch_record.result.actions.0.status" : "success" }
- match: { "watch_record.result.actions.0.logging.logged_text" : "foobar" }

View File

@ -22,7 +22,17 @@ public interface Action extends ToXContent {
abstract class Result implements ToXContent {
public enum Status { SUCCESS, FAILURE, THROTTLED, SIMULATED }
public enum Status implements ToXContent {
SUCCESS,
FAILURE,
THROTTLED,
SIMULATED;
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.value(name().toLowerCase(Locale.ROOT));
}
}
protected final String type;
protected final Status status;
@ -40,16 +50,6 @@ public interface Action extends ToXContent {
return status;
}
@Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.STATUS.getPreferredName(), status.name().toLowerCase(Locale.ROOT));
xContentBody(builder, params);
return builder.endObject();
}
protected abstract XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException;
public static class Failure extends Result {
private final String reason;
@ -64,7 +64,7 @@ public interface Action extends ToXContent {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.REASON.getPreferredName(), reason);
}
}
@ -83,7 +83,7 @@ public interface Action extends ToXContent {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.REASON.getPreferredName(), reason);
}
}

View File

@ -223,17 +223,19 @@ public class ActionWrapper implements ToXContent {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.ID.getPreferredName(), id);
builder.field(Field.TYPE.getPreferredName(), action.type());
builder.field(Field.STATUS.getPreferredName(), action.status, params);
if (transform != null) {
builder.startObject(Transform.Field.TRANSFORM.getPreferredName())
.field(transform.type(), transform, params)
.endObject();
builder.field(Transform.Field.TRANSFORM.getPreferredName(), transform, params);
}
builder.field(action.type(), action, params);
action.toXContent(builder, params);
return builder.endObject();
}
}
interface Field {
ParseField ID = new ParseField("id");
ParseField TYPE = new ParseField("type");
ParseField STATUS = new ParseField("status");
}
}

View File

@ -189,9 +189,11 @@ public class EmailAction implements Action {
}
@Override
public XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.ACCOUNT.getPreferredName(), account)
.field(Field.EMAIL.getPreferredName(), email, params);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.ACCOUNT.getPreferredName(), account)
.field(Field.EMAIL.getPreferredName(), email, params)
.endObject();
}
}
@ -209,8 +211,10 @@ public class EmailAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.EMAIL.getPreferredName(), email, params);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.EMAIL.getPreferredName(), email, params)
.endObject();
}
}
}

View File

@ -100,12 +100,6 @@ public class IndexAction implements Action {
return new IndexAction(index, docType);
}
private static void assertNotNull(Object value, String message, Object... args) {
if (value == null) {
throw new IndexActionException(message, args);
}
}
public static Builder builder(String index, String docType) {
return new Builder(index, docType);
}
@ -126,11 +120,10 @@ public class IndexAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
if (response != null) {
builder.field(Field.RESPONSE.getPreferredName(), response, params);
}
return builder;
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.RESPONSE.getPreferredName(), response, params)
.endObject();
}
}
@ -160,11 +153,13 @@ public class IndexAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(Field.REQUEST.getPreferredName())
.field(Field.INDEX.getPreferredName(), index)
.field(Field.DOC_TYPE.getPreferredName(), docType)
.field(Field.SOURCE.getPreferredName(), source, params)
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.startObject(Field.REQUEST.getPreferredName())
.field(Field.INDEX.getPreferredName(), index)
.field(Field.DOC_TYPE.getPreferredName(), docType)
.field(Field.SOURCE.getPreferredName(), source, params)
.endObject()
.endObject();
}
}

View File

@ -108,12 +108,6 @@ public class LoggingAction implements Action {
return new LoggingAction(text, level, category);
}
private static void assertNotNull(Object value, String message, Object... args) {
if (value == null) {
throw new LoggingActionException(message, args);
}
}
public static Builder builder(Template template) {
return new Builder(template);
}
@ -134,8 +128,10 @@ public class LoggingAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.LOGGED_TEXT.getPreferredName(), loggedText);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.LOGGED_TEXT.getPreferredName(), loggedText)
.endObject();
}
}
@ -153,8 +149,10 @@ public class LoggingAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.LOGGED_TEXT.getPreferredName(), loggedText);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.LOGGED_TEXT.getPreferredName(), loggedText)
.endObject();
}
}
}

View File

@ -66,12 +66,6 @@ public class WebhookAction implements Action {
}
}
private static void assertNotNull(Object value, String message, Object... args) {
if (value == null) {
throw new WebhookActionException(message, args);
}
}
public static Builder builder(HttpRequestTemplate requestTemplate) {
return new Builder(requestTemplate);
}
@ -98,9 +92,11 @@ public class WebhookAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.RESPONSE.getPreferredName(), response, params);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.RESPONSE.getPreferredName(), response, params)
.endObject();
}
}
@ -128,10 +124,12 @@ public class WebhookAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
super.xContentBody(builder, params);
return builder.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.RESPONSE.getPreferredName(), response, params);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
super.toXContent(builder, params);
return builder.startObject(type)
.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.RESPONSE.getPreferredName(), response, params)
.endObject();
}
}
@ -149,8 +147,10 @@ public class WebhookAction implements Action {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.REQUEST.getPreferredName(), request, params);
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.REQUEST.getPreferredName(), request, params)
.endObject();
}
}

View File

@ -7,6 +7,9 @@ package org.elasticsearch.watcher.condition;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
/**
*
@ -17,7 +20,7 @@ public interface Condition extends ToXContent {
abstract class Result implements ToXContent {
private final String type;
protected final String type;
protected final boolean met;
public Result(String type, boolean met) {
@ -31,6 +34,16 @@ public interface Condition extends ToXContent {
public boolean met() { return met; }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.TYPE.getPreferredName(), type);
builder.field(Field.MET.getPreferredName(), met);
typeXContent(builder, params);
return builder.endObject();
}
protected abstract XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException;
}
interface Builder<C extends Condition> {
@ -39,6 +52,7 @@ public interface Condition extends ToXContent {
}
interface Field {
ParseField TYPE = new ParseField("type");
ParseField MET = new ParseField("met");
}
}

View File

@ -49,8 +49,8 @@ public class AlwaysCondition implements Condition {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -137,9 +137,8 @@ public class CompareCondition implements Condition {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field(Field.MET.getPreferredName(), met)
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.RESOLVED_VALUE.getPreferredName(), resolveValue)
.endObject();
}

View File

@ -49,8 +49,8 @@ public class NeverCondition implements Condition {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -77,10 +77,8 @@ public class ScriptCondition implements Condition {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field(Field.MET.getPreferredName(), met)
.endObject();
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -14,6 +14,7 @@ import org.elasticsearch.watcher.actions.ExecutableActions;
import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.condition.ConditionRegistry;
import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.InputRegistry;
import org.elasticsearch.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.watcher.transform.Transform;
@ -76,18 +77,13 @@ public class WatchExecutionResult implements ToXContent {
builder.field(Field.EXECUTION_DURATION.getPreferredName(), executionDurationMs);
if (inputResult != null) {
builder.startObject(Field.INPUT.getPreferredName())
.field(inputResult.type(), inputResult, params)
.endObject();
builder.field(Field.INPUT.getPreferredName(), inputResult, params);
}
if (conditionResult != null) {
builder.field(Field.CONDITION.getPreferredName());
ConditionRegistry.writeResult(conditionResult, builder, params);
builder.field(Field.CONDITION.getPreferredName(), conditionResult, params);
}
if (transformResult != null) {
builder.startObject(Transform.Field.TRANSFORM.getPreferredName())
.field(transformResult.type(), transformResult, params)
.endObject();
builder.field(Transform.Field.TRANSFORM.getPreferredName(), transformResult, params);
}
builder.field(Field.ACTIONS.getPreferredName(), actionsResults, params);
builder.endObject();
@ -96,9 +92,11 @@ public class WatchExecutionResult implements ToXContent {
interface Field {
ParseField EXECUTION_TIME = new ParseField("execution_time");
ParseField EXECUTION_DURATION = new ParseField("execution_duration");
ParseField INPUT = new ParseField("input");
ParseField CONDITION = new ParseField("condition");
ParseField ACTIONS = new ParseField("actions");
ParseField EXECUTION_DURATION = new ParseField("execution_duration");
ParseField TYPE = new ParseField("type");
}
}

View File

@ -29,12 +29,12 @@ public class WatchRecord implements ToXContent {
private final @Nullable Map<String,Object> metadata;
private final @Nullable String message;
private final @Nullable WatchExecutionResult execution;
private final @Nullable WatchExecutionResult executionResult;
public WatchRecord(Wid id, TriggerEvent triggerEvent, String message, ExecutionState state) {
this.id = id;
this.triggerEvent = triggerEvent;
this.execution = null;
this.executionResult = null;
this.state = state;
this.message = message;
this.condition = null;
@ -42,19 +42,19 @@ public class WatchRecord implements ToXContent {
this.metadata = null;
}
public WatchRecord(WatchExecutionContext context, WatchExecutionResult execution) {
public WatchRecord(WatchExecutionContext context, WatchExecutionResult executionResult) {
this.id = context.id();
this.triggerEvent = context.triggerEvent();
this.condition = context.watch().condition().condition();
this.input = context.watch().input();
this.execution = execution;
this.executionResult = executionResult;
this.metadata = context.watch().metadata();
this.message = null;
if (!this.execution.conditionResult().met()) {
if (!this.executionResult.conditionResult().met()) {
state = ExecutionState.EXECUTION_NOT_NEEDED;
} else {
if (this.execution.actionsResults().throttled()) {
if (this.executionResult.actionsResults().throttled()) {
state = ExecutionState.THROTTLED;
} else {
state = ExecutionState.EXECUTED;
@ -93,16 +93,17 @@ public class WatchRecord implements ToXContent {
}
public WatchExecutionResult execution() {
return execution;
return executionResult;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.WATCH_ID.getPreferredName(), id.watchId());
builder.startObject(Field.TRIGGER_EVENT.getPreferredName())
.field(triggerEvent.type(), triggerEvent, params)
.endObject();
builder.field(Field.TRIGGER_EVENT.getPreferredName());
triggerEvent.recordXContent(builder, params);
builder.field(Field.STATE.getPreferredName(), state.id());
if (input != null) {
builder.startObject(Watch.Field.INPUT.getPreferredName())
@ -122,8 +123,8 @@ public class WatchRecord implements ToXContent {
builder.field(Field.METADATA.getPreferredName(), metadata);
}
if (execution != null) {
builder.field(Field.EXECUTION_RESULT.getPreferredName(), execution, params);
if (executionResult != null) {
builder.field(Field.EXECUTION_RESULT.getPreferredName(), executionResult, params);
}
builder.endObject();
@ -157,6 +158,6 @@ public class WatchRecord implements ToXContent {
ParseField MESSAGE = new ParseField("message");
ParseField STATE = new ParseField("state");
ParseField METADATA = new ParseField("metadata");
ParseField EXECUTION_RESULT = new ParseField("execution_result");
ParseField EXECUTION_RESULT = new ParseField("result");
}
}

View File

@ -21,7 +21,7 @@ public interface Input extends ToXContent {
abstract class Result implements ToXContent {
private final String type;
protected final String type;
private final Payload payload;
public Result(String type, Payload payload) {
@ -40,13 +40,14 @@ public interface Input extends ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject()
.field(Field.PAYLOAD.getPreferredName(), payload, params);
toXContentBody(builder, params);
builder.startObject();
builder.field(Field.TYPE.getPreferredName(), type);
builder.field(Field.PAYLOAD.getPreferredName(), payload, params);
typeXContent(builder, params);
return builder.endObject();
}
protected abstract XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException;
protected abstract XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException;
}
interface Builder<I extends Input> {
@ -56,6 +57,7 @@ public interface Input extends ToXContent {
}
interface Field {
ParseField TYPE = new ParseField("type");
ParseField PAYLOAD = new ParseField("payload");
}
}

View File

@ -7,6 +7,8 @@ package org.elasticsearch.watcher.input;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;

View File

@ -123,9 +123,11 @@ public class HttpInput implements Input {
}
@Override
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.STATUS.getPreferredName(), status);
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(type)
.field(Field.REQUEST.getPreferredName(), request, params)
.field(Field.STATUS.getPreferredName(), status)
.endObject();
}
}

View File

@ -56,12 +56,7 @@ public class NoneInput implements Input {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
}
@Override
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -138,10 +138,11 @@ public class SearchInput implements Input {
}
@Override
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(type);
builder.field(Field.REQUEST.getPreferredName());
WatcherUtils.writeSearchRequest(request, builder, params);
return builder;
return builder.endObject();
}
}

View File

@ -73,7 +73,7 @@ public class SimpleInput implements Input {
}
@Override
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -40,12 +40,13 @@ public interface Transform extends ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.TYPE.getPreferredName(), type);
builder.field(Field.PAYLOAD.getPreferredName(), payload, params);
xContentBody(builder, params);
typeXContent(builder, params);
return builder.endObject();
}
protected abstract XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException;
protected abstract XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException;
}
@ -55,6 +56,7 @@ public interface Transform extends ToXContent {
}
interface Field {
ParseField TYPE = new ParseField("type");
ParseField PAYLOAD = new ParseField("payload");
ParseField TRANSFORM = new ParseField("transform");
}

View File

@ -105,14 +105,14 @@ public class ChainTransform implements Transform {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(type);
builder.startArray(Field.RESULTS.getPreferredName());
for (Transform.Result result : results) {
builder.startObject()
.field(result.type(), result, params)
.endObject();
result.toXContent(builder, params);
}
return builder.endArray();
builder.endArray();
return builder.endObject();
}
}

View File

@ -75,7 +75,7 @@ public class ScriptTransform implements Transform {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}

View File

@ -86,10 +86,11 @@ public class SearchTransform implements Transform {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(type);
builder.field(Field.REQUEST.getPreferredName());
WatcherUtils.writeSearchRequest(request, builder, params);
return builder;
return builder.endObject();
}
}

View File

@ -8,7 +8,10 @@ package org.elasticsearch.watcher.trigger;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.watcher.support.WatcherDateTimeUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@ -42,7 +45,18 @@ public abstract class TriggerEvent implements ToXContent {
return data;
}
public void recordXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.TYPE.getPreferredName(), type());
WatcherDateTimeUtils.writeDate(Field.TRIGGERED_TIME.getPreferredName(), builder, triggeredTime);
recordDataXContent(builder, params);
builder.endObject();
}
public abstract void recordDataXContent(XContentBuilder builder, Params params) throws IOException;
protected interface Field {
ParseField TYPE = new ParseField("type");
ParseField TRIGGERED_TIME = new ParseField("triggered_time");
}

View File

@ -19,7 +19,6 @@ public class ManualTriggerEvent extends TriggerEvent {
private final TriggerEvent triggerEvent;
public ManualTriggerEvent(String jobName, TriggerEvent triggerEvent) {
super(jobName, triggerEvent.triggeredTime());
this.triggerEvent = triggerEvent;
@ -38,6 +37,13 @@ public class ManualTriggerEvent extends TriggerEvent {
return builder.endObject();
}
@Override
public void recordDataXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(ManualTriggerEngine.TYPE);
triggerEvent.recordDataXContent(builder, params);
builder.endObject();
}
public static ManualTriggerEvent parse(TriggerService triggerService, String watchId, String context, XContentParser parser) throws IOException {
TriggerEvent parsedTriggerEvent = triggerService.parseTriggerEvent(watchId, context, parser);
return new ManualTriggerEvent(context, parsedTriggerEvent);

View File

@ -52,6 +52,13 @@ public class ScheduleTriggerEvent extends TriggerEvent {
return builder.endObject();
}
@Override
public void recordDataXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(ScheduleTrigger.TYPE);
WatcherDateTimeUtils.writeDate(Field.SCHEDULED_TIME.getPreferredName(), builder, scheduledTime);
builder.endObject();
}
public static ScheduleTriggerEvent parse(XContentParser parser, String watchId, String context, Clock clock) throws IOException {
DateTime triggeredTime = null;
DateTime scheduledTime = null;

View File

@ -10,7 +10,7 @@
"dynamic_templates": [
{
"disabled_payload_fields": {
"path_match": "execution_result\\.((input\\..+)|(actions\\.transform\\..+)|(transform\\..+))\\.payload",
"path_match": "result\\.(input|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.payload",
"match_pattern": "regex",
"mapping": {
"type": "object",
@ -20,7 +20,7 @@
},
{
"disabled_search_request_body_fields": {
"path_match": "execution_result\\.((input)|(actions\\.transform.*)|(transform.*))\\.search\\.request\\.(body|template)",
"path_match": "result\\.(input|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.search\\.request\\.(body|template)",
"match_pattern": "regex",
"mapping": {
"type": "object",
@ -42,13 +42,32 @@
"type": "object",
"dynamic": true,
"properties": {
"type" : {
"type" : "string",
"index" : "not_analyzed"
},
"triggered_time": {
"type": "date"
},
"manual": {
"type": "object",
"dynamic": true,
"properties": {
"schedule": {
"type": "object",
"dynamic": true,
"properties": {
"scheduled_time": {
"type": "date"
}
}
}
}
},
"schedule": {
"type": "object",
"dynamic": true,
"properties": {
"triggered_time": {
"type": "date"
},
"scheduled_time": {
"type": "date"
}
@ -71,7 +90,7 @@
"message": {
"type": "string"
},
"execution_result": {
"result": {
"type": "object",
"dynamic": true,
"properties": {
@ -85,6 +104,14 @@
"type": "object",
"dynamic": true,
"properties": {
"type" : {
"type" : "string",
"index" : "not_analyzed"
},
"payload" : {
"type" : "object",
"enabled" : false
},
"search": {
"type": "object",
"dynamic": true,
@ -135,6 +162,13 @@
"type" : "object",
"dynamic" : true,
"properties" : {
"type" : {
"type" : "string",
"index" : "not_analyzed"
},
"met" : {
"type" : "boolean"
},
"compare" : {
"type" : "object",
"enabled" : false
@ -142,14 +176,6 @@
"script" : {
"type" : "object",
"enabled" : false
},
"always" : {
"type" : "object",
"enabled" : false
},
"never" : {
"type" : "object",
"enabled" : false
}
}
},
@ -157,6 +183,10 @@
"type" : "object",
"dynamic" : true,
"properties" : {
"type" : {
"type" : "string",
"index" : "not_analyzed"
},
"search" : {
"type" : "object",
"dynamic" : true,
@ -178,6 +208,22 @@
"include_in_parent": true,
"dynamic": true,
"properties": {
"id" : {
"type" : "string",
"index" : "not_analyzed"
},
"type" : {
"type" : "string",
"index" : "not_analyzed"
},
"status" : {
"type" : "string",
"index" : "not_analyzed"
},
"reason" : {
"type" : "string",
"index" : "analyzed"
},
"email": {
"type": "object",
"dynamic": true,

View File

@ -209,7 +209,7 @@ public class ManualExecutionTests extends AbstractWatcherIntegrationTests {
assertThat(MapPath.<String>eval("state", executeWatchResult), equalTo(ExecutionState.EXECUTION_NOT_NEEDED.toString()));
assertThat(MapPath.<String>eval("execution_result.input.simple.payload.foo", executeWatchResult), equalTo("bar"));
assertThat(MapPath.<String>eval("result.input.payload.foo", executeWatchResult), equalTo("bar"));
watchBuilder = watchBuilder()
.trigger(schedule(cron("0 0 0 1 * ? 2099")))
@ -225,8 +225,8 @@ public class ManualExecutionTests extends AbstractWatcherIntegrationTests {
.get().getRecordSource().getAsMap();
assertThat(MapPath.<String>eval("state", executeWatchResult), equalTo(ExecutionState.EXECUTED.toString()));
assertThat(MapPath.<String>eval("execution_result.input.simple.payload.foo", executeWatchResult), equalTo("bar"));
assertThat(MapPath.<String>eval("execution_result.actions.0.id", executeWatchResult), equalTo("log"));
assertThat(MapPath.<String>eval("result.input.payload.foo", executeWatchResult), equalTo("bar"));
assertThat(MapPath.<String>eval("result.actions.0.id", executeWatchResult), equalTo("log"));
executeWatchResult = watcherClient().prepareExecuteWatch()

View File

@ -162,8 +162,8 @@ public class LicenseIntegrationTests extends AbstractWatcherIntegrationTests {
// and last... lets verify that we have throttled watches due to license expiration
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, filteredQuery(
matchQuery("execution_result.actions.index.reason", "watcher license expired"),
termFilter("execution_result.actions.index.status", "throttled")));
matchQuery("result.actions.reason", "watcher license expired"),
termFilter("result.actions.status", "throttled")));
assertThat(throttledCount, is(1L));
//=====

View File

@ -305,7 +305,7 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
.get();
assertThat("could not find executed watch record", searchResponse.getHits().getTotalHits(), greaterThanOrEqualTo(minimumExpectedWatchActionsWithActionPerformed));
if (assertConditionMet) {
assertThat((Integer) XContentMapValues.extractValue("execution_result.input.search.payload.hits.total", searchResponse.getHits().getAt(0).sourceAsMap()), greaterThanOrEqualTo(1));
assertThat((Integer) XContentMapValues.extractValue("result.input.payload.hits.total", searchResponse.getHits().getAt(0).sourceAsMap()), greaterThanOrEqualTo(1));
}
}
});

View File

@ -364,7 +364,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
.get();
assertHitCount(searchResponse, 1);
XContentSource source = new XContentSource(searchResponse.getHits().getAt(0).getSourceRef());
assertThat(source.getValue("execution_result.input.search.payload.hits.total"), equalTo((Object) 1));
assertThat(source.getValue("result.input.payload.hits.total"), equalTo((Object) 1));
}
@Test

View File

@ -144,7 +144,7 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
assertThat(executeResponse, notNullValue());
contentSource = executeResponse.getRecordSource();
value = contentSource.getValue("execution_result.actions.0.email.status");
value = contentSource.getValue("result.actions.0.status");
assertThat((String) value, is("success"));
if (!latch.await(5, TimeUnit.SECONDS)) {

View File

@ -101,11 +101,11 @@ public class HistoryTemplateEmailMappingsTests extends AbstractWatcherIntegratio
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
.aggregation(terms("from").field("execution_result.actions.email.email.from"))
.aggregation(terms("to").field("execution_result.actions.email.email.to"))
.aggregation(terms("cc").field("execution_result.actions.email.email.cc"))
.aggregation(terms("bcc").field("execution_result.actions.email.email.bcc"))
.aggregation(terms("reply_to").field("execution_result.actions.email.email.reply_to"))
.aggregation(terms("from").field("result.actions.email.email.from"))
.aggregation(terms("to").field("result.actions.email.email.to"))
.aggregation(terms("cc").field("result.actions.email.email.cc"))
.aggregation(terms("bcc").field("result.actions.email.email.bcc"))
.aggregation(terms("reply_to").field("result.actions.email.email.reply_to"))
.buildAsBytes())
.get();

View File

@ -98,9 +98,9 @@ public class HistoryTemplateHttpMappingsTests extends AbstractWatcherIntegration
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
.aggregation(terms("input_result_path").field("execution_result.input.http.request.path"))
.aggregation(terms("input_result_host").field("execution_result.input.http.request.host"))
.aggregation(terms("webhook_path").field("execution_result.actions.webhook.request.path"))
.aggregation(terms("input_result_path").field("result.input.http.request.path"))
.aggregation(terms("input_result_host").field("result.input.http.request.host"))
.aggregation(terms("webhook_path").field("result.actions.webhook.request.path"))
.buildAsBytes())
.get();

View File

@ -60,8 +60,8 @@ public class HistoryTemplateIndexActionMappingsTests extends AbstractWatcherInte
refresh();
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
.aggregation(terms("index_action_indices").field("execution_result.actions.index.response.index"))
.aggregation(terms("index_action_types").field("execution_result.actions.index.response.type"))
.aggregation(terms("index_action_indices").field("result.actions.index.response.index"))
.aggregation(terms("index_action_types").field("result.actions.index.response.type"))
.buildAsBytes())
.get();

View File

@ -70,10 +70,10 @@ public class HistoryTemplateSearchInputMappingsTests extends AbstractWatcherInte
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
.aggregation(terms("input_search_type").field("execution_result.input.search.request.search_type"))
.aggregation(terms("input_indices").field("execution_result.input.search.request.indices"))
.aggregation(terms("input_types").field("execution_result.input.search.request.types"))
.aggregation(terms("input_body").field("execution_result.input.search.request.body"))
.aggregation(terms("input_search_type").field("result.input.search.request.search_type"))
.aggregation(terms("input_indices").field("result.input.search.request.indices"))
.aggregation(terms("input_types").field("result.input.search.request.types"))
.aggregation(terms("input_body").field("result.input.search.request.body"))
.buildAsBytes())
.get();

View File

@ -74,9 +74,11 @@ public class HistoryTemplateTimeMappingsTests extends AbstractWatcherIntegration
try {
Map<String, Object> source = metadata.getSourceAsMap();
logger.info("checking index [{}] with metadata:\n[{}]", metadatas.key, metadata.source().toString());
assertThat(extractValue("properties.trigger_event.properties.type.type", source), is((Object) "string"));
assertThat(extractValue("properties.trigger_event.properties.type.index", source), is((Object) "not_analyzed"));
assertThat(extractValue("properties.trigger_event.properties.triggered_time.type", source), is((Object) "date"));
assertThat(extractValue("properties.trigger_event.properties.schedule.properties.scheduled_time.type", source), is((Object) "date"));
assertThat(extractValue("properties.trigger_event.properties.schedule.properties.triggered_time.type", source), is((Object) "date"));
assertThat(extractValue("properties.execution_result.properties.execution_time.type", source), is((Object) "date"));
assertThat(extractValue("properties.result.properties.execution_time.type", source), is((Object) "date"));
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@ -98,8 +98,8 @@ public class HistoryTemplateTransformMappingsTests extends AbstractWatcherIntegr
try {
Map<String, Object> source = metadata.getSourceAsMap();
logger.info("checking index [{}] with metadata:\n[{}]", metadatas.key, metadata.source().toString());
assertThat(extractValue("properties.execution_result.properties.transform.properties.script.properties.payload.enabled", source), is((Object) false));
assertThat(extractValue("properties.execution_result.properties.actions.properties.transform.properties.script.properties.payload.enabled", source), is((Object) false));
assertThat(extractValue("properties.result.properties.transform.properties.payload.enabled", source), is((Object) false));
assertThat(extractValue("properties.result.properties.actions.properties.transform.properties.payload.enabled", source), is((Object) false));
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@ -147,7 +147,7 @@ public class HttpInputIntegrationTest extends AbstractWatcherIntegrationTests {
.get();
assertHitCount(searchResponse, 1);
XContentSource source = new XContentSource(searchResponse.getHits().getAt(0).getSourceRef());
assertThat(source.getValue("execution_result.input.http.payload.hits.total"), equalTo((Object) 1));
assertThat(source.getValue("result.input.payload.hits.total"), equalTo((Object) 1));
}
}

View File

@ -152,7 +152,7 @@ public class HttpSecretsIntegrationTests extends AbstractWatcherIntegrationTests
.get();
assertThat(executeResponse, notNullValue());
contentSource = executeResponse.getRecordSource();
value = contentSource.getValue("execution_result.input.http.status");
value = contentSource.getValue("result.input.http.status");
assertThat(value, notNullValue());
assertThat(value, is((Object) 200));
@ -225,17 +225,17 @@ public class HttpSecretsIntegrationTests extends AbstractWatcherIntegrationTests
assertThat(executeResponse, notNullValue());
contentSource = executeResponse.getRecordSource();
value = contentSource.getValue("execution_result.actions.0.webhook.response.status");
value = contentSource.getValue("result.actions.0.webhook.response.status");
assertThat(value, notNullValue());
assertThat(value, instanceOf(Number.class));
assertThat(((Number) value).intValue(), is(200));
value = contentSource.getValue("execution_result.actions.0.webhook.request.auth.username");
value = contentSource.getValue("result.actions.0.webhook.request.auth.username");
assertThat(value, notNullValue());
assertThat(value, instanceOf(String.class));
assertThat((String) value, is(USERNAME)); // the auth username exists
value = contentSource.getValue("execution_result.actions.0.webhook.request.auth.password");
value = contentSource.getValue("result.actions.0.webhook.request.auth.password");
assertThat(value, nullValue()); // but the auth password was filtered out
RecordedRequest request = webServer.takeRequest();

View File

@ -101,7 +101,7 @@ public class WatchMetadataTests extends AbstractWatcherIntegrationTests {
Map<String, Object> result = executeWatchResponse.getRecordSource().getAsMap();;
assertThat(MapPath.<String>eval("metadata.foo", result), equalTo("bar"));
assertThat(MapPath.<String>eval("execution_result.actions.0.id", result), equalTo("testLogger"));
assertThat(MapPath.<String>eval("execution_result.actions.0.logging.logged_text", result), equalTo("This is a test"));
assertThat(MapPath.<String>eval("result.actions.0.id", result), equalTo("testLogger"));
assertThat(MapPath.<String>eval("result.actions.0.logging.logged_text", result), equalTo("This is a test"));
}
}

View File

@ -119,11 +119,11 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
.get();
assertNoFailures(response);
XContentSource source = new XContentSource(response.getHits().getAt(0).sourceRef());
String body = source.getValue("execution_result.actions.0.webhook.response.body");
String body = source.getValue("result.actions.0.webhook.response.body");
assertThat(body, notNullValue());
assertThat(body, is("body"));
Number status = source.getValue("execution_result.actions.0.webhook.response.status");
Number status = source.getValue("result.actions.0.webhook.response.status");
assertThat(status, notNullValue());
assertThat(status.intValue(), is(200));
}

View File

@ -97,10 +97,10 @@ public class WebhookIntegrationTests extends AbstractWatcherIntegrationTests {
assertNoFailures(response);
XContentSource source = new XContentSource(response.getHits().getAt(0).getSourceRef());
String body = source.getValue("execution_result.actions.0.webhook.response.body");
String body = source.getValue("result.actions.0.webhook.response.body");
assertThat(body, notNullValue());
assertThat(body, is("body"));
Number status = source.getValue("execution_result.actions.0.webhook.response.status");
Number status = source.getValue("result.actions.0.webhook.response.status");
assertThat(status, notNullValue());
assertThat(status.intValue(), is(200));
}

View File

@ -140,7 +140,7 @@ public class ChainTransformTests extends ElasticsearchTestCase {
}
@Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
return builder;
}
}