feat(alerting): core domain records (rule, instance, silence, notification)
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertInstance(
|
||||||
|
UUID id,
|
||||||
|
UUID ruleId, // nullable after rule deletion
|
||||||
|
Map<String, Object> ruleSnapshot,
|
||||||
|
UUID environmentId,
|
||||||
|
AlertState state,
|
||||||
|
AlertSeverity severity,
|
||||||
|
Instant firedAt,
|
||||||
|
Instant ackedAt,
|
||||||
|
String ackedBy,
|
||||||
|
Instant resolvedAt,
|
||||||
|
Instant lastNotifiedAt,
|
||||||
|
boolean silenced,
|
||||||
|
Double currentValue,
|
||||||
|
Double threshold,
|
||||||
|
Map<String, Object> context,
|
||||||
|
String title,
|
||||||
|
String message,
|
||||||
|
List<String> targetUserIds,
|
||||||
|
List<UUID> targetGroupIds,
|
||||||
|
List<String> targetRoleNames) {
|
||||||
|
|
||||||
|
public AlertInstance {
|
||||||
|
ruleSnapshot = ruleSnapshot == null ? Map.of() : Map.copyOf(ruleSnapshot);
|
||||||
|
context = context == null ? Map.of() : Map.copyOf(context);
|
||||||
|
targetUserIds = targetUserIds == null ? List.of() : List.copyOf(targetUserIds);
|
||||||
|
targetGroupIds = targetGroupIds == null ? List.of() : List.copyOf(targetGroupIds);
|
||||||
|
targetRoleNames = targetRoleNames == null ? List.of() : List.copyOf(targetRoleNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertNotification(
|
||||||
|
UUID id,
|
||||||
|
UUID alertInstanceId,
|
||||||
|
UUID webhookId,
|
||||||
|
UUID outboundConnectionId,
|
||||||
|
NotificationStatus status,
|
||||||
|
int attempts,
|
||||||
|
Instant nextAttemptAt,
|
||||||
|
String claimedBy,
|
||||||
|
Instant claimedUntil,
|
||||||
|
Integer lastResponseStatus,
|
||||||
|
String lastResponseSnippet,
|
||||||
|
Map<String, Object> payload,
|
||||||
|
Instant deliveredAt,
|
||||||
|
Instant createdAt) {
|
||||||
|
|
||||||
|
public AlertNotification {
|
||||||
|
payload = payload == null ? Map.of() : Map.copyOf(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertRule(
|
||||||
|
UUID id,
|
||||||
|
UUID environmentId,
|
||||||
|
String name,
|
||||||
|
String description,
|
||||||
|
AlertSeverity severity,
|
||||||
|
boolean enabled,
|
||||||
|
ConditionKind conditionKind,
|
||||||
|
AlertCondition condition,
|
||||||
|
int evaluationIntervalSeconds,
|
||||||
|
int forDurationSeconds,
|
||||||
|
int reNotifyMinutes,
|
||||||
|
String notificationTitleTmpl,
|
||||||
|
String notificationMessageTmpl,
|
||||||
|
List<WebhookBinding> webhooks,
|
||||||
|
List<AlertRuleTarget> targets,
|
||||||
|
Instant nextEvaluationAt,
|
||||||
|
String claimedBy,
|
||||||
|
Instant claimedUntil,
|
||||||
|
Map<String, Object> evalState,
|
||||||
|
Instant createdAt,
|
||||||
|
String createdBy,
|
||||||
|
Instant updatedAt,
|
||||||
|
String updatedBy) {
|
||||||
|
|
||||||
|
public AlertRule {
|
||||||
|
webhooks = webhooks == null ? List.of() : List.copyOf(webhooks);
|
||||||
|
targets = targets == null ? List.of() : List.copyOf(targets);
|
||||||
|
evalState = evalState == null ? Map.of() : Map.copyOf(evalState);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertRuleTarget(UUID id, UUID ruleId, TargetKind kind, String targetId) {}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record AlertSilence(
|
||||||
|
UUID id,
|
||||||
|
UUID environmentId,
|
||||||
|
SilenceMatcher matcher,
|
||||||
|
String reason,
|
||||||
|
Instant startsAt,
|
||||||
|
Instant endsAt,
|
||||||
|
String createdBy,
|
||||||
|
Instant createdAt) {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record SilenceMatcher(
|
||||||
|
UUID ruleId, String appSlug, String routeId, String agentId, AlertSeverity severity) {
|
||||||
|
|
||||||
|
public boolean isWildcard() {
|
||||||
|
return ruleId == null && appSlug == null && routeId == null && agentId == null && severity == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record WebhookBinding(
|
||||||
|
UUID id,
|
||||||
|
UUID outboundConnectionId,
|
||||||
|
String bodyOverride,
|
||||||
|
Map<String, String> headerOverrides) {
|
||||||
|
|
||||||
|
public WebhookBinding {
|
||||||
|
headerOverrides = headerOverrides == null ? Map.of() : Map.copyOf(headerOverrides);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.cameleer.server.core.alerting;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class AlertDomainRecordsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void alertRuleDefensiveCopy() {
|
||||||
|
var webhooks = new java.util.ArrayList<WebhookBinding>();
|
||||||
|
webhooks.add(new WebhookBinding(UUID.randomUUID(), UUID.randomUUID(), null, null));
|
||||||
|
var r = newRule(webhooks);
|
||||||
|
webhooks.clear();
|
||||||
|
assertThat(r.webhooks()).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void silenceMatcherAllFieldsNullMatchesEverything() {
|
||||||
|
var m = new SilenceMatcher(null, null, null, null, null);
|
||||||
|
assertThat(m.isWildcard()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertRule newRule(List<WebhookBinding> wh) {
|
||||||
|
return new AlertRule(
|
||||||
|
UUID.randomUUID(), UUID.randomUUID(), "r", null,
|
||||||
|
AlertSeverity.WARNING, true, ConditionKind.AGENT_STATE,
|
||||||
|
new AgentStateCondition(new AlertScope(null,null,null), "DEAD", 60),
|
||||||
|
60, 0, 60, "t", "m", wh, List.of(),
|
||||||
|
Instant.now(), null, null, Map.of(),
|
||||||
|
Instant.now(), "u1", Instant.now(), "u1");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user