Documentation
¶
Overview ¶
Package watcher parses Elasticsearch Watcher definitions (the exact PUT _watcher/watch body) and projects them onto Coremetry alert rules — Faz-1 of the operator requirement "birebir aynı Watcher JSON'ı Coremetry çalışabilsin" (v0.9.x).
Design contract:
- Field names mirror the ES Watcher schema verbatim. Anything we don't interpret rides along as json.RawMessage — the FULL raw JSON is stored on the rule (AlertRule.WatcherJSON) so the definition round-trips byte-identical regardless of what this package understands.
- Parse never rejects unknown fields; it records them so Validate can report "preserved but ignored".
- Validate is a field-by-field mapping report (Supported / Partial / Unsupported + reason), the honest contract shown to the operator at import time.
- ToRule is the executable projection: metric="watcher", comparator/threshold from condition.compare, window from the schedule interval, cooldown from throttle_period. Watches whose condition cannot be evaluated (script / never / non-hits.total compare) or that have no search input import DISABLED — the definition is kept, nothing silently fires wrong.
Pure package: no store, no network. The evaluator executes the projected rules via logstore.RawSearch.
Index ¶
- func NextFire(expr string, after time.Time) (time.Time, error)
- func NormalizeDevTools(raw []byte) []byte
- type Action
- type CompareClause
- type CondKind
- type Condition
- type ConditionSpec
- type CronSchedule
- type Finding
- type Input
- type Report
- type Schedule
- type SearchInput
- type SearchRequest
- type Support
- type Trigger
- type Watch
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NextFire ¶ added in v0.9.202
NextFire parses expr and returns the next fire time strictly after `after`. Unparseable expressions and schedules with no future fire time (e.g. an exhausted year constraint) error.
func NormalizeDevTools ¶
NormalizeDevTools converts Kibana DevTools' triple-quoted string syntax ("""…raw body…""" — not valid JSON) into properly escaped JSON strings, so an operator can paste a watch straight out of the DevTools console (v0.9.x — review improvement b). Input without `"""` is returned UNCHANGED (byte-identical — the verbatim-storage contract holds); the import path stores the NORMALIZED form, since the evaluator re-parses the stored definition as JSON on every run. An unterminated `"""` is left as-is for Parse to reject with a pointer.
Types ¶
type Action ¶
type Action struct {
Email json.RawMessage `json:"email,omitempty"`
Webhook json.RawMessage `json:"webhook,omitempty"`
Slack json.RawMessage `json:"slack,omitempty"`
Logging json.RawMessage `json:"logging,omitempty"`
Index json.RawMessage `json:"index,omitempty"`
// Per-action modifiers.
ThrottlePeriod string `json:"throttle_period,omitempty"`
Condition json.RawMessage `json:"condition,omitempty"`
Transform json.RawMessage `json:"transform,omitempty"`
// Other lists action kinds this package doesn't model
// (pagerduty, jira, …) — reported Unsupported.
Other []string `json:"-"`
}
Action is one named entry under "actions". Kind payloads ride raw — Faz-1 never executes them (Coremetry's own notification channels fire on problem open/resolve); they're kept for round-trip + report.
func (*Action) UnmarshalJSON ¶
type CompareClause ¶
CompareClause is one {op: value} object, e.g. {"gte": 100}.
type CondKind ¶ added in v0.9.202
type CondKind int
CondKind classifies how the evaluator obtains the value it compares.
const ( // CondAlways — no condition / always / empty compare: fires // whenever the search runs (hits.total >= 0). CondAlways CondKind = iota // CondHitsTotal — compare on ctx.payload.hits.total(.value). CondHitsTotal // CondAggValue — compare on a ctx.payload.aggregations.… path. CondAggValue // CondArrayCompare — array_compare over an aggregations array: // fires when ANY element matches (value = MAX of the matches). CondArrayCompare )
type Condition ¶
type Condition struct {
Compare map[string]CompareClause `json:"compare,omitempty"`
ArrayCompare json.RawMessage `json:"array_compare,omitempty"`
Script json.RawMessage `json:"script,omitempty"`
Always bool `json:"-"`
Never bool `json:"-"`
}
Condition — compare on ctx.payload.hits.total is the executable subset; always maps to unconditional fire, never to a disabled rule; script / array_compare have no engine here.
func (*Condition) UnmarshalJSON ¶
UnmarshalJSON handles the presence-typed always/never members ({"always": {}}) alongside the object-valued kinds.
type ConditionSpec ¶ added in v0.9.202
type ConditionSpec struct {
Kind CondKind
Path string // CondAggValue: dotted payload path
ArrayPath string // CondArrayCompare: path to the array
ItemPath string // CondArrayCompare: per-element path ("" = the element itself)
Comparator string
Threshold float64
}
ConditionSpec is the executable projection of the watch condition. Path/ArrayPath come back PAYLOAD-RELATIVE (the "ctx.payload." prefix stripped) so the evaluator can walk the RawSearchPayload result — {"hits":{"total":{"value":N}},"aggregations":{…}} — directly. Comparator is in the evaluator's set (> >= < <=).
type CronSchedule ¶ added in v0.9.202
type CronSchedule struct {
// contains filtered or unexported fields
}
CronSchedule is a parsed Quartz expression in the supported subset.
func ParseCron ¶ added in v0.9.202
func ParseCron(expr string) (*CronSchedule, error)
ParseCron validates a Quartz cron expression against the supported subset and returns the parsed schedule. Errors carry the reason the Validate report shows the operator.
type Finding ¶
type Finding struct {
Field string `json:"field"`
Status Support `json:"status"`
Reason string `json:"reason"`
}
Finding is one field's verdict with the reason an operator reads at import time.
type Input ¶
type Input struct {
Search *SearchInput `json:"search,omitempty"`
Simple json.RawMessage `json:"simple,omitempty"`
HTTP json.RawMessage `json:"http,omitempty"`
Chain json.RawMessage `json:"chain,omitempty"`
}
Input — search is the only kind Faz-1 executes; http / simple / chain are preserved raw and reported Unsupported.
type Report ¶
type Report struct {
Findings []Finding `json:"findings"`
Disabled bool `json:"disabled"`
DisabledReason string `json:"disabledReason,omitempty"`
}
Report is the whole-watch mapping verdict. Disabled means the projected rule cannot (or must not) run and imports with Enabled=false; the definition itself is always kept.
func ToRule ¶
ToRule projects a parsed watch onto an executable alert rule and returns the mapping report alongside. The caller (Faz-2 import API) assigns ID and, when metadata.name is absent, Name. raw is stored verbatim on the rule for round-trip + re-evaluation.
func Validate ¶
Validate produces the field-by-field mapping report for a parsed watch. It never mutates the watch.
func (Report) HasUnsupported ¶
HasUnsupported reports whether any finding is Unsupported.
type Schedule ¶
type Schedule struct {
Interval string `json:"interval,omitempty"`
Cron []string `json:"cron,omitempty"`
Other []string `json:"-"`
}
Schedule is the parsed trigger.schedule. Interval keeps the ES string form ("5m"); a numeric interval (seconds) is normalised to "Ns". Cron carries the expression(s) — string or array in ES. Other lists further schedule kinds present (hourly / daily / …).
func (*Schedule) HasTimezone ¶ added in v0.9.202
HasTimezone — trigger.schedule bir timezone anahtarı taşıyor mu (ES 8.13+; UnmarshalJSON bilinmeyen anahtarları Other'a düşürür). v0.9.202: timezone'lu cron takvim yoluna ALINMAZ — UTC pacing ES'in tz-aware ateşlemesinden saatlerce kayar (kanıtlı 3h drift).
func (*Schedule) UnmarshalJSON ¶
UnmarshalJSON tolerates the ES shapes: interval as string or number-of-seconds, cron as string or []string, plus any other schedule kind recorded by name.
type SearchInput ¶
type SearchInput struct {
Request SearchRequest `json:"request"`
Extract json.RawMessage `json:"extract,omitempty"`
Timeout string `json:"timeout,omitempty"`
}
type SearchRequest ¶
type SearchRequest struct {
Indices indices `json:"indices,omitempty"`
Body json.RawMessage `json:"body,omitempty"`
Template json.RawMessage `json:"template,omitempty"`
SearchType string `json:"search_type,omitempty"`
IndicesOptions json.RawMessage `json:"indices_options,omitempty"`
// RestTotalHitsAsInt is a response-SHAPE flag (hits.total as a
// bare int instead of {value, relation}); Coremetry issues the
// search itself and reads hits.total.value directly, so this is
// ignored by design — reported Supported, not scary-Partial.
RestTotalHitsAsInt bool `json:"rest_total_hits_as_int,omitempty"`
}
SearchRequest carries the ES search verbatim: indices + body pass straight through to logstore.RawSearch (which injects the cost guards). Template / indices_options ride raw.
type Support ¶
type Support string
Support classifies how faithfully one watcher field maps onto Coremetry's evaluator.
type Trigger ¶
type Trigger struct {
Schedule *Schedule `json:"schedule,omitempty"`
}
Trigger — only the schedule trigger exists in ES today.
type Watch ¶
type Watch struct {
Trigger *Trigger `json:"trigger,omitempty"`
Input *Input `json:"input,omitempty"`
Condition *Condition `json:"condition,omitempty"`
Actions map[string]Action `json:"actions,omitempty"`
// ThrottlePeriod is the watch-level action throttle ("5m", "30s",
// "1d"); the millis twin is the alternative ES serialisation.
ThrottlePeriod string `json:"throttle_period,omitempty"`
ThrottlePeriodInMillis int64 `json:"throttle_period_in_millis,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
Transform json.RawMessage `json:"transform,omitempty"`
// Unknown lists top-level keys this package doesn't model
// (sorted). They are preserved via the stored raw JSON and
// surfaced on the Validate report.
Unknown []string `json:"-"`
}
Watch is the parsed ES watcher definition. Interpreted fields are typed; everything else is carried as raw JSON.
func Parse ¶
Parse decodes an ES watcher body. Unknown top-level fields never fail the parse — they land in Watch.Unknown and the stored raw JSON preserves them byte-for-byte for round-trip.
func (*Watch) CalendarCron ¶ added in v0.9.202
CalendarCron returns the schedule's cron expressions when the watch paces via CALENDAR cron: cron-only schedule (an interval, parseable or not, keeps the Faz-1 interval path — mirrors IntervalSec priority), NOT the fixed-rate cron→interval subset (geriye uyum: those watches keep their Faz-1 pacing and report message), and every expression parseable by ParseCron. nil otherwise — the caller falls back to interval/default pacing.
func (*Watch) ConditionSpec ¶ added in v0.9.202
func (w *Watch) ConditionSpec() (ConditionSpec, bool)
ConditionSpec projects the condition onto the executable subset. ok=false means the condition cannot run (script / never / unsupported path / non-numeric value…) — Validate carries the operator-facing reason; this is the machine-facing twin.
func (*Watch) IntervalSec ¶
IntervalSec returns the schedule interval in seconds, clamped to Coremetry's 1m evaluator tick floor. A fixed-rate Quartz cron (cron→interval subset, v0.9.x) counts as an interval schedule. 0 = no parseable interval schedule (caller applies the 5m default).