Skip to content

Commit 5d0bba2

Browse files
committed
feat(alerts): add status update events and enhance query filters for alerts
1 parent 8fe47a6 commit 5d0bba2

File tree

6 files changed

+66
-20
lines changed

6 files changed

+66
-20
lines changed

backend/src/main/java/com/park/utmstack/config/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public final class Constants {
7474
// - Alert index common fields
7575
// ----------------------------------------------------------------------------------
7676
public static final String alertIdKeyword = "id.keyword";
77+
public static final String parentIdKeyword = "parentId.keyword";
7778
public static final String alertStatus = "status";
7879
public static final String alertTags = "tags";
7980
public static final String alertIsIncident = "isIncident";

backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public enum ApplicationEventType {
1313
ACCESS_DENIED,
1414
ALERT_UPDATE_ATTEMPT,
1515
ALERT_UPDATE_SUCCESS,
16+
ALERT_STATUS_UPDATE_ATTEMPT,
17+
ALERT_STATUS_UPDATE_SUCCESS,
1618
ALERT_NOTE_UPDATE_ATTEMPT,
1719
ALERT_NOTE_UPDATE_SUCCESS,
1820
ALERT_TAG_UPDATE_ATTEMPT,

backend/src/main/java/com/park/utmstack/domain/chart_builder/types/query/OperatorType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public enum OperatorType {
1010
IS_ONE_OF,
1111
IS_NOT_ONE_OF,
1212
IS_ONE_OF_TERMS,
13+
IS_ONE_OF_TERMS_OR,
1314
EXIST,
1415
DOES_NOT_EXIST,
1516
IS_BETWEEN,
@@ -22,4 +23,5 @@ public enum OperatorType {
2223
NOT_START_WITH,
2324
IS_GREATER_THAN,
2425
IS_LESS_THAN_OR_EQUALS
26+
2527
}

backend/src/main/java/com/park/utmstack/service/elasticsearch/SearchUtil.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ public class SearchUtil {
3131
public static Query toQuery(List<FilterType> filters) {
3232
final String ctx = CLASSNAME + ".toQuery";
3333
try {
34+
boolean hasShouldClauses = false;
3435
BoolQuery.Builder bool = new BoolQuery.Builder();
35-
bool.filter(Query.of(q -> q.matchAll(MatchAllQuery.of(m -> m))));
36+
/*bool.filter(Query.of(q -> q.matchAll(MatchAllQuery.of(m -> m))));*/
3637

3738
if (!CollectionUtils.isEmpty(filters)) {
3839
for (FilterType filter : filters) {
@@ -100,9 +101,18 @@ public static Query toQuery(List<FilterType> filters) {
100101
case IS_LESS_THAN_OR_EQUALS:
101102
buildIsLessThanOrEquals(bool, filter);
102103
break;
104+
case IS_ONE_OF_TERMS_OR:
105+
hasShouldClauses = true;
106+
buildIsOneOfOr(bool, filter);
107+
break;
103108
}
104109
}
105110
}
111+
112+
if (hasShouldClauses) {
113+
bool.minimumShouldMatch("1");
114+
}
115+
106116
return Query.of(q -> q.bool(bool.build()));
107117
} catch (Exception e) {
108118
throw new RuntimeException(ctx + ": " + e.getLocalizedMessage());
@@ -373,6 +383,16 @@ private static void buildIsLessThanOrEquals(BoolQuery.Builder bool, FilterType f
373383
}
374384
}
375385

386+
private static void buildIsOneOfOr(BoolQuery.Builder bool, FilterType filter) {
387+
List<FieldValue> termsValues = ((List<?>) filter.getValue()).stream().map(str -> FieldValue.of((String) str)).toList();
388+
389+
Query termsQuery = Query.of(q -> q.terms(t -> t
390+
.field(filter.getField())
391+
.terms(terms -> terms.value(termsValues))));
392+
393+
bool.should(termsQuery);
394+
}
395+
376396
/**
377397
* Apply a sort to a elasticsearch query
378398
*

backend/src/main/java/com/park/utmstack/service/impl/UtmAlertServiceImpl.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.park.utmstack.util.exceptions.UtmElasticsearchException;
3030
import com.utmstack.opensearch_connector.parsers.TermAggregateParser;
3131
import com.utmstack.opensearch_connector.types.BucketAggregation;
32+
import lombok.RequiredArgsConstructor;
3233
import org.apache.commons.text.StringEscapeUtils;
3334
import org.opensearch.client.opensearch._types.query_dsl.Query;
3435
import org.opensearch.client.opensearch.core.SearchRequest;
@@ -52,6 +53,7 @@
5253
import java.util.stream.Collectors;
5354

5455
@Service
56+
@RequiredArgsConstructor
5557
@Transactional
5658
public class UtmAlertServiceImpl implements UtmAlertService {
5759

@@ -67,22 +69,7 @@ public class UtmAlertServiceImpl implements UtmAlertService {
6769
private final SocAIService socAIService;
6870
private final UtmAlertResponseRuleService alertResponseRuleService;
6971

70-
public UtmAlertServiceImpl(MailService mailService,
71-
ApplicationEventService eventService,
72-
AlertPointcut alertPointcut,
73-
UtmAlertLastRepository lastAlertRepository,
74-
ElasticsearchService elasticsearchService,
75-
UtmModuleService moduleService, SocAIService socAIService,
76-
UtmAlertResponseRuleService alertResponseRuleService) {
77-
this.mailService = mailService;
78-
this.eventService = eventService;
79-
this.alertPointcut = alertPointcut;
80-
this.lastAlertRepository = lastAlertRepository;
81-
this.elasticsearchService = elasticsearchService;
82-
this.moduleService = moduleService;
83-
this.socAIService = socAIService;
84-
this.alertResponseRuleService = alertResponseRuleService;
85-
}
72+
8673

8774
@EventListener(RulesEvaluationEndEvent.class)
8875
public void checkForNewAlerts() {
@@ -177,13 +164,24 @@ private List<LogType> getRelatedAlerts(List<String> logs) throws UtmElasticsearc
177164
public void updateStatus(List<String> alertIds, int status, String statusObservation) throws
178165
ElasticsearchIndexDocumentUpdateException {
179166
final String ctx = CLASS_NAME + ".updateStatus";
167+
long start = System.currentTimeMillis();
180168
try {
169+
String alertsIds = String.join(",", alertIds);
170+
Map<String, Object> extra = Map.of(
171+
"alertIds", alertsIds,
172+
"newStatus", status
173+
);
174+
175+
String attemptMsg = String.format("Attempt to update status to %1$s for alerts with ids: %2$s",
176+
AlertStatus.getByCode(status).getName(), alertsIds);
177+
eventService.createEvent(attemptMsg, ApplicationEventType.ALERT_STATUS_UPDATE_ATTEMPT, extra);
181178
String ruleScript = "ctx._source.status=%1$s;" +
182179
"ctx._source.statusLabel='%2$s';" +
183180
"ctx._source.statusObservation=\"%3$s\";";
184181

185182
List<FilterType> filters = new ArrayList<>();
186-
filters.add(new FilterType(Constants.alertIdKeyword, OperatorType.IS_ONE_OF_TERMS, alertIds));
183+
filters.add(new FilterType(Constants.alertIdKeyword, OperatorType.IS_ONE_OF_TERMS_OR, alertIds));
184+
filters.add(new FilterType(Constants.parentIdKeyword, OperatorType.IS_ONE_OF_TERMS_OR, alertIds));
187185

188186
String script = String.format(ruleScript, status,
189187
AlertStatus.getByCode(status).getName(), StringEscapeUtils.escapeJava(statusObservation));
@@ -192,6 +190,11 @@ public void updateStatus(List<String> alertIds, int status, String statusObserva
192190

193191
elasticsearchService.updateByQuery(SearchUtil.toQuery(filters),
194192
Constants.SYS_INDEX_PATTERN.get(SystemIndexPattern.ALERTS), script);
193+
194+
long duration = System.currentTimeMillis() - start;
195+
String successMsg = String.format("Status updated to %1$s for alerts with ids: %2$s in %3$s ms",
196+
AlertStatus.getByCode(status).getName(), alertsIds, duration);
197+
eventService.createEvent(successMsg, ApplicationEventType.ALERT_NOTE_UPDATE_SUCCESS, extra);
195198
} catch (Exception e) {
196199
throw new ElasticsearchIndexDocumentUpdateException(ctx + ": " + e.getMessage());
197200
}

backend/src/main/java/com/park/utmstack/web/rest/elasticsearch/ElasticsearchResource.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.park.utmstack.domain.application_events.enums.ApplicationEventType;
44
import com.park.utmstack.domain.chart_builder.types.query.FilterType;
5+
import com.park.utmstack.domain.chart_builder.types.query.OperatorType;
56
import com.park.utmstack.domain.shared_types.CsvExportingParams;
67
import com.park.utmstack.service.application_events.ApplicationEventService;
78
import com.park.utmstack.service.elasticsearch.ElasticsearchService;
@@ -146,6 +147,7 @@ public ResponseEntity<Void> deleteIndex(@RequestBody List<String> indexes) {
146147
@PostMapping("/search")
147148
public ResponseEntity<List<Map>> search(@RequestBody(required = false) List<FilterType> filters,
148149
@RequestParam Integer top, @RequestParam String indexPattern,
150+
@RequestParam(required = false, defaultValue = "false") boolean includeChildren,
149151
Pageable pageable) {
150152
final String ctx = CLASSNAME + ".search";
151153
try {
@@ -159,8 +161,24 @@ public ResponseEntity<List<Map>> search(@RequestBody(required = false) List<Filt
159161
HttpHeaders headers = UtilPagination.generatePaginationHttpHeaders(Math.min(hits.total().value(), top),
160162
pageable.getPageNumber(), pageable.getPageSize(), "/api/elasticsearch/search");
161163

162-
return ResponseEntity.ok().headers(headers).body(hits.hits().stream()
163-
.map(Hit::source).collect(Collectors.toList()));
164+
List<Map> results = hits.hits().stream()
165+
.map(Hit::source)
166+
.toList();
167+
168+
if (includeChildren) {
169+
results.forEach(d -> {
170+
Object id = d.get("id");
171+
if (id != null) {
172+
boolean hasChildren = elasticsearchService.exists(
173+
List.of(new FilterType("parentId", OperatorType.IS, id.toString())),
174+
indexPattern
175+
);
176+
d.put("hasChildren", hasChildren);
177+
}
178+
});
179+
}
180+
181+
return ResponseEntity.ok().headers(headers).body(results);
164182
} catch (Exception e) {
165183
String msg = ctx + ": " + e.getMessage();
166184
log.error(msg);

0 commit comments

Comments
 (0)