api

package
v0.9.398 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 64 Imported by: 0

Documentation

Overview

Package api — AI observability endpoints (v0.5.163). The /ai page is the Coremetry-native counterpart to Langfuse: every Copilot Explain call lands as a row in the ai_calls CH table and these endpoints surface it as KPIs / timeseries / a recent- calls table. No external service involvement: prompts + samples stay inside the customer's CH cluster.

Package api handler for /admin/alert-tuning — surfaces the noisiest rules in a window plus per-rule actionable suggestions for the v0.5.127-129 dampening knobs. Admin-only read endpoint; cached 5 min because rule-noise pattern doesn't shift minute- to-minute and operators commonly load this page in bursts.

Package api handler for SLO autocreate (v0.5.147). Scans recent telemetry, picks the busiest N services, and stamps a baseline-grounded availability + latency SLO for each one the install doesn't already have. Admin-only, audit-logged, idempotent.

Tempo-compatible HTTP API. Lets Grafana add Coremetry as a Tempo datasource: only the endpoints Grafana actually calls during search and trace view are implemented (echo, search, search/tags, search/tag/{name}/values, traces/{id}).

Both the v1 and v2 paths are wired so older / newer Grafana versions work.

Spec reference: https://grafana.com/docs/tempo/latest/api_docs/

traces_extras.go — the /api/traces?traceIds= phase-2-only path + the shared extraAttrs parsing (FAZ 2, docs/audit/traces-attribute-columns.md §6). Lives OUTSIDE api.go by operator constraint (api.go must not grow; the extraAttrs parse moved here from getTraces/exportTracesCSV for a net shrink).

No separate route is registered: `traceIds` is a param-branch of the existing GET /api/traces contract (the frontend's enrichment call rides the same client method family), and Go 1.22's ServeMux panics on a second "GET /api/traces" pattern — so getTraces delegates here first via serveTracesExtras and the api.go route table is untouched.

Contract:

GET /api/traces?traceIds=<id,id,…>&extraAttrs=<k,k…>&from=<ns>&to=<ns>
→ 200 {"extras": {"<traceId>": {"<key>": "<value>", …}, …}}

When traceIds is present, phase-1 (the list query) is SKIPPED entirely: only the bounded phase-2 (Store.TraceExtras — time-bounded WHERE + id IN-list + LIMIT) runs. from/to are REQUIRED — they are the phase-2 time bound; the client sends the visible rows' real min/max timestamps and the store pads `to` by the +5m slack. Without traceIds the request falls through to the normal getTraces flow, so the existing API contract (optional extraAttrs, extras inside each TraceRow) is unchanged.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AIRate added in v0.5.167

type AIRate struct {
	InputPer1M  float64 `json:"inputPer1M"`
	OutputPer1M float64 `json:"outputPer1M"`
}

AIRate is the per-model price quote used by the /ai cost estimate (v0.5.167). USD per 1M tokens, separately for input and output. Stored as a JSON blob in system_settings["ai.rates"] so admins can override the bundled defaults without code change. Local-model endpoints (Ollama, vLLM, LM Studio) should configure 0/0 — that's the default shape for any model not in the table.

type AnnotationItem added in v0.9.394

type AnnotationItem struct {
	TS         int64  `json:"ts"` // unix ns
	Kind       string `json:"kind"`
	Title      string `json:"title"`
	Service    string `json:"service,omitempty"`
	TargetType string `json:"targetType,omitempty"` // problem | anomaly | event | rollout
	TargetID   string `json:"targetId,omitempty"`
	Link       string `json:"link,omitempty"`
}

AnnotationItem — şeridin tek olay modeli (beş marker mekanizmasının hedef birleşimi; Ş3 emeklilikleri bunun üstüne).

type AnomalyRootCause added in v0.8.167

type AnomalyRootCause struct {
	RootCause
	AnomalyID   string `json:"anomalyId"`
	AnomalyKind string `json:"anomalyKind"` // log_pattern | log_template_new | trace_op
	Pattern     string `json:"pattern"`     // log pattern name OR operation name (trace_op)
}

AnomalyRootCause is the anomaly-anchored sibling of RootCause (v0.8.x). It embeds the SAME RootCause fan-out result so /anomalies and /problems share one rendering path later, and stamps the anchor from the AnomalyEvent (id/kind/pattern/service) instead of a Problem. Read-only.

type AvailablePage added in v0.5.251

type AvailablePage struct {
	ID    string `json:"id"`    // route path; matches Sidebar href
	Label string `json:"label"` // i18n key (e.g. "nav.inbox")
	Group string `json:"group"` // i18n key for group heading
}

AvailablePage is one entry in the canonical sidebar-page registry that powers the custom-role checkbox grid in Settings → Roles. The frontend Sidebar.tsx mirrors these IDs as `href` values; keeping the registry on the backend means the role catalog's page IDs are validated against a single source of truth instead of drifting when somebody adds a sidebar entry.

IDs match the frontend route paths verbatim (e.g. "/inbox", "/services"). Group + label are i18n keys; the frontend resolves them via useT() so a language switch surfaces immediately.

AdminOnly pages are excluded from this registry — custom roles subset viewer's access only; admin/editor surfaces remain gated by their hard-coded role checks.

type CHAsyncInsert added in v0.5.346

type CHAsyncInsert struct {
	Database         string `json:"database"`
	Table            string `json:"table"`
	TotalBytes       uint64 `json:"totalBytes"`
	EntriesCount     uint64 `json:"entriesCount"`
	FirstUpdateMsAgo uint64 `json:"firstUpdateMsAgo"`
}

CHAsyncInsert mirrors one row of system.asynchronous_inserts — a buffered INSERT awaiting the server-side coalescing flush. ageMs > 0 = how long it's been sitting; bytes/rows reflect what's queued so far. The whole list usually has a few rows during steady ingest, climbs visibly under burst (good sign — coalescence working) and falls back as the busy_timeout fires.

type CHClusterNode added in v0.5.388

type CHClusterNode struct {
	Cluster     string `json:"cluster"`
	ShardNum    uint32 `json:"shardNum"`
	ReplicaNum  uint32 `json:"replicaNum"`
	HostName    string `json:"hostName"`
	HostAddress string `json:"hostAddress,omitempty"`
	Port        uint16 `json:"port"`
	IsLocal     bool   `json:"isLocal"`
}

type CHHealth added in v0.5.319

type CHHealth struct {
	// v0.5.388 — topology banner. First field on the payload so
	// the operator's eye lands on the cluster mode + node count
	// before drilling into the perf panels. Powered by:
	//   - cfg.ClusterName (operator-set env var) → "configured"
	//     side
	//   - system.clusters lookup (CH self-report) → "live" side
	//   - system.tables engine filter → which tables wear the
	//     Distributed wrapper vs plain MergeTree
	// All three are needed because a misconfigured cluster name
	// looks identical to standalone from the driver — only
	// system.clusters confirms ZK actually wired the node up.
	Topology     CHTopology         `json:"topology"`
	SlowQueries  []CHSlowQuery      `json:"slowQueries"`
	Merges       []CHMerge          `json:"merges"`
	PartHotspots []CHPartHotspot    `json:"partHotspots"`
	Replication  []CHReplicationLag `json:"replicationLag,omitempty"`
	// v0.5.346 — in-flight async_insert batches. Each row =
	// one currently-buffered INSERT awaiting flush. Lets the
	// operator see whether the tuned async_insert_busy_timeout
	// is doing useful coalescence or sitting idle.
	AsyncInserts []CHAsyncInsert `json:"asyncInserts,omitempty"`
	// v0.6.22 — in-flight ALTER TABLE … DELETE / UPDATE
	// mutations. Healthy queue is empty; growing queue is an
	// operator-visible signal that a state-table mutation
	// pattern needs rethinking (tombstone, ReplacingMergeTree,
	// etc.). Top 20 most-recent unfinished, sorted by parts-
	// remaining desc so the worst offender lands on top.
	Mutations []CHMutation `json:"mutations,omitempty"`
	Generated int64        `json:"generatedAt"` // unix ns of snapshot
}

CHHealth — v0.5.319. Datadog-style ClickHouse dashboard payload. Gives the operator a single-page view of CH-side perf health: slow queries, merge queue depth, part overflow risk, async insert pressure. Powers the new /admin/clickhouse page.

Read directly from system.* tables which CH provides as built-in observability surface. Each panel is fail-isolated — a CH version without one of the views (e.g. older OS edition without system.async_inserts) leaves the slot at its zero value rather than 500-ing the whole page.

func (CHHealth) String added in v0.5.319

func (h CHHealth) String() string

String — short summary line used in /admin/stats footer link.

type CHMerge added in v0.5.319

type CHMerge struct {
	Database    string  `json:"database"`
	Table       string  `json:"table"`
	ElapsedSec  float64 `json:"elapsedSec"`
	ProgressPct float64 `json:"progressPct"`
	RowsRead    uint64  `json:"rowsRead"`
	MergedSize  uint64  `json:"mergedSizeBytes"`
}

type CHMutation added in v0.6.22

type CHMutation struct {
	Database   string `json:"database"`
	Table      string `json:"table"`
	Command    string `json:"command"`   // trimmed; full text would be unbounded
	Parts      uint64 `json:"parts"`     // parts left to mutate
	ElapsedMs  int64  `json:"elapsedMs"` // since the mutation was submitted
	LatestFail string `json:"latestFail,omitempty"`
}

CHMutation — v0.6.22. One row per in-flight or recently-stuck ALTER TABLE … DELETE / UPDATE mutation. ALTER mutations rewrite matching parts in the background; healthy systems clear them within seconds. A growing queue is the operator-visible signature that a state table is being mutated faster than CH can rebuild parts — at which point the right fix is a tombstone or ReplacingMergeTree pattern, not "wait longer".

Powered by system.mutations. Filter is_done = 0 so only the queue depth shows up; finished mutations age out of the table after ~7 days and don't matter for live ops.

type CHPartHotspot added in v0.5.319

type CHPartHotspot struct {
	Database   string `json:"database"`
	Table      string `json:"table"`
	Parts      uint64 `json:"parts"` // active parts count
	RowsTotal  uint64 `json:"rowsTotal"`
	BytesTotal uint64 `json:"bytesTotal"`
}

type CHReplicationLag added in v0.5.319

type CHReplicationLag struct {
	Database      string `json:"database"`
	Table         string `json:"table"`
	QueueSize     uint32 `json:"queueSize"`
	AbsoluteDelay uint64 `json:"absoluteDelaySec"`
}

type CHSlowQuery added in v0.5.319

type CHSlowQuery struct {
	Query       string  `json:"query"`
	ElapsedMs   float64 `json:"elapsedMs"`
	MemoryMB    float64 `json:"memoryMb"`
	ReadRows    uint64  `json:"readRows"`
	ResultRows  uint64  `json:"resultRows"`
	EventTimeNs int64   `json:"eventTimeNs"`
	User        string  `json:"user"`
}

type CHTopology added in v0.5.388

type CHTopology struct {
	// Mode is "cluster" when an ON CLUSTER name is configured AND
	// system.clusters confirms it exists; "standalone" otherwise.
	// A misconfigured cluster name (operator set the env var but
	// the CH server has no matching <remote_servers> block) shows
	// up as "standalone" with a non-empty ConfiguredCluster — the
	// banner flags this mismatch.
	Mode              string   `json:"mode"`
	ConfiguredCluster string   `json:"configuredCluster,omitempty"`
	Database          string   `json:"database"`
	ConnectedHosts    []string `json:"connectedHosts,omitempty"`
	// Nodes — one entry per (shard, replica) registered in
	// system.clusters for the configured cluster. Empty in
	// standalone mode.
	Nodes []CHClusterNode `json:"nodes,omitempty"`
	// Table engine breakdown — drives the "distributed table?"
	// answer. DistributedTables > 0 = the install is running the
	// full cluster pattern (Distributed wrapper + _local
	// Replicated tables). LocalReplicated = Replicated*MergeTree
	// count. Plain = MergeTree / ReplacingMergeTree without
	// replication. Used to confirm migrations actually built the
	// cluster pattern they were supposed to.
	DistributedTables int `json:"distributedTables"`
	LocalReplicated   int `json:"localReplicated"`
	PlainMergeTree    int `json:"plainMergeTree"`
	// ZK / Keeper presence — system.zookeeper exists only when
	// CH is configured with a Keeper endpoint. ReplicatedMergeTree
	// needs this; absence on a cluster mode install is a config
	// bug that should surface here, not via a CREATE TABLE failure
	// six hours into ingest.
	ZooKeeperConnected bool `json:"zookeeperConnected"`
	// v0.5.419 — resolved per-table shard expression map. Lets
	// the operator audit "which shard key did each table actually
	// get?" without `SHOW CREATE TABLE` round-trips. Empty in
	// standalone mode.
	ShardPolicy map[string]string `json:"shardPolicy,omitempty"`
	// v0.5.428 — bug-fix: distinguish "system.clusters probe failed"
	// from "probe succeeded but returned no rows". Without this the
	// frontend's misconfig banner false-positives when CH is busy
	// enough to time out the probe (v0.5.424 raised the timeout
	// from 3s to 8s, but operators still hit it intermittently).
	// Empty when the probe completed cleanly (regardless of result
	// count); populated with the error string when it failed. The
	// frontend treats a populated error as "soft warning, can't
	// confirm cluster" rather than the hard "misconfig" banner.
	ClusterProbeError string `json:"clusterProbeError,omitempty"`
	// v0.5.439 — when the live probe fails but a recent successful
	// probe is cached, Nodes is filled from the cache and these
	// two flags surface the staleness so the frontend renders a
	// small "last refreshed N min ago" pill instead of the warn
	// banner. ClusterProbeError stays empty in this path — the
	// banner only fires when there's no cache to fall back on.
	ClusterNodesStale bool  `json:"clusterNodesStale,omitempty"`
	ClusterNodesAgeMs int64 `json:"clusterNodesAgeMs,omitempty"`
}

CHTopology — what cluster does Coremetry think it's talking to, and does the live CH agree.

type CacheKeyHit added in v0.5.37

type CacheKeyHit struct {
	Key  string `json:"key"`
	Hits int64  `json:"hits"`
}

type CacheStatsSnapshot added in v0.5.37

type CacheStatsSnapshot struct {
	SinceUnixNano int64            `json:"sinceUnixNano"`
	Counts        map[string]int64 `json:"counts"`
	TopKeys       []CacheKeyHit    `json:"topKeys"`
	L1Size        int              `json:"l1Size"`
	L1Cap         int              `json:"l1Cap"`
}

CacheStatsSnapshot is the wire shape for the admin endpoint. Counts is a tier → hit count map; TopKeys is a sorted slice of the most-frequently-served keys (capped at 20).

type CorrelationAnchor added in v0.8.153

type CorrelationAnchor struct {
	Kind    CorrelationKind `json:"kind"`
	TraceID string          `json:"traceId,omitempty"`
	Service string          `json:"service,omitempty"`
	TsNs    int64           `json:"tsNs,omitempty"`
	FromNs  int64           `json:"fromNs"`
	ToNs    int64           `json:"toNs"`
	// JoinKey is the strongest join the bundle actually used:
	//   "trace_id"       — exact cross-signal join (no time fuzz)
	//   "exemplar"       — a real representative trace from the spanmetrics
	//                      rollup (or the slowest/erroring raw span): the
	//                      metric→trace pivot for latency/error anchors. Not the
	//                      literal data point, but exact-enough to pivot into.
	//   "service+window" — the genuinely-fuzzy fallback (throughput/count
	//                      metric, or no exemplar resolved): the operator must
	//                      see this.
	JoinKey string `json:"joinKey"`
}

CorrelationAnchor is what the operator pivoted FROM, echoed back so the drawer's anchor header + join-key chip can render which join is being trusted.

type CorrelationContext added in v0.8.153

type CorrelationContext struct {
	Anchor   CorrelationAnchor          `json:"anchor"`
	Trace    *CorrelationTrace          `json:"trace,omitempty"`
	Logs     []*logstore.LogRecord      `json:"logs"`               // always present (possibly empty)
	Metrics  []chstore.SpanMetricSeries `json:"metrics"`            // anchor service RED series (possibly empty)
	Exemplar *chstore.Exemplar          `json:"exemplar,omitempty"` // metric anchor: a REAL representative trace to pivot INTO (slow/error rollup exemplar, raw-span fallback)
}

CorrelationContext is the assembled pivot bundle. Every lens is best-effort: a lens with no data soft-fails to nil/empty, exactly like rootcause.go — a partial bundle still helps the operator.

type CorrelationKind added in v0.8.153

type CorrelationKind string

CorrelationKind is the pivot anchor's signal shape.

const (
	CorrelateTrace  CorrelationKind = "trace"
	CorrelateLog    CorrelationKind = "log"
	CorrelateMetric CorrelationKind = "metric"
)

type CorrelationTrace added in v0.8.153

type CorrelationTrace struct {
	TraceID     string   `json:"traceId"`
	RootName    string   `json:"rootName"`
	Service     string   `json:"service"`
	DurationMs  float64  `json:"durationMs"`
	SpanCount   int      `json:"spanCount"`
	Services    []string `json:"services"`
	ErrSpans    int      `json:"errSpans"`
	StartTimeNs int64    `json:"startTimeNs"`
	EndTimeNs   int64    `json:"endTimeNs"`
	// Spans is the raw span list (capped) so the drawer's extracted
	// ServiceTimeline sub-component renders the SAME per-service density bars
	// TracePeekDrawer does — no second derivation. Capped to keep the bundle
	// bounded for very large traces.
	Spans []chstore.SpanRow `json:"spans"`
}

CorrelationTrace is the condensed trace lens — enough for the service-timeline mini-waterfall + a header, without re-loading the full /trace page. Derived from the same GetTrace spans the /api/traces/{id} endpoint returns.

type FlowsResponse added in v0.5.103

type FlowsResponse struct {
	Flows []chstore.RootFlow `json:"flows"`
	From  int64              `json:"from"`
	To    int64              `json:"to"`
	// v0.7.39 — total distinct flows in the window (the list is capped at
	// ?top). >len(Flows) → the UI shows "showing N of M flows — raise top".
	TotalFlows int `json:"totalFlows,omitempty"`
}

FlowsResponse lists the top root-anchored business flows in a window. Each entry pairs a root signature with its trace count and the unique set of services those traces touched.

type GraphEdge added in v0.8.10

type GraphEdge struct {
	Source    string  `json:"source"`
	Target    string  `json:"target"`
	Calls     uint64  `json:"calls"`
	Errors    uint64  `json:"errors"`
	ErrorRate float64 `json:"errorRate"`
	Rate      float64 `json:"rate"` // calls per minute over the window (v0.8.x)
	AvgMs     float64 `json:"avgMs"`
	P99Ms     float64 `json:"p99Ms"`
	Protocol  string  `json:"protocol,omitempty"` // http | grpc | db | kafka — SpanKind proxy
}

GraphEdge is one directed caller→callee edge carrying RED metrics + protocol.

type GraphNode added in v0.8.10

type GraphNode struct {
	ID        string  `json:"id"`               // canonical id (the MV's raw name, e.g. "payments" or "db:h2")
	Name      string  `json:"name"`             // display name, prefix-decoded ("payments", "h2")
	Kind      string  `json:"kind"`             // service | database | queue | external | internal
	System    string  `json:"system,omitempty"` // db.system / messaging.system when applicable
	DbName    string  `json:"dbName,omitempty"` // db.name (schema/instance) — database nodes only
	Env       string  `json:"env,omitempty"`    // deployment.environment
	Calls     uint64  `json:"calls"`            // node throughput (inbound preferred, else outbound)
	Errors    uint64  `json:"errors"`
	ErrorRate float64 `json:"errorRate"` // (errors/calls)*100 — drives health color
	Rate      float64 `json:"rate"`      // calls per minute over the window — node-size encoding (v0.8.x)
	// v0.9.367 — which population Calls/Errors/ErrorRate came from:
	// "inbound" (calls INTO the node — the normal basis) or "outbound"
	// (the entry-service fallback: no instrumented caller, so the totals
	// are what the node's DEPENDENCIES returned). The UI labels the two
	// differently; without this the fallback was silent and a gateway's
	// health dot read as its own error rate.
	CallsBasis string `json:"callsBasis,omitempty"`
}

GraphNode is one node in the OTel-native service map.

type InboxAnomalyRef added in v0.5.211

type InboxAnomalyRef struct {
	ID           string  `json:"id"`
	Kind         string  `json:"kind"` // "log_pattern" | "trace_op"
	Pattern      string  `json:"pattern"`
	PeakRatio    float64 `json:"peakRatio"`
	CurrentRatio float64 `json:"currentRatio"`
}

type InboxExceptionRef added in v0.5.211

type InboxExceptionRef struct {
	Fingerprint string `json:"fingerprint"`
	Type        string `json:"type"`
	Message     string `json:"message"`
	Occurrences uint64 `json:"occurrences"`
}

type InboxIncidentRef added in v0.9.321

type InboxIncidentRef struct {
	ID       string `json:"id"`
	Severity string `json:"severity"`
	Status   string `json:"status"`
}

InboxIncidentRef — v0.9.321. A declared Incident is the one triage object a HUMAN created on purpose, and it was the only source the merged queue never showed: an operator working from /inbox could miss an open incident entirely while the sidebar's own /incidents badge counted it.

type InboxItem added in v0.5.211

type InboxItem struct {
	ID             string `json:"id"`       // composite: "<kind>:<nativeId>"
	Kind           string `json:"kind"`     // problem | exception | anomaly
	Source         string `json:"source"`   // human label: "Alert rule" / "Exception" / "Anomaly"
	Priority       string `json:"priority"` // P1 | P2 | P3
	PriorityReason string `json:"priorityReason"`
	Severity       string `json:"severity"` // critical | warning | info
	Service        string `json:"service"`
	Title          string `json:"title"` // rule name / exception type / pattern
	Description    string `json:"description"`
	StartedAt      int64  `json:"startedAt"` // unix ns
	LastSeen       int64  `json:"lastSeen"`  // unix ns; for problems == StartedAt
	Assignee       string `json:"assignee,omitempty"`
	// OwnerTeam + SRETeam attached server-side from
	// service_metadata so the inbox can render team chips
	// without each row firing a per-service lookup. Empty when
	// no catalog row exists for the service. OwnerTeam mirrors
	// what's auto-set on Problem.Assignee at open time;
	// surfacing it on every row (even exceptions / anomalies)
	// keeps the column meaningful across kinds.
	OwnerTeam string `json:"ownerTeam,omitempty"`
	SRETeam   string `json:"sreTeam,omitempty"`
	Status    string `json:"status"` // open | acknowledged | resolved (problems);
	// open | regressed (exceptions); active | cleared (anomalies)
	Clusters []string `json:"clusters,omitempty"`

	// v0.9.255 — enrichment results the inbox was already PAYING for and
	// then dropping. listInbox runs EnrichProblemsWithRunbooks /
	// WithDeploys before mapping (three CH round-trips per poll), but
	// problemToInbox never copied the results out, so every triage row
	// arrived without the two facts an operator reaches for first:
	// "is there a runbook" and "did something just deploy". The queries
	// were billed and the answers thrown away.
	//
	// Problem-kind only for now: exceptions and anomalies have their own
	// deploy correlation paths and are not enriched on this route.
	RunbookURL   string                `json:"runbookUrl,omitempty"`
	RecentDeploy *chstore.RecentDeploy `json:"recentDeploy,omitempty"`
	// Kind-specific drill-down hints. Only one is populated per
	// row. Keeps the JSON shape skinny — frontend reads exactly
	// the one matching `kind`.
	Problem   *InboxProblemRef   `json:"problem,omitempty"`
	Exception *InboxExceptionRef `json:"exception,omitempty"`
	Anomaly   *InboxAnomalyRef   `json:"anomaly,omitempty"`
	Incident  *InboxIncidentRef  `json:"incident,omitempty"`
}

InboxItem is the unified shape every triage-worthy thing (Problem / Exception group / Anomaly event) collapses into. Kind discriminates which source it came from; the kind- specific blob carries the bits needed to drill-down.

Designed so a single table on /inbox can show "everything needing a human" without operators tab-hopping between Problems / Exceptions / Anomalies pages — same priority blend, same age column, same assignee column. The per-source pages still exist as drill-down targets.

type InboxProblemRef added in v0.5.211

type InboxProblemRef struct {
	ID        string  `json:"id"`
	RuleID    string  `json:"ruleId"`
	Metric    string  `json:"metric"`
	Value     float64 `json:"value"`
	Threshold float64 `json:"threshold"`
}

type NoisyRuleWithSuggestion added in v0.5.131

type NoisyRuleWithSuggestion struct {
	chstore.NoisyRule
	Suggestion   string `json:"suggestion"`
	SuggestedFor uint32 `json:"suggestedForSec,omitempty"`
	SuggestedMin uint32 `json:"suggestedMinSamples,omitempty"`
	SuggestedCD  uint32 `json:"suggestedCooldownSec,omitempty"`
	CurrentFor   uint32 `json:"currentForSec"`
	CurrentMin   uint32 `json:"currentMinSamples"`
	CurrentCD    uint32 `json:"currentCooldownSec"`
}

NoisyRuleWithSuggestion enriches the raw NoisyRule with a heuristic suggestion string + structured deltas the UI can apply with one click via the existing AlertRule edit endpoint.

type RootCause added in v0.7.51

type RootCause struct {
	ProblemID    string                   `json:"problemId"`
	Service      string                   `json:"service"`
	Metric       string                   `json:"metric"`
	StartedAt    int64                    `json:"startedAt"`
	FromNs       int64                    `json:"fromNs"`
	ToNs         int64                    `json:"toNs"`
	RecentDeploy *chstore.RecentDeploy    `json:"recentDeploy,omitempty"`
	Correlations []chstore.ChangedService `json:"correlations"`
	BlastRadius  *chstore.BlastRadius     `json:"blastRadius,omitempty"`
	BubbleUp     *chstore.BubbleUpResult  `json:"bubbleUp,omitempty"`
	Exemplar     *chstore.Exemplar        `json:"exemplar,omitempty"`
}

RootCause is the assembled "what changed / likely cause" bundle for one Problem (v0.7.51). It orchestrates signals that already exist but were scattered — recent deploy, correlated service changes, dimension bubble-up, blast radius, an exemplar trace — into a single cached read so the Problem triage drawer shows one root-cause surface instead of the operator hopping across pages. Read-only.

type SchemaColumn

type SchemaColumn struct {
	Name string `json:"name"`
	Type string `json:"type"`
}

type SchemaTable

type SchemaTable struct {
	Table   string         `json:"table"`
	Engine  string         `json:"engine"`
	Columns []SchemaColumn `json:"columns"`
}

SchemaTable + SchemaColumn drive the playground's left-side browser. Operator clicks a column → it pastes into the editor at cursor; click a table → SELECT * FROM <table> LIMIT 100 gets generated. Both query system.tables / system.columns, pre-filtered to the current database. Results cached 60s.

type Server

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

func NewServer

func NewServer(addr string, ing *otlp.Ingester, store *chstore.Store, logs logstore.Store, webFS embed.FS, authSvc *auth.Service, oidcSvc *auth.OIDCService, ldapSvc *ldap.Service, c cache.Cache, n *notify.Notifier, cop *copilot.Service, bus *sse.Broker) *Server

func (*Server) EnableDemoMode

func (s *Server) EnableDemoMode(email, password string)

EnableDemoMode wires the demo credentials returned by /api/auth/config. Loud no-op when called with empty credentials so a misconfigured demo flag doesn't silently expose nothing.

func (*Server) SetAutocomplete added in v0.8.80

func (s *Server) SetAutocomplete(a *acache.Store)

SetAutocomplete wires the Redis autocomplete cache (v0.8.80). Called once from main() after the api.Server is constructed. nil-safe — the picker handlers fall back to ClickHouse when it's absent or cold.

func (*Server) SetBackgroundConfig added in v0.4.95

func (s *Server) SetBackgroundConfig(b config.BackgroundConfig)

SetBackgroundConfig wires the cadence/timeout knobs to the Server. Called once from main() after Load() so the status probe respects the configured ceiling.

func (*Server) SetBuildVersion added in v0.9.339

func (s *Server) SetBuildVersion(v string)

SetBuildVersion records what the IMAGE actually is, independent of any display override. v0.5.394 removed the env override precisely because a stale value masked this; keeping both is what lets the override come back safely (v0.9.339).

func (*Server) SetCluster added in v0.5.253

func (s *Server) SetCluster(c *cluster.Service)

SetCluster wires the per-pod heartbeat / membership service (v0.5.253). Always called from main() — the service degenerates to a single-pod view when Redis isn't configured so handlers don't need to nil-check before calling Members.

func (*Server) SetLdapGroupSync added in v0.8.526

func (s *Server) SetLdapGroupSync(e *ldap.SyncEngine)

SetLdapGroupSync wires the LDAP group-sync engine (v0.8.526).

func (*Server) SetLockDegraded added in v0.8.212

func (s *Server) SetLockDegraded(b bool)

SetLockDegraded records that the distributed leader lock fell back to the always-leader Noop despite Redis being configured (Redis down at boot) — so /admin/stats can warn that multi-pod background jobs are duplicated. v0.8.212. Called with false by the Redis re-probe (v0.8.341) once the real lock is swapped back in — the /admin/stats warning clears without a pod restart.

func (*Server) SetLogstoreESManager added in v0.8.232

func (s *Server) SetLogstoreESManager(m *logstore.ESManager)

SetLogstoreESManager wires the UI-managed logstore config owner (v0.8.232). main() constructs the manager alongside the Switchable logstore; the Settings → Elasticsearch handlers are 503 no-ops without it (partial init / tests).

func (*Server) SetMCP added in v0.6.4

func (s *Server) SetMCP(m *mcp.Server)

SetMCP wires the Model Context Protocol server (v0.6.4). Called once from main() after the api.Server is constructed. nil is valid — leaves the /api/mcp/* routes unregistered.

func (*Server) SetPipeline added in v0.5.263

func (s *Server) SetPipeline(p *pipeline.Engine)

SetPipeline wires the engine. Always called from main(); the admin handlers nil-check so a misconfigured boot doesn't 500 every request — they return 503 with a clear reason.

func (*Server) SetRAG added in v0.8.441

func (s *Server) SetRAG(r *rag.Service)

SetRAG bağlar (v0.8.438) — cluster.Set deseninde opsiyonel bağımlılık.

func (*Server) SetRoles added in v0.8.346

func (s *Server) SetRoles(ingest, apiRole bool)

SetRoles wires the pod's runtime role split into the HTTP surface (v0.8.346, HA audit H6). main.go's old comment claimed "api.NewServer handles the role guard internally" — no such code existed: every role registered POST /v1/* while only ingest pods Start() the consumers, so a collector pointed at an api-role pod had its Exports 200-OK'd into channels NOBODY DRAINED (silent black hole; queue gauges even looked healthy at a constant 100%). Defaults (unset) = all roles on, which keeps monolithic mode and test-constructed Servers byte-identical.

func (*Server) SetTempo added in v0.5.208

func (s *Server) SetTempo(t *tempo.Service)

SetTempo wires the external Tempo client. Always called from main() with a non-nil service — Configured() reports whether the operator has actually filled in the settings.

func (*Server) SetThanos added in v0.8.576

func (s *Server) SetThanos(t *thanos.Service)

SetThanos wires the multi-cluster Thanos Querier client (v0.8.576). Always called from main() with a non-nil service — HasEnabledClusters() reports whether the operator configured any cluster.

func (*Server) SetVersion

func (s *Server) SetVersion(v string)

SetVersion records the build-time tag. Called once from main(); safe to call before Start() since /api/version is only consulted by SPA after the server is listening.

func (*Server) Shutdown added in v0.8.336

func (s *Server) Shutdown(ctx context.Context) error

Shutdown drains the HTTP server (v0.8.336, HA audit H1): stops accepting new connections, lets in-flight requests finish within ctx's deadline. Safe before Start() (nil server = no-op).

func (*Server) Start

func (s *Server) Start() error

func (*Server) StartAuditDrainer added in v0.5.339

func (s *Server) StartAuditDrainer(ctx context.Context)

StartAuditDrainer runs the batched audit-write loop until ctx is cancelled. Triggers a flush when either the channel hits 64 pending entries or the 200ms tick elapses — whichever comes first. Errors are logged but don't tear down the drainer; the next tick reattempts.

func (*Server) StartCacheInvalidation added in v0.5.337

func (s *Server) StartCacheInvalidation(ctx context.Context)

StartCacheInvalidation subscribes to the invalidation channel and drains incoming messages into l1.del. Runs once per Server; the subscription lifetime is bound to the server's lifetime context. When Subscribe returns an error (Redis down, or pub/sub unsupported), we log and exit — the soft TTL keeps the L1 tier from growing stale unbounded, just for longer.

Called from main.go alongside the other StartConfigRefresh loops, exported because the constructor doesn't take a ctx.

func (*Server) StartRAGSync added in v0.8.442

func (s *Server) StartRAGSync(ctx context.Context, lock cache.Lock)

StartRAGSync — 30 dk'lık leader-gated arka plan senkronu (deriver deseni). api rolündeki pod'larda main.go'dan başlatılır.

type ServiceGraphResponse added in v0.8.10

type ServiceGraphResponse struct {
	Nodes []GraphNode `json:"nodes"`
	Edges []GraphEdge `json:"edges"`
	Scope string      `json:"scope"`
	Focus string      `json:"focus,omitempty"`
	// TotalNodes / ShownNodes (v0.8.295, re-land of v0.8.277) — set by
	// pruneServiceGraphTopN. When the global render budget trims a large
	// graph, ShownNodes < TotalNodes and the UI can show "showing X of Y
	// services" (same contract as the v0.8.215 cap on sampled
	// /api/service-map).
	TotalNodes int `json:"totalNodes"`
	ShownNodes int `json:"shownNodes"`
}

ServiceGraphResponse is the compact payload the canonical renderer consumes.

type ServiceTopologyNode added in v0.5.102

type ServiceTopologyNode struct {
	ID   string `json:"id"`   // canonical id used by edges (service name OR "db:postgresql")
	Name string `json:"name"` // display label, sans prefix for infra ("postgresql" not "db:postgresql")
	Kind string `json:"kind"` // "service" | "db" | "queue" | "external"
	// v0.5.312 — Phase 2 enrichment for the topology redux:
	// soft-cluster the diagram by k8s.namespace / service.namespace
	// and paint each node with a health badge from open-problems
	// count. Both are read-time-enriched (no schema change), nil-
	// safe (omitempty), so older frontends keep working.
	Namespace    string `json:"namespace,omitempty"`
	Health       string `json:"health,omitempty"`       // "" | "green" | "yellow" | "red"
	HealthReason string `json:"healthReason,omitempty"` // short "2 open criticals" etc.
	OpenCritical int    `json:"openCritical,omitempty"`
	OpenWarning  int    `json:"openWarning,omitempty"`
	// v0.5.409 — known 3rd-party SaaS / cloud annotation for
	// external nodes. Populated from the edge's ExtDisplay /
	// ExtKind (set by external_catalogue lookup). UI renders a
	// human-readable display name + category badge instead of
	// the raw `ext:api.stripe.com` hostname.
	ExtDisplay string `json:"extDisplay,omitempty"`
	ExtKind    string `json:"extKind,omitempty"`
	// v0.5.410 — display-only environment annotation
	// (deployment.environment / service.namespace /
	// k8s.namespace.name). Populated from the edge that
	// brought this node into the graph. UI surfaces it as a
	// small chip ("prod" / "stage") next to the service name
	// so multi-env installs distinguish at-a-glance.
	Env string `json:"env,omitempty"`
	// v0.7.32 — for a collapsed broadcast queue node, the real number of
	// distinct consumer services its fan-out was hidden behind. The renderer
	// shows "→ N services (broadcast)" on the node instead of N edges. Only set
	// on queue nodes whose consumer count exceeded the broadcast threshold.
	BroadcastFanout int `json:"broadcastFanout,omitempty"`
}

ServiceTopologyNode is one node in the service-level graph. Kind distinguishes a real service from synthetic infra nodes (db, queue, cache, external) so the renderer can paint them differently without per-node lookup.

type ServiceTopologyResponse added in v0.5.102

type ServiceTopologyResponse struct {
	Nodes     []ServiceTopologyNode         `json:"nodes"`
	Edges     []chstore.ServiceTopologyEdge `json:"edges"`
	From      int64                         `json:"from"`
	To        int64                         `json:"to"`
	Truncated bool                          `json:"truncated"`
	// v0.6.48 — server-side scoping for thousand-service fabrics.
	// TotalServices is the distinct service count BEFORE the top-N /
	// focus bound was applied, so the UI can show "showing N of M
	// services — search or focus to refine". Scoped is true when the
	// returned graph is a bounded subset (top-N by call volume, or a
	// focus neighbourhood) rather than the full fabric.
	TotalServices int    `json:"totalServices"`
	Scoped        bool   `json:"scoped"`
	ScopeReason   string `json:"scopeReason,omitempty"` // "top-50 by call volume" | "focus: <svc> +2 hops"
	// v0.7.32 — number of broadcast queue topics whose consumer fan-out was
	// collapsed (a topic with >threshold distinct consumers, e.g. a kafka
	// cache-refresh broadcast). The UI shows a "N broadcast topics collapsed —
	// show" affordance that flips ?broadcast=show. 0 when none / ?broadcast=show.
	BroadcastCollapsed int `json:"broadcastCollapsed,omitempty"`
}

ServiceTopologyResponse is the JSON shape served by /api/topology/service — flat node + edge lists matching the chstore ServiceTopologyEdge model. Includes the time window so the UI can render the active window and a draw.io export can embed it in the filename.

type SpanMetricServiceRow added in v0.5.350

type SpanMetricServiceRow struct {
	Service   string  `json:"service"`
	Calls     uint64  `json:"calls"`
	Errors    uint64  `json:"errors"`
	ErrorRate float64 `json:"errorRate"`
	AvgMs     float64 `json:"avgMs,omitempty"`
	MaxMs     float64 `json:"maxMs,omitempty"`
	P50Ms     float64 `json:"p50Ms,omitempty"`
	P99Ms     float64 `json:"p99Ms,omitempty"`
	// Inline call-rate sparkline — 30 buckets evenly spread
	// across the requested window. Float so a SVG renderer can
	// scale by max() without integer truncation; counts are
	// integers in the source data but we already pay the
	// float math in the aggregation step.
	Sparkline []float64 `json:"sparkline,omitempty"`
	// Source metric names this row aggregated — surfaced to
	// the UI so the operator can confirm which spanmetrics
	// processor variant their collector is emitting.
	CallsMetric    string `json:"callsMetric,omitempty"`
	DurationMetric string `json:"durationMetric,omitempty"`
}

SpanMetricServiceRow is one row of the span-metric-derived service overview — call volume + error fraction in the window, optionally augmented with histogram-derived latency once we wire that. Returned by /api/spanmetrics/services.

type TopologyNode added in v0.5.100

type TopologyNode struct {
	ID      string `json:"id"`
	Service string `json:"service"`
	Op      string `json:"op"`
}

TopologyNode is a service.operation node in the response. The frontend keys nodes by `id` (service|op) so render-time edge lookups stay O(1).

type TopologyResponse added in v0.5.100

type TopologyResponse struct {
	Nodes       []TopologyNode         `json:"nodes"`
	Edges       []chstore.TopologyEdge `json:"edges"`
	RootService string                 `json:"rootService"`
	Depth       int                    `json:"depth"`
	From        int64                  `json:"from"` // unix ns
	To          int64                  `json:"to"`
	Truncated   bool                   `json:"truncated"`
}

TopologyResponse is the JSON shape served by /api/topology. Truncated is true when the underlying edge query hit the LIMIT — the UI shows a banner so the operator knows the view is partial.

Jump to

Keyboard shortcuts

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