Alerting : Add scripted triggers and alert disabling.
This commit adds support for disabling alerts. This commit adds preliminary support for scripted triggers. Original commit: elastic/x-pack-elasticsearch@e14a56dbeb
This commit is contained in:
parent
4c1c502f80
commit
418b9f1a31
|
@ -15,9 +15,6 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by brian on 8/12/14.
|
||||
*/
|
||||
public class Alert implements ToXContent{
|
||||
private final String alertName;
|
||||
private String queryName;
|
||||
|
@ -28,6 +25,16 @@ public class Alert implements ToXContent{
|
|||
private DateTime lastRan;
|
||||
private long version;
|
||||
private DateTime running;
|
||||
private boolean enabled;
|
||||
|
||||
|
||||
public boolean enabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void enabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public DateTime running() {
|
||||
return running;
|
||||
|
@ -109,7 +116,7 @@ public class Alert implements ToXContent{
|
|||
|
||||
public Alert(String alertName, String queryName, AlertTrigger trigger,
|
||||
TimeValue timePeriod, List<AlertAction> actions, String schedule, DateTime lastRan,
|
||||
List<String> indices, DateTime running, long version){
|
||||
List<String> indices, DateTime running, long version, boolean enabled){
|
||||
this.alertName = alertName;
|
||||
this.queryName = queryName;
|
||||
this.trigger = trigger;
|
||||
|
@ -120,6 +127,7 @@ public class Alert implements ToXContent{
|
|||
this.indices = indices;
|
||||
this.version = version;
|
||||
this.running = running;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,6 +140,8 @@ public class Alert implements ToXContent{
|
|||
builder.field(AlertManager.TIMEPERIOD_FIELD.getPreferredName(), timePeriod);
|
||||
builder.field(AlertManager.LASTRAN_FIELD.getPreferredName(), lastRan);
|
||||
builder.field(AlertManager.CURRENTLY_RUNNING.getPreferredName(), running);
|
||||
builder.field(AlertManager.ENABLED.getPreferredName(), enabled);
|
||||
|
||||
builder.field(AlertManager.TRIGGER_FIELD.getPreferredName());
|
||||
trigger.toXContent(builder, params);
|
||||
builder.field(AlertManager.ACTION_FIELD.getPreferredName());
|
||||
|
|
|
@ -28,17 +28,11 @@ import org.elasticsearch.common.inject.Inject;
|
|||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.*;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -57,6 +51,7 @@ public class AlertManager extends AbstractLifecycleComponent {
|
|||
public static final ParseField LASTRAN_FIELD = new ParseField("lastRan");
|
||||
public static final ParseField INDICES = new ParseField("indices");
|
||||
public static final ParseField CURRENTLY_RUNNING = new ParseField("running");
|
||||
public static final ParseField ENABLED = new ParseField("enabled");
|
||||
|
||||
private final Client client;
|
||||
private AlertScheduler scheduler;
|
||||
|
@ -429,7 +424,26 @@ public class AlertManager extends AbstractLifecycleComponent {
|
|||
logger.warn("Indices : " + fields.get(INDICES.getPreferredName()) + " class " + fields.get(INDICES.getPreferredName()).getClass() );
|
||||
}
|
||||
|
||||
return new Alert(alertId, query, trigger, timePeriod, actions, schedule, lastRan, indices, running, version);
|
||||
boolean enabled = true;
|
||||
if (fields.get(ENABLED.getPreferredName()) != null ) {
|
||||
Object enabledObj = fields.get(ENABLED.getPreferredName());
|
||||
if (enabledObj instanceof Boolean){
|
||||
enabled = (Boolean)enabledObj;
|
||||
} else {
|
||||
if (enabledObj.toString().toLowerCase(Locale.ROOT).equals("true") ||
|
||||
enabledObj.toString().toLowerCase(Locale.ROOT).equals("1")) {
|
||||
enabled = true;
|
||||
} else if ( enabledObj.toString().toLowerCase(Locale.ROOT).equals("false") ||
|
||||
enabledObj.toString().toLowerCase(Locale.ROOT).equals("0")) {
|
||||
enabled = false;
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + enabledObj + "] as a boolean");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new Alert(alertId, query, trigger, timePeriod, actions, schedule, lastRan, indices, running, version, enabled);
|
||||
}
|
||||
|
||||
public Map<String,Alert> getSafeAlertMap() {
|
||||
|
|
|
@ -67,6 +67,9 @@ public class AlertScheduler extends AbstractLifecycleComponent {
|
|||
logger.warn("Running [{}]",alertName);
|
||||
Alert alert = alertManager.getAlertForName(alertName);
|
||||
DateTime scheduledTime = new DateTime(jobExecutionContext.getScheduledFireTime());
|
||||
if (!alert.enabled()) {
|
||||
logger.warn("Alert [{}] is not enabled", alertName);
|
||||
}
|
||||
try {
|
||||
if (!alertManager.claimAlertRun(alertName, scheduledTime) ){
|
||||
logger.warn("Another process has already run this alert.");
|
||||
|
|
|
@ -8,8 +8,6 @@ package org.elasticsearch.alerting;
|
|||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -19,6 +17,16 @@ public class AlertTrigger implements ToXContent {
|
|||
private TriggerType triggerType;
|
||||
private int value;
|
||||
|
||||
public ScriptedAlertTrigger scriptedTrigger() {
|
||||
return scriptedTrigger;
|
||||
}
|
||||
|
||||
public void scriptedTrigger(ScriptedAlertTrigger scriptedTrigger) {
|
||||
this.scriptedTrigger = scriptedTrigger;
|
||||
}
|
||||
|
||||
private ScriptedAlertTrigger scriptedTrigger;
|
||||
|
||||
public SimpleTrigger trigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
@ -49,8 +57,17 @@ public class AlertTrigger implements ToXContent {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
public AlertTrigger(ScriptedAlertTrigger scriptedTrigger){
|
||||
this.scriptedTrigger = scriptedTrigger;
|
||||
this.triggerType = TriggerType.SCRIPT;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return triggerType + " " + trigger + " " + value;
|
||||
if(triggerType != TriggerType.SCRIPT) {
|
||||
return triggerType + " " + trigger + " " + value;
|
||||
} else {
|
||||
return scriptedTrigger.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SimpleTrigger {
|
||||
|
@ -107,19 +124,26 @@ public class AlertTrigger implements ToXContent {
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(triggerType.toString(), trigger.toString() + value);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
if (triggerType != TriggerType.SCRIPT) {
|
||||
builder.startObject();
|
||||
builder.field(triggerType.toString(), trigger.toString() + value);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
} else {
|
||||
return scriptedTrigger.toXContent(builder, params);
|
||||
}
|
||||
}
|
||||
|
||||
public static enum TriggerType {
|
||||
NUMBER_OF_EVENTS;
|
||||
NUMBER_OF_EVENTS,
|
||||
SCRIPT;
|
||||
|
||||
public static TriggerType fromString(final String sTriggerType) {
|
||||
switch (sTriggerType) {
|
||||
case "numberOfEvents":
|
||||
return NUMBER_OF_EVENTS;
|
||||
case "script":
|
||||
return SCRIPT;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unknown AlertTrigger:TriggerType [" + sTriggerType + "]");
|
||||
}
|
||||
|
@ -129,6 +153,8 @@ public class AlertTrigger implements ToXContent {
|
|||
switch (triggerType) {
|
||||
case NUMBER_OF_EVENTS:
|
||||
return "numberOfEvents";
|
||||
case SCRIPT:
|
||||
return "script";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.alerting;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ScriptedAlertTrigger implements ToXContent {
|
||||
public String script;
|
||||
public ScriptService.ScriptType scriptType;
|
||||
public String scriptLang;
|
||||
|
||||
|
||||
public ScriptedAlertTrigger(String script, ScriptService.ScriptType scriptType, String scriptLang) {
|
||||
this.script = script;
|
||||
this.scriptType = scriptType;
|
||||
this.scriptLang = scriptLang;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("script",script);
|
||||
builder.field("script_type", scriptType);
|
||||
builder.field("script_lang", scriptLang);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
}
|
|
@ -10,29 +10,76 @@ import org.elasticsearch.action.search.SearchResponse;
|
|||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/*
|
||||
* TODO : The trigger classes need cleanup and refactoring to be similar to the AlertActions and be pluggable
|
||||
*/
|
||||
public class TriggerManager extends AbstractComponent {
|
||||
|
||||
private final AlertManager alertManager;
|
||||
private final ScriptService scriptService;
|
||||
|
||||
public static AlertTrigger parseTriggerFromMap(Map<String, Object> triggerMap) {
|
||||
|
||||
//For now just trigger on number of events greater than 1
|
||||
for (Map.Entry<String,Object> entry : triggerMap.entrySet()){
|
||||
AlertTrigger.TriggerType type = AlertTrigger.TriggerType.fromString(entry.getKey());
|
||||
|
||||
AlertTrigger.SimpleTrigger simpleTrigger = AlertTrigger.SimpleTrigger.fromString(entry.getValue().toString().substring(0, 1));
|
||||
int value = Integer.valueOf(entry.getValue().toString().substring(1));
|
||||
return new AlertTrigger(simpleTrigger, type, value);
|
||||
if (type == AlertTrigger.TriggerType.SCRIPT) {
|
||||
ScriptedAlertTrigger scriptedTrigger = parseScriptedTrigger(entry.getValue());
|
||||
return new AlertTrigger(scriptedTrigger);
|
||||
} else {
|
||||
AlertTrigger.SimpleTrigger simpleTrigger = AlertTrigger.SimpleTrigger.fromString(entry.getValue().toString().substring(0, 1));
|
||||
int value = Integer.valueOf(entry.getValue().toString().substring(1));
|
||||
return new AlertTrigger(simpleTrigger, type, value);
|
||||
}
|
||||
}
|
||||
throw new ElasticsearchIllegalArgumentException();
|
||||
}
|
||||
private static ScriptedAlertTrigger parseScriptedTrigger(Object value) {
|
||||
if (value instanceof Map) {
|
||||
Map<String,Object> valueMap = (Map<String,Object>)value;
|
||||
try {
|
||||
return new ScriptedAlertTrigger(valueMap.get("script").toString(),
|
||||
ScriptService.ScriptType.valueOf(valueMap.get("script_type").toString()),
|
||||
valueMap.get("script_lang").toString());
|
||||
} catch (Exception e){
|
||||
throw new ElasticsearchIllegalArgumentException("Unable to parse " + value + " as a ScriptedAlertTrigger");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unable to parse " + value + " as a ScriptedAlertTrigger");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
public TriggerManager(Settings settings, AlertManager alertManager) {
|
||||
public TriggerManager(Settings settings, AlertManager alertManager, ScriptService scriptService) {
|
||||
super(settings);
|
||||
this.alertManager = alertManager;
|
||||
this.scriptService = scriptService;
|
||||
}
|
||||
|
||||
public boolean doScriptTrigger(ScriptedAlertTrigger scriptTrigger, SearchResponse response) {
|
||||
try {
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
builder = response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
Map<String, Object> responseMap = XContentHelper.convertToMap(builder.bytes(), false).v2();
|
||||
ExecutableScript executable = scriptService.executable(scriptTrigger.scriptLang, scriptTrigger.script,
|
||||
scriptTrigger.scriptType, responseMap);
|
||||
Object returnValue = executable.run();
|
||||
logger.warn("Returned [{}] from script", returnValue);
|
||||
} catch (Exception e ){
|
||||
logger.error("Failed to execute script trigger", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTriggered(String alertName, SearchResponse response) {
|
||||
|
@ -46,6 +93,8 @@ public class TriggerManager extends AbstractComponent {
|
|||
case NUMBER_OF_EVENTS:
|
||||
testValue = response.getHits().getTotalHits();
|
||||
break;
|
||||
case SCRIPT:
|
||||
return doScriptTrigger(alert.trigger().scriptedTrigger(), response);
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Bad value for trigger.triggerType [" + alert.trigger().triggerType() + "]");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue