diff --git a/src/lib/alert.ts b/src/lib/alert.ts index d9a5d486..98fbd8ca 100644 --- a/src/lib/alert.ts +++ b/src/lib/alert.ts @@ -18,33 +18,42 @@ export const ALERT_METRICS: AlertMetricMeta[] = [ { value: 'egress', label: 'Egress (bytes per minute)' } ] +export const ALERT_CUSTOM_METRICS: AlertMetricMeta[] = [ + { value: 'value', label: 'Value (gauge)' }, + { value: 'rate', label: 'Rate (per minute)' } +] + export const ALERT_OPS = [ { value: '>=', label: '>= (at or above)' }, { value: '<=', label: '<= (at or below)' } ] export function alertMetricLabel (metric: string): string { - return ALERT_METRICS.find((m) => m.value === metric)?.label ?? metric + return ALERT_METRICS.concat(ALERT_CUSTOM_METRICS).find((m) => m.value === metric)?.label ?? metric } /** * Format a threshold/value for its metric's unit — percent for cpu/memory, - * binary bytes/min for egress, req/min otherwise. + * binary bytes/min for egress, the raw gauge for kind=custom value, per-minute + * for rate/requests. */ export function alertThresholdString (metric: string, value: number): string { if (metric === 'cpu' || metric === 'memory') return `${value}%` if (metric === 'egress') return `${format.storage(value)}/min` + if (metric === 'value') return String(value) return `${value}/min` } /** - * Human-readable one-liner for a condition, e.g. "cpu >= 90% for 10m". + * Human-readable one-liner for a condition, e.g. "cpu >= 90% for 10m" or + * "value >= 10 for 5m". */ export function alertConditionString (c: Api.AlertCondition): string { return `${c.metric} ${c.op} ${alertThresholdString(c.metric, c.threshold)} for ${c.forMinutes}m` } export function alertTargetString (t: Api.AlertTarget): string { + if (t.kind === 'custom') return `${t.source} / ${t.series}` return `${t.location} / ${t.deployment}` } diff --git a/src/lib/components/CustomMetricsChart.svelte b/src/lib/components/CustomMetricsChart.svelte new file mode 100644 index 00000000..1094ad23 --- /dev/null +++ b/src/lib/components/CustomMetricsChart.svelte @@ -0,0 +1,185 @@ + + +{#if source.truncated} +
+{/if} +{#if source.lastError} + +{/if} +{#if queryError} + +{/if} + + + +{#if isEmpty} + +{:else} +Notify when a deployment metric crosses a threshold for a sustained period.
+Notify when a deployment or custom metric crosses a threshold for a sustained period.
- - {alert.target.location} / {alert.target.deployment} - + {#if alert.target.kind === 'custom'} + + {alert.target.source} / {alert.target.series} + + {:else} + + {alert.target.location} / {alert.target.deployment} + + {/if}
Scrape a path on one of your deployments once a minute. The platform reaches the pod in-cluster — there is no URL to set.
++ {#if status === 'disabled'} + Disabled + {:else} + {status} + {/if} + {source.location} / {source.deployment}:{source.port}{source.path} +
+Scraped series for this source. Leave the series filter empty to chart the most recently seen.
+Gauges, counters, and untyped metrics kept from the last scrape. Histograms and summaries are dropped.
+| Series | +Type | +Last seen | +
|---|---|---|
| {s.series} | +{s.type} | ++ {format.fromNow(s.lastSeenAt) || '—'} + | +
| No series discovered yet. | ||