services

package
v1.4.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const IntakeSettingsBlobName = "models/settings/intake-settings"

IntakeSettingsBlobName is the blob the intake settings live under, a sibling of the report settings in the models/settings/ namespace.

View Source
const ReportScheduleJobName = "report-daily-digest"

ReportScheduleJobName is the ownership key the daily digest gates on. Under enterprise HA the cluster identity installs a predicate via scheduler.SetOwnership; keyed by this name, exactly one replica sends. OSS installs no predicate (scheduler.Owns is a constant true), so a single- instance deployment always sends. Both entrypoints reference this SAME constant so the two binaries gate on an identical key.

View Source
const ReportSettingsBlobName = "models/settings/report-settings"

ReportSettingsBlobName is the single blob the report settings live under, in the models/settings/ namespace (a sibling of the model-state artifacts, deliberately NOT the encrypted channel store).

Variables

View Source
var (
	// ErrReportDisabled is returned when the runtime report setting
	// enable is false.
	ErrReportDisabled = errors.New("report: feature disabled")
	// ErrReportRateLimited is returned when the per-window render/send
	// token bucket is exhausted.
	ErrReportRateLimited = errors.New("report: rate limited")
	// ErrReportNoRenderer is returned when no renderer is installed.
	ErrReportNoRenderer = errors.New("report: no renderer configured")
	// ErrReportNoStorage is returned when persistence is not configured.
	ErrReportNoStorage = errors.New("report: storage not configured")
	// ErrReportNoChannel is returned when no enabled channel resolves for
	// delivery.
	ErrReportNoChannel = errors.New("report: no enabled channel resolved")
)
View Source
var ErrIntakeNoStorage = errors.New("intake: storage not configured")

ErrIntakeNoStorage is returned by SaveIntakeSettings when no storage backend is configured, so the admin API can map it to 503.

Functions

func AnalyzeAgent added in v1.4.3

func AnalyzeAgent() core.AIAgent

AnalyzeAgent returns the installed analyze agent or nil.

func BuildAggregateReportModel added in v1.4.8

func BuildAggregateReportModel(recs []*storage.IncidentRecord, window string, start, end time.Time, unit string, scrubber core.Scrubber, includeCharts bool, loc *time.Location) core.ReportModel

BuildAggregateReportModel assembles the channel-agnostic, already-redacted aggregate ReportModel for a window. recs are the incidents whose CreatedAt falls in [start, end) (newest first). scrubber MUST be non-nil in production (callers pass reportScrubber()); it is the DLP boundary for every attacker-influenced label. window/start/end/unit come from WindowBoundsIn. loc is the timezone the model's timestamps are expressed in (its IANA name is stamped on the model so the renderer/caption print it); a nil loc is treated as UTC, keeping the model byte-for-byte identical to the pre-timezone behaviour.

func CreateIncident

func CreateIncident(teamID string, content *map[string]interface{}, params ...*map[string]string) error

func CreateIncidentFromFinding added in v1.4.0

func CreateIncidentFromFinding(f *core.AIFinding, r core.AgentResult, source, service string) error

CreateIncidentFromFinding maps an AI SRE finding into the standard content map and delegates to CreateIncident so all existing channels (Slack, Telegram, MS Teams, Lark, Email, Viber) and the on-call workflow trigger with no per-channel changes.

Source identifies the agent + signal source (e.g. "agent:elasticsearch:prod-app"). Service is the operator-facing service name extracted from the log pattern; "_unknown" when no service_pattern matched.

All keys added here are stable and additive — existing template files keep working unchanged. Operators who want to surface AI-specific detail can reference {{ .Summary }}, {{ .Suggestions }}, {{ .Confidence }}, {{ .PatternID }}, {{ .Verdict }}.

func RenderIncidentsReport added in v1.4.8

func RenderIncidentsReport(ctx context.Context, window string) (*core.ReportImage, error)

RenderIncidentsReport renders the aggregate report PNG for a window (preview / download). It is read-only over stored state.

func ReportRenderer added in v1.4.8

func ReportRenderer() core.ReportRenderer

ReportRenderer returns the installed report renderer, or nil.

func ReportSendDue added in v1.4.11

func ReportSendDue(now time.Time, s ReportSettings, lastSent time.Time) bool

ReportSendDue reports whether the scheduled daily digest should fire at `now`, given the current settings and the moment the digest was last sent (zero when it has never been sent this process). It is deliberately pure:

  • Fires ONLY when both Enable and ScheduleEnabled are true.
  • Fires ONLY on the exact wall-clock minute SendTime in the configured Timezone (a 1-minute ticker visits each minute-of-hour exactly once, so the exact-minute check never misses and never fires on a wrong minute).
  • Fires at most once per LOCAL calendar day: once lastSent falls on the same local day as `now`, further ticks that same day are suppressed.

Because the comparison is done entirely in the configured *time.Location, it is DST-safe: "09:00 local" is well-defined on both sides of a clock change, and the once-per-local-day guard keys off the local calendar date.

func SaveIntakeSettings added in v1.4.11

func SaveIntakeSettings(st storage.Provider, s IntakeSettings) error

SaveIntakeSettings persists the intake settings blob. It returns ErrIntakeNoStorage when no backend is configured so the API can map it to 503, consistent with the report settings path.

func SaveReportSettings added in v1.4.8

func SaveReportSettings(st storage.Provider, s ReportSettings) error

SaveReportSettings persists the settings blob after sanitizing it. It returns ErrReportNoStorage when no backend is configured so the API can map it to 503, consistent with the render/send paths.

func SetAnalyzeAgent added in v1.4.3

func SetAnalyzeAgent(a core.AIAgent)

SetAnalyzeAgent installs the analyze agent used by the admin /analyze endpoint. Pass nil to disable analyze.

func SetReportRedactor added in v1.4.8

func SetReportRedactor(s core.Scrubber)

SetReportRedactor installs the DLP scrubber every report text field is run through before it reaches the card or a channel. Boot installs the operator-configured redactor; when none is installed a safe default (the built-in agent redaction rules) is used instead, so a report is NEVER rendered from unredacted text.

func SetReportRenderer added in v1.4.8

func SetReportRenderer(r core.ReportRenderer)

SetReportRenderer installs the renderer used by the report endpoints.

func SetStorage added in v1.3.9

func SetStorage(p storage.Provider)

SetStorage installs the storage provider used to persist incidents and record acks. Called once from main after config load.

func StartReportScheduler added in v1.4.11

func StartReportScheduler(ctx context.Context, store storage.Provider)

StartReportScheduler drives the recurring daily incident digest from a single 1-minute ticker bound to ctx. Each tick it RE-READS the report settings (so an operator's change to the send time / timezone / channel applies live, no restart) and asks the pure ReportSendDue predicate whether the digest is due right now. When it is, it sends the DefaultWindow report to the DefaultChannel via the same SendIncidentsReport path the manual button uses — which enforces the enable flag, the rate limiter, and redaction.

HA / multi-instance caveat: the SEND is gated behind scheduler.Owns so that under enterprise HA (where cluster.Identity installs an ownership predicate via scheduler.SetOwnership) exactly one replica fires the digest. OSS installs no predicate, so scheduler.Owns is always true and a single- instance deployment always sends; if an operator runs multiple replicas WITHOUT installing an ownership predicate, each replica would send its own copy — the same single-owner caveat that applies to every scheduled job.

func Storage added in v1.3.9

func Storage() storage.Provider

Storage returns the currently installed storage provider, or nil when the process is running without persistence (older tests).

func ValidSendTime added in v1.4.11

func ValidSendTime(v string) bool

ValidSendTime reports whether v is a valid "HH:MM" 24-hour wall-clock time. It is the boundary check the admin PUT handler applies before persisting.

func ValidTimezone added in v1.4.11

func ValidTimezone(v string) bool

ValidTimezone reports whether v is "UTC" or a loadable IANA location name. It is the boundary check the admin PUT handler applies before persisting.

func WindowBounds added in v1.4.8

func WindowBounds(window string, now time.Time) (start, end time.Time, unit string)

WindowBounds resolves a window label to a [start, end) UTC range and the trend unit ("hour" for today/24h, "day" for 7d). It is the UTC convenience wrapper over WindowBoundsIn; timezone-aware callers use WindowBoundsIn directly.

func WindowBoundsIn added in v1.4.11

func WindowBoundsIn(window string, now time.Time, loc *time.Location) (start, end time.Time, unit string)

WindowBoundsIn resolves a window label to a [start, end) range and the trend unit ("hour" for today/24h, "day" for 7d), computed in loc. An unknown/absent window defaults to today. now is the reference time; callers pass time.Now() in production and a fixed time in tests. A nil loc is treated as UTC, so WindowBoundsIn(window, now, nil) equals the legacy UTC behaviour byte-for- byte. "today" is the start of the calendar day IN loc (e.g. local midnight), which is why the timezone controls both the window and the printed times.

Types

type IntakeSettings added in v1.4.11

type IntakeSettings struct {
	// AutoResolveWebhook makes an incident that arrives via the PUBLIC
	// webhook intake run the full normal flow — alert fan-out, ack URL, and
	// on-call escalation, exactly as an ordinary incident — and then stamps
	// the stored record resolved so it does not sit in the open list. The only
	// difference from a normal webhook incident is the persisted resolved /
	// resolved_at; alerting, ack URL, and on-call are unchanged. DEFAULT true:
	// an install with no stored blob auto-resolves webhook incidents. It is
	// scoped strictly to the webhook origin, so SNS/SQS-transported and
	// agent-emitted incidents are never affected.
	AutoResolveWebhook bool `json:"auto_resolve_webhook"`
}

IntakeSettings is the non-secret runtime configuration for incident intake. It is the JSON shape persisted in the settings blob and exchanged by the admin GET/PUT endpoints.

func DefaultIntakeSettings added in v1.4.11

func DefaultIntakeSettings() IntakeSettings

DefaultIntakeSettings is the built-in floor applied when the store holds no value: webhook auto-resolve is ON. This is a deliberate default-on that changes public-webhook behaviour out of the box — an operator disables it in the UI when they want webhook incidents to stay open and escalate.

func LoadIntakeSettings added in v1.4.11

func LoadIntakeSettings(st storage.Provider) IntakeSettings

LoadIntakeSettings returns the effective intake settings: the stored blob merged over the built-in defaults. A nil store or an absent/empty/corrupt blob yields the built-in defaults (auto-resolve ON) — never an error, mirroring the ReadBlob "fresh start" contract. Callers get a fresh value each time, so there is no shared mutable state to guard.

type ReportOutcome added in v1.4.8

type ReportOutcome struct {
	Window   string            `json:"window"`
	Sent     []string          `json:"sent"`
	Fallback []string          `json:"fallback"`
	Failed   map[string]string `json:"failed"`
	Bytes    int               `json:"bytes"`
}

ReportOutcome aggregates per-channel delivery results — never short-circuiting, exactly like AlertResult. Sent = image delivered; Fallback = text summary + note delivered (image-incapable channel); Failed = channel returned an error (the PNG is still downloadable).

func SendIncidentsReport added in v1.4.8

func SendIncidentsReport(ctx context.Context, opts ReportSendOptions) (*ReportOutcome, error)

SendIncidentsReport renders the aggregate report and delivers it to the resolved channel(s): image upload where supported, redacted text summary + note where not. Per-channel outcomes are aggregated without short-circuiting.

type ReportSendOptions added in v1.4.8

type ReportSendOptions struct {
	Window      string
	Channel     string
	RequestedBy string
}

ReportSendOptions selects the window and (optionally) the channel for an aggregate report send. Channel is the explicit target; empty falls through the resolution precedence (runtime default_channel → error).

type ReportSettings added in v1.4.8

type ReportSettings struct {
	Enable         bool   `json:"enable"`
	DefaultChannel string `json:"default_channel"`
	IncludeChart   bool   `json:"include_chart"`
	RatePerMinute  int    `json:"rate_per_minute"`
	DefaultWindow  string `json:"default_window"`
	// ScheduleEnabled turns on the recurring daily digest: when Enable AND
	// ScheduleEnabled are both true, the report is sent once per local day at
	// SendTime in Timezone, over DefaultWindow to DefaultChannel. Default
	// false — a fresh install never sends on a schedule until an operator
	// opts in.
	ScheduleEnabled bool `json:"schedule_enabled"`
	// SendTime is the wall-clock "HH:MM" (24-hour) at which the daily digest
	// fires, interpreted in Timezone. Default "09:00".
	SendTime string `json:"send_time"`
	// Timezone is the IANA location name (e.g. "UTC" or "Asia/Ho_Chi_Minh")
	// that BOTH schedules the daily send AND controls the report's printed
	// timestamps and window bounds. Default "UTC" — which keeps the rendered
	// report byte-for-byte identical to the pre-timezone behaviour.
	Timezone string `json:"timezone"`
}

ReportSettings is the non-secret runtime configuration for the incidents analytics report. It is the JSON shape persisted in the settings blob and the shape the admin GET/PUT endpoints exchange.

func DefaultReportSettings added in v1.4.8

func DefaultReportSettings() ReportSettings

DefaultReportSettings is the built-in floor applied when the store holds no value: the feature is OFF, charts on, a 6/min render cap, today as the default window, and the daily schedule OFF (09:00 UTC once enabled). A fresh install therefore has the report disabled until an operator enables it in the UI.

func LoadReportSettings added in v1.4.8

func LoadReportSettings(st storage.Provider) ReportSettings

LoadReportSettings returns the effective report settings: the stored blob merged over the built-in defaults, sanitized. A nil store or an absent/empty/corrupt blob yields the built-in defaults (feature off) — never an error, mirroring the ReadBlob "fresh start" contract. Callers get a fresh value each time, so there is no shared mutable state to guard.

func (ReportSettings) Location added in v1.4.11

func (s ReportSettings) Location() *time.Location

Location resolves the settings Timezone to a *time.Location. An empty or unloadable value falls back to UTC so rendering and scheduling never fail on a bad blob (the PUT boundary rejects invalid zones, so this is defence in depth for a legacy/hand-edited blob).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL