monitor

package
v1.18.2 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package monitor watches what a vhost's models are asked and answer. It keeps a sampled, masked log of predictions in the log store, and measures drift: how far each feature's live values have moved from the rows the model version was trained on (the worker's feature_stats), as a population stability index per feature.

Nothing here may slow or fail a prediction. Observe copies what it needs and hands it to a bounded queue without blocking; a full queue drops the observation and counts it. Masking, counting, writing and alerting all run on the one goroutine Run starts.

Drift is counted in memory, per Hermod process, over every prediction that process makes (not only the logged sample), in tumbling windows: at each tick of Config.Window a model's window is judged if it holds at least Config.MinRows rows, and a new one starts. Several Hermod processes each judge their own traffic; their hermod_ml_feature_drift series carry the scrape's instance label, and the drift API answers for the process that serves it. Merging counts across processes through storage was left out: the default deployment runs the API and the workflow engine in one process, where this is all the traffic there is.

Index

Constants

View Source
const (
	StatusOK    = "ok"
	StatusWarn  = "warn"
	StatusAlert = "alert"
)

Drift statuses, per feature and for a whole report.

View Source
const (
	DefaultWindow  = 5 * time.Minute
	DefaultMinRows = 100
)

Defaults of Config.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Window is how often drift is judged; MinRows how many predicted rows a
	// window needs before it is.
	Window  time.Duration
	MinRows int
	// Queue bounds the observations waiting for the monitor's goroutine.
	Queue int
	// Batch and Flush bound how many logged rows wait to be written, and for
	// how long.
	Batch int
	Flush time.Duration
}

Config sizes the monitor. Zero values are the defaults.

func ConfigFromEnv

func ConfigFromEnv() Config

ConfigFromEnv reads HERMOD_ML_DRIFT_WINDOW (a Go duration) and HERMOD_ML_DRIFT_MIN_ROWS. A value that does not read is left to the default.

type Deps

type Deps struct {
	// Logs returns the current log store; one that is not a
	// storage.MLPredictionLogStore drops logged rows, counted.
	Logs   func() any
	Stats  StatsFunc
	Notify NotifyFunc
	Logger hermod.Logger
}

Deps are what the monitor reads from and reports to.

type FeatureDrift

type FeatureDrift struct {
	Feature string `json:"feature"`
	Kind    string `json:"kind"`
	// PSI is the population stability index of the live values against the
	// training split, over the training bins plus one bin for missing values.
	PSI    float64 `json:"psi"`
	Status string  `json:"status"`
	// NullFraction and TrainingNullFraction are the share of missing values
	// live and in training, the commonest drift there is.
	NullFraction         float64 `json:"null_fraction"`
	TrainingNullFraction float64 `json:"training_null_fraction"`
}

FeatureDrift is how far one feature's live values have moved from the values the model was trained on.

type Monitor

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

Monitor is safe for concurrent use. The zero value is not usable; a nil *Monitor ignores every observation.

func New

func New(cfg Config, deps Deps) *Monitor

New builds a monitor. Run must be started for anything to be logged or judged.

func (*Monitor) Forget

func (m *Monitor) Forget(vhost, model string)

Forget drops what is held about a model: it was deleted.

func (*Monitor) MinRows

func (m *Monitor) MinRows() int

MinRows is how many rows a window needs to be judged.

func (*Monitor) Observe

func (m *Monitor) Observe(o Observation)

Observe hands one prediction call to the monitor. It never blocks: when the queue is full the call is dropped and counted.

func (*Monitor) OnDrift

func (m *Monitor) OnDrift(fn func(Report))

OnDrift adds fn to what is called with every drift report, whatever its status, once per judged window. It is the hook a retraining policy uses; fn runs on the monitor's goroutine and must not block.

func (*Monitor) Recommendations

func (m *Monitor) Recommendations(vhost, model string) (RecommendationReport, bool)

Recommendations returns the latest report of a recommendation model.

func (*Monitor) Report

func (m *Monitor) Report(vhost, model string) (Report, bool)

Report returns the latest drift report of a model.

func (*Monitor) Run

func (m *Monitor) Run(ctx context.Context)

Run processes observations until ctx ends, then writes what is pending.

func (*Monitor) Window

func (m *Monitor) Window() time.Duration

Window is how often drift is judged.

type NotifyFunc

type NotifyFunc func(ctx context.Context, r Report)

NotifyFunc raises an alert for a report whose status is StatusAlert.

type Observation

type Observation struct {
	// Model is the model as it was called: its live version, features and
	// monitoring settings.
	Model      storage.MLModel
	CallerKind string
	CallerID   string
	// Inputs and Outputs are the rows sent and the predictions returned, in
	// the same order.
	Inputs  []map[string]any
	Outputs []map[string]any
	Latency time.Duration
	At      time.Time
	// Recommendation is set for a call of a recommendation model, which is
	// watched by coverage and popular share rather than drift
	// (recommendations.go).
	Recommendation *RecommendationCall
}

Observation is one prediction call as the caller made it.

type RecommendationCall

type RecommendationCall struct {
	// Items are the ids it answered.
	Items []string
	// Fallback reports that the person or item was unknown, so the answer is
	// the popular items.
	Fallback bool
	// Catalog is how many items the model can recommend.
	Catalog int
}

RecommendationCall is one call of a recommendation model, for Observation.

type RecommendationReport

type RecommendationReport struct {
	VHost       string    `json:"vhost"`
	Model       string    `json:"model"`
	Version     string    `json:"version"`
	WindowStart time.Time `json:"window_start"`
	WindowEnd   time.Time `json:"window_end"`
	// Calls is how many calls the window holds; Fallbacks how many were
	// answered with popular items.
	Calls     int64 `json:"calls"`
	Fallbacks int64 `json:"fallbacks"`
	// PopularShare is Fallbacks / Calls.
	PopularShare float64 `json:"popular_share"`
	// Recommended is how many distinct items were recommended, of Catalog;
	// Coverage is the share.
	Recommended int     `json:"recommended"`
	Catalog     int     `json:"catalog"`
	Coverage    float64 `json:"coverage"`
}

RecommendationReport is one window of a recommendation model's calls.

type Report

type Report struct {
	VHost       string    `json:"vhost"`
	Model       string    `json:"model"`
	Version     string    `json:"version"`
	WindowStart time.Time `json:"window_start"`
	WindowEnd   time.Time `json:"window_end"`
	// Rows is how many predicted rows the window holds.
	Rows  int64   `json:"rows"`
	Warn  float64 `json:"warn"`
	Alert float64 `json:"alert"`
	// Status is the worst of the features'.
	Status string `json:"status"`
	// Features are ordered most drifted first.
	Features []FeatureDrift `json:"features"`
}

Report is the drift of one model version over one window of predictions.

type StatsFunc

type StatsFunc func(ctx context.Context, vhost, model, version string) (map[string]worker.FeatureStats, error)

StatsFunc answers the training stats of one model version: none, without an error, for a version trained before the worker recorded them.

Jump to

Keyboard shortcuts

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