-
Notifications
You must be signed in to change notification settings - Fork 132
PPL Alerting: Models #1955
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
PPL Alerting: Models #1955
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
2ebfb97
PPL Alerting Models
toepkerd-zz e30b55e
correcting readFrom in PPLTriggerRunResult
toepkerd-zz 9c54e86
adding minutes to duration fields, changing name from PPLMonitor to P…
toepkerd-zz ff0458f
adjusting comment positions
toepkerd-zz 7cee3c2
adding description field to monitor
toepkerd-zz 95b5fe3
adding description javadoc
toepkerd-zz 34a3e77
various refactors
toepkerd-zz 79e9699
making alert initiate its own parsing pointer
toepkerd-zz 2827aea
adding number of results value validations
toepkerd-zz 92491f2
adding full stops to error messages
toepkerd-zz 5b7b9a2
adding another missing full stop
toepkerd-zz f968289
renaming customer exposed field name back to ppl_monitor
toepkerd-zz 8eb0651
renaming PPL to PPL_SQL in certain places
toepkerd-zz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
255 changes: 255 additions & 0 deletions
255
alerting/src/main/kotlin/org/opensearch/alerting/modelv2/AlertV2.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,255 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.alerting.modelv2 | ||
|
|
||
| import org.opensearch.alerting.core.util.nonOptionalTimeField | ||
| import org.opensearch.alerting.modelv2.TriggerV2.Severity | ||
| import org.opensearch.common.lucene.uid.Versions | ||
| import org.opensearch.commons.alerting.util.instant | ||
| import org.opensearch.commons.alerting.util.optionalUserField | ||
| import org.opensearch.commons.authuser.User | ||
| import org.opensearch.core.common.io.stream.StreamInput | ||
| import org.opensearch.core.common.io.stream.StreamOutput | ||
| import org.opensearch.core.common.io.stream.Writeable | ||
| import org.opensearch.core.xcontent.ToXContent | ||
| import org.opensearch.core.xcontent.XContentBuilder | ||
| import org.opensearch.core.xcontent.XContentParser | ||
| import org.opensearch.core.xcontent.XContentParserUtils.ensureExpectedToken | ||
| import java.io.IOException | ||
| import java.time.Instant | ||
|
|
||
| /** | ||
| * Alert generated by Alerting V2 | ||
| * An alert is created when a Trigger's trigger conditions are met. | ||
| * | ||
| * @property id Alert ID. Defaults to [NO_ID]. | ||
| * @property version Version number of the Alert. Defaults to [NO_VERSION]. | ||
| * @property schemaVersion Version of the alerting-alerts index schema when this Alert was indexed. Defaults to [NO_SCHEMA_VERSION]. | ||
| * @property monitorId ID of the Monitor that generated this Alert. | ||
| * @property monitorName Name of the Monitor that generated this Alert. | ||
| * @property monitorVersion Version of the Monitor at the time it generated this Alert. | ||
| * @property triggerId ID of the Trigger in the Monitor that generated this alert. | ||
| * @property triggerName Name of the trigger in the Monitor that generated this alert. | ||
| * @property queryResults Results from the Monitor's query that caused the Trigger to fire. | ||
| * @property triggeredTime Timestamp for when the Alert was generated. | ||
| * @property errorMessage Optional error message if there were issues during Trigger execution. | ||
| * Null indicates no errors occurred. | ||
| * @property severity Severity level of the alert (e.g., "HIGH", "MEDIUM", "LOW"). | ||
| * @property executionId Optional ID for the Monitor execution that generated this Alert. | ||
| * | ||
| * @see MonitorV2 For the monitor that generates alerts | ||
| * @see TriggerV2 For the trigger conditions that create alerts | ||
| * | ||
| * Lifecycle: | ||
| * 1. AlertV2 is generated when a TriggerV2's condition is met. The TriggerV2 fires and forgets the AlertV2. | ||
| * 2. AlertV2 is stored in the alerts index. AlertV2s are stateless. (e.g. they are never ACTIVE or COMPLETED) | ||
| * 3. AlertV2 is soft deleted after its expire duration (determined by its trigger), and archived in an alert history index | ||
| * 4. Based on the alert v2 history retention period, the AlertV2 is permanently deleted | ||
| */ | ||
| data class AlertV2( | ||
| val id: String = NO_ID, | ||
| val version: Long = NO_VERSION, | ||
| val schemaVersion: Int = NO_SCHEMA_VERSION, | ||
| val monitorId: String, | ||
| val monitorName: String, | ||
| val monitorVersion: Long, | ||
| val monitorUser: User?, | ||
| val triggerId: String, | ||
| val triggerName: String, | ||
| val query: String, | ||
| val queryResults: Map<String, Any>, | ||
| val triggeredTime: Instant, | ||
| val errorMessage: String? = null, | ||
| val severity: Severity, | ||
| val executionId: String? = null | ||
| ) : Writeable, ToXContent { | ||
| @Throws(IOException::class) | ||
| constructor(sin: StreamInput) : this( | ||
| id = sin.readString(), | ||
| version = sin.readLong(), | ||
| schemaVersion = sin.readInt(), | ||
| monitorId = sin.readString(), | ||
| monitorName = sin.readString(), | ||
| monitorVersion = sin.readLong(), | ||
| monitorUser = if (sin.readBoolean()) { | ||
| User(sin) | ||
| } else { | ||
| null | ||
| }, | ||
| triggerId = sin.readString(), | ||
| triggerName = sin.readString(), | ||
| query = sin.readString(), | ||
| queryResults = sin.readMap(), | ||
| triggeredTime = sin.readInstant(), | ||
| errorMessage = sin.readOptionalString(), | ||
| severity = sin.readEnum(Severity::class.java), | ||
| executionId = sin.readOptionalString() | ||
| ) | ||
|
|
||
| @Throws(IOException::class) | ||
| override fun writeTo(out: StreamOutput) { | ||
| out.writeString(id) | ||
| out.writeLong(version) | ||
| out.writeInt(schemaVersion) | ||
| out.writeString(monitorId) | ||
| out.writeString(monitorName) | ||
| out.writeLong(monitorVersion) | ||
| out.writeBoolean(monitorUser != null) | ||
| monitorUser?.writeTo(out) | ||
| out.writeString(triggerId) | ||
| out.writeString(triggerName) | ||
| out.writeString(query) | ||
| out.writeMap(queryResults) | ||
| out.writeInstant(triggeredTime) | ||
| out.writeOptionalString(errorMessage) | ||
| out.writeEnum(severity) | ||
| out.writeOptionalString(executionId) | ||
| } | ||
|
|
||
| override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { | ||
| return createXContentBuilder(builder, false) | ||
| } | ||
|
|
||
| fun toXContentWithUser(builder: XContentBuilder): XContentBuilder { | ||
| return createXContentBuilder(builder, true) | ||
| } | ||
|
|
||
| private fun createXContentBuilder(builder: XContentBuilder, withUser: Boolean): XContentBuilder { | ||
| builder.startObject() | ||
| .field(ALERT_V2_ID_FIELD, id) | ||
| .field(ALERT_V2_VERSION_FIELD, version) | ||
| .field(MONITOR_V2_ID_FIELD, monitorId) | ||
| .field(SCHEMA_VERSION_FIELD, schemaVersion) | ||
| .field(MONITOR_V2_VERSION_FIELD, monitorVersion) | ||
| .field(MONITOR_V2_NAME_FIELD, monitorName) | ||
| .field(EXECUTION_ID_FIELD, executionId) | ||
| .field(TRIGGER_V2_ID_FIELD, triggerId) | ||
| .field(TRIGGER_V2_NAME_FIELD, triggerName) | ||
| .field(QUERY_FIELD, query) | ||
| .field(QUERY_RESULTS_FIELD, queryResults) | ||
| .field(ERROR_MESSAGE_FIELD, errorMessage) | ||
| .field(SEVERITY_FIELD, severity.value) | ||
| .nonOptionalTimeField(TRIGGERED_TIME_FIELD, triggeredTime) | ||
|
|
||
| if (withUser) { | ||
| builder.optionalUserField(MONITOR_V2_USER_FIELD, monitorUser) | ||
| } | ||
|
|
||
| builder.endObject() | ||
|
|
||
| return builder | ||
| } | ||
|
|
||
| fun asTemplateArg(): Map<String, Any?> { | ||
| return mapOf( | ||
| ALERT_V2_ID_FIELD to id, | ||
| ALERT_V2_VERSION_FIELD to version, | ||
| ERROR_MESSAGE_FIELD to errorMessage, | ||
| EXECUTION_ID_FIELD to executionId, | ||
| SEVERITY_FIELD to severity.value | ||
| ) | ||
| } | ||
|
|
||
| companion object { | ||
| const val ALERT_V2_ID_FIELD = "id" | ||
| const val ALERT_V2_VERSION_FIELD = "version" | ||
| const val MONITOR_V2_ID_FIELD = "monitor_v2_id" | ||
| const val MONITOR_V2_VERSION_FIELD = "monitor_v2_version" | ||
| const val MONITOR_V2_NAME_FIELD = "monitor_v2_name" | ||
| const val MONITOR_V2_USER_FIELD = "monitor_v2_user" | ||
| const val TRIGGER_V2_ID_FIELD = "trigger_v2_id" | ||
| const val TRIGGER_V2_NAME_FIELD = "trigger_v2_name" | ||
| const val TRIGGERED_TIME_FIELD = "triggered_time" | ||
| const val QUERY_FIELD = "query" | ||
| const val QUERY_RESULTS_FIELD = "query_results" | ||
| const val ERROR_MESSAGE_FIELD = "error_message" | ||
| const val EXECUTION_ID_FIELD = "execution_id" | ||
| const val SEVERITY_FIELD = "severity" | ||
| const val SCHEMA_VERSION_FIELD = "schema_version" | ||
|
|
||
| const val NO_ID = "" | ||
| const val NO_VERSION = Versions.NOT_FOUND | ||
| const val NO_SCHEMA_VERSION = 0 | ||
|
|
||
| @JvmStatic | ||
| @JvmOverloads | ||
| @Throws(IOException::class) | ||
| fun parse(xcp: XContentParser, id: String = NO_ID, version: Long = NO_VERSION): AlertV2 { | ||
|
eirsep marked this conversation as resolved.
|
||
| var schemaVersion = NO_SCHEMA_VERSION | ||
| lateinit var monitorId: String | ||
| lateinit var monitorName: String | ||
| var monitorVersion: Long = Versions.NOT_FOUND | ||
| var monitorUser: User? = null | ||
| lateinit var triggerId: String | ||
| lateinit var triggerName: String | ||
| lateinit var query: String | ||
| var queryResults: Map<String, Any> = mapOf() | ||
| lateinit var severity: Severity | ||
| var triggeredTime: Instant? = null | ||
| var errorMessage: String? = null | ||
| var executionId: String? = null | ||
|
|
||
| ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.nextToken(), xcp) | ||
| while (xcp.nextToken() != XContentParser.Token.END_OBJECT) { | ||
| val fieldName = xcp.currentName() | ||
| xcp.nextToken() | ||
|
|
||
| when (fieldName) { | ||
| MONITOR_V2_ID_FIELD -> monitorId = xcp.text() | ||
| SCHEMA_VERSION_FIELD -> schemaVersion = xcp.intValue() | ||
| MONITOR_V2_NAME_FIELD -> monitorName = xcp.text() | ||
| MONITOR_V2_VERSION_FIELD -> monitorVersion = xcp.longValue() | ||
| MONITOR_V2_USER_FIELD -> | ||
| monitorUser = if (xcp.currentToken() == XContentParser.Token.VALUE_NULL) { | ||
| null | ||
| } else { | ||
| User.parse(xcp) | ||
| } | ||
| TRIGGER_V2_ID_FIELD -> triggerId = xcp.text() | ||
| TRIGGER_V2_NAME_FIELD -> triggerName = xcp.text() | ||
| QUERY_FIELD -> query = xcp.text() | ||
| QUERY_RESULTS_FIELD -> queryResults = xcp.map() | ||
| TRIGGERED_TIME_FIELD -> triggeredTime = xcp.instant() | ||
| ERROR_MESSAGE_FIELD -> errorMessage = xcp.textOrNull() | ||
| EXECUTION_ID_FIELD -> executionId = xcp.textOrNull() | ||
| TriggerV2.SEVERITY_FIELD -> { | ||
| val input = xcp.text() | ||
| val enumMatchResult = Severity.enumFromString(input) | ||
| ?: throw IllegalArgumentException( | ||
| "Invalid value for ${TriggerV2.SEVERITY_FIELD}: $input. " + | ||
| "Supported values are ${Severity.entries.map { it.value }}" | ||
| ) | ||
| severity = enumMatchResult | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return AlertV2( | ||
| id = id, | ||
| version = version, | ||
| schemaVersion = schemaVersion, | ||
| monitorId = requireNotNull(monitorId), | ||
| monitorName = requireNotNull(monitorName), | ||
| monitorVersion = monitorVersion, | ||
| monitorUser = monitorUser, | ||
| triggerId = requireNotNull(triggerId), | ||
| triggerName = requireNotNull(triggerName), | ||
| query = requireNotNull(query), | ||
| queryResults = requireNotNull(queryResults), | ||
| triggeredTime = requireNotNull(triggeredTime), | ||
| errorMessage = errorMessage, | ||
| severity = severity, | ||
| executionId = executionId | ||
| ) | ||
| } | ||
|
|
||
| @JvmStatic | ||
| @Throws(IOException::class) | ||
| fun readFrom(sin: StreamInput): AlertV2 { | ||
| return AlertV2(sin) | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.