analysis

package
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package analysis builds deterministic incident and cost reports from existing telemetry (ADR 051, phase one). It never calls a model and is never part of reconciliation.

Index

Constants

View Source
const (
	StatusComplete     = "complete"
	StatusInsufficient = "insufficient_data"
)

Report statuses.

View Source
const (
	TriggerAlert = "alert"
	TriggerSpend = "spend"
	// TriggerManual marks a report an operator asked for on demand.
	TriggerManual = "manual"
)

Trigger kinds.

View Source
const SchemaVersion = 1

SchemaVersion is stored with every report so readers can evolve.

Variables

View Source
var ErrBusy = errors.New("analysis: report capacity is full")

ErrBusy means every report slot is in use; callers answer 429 and retry later.

Functions

This section is empty.

Types

type AlertReader

type AlertReader interface {
	ListHistory(ctx context.Context, f alerting.HistoryFilter) ([]alerting.HistoryEntry, error)
}

AlertReader reads alert history.

type Cause

type Cause struct {
	Rank       int      `json:"rank"`
	ID         string   `json:"id"`
	Title      string   `json:"title"`
	Score      int      `json:"score"`
	Confidence string   `json:"confidence"`
	Evidence   []string `json:"evidence"`
}

Cause is one ranked suspected cause with the evidence ids that back it.

type Config

type Config struct {
	Enabled         bool
	Window          time.Duration
	Baseline        time.Duration
	AnomalyZ        float64
	TrendPct        float64
	UtilizationPct  float64
	RestartMin      int
	LogErrorMin     int
	LogGroups       int
	LogSampleBytes  int
	MaxEvents       int
	DeployProximity time.Duration
	MinInterval     time.Duration
	MaxConcurrent   int
	Timeout         time.Duration
	Retention       time.Duration
	// Sizing feeds the right-sizing engine; a zero field keeps the engine default.
	Sizing rightsizing.Tuning
}

Config holds every threshold, read from APP_ANALYSIS_* so operators tune them.

func ConfigFromEnv

func ConfigFromEnv(lookup func(string) (string, bool)) Config

ConfigFromEnv reads the knobs. Analysis stays off unless APP_ANALYSIS_ENABLED is "on".

type DeployReader

type DeployReader interface {
	ListDeployAttempts(ctx context.Context, serviceName string) ([]store.DeployAttempt, error)
}

DeployReader lists an app's deploy attempts.

type Digest

type Digest struct {
	App         string       `json:"app"`
	WindowStart time.Time    `json:"window_start"`
	WindowEnd   time.Time    `json:"window_end"`
	Metrics     []MetricStat `json:"metrics"`
	Logs        []LogGroup   `json:"logs"`
	LogLines    int          `json:"log_lines"`
	Restarts    int          `json:"restarts"`
	Timeline    []Event      `json:"timeline"`
	Sizing      []Sizing     `json:"sizing,omitempty"`
	// MonthlySavingUSD and SavingProvider come from internal/costestimate.
	MonthlySavingUSD float64 `json:"monthly_saving_usd,omitempty"`
	SavingProvider   string  `json:"saving_provider,omitempty"`
	// MemoryLimit and CPUPercentLimit are the declared limits (0 when unset).
	MemoryLimit     int64   `json:"memory_limit_bytes"`
	CPUPercentLimit float64 `json:"cpu_percent_limit"`
}

Digest is the deterministic evidence bundle.

func Collect

func Collect(ctx context.Context, src Sources, cfg Config, app string, end time.Time) Digest

Collect builds the digest for app ending at end. A failing reader only drops its own section, so partial data still yields a digest.

type Event

type Event struct {
	At     time.Time `json:"at"`
	Kind   string    `json:"kind"`
	Ref    string    `json:"ref"`
	Detail string    `json:"detail,omitempty"`
}

Event is one timeline entry: a deploy, restart or alert firing.

type LogGroup

type LogGroup struct {
	Evidence    string    `json:"evidence"`
	Level       string    `json:"level"`
	Fingerprint string    `json:"fingerprint"`
	Sample      string    `json:"sample"`
	Count       int       `json:"count"`
	FirstSeen   time.Time `json:"first_seen"`
	LastSeen    time.Time `json:"last_seen"`
}

LogGroup is one level plus normalized message fingerprint.

type MetricStat

type MetricStat struct {
	Evidence     string     `json:"evidence"`
	Metric       string     `json:"metric"`
	Samples      int        `json:"samples"`
	Min          float64    `json:"min"`
	P50          float64    `json:"p50"`
	P95          float64    `json:"p95"`
	Max          float64    `json:"max"`
	Mean         float64    `json:"mean"`
	BaselineMean float64    `json:"baseline_mean"`
	TrendPct     float64    `json:"trend_pct"`
	Trend        string     `json:"trend"`
	AnomalyCount int        `json:"anomaly_count"`
	MaxZ         float64    `json:"max_z"`
	FirstAnomaly *time.Time `json:"first_anomaly,omitempty"`
}

MetricStat summarises one series. Every number is computed in code.

type Recommendation

type Recommendation struct {
	ID               string   `json:"id"`
	Text             string   `json:"text"`
	MonthlySavingUSD float64  `json:"monthly_saving_usd,omitempty"`
	Evidence         []string `json:"evidence"`
}

Recommendation is a suggested operator action; applied by people only.

type Report

type Report struct {
	SchemaVersion   int              `json:"schema_version"`
	Status          string           `json:"status"`
	App             string           `json:"app"`
	GeneratedAt     time.Time        `json:"generated_at"`
	Trigger         Trigger          `json:"trigger"`
	Summary         string           `json:"summary"`
	Timeline        []Event          `json:"timeline"`
	Causes          []Cause          `json:"causes"`
	Recommendations []Recommendation `json:"recommendations"`
	Digest          Digest           `json:"digest"`
}

Report is the stored artifact.

func Build

func Build(tr Trigger, d Digest, cfg Config, now time.Time) Report

Build turns a digest and its trigger into a report. It is pure: same input, same output, and every number is copied from the digest.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner generates reports off the alert path. A nil Runner is a no-op, which is what a disabled feature gets.

func NewRunner

func NewRunner(cfg Config, src Sources, saver Saver, logger *slog.Logger) *Runner

NewRunner returns nil unless cfg.Enabled, so callers can wire it unconditionally.

func (*Runner) Generate

func (r *Runner) Generate(ctx context.Context, tr Trigger) (store.AnalysisReport, error)

Generate collects, builds and stores one report.

func (*Runner) GenerateManual

func (r *Runner) GenerateManual(ctx context.Context, tr Trigger) (store.AnalysisReport, error)

GenerateManual runs one operator-requested report inside the same concurrency cap and timeout as alert-driven ones, without the per-app interval.

func (*Runner) OnAlert

func (r *Runner) OnAlert(e alerting.HistoryEntry)

OnAlert is the alerting hook. It only filters and schedules; any failure is logged and never reaches the alert pipeline.

func (*Runner) Wait

func (r *Runner) Wait()

Wait blocks until in-flight reports finish; tests use it.

type Saver

type Saver interface {
	SaveAnalysisReport(ctx context.Context, r store.AnalysisReport) error
	PruneAnalysisReports(ctx context.Context, cutoff time.Time) (int64, error)
}

Saver persists reports; *store.DB satisfies it.

type ServiceReader

type ServiceReader interface {
	GetDesiredService(ctx context.Context, name string) (*store.DesiredService, error)
}

ServiceReader reads the declared resource limits.

type Sizing

type Sizing struct {
	Dimension      string  `json:"dimension"`
	Action         string  `json:"action"`
	Confidence     string  `json:"confidence"`
	DataSufficient bool    `json:"data_sufficient"`
	CurrentLimit   int64   `json:"current_limit"`
	P95Usage       float64 `json:"p95_usage"`
	SuggestedLimit int64   `json:"suggested_limit"`
	SuggestedText  string  `json:"suggested_text,omitempty"`
}

Sizing is the right-sizing view of one dimension, from internal/rightsizing.

type Sources

type Sources struct {
	Telemetry TelemetryReader
	Deploys   DeployReader
	Alerts    AlertReader
	Services  ServiceReader
}

Sources groups the existing readers the digest uses; nil ones are skipped.

type TelemetryReader

type TelemetryReader interface {
	QueryMetrics(ctx context.Context, resourceID, metric string, from, to time.Time) ([]telemetry.Sample, error)
	QueryLogs(ctx context.Context, resourceID string, from, to time.Time, query string) ([]telemetry.LogEntry, error)
}

TelemetryReader is the metrics and logs surface the dashboard already uses.

type Trigger

type Trigger struct {
	Kind     string    `json:"kind"`
	ID       string    `json:"id"`
	App      string    `json:"app"`
	RuleName string    `json:"rule_name,omitempty"`
	Severity string    `json:"severity,omitempty"`
	Detail   string    `json:"detail,omitempty"`
	At       time.Time `json:"at"`
}

Trigger is the alert or spend event a report answers.

Jump to

Keyboard shortcuts

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