Skip to main content

βš™οΈ General configuration

This is the complete settings reference. Most people only need to choose an alert channel; the defaults already cover the common Kubernetes failures.

πŸ—ΊοΈ Find a setting quickly​

You want to...Start with...
Choose a notification destinationChannels
Watch fewer namespacesnamespaces
Ignore an intentional failureSilences
Group related incidentsCorrelation
Add a runbook linkCustom templates and runbooks
Keep credentials safeSecret-backed credentials
See every accepted keyComplete configuration reference

βœ… A safe change checklist​

  1. Change one setting.
  2. Run kwatch lint.
  3. Apply the config through kwatch.sh and wait for the Pod to become ready.
  4. Use kwatch lint --check or /test-alert after changing a provider.

Every default below is the value used by the binary unless the installation method says otherwise. TLS, heartbeat, Metrics Server, and active probes are opt-in.

The base config is read from CONFIG_FILE (default /config/config.yaml). The interactive manager mounts it from a Kubernetes Secret and can also enable a KwatchConfig resource as a versioned configuration overlay. If you maintain a custom deployment, preserve the same file and Secret contract. Every field below maps directly to the Go struct at internal/config/config.go. Sensitive strings must use an exact ${file:/absolute/path} reference to read a file mounted from a Kubernetes Secret at startup.

The good news: you probably don't need this page. Every option below has a safe default and works out of the box. Use this reference when you want to change something β€” fewer alerts, a different channel, a custom message β€” or when a term in an alert confuses you. After editing your config.yaml, run kwatch lint (add --check to also verify credentials for providers that support checks).


πŸ”§ General​

Decide what to watch and how often.

ParameterTypeDefaultDescription
maxRecentLogLinesint50Max recent log lines per container in alert messages. Also caps events.
resyncSecondsint0Periodic informer resync interval. 0 = event-driven only (recommended). Raisable to e.g. 600 as a safety net.
workersint1Parallel reconcile workers per queue. Raise for clusters with 200+ pods. Alert ordering becomes non-deterministic (dedup unaffected).
containerRestartThresholdint0Alert when a running container exceeds this cumulative restart count. 0 = disabled.
ignoreFailedGracefulShutdownbooltrueSkip containers stopped by a clean/graceful shutdown.
ignoreDisruptionTerminationsbooltrueSkip pods evicted during node drains (DeletionTimestamp / DisruptionTarget).
adaptiveThresholdsbooltrueAdd bounded workload-aware grace during normal partial rollouts.
reportStartupBaselinebooltrueSend one startup summary of pre-existing issues (suppressed from individual alerts). Anything already broken when kwatch starts is otherwise quiet for 24 hours, so keep this on.
maintenanceobjectenabledSuppress explicitly marked pod/container maintenance without disabling cluster-level alerts.
namespaces[]stringallWatch only these namespaces β€” or use !kube-system to watch everything except it.
namespaceSelectorstring""Kubernetes label selector to discover namespaces. Use instead of namespaces, not with it.
reasons[]stringallAlert on these event reasons only β€” or exclude with ! (e.g. reasons: ["!Started"]).
includeEventsbooltrueInclude Kubernetes events in alert messages (at most the 40 most recent).
includeLogsbooltrueInclude container logs in alert messages.
runbooksmap[string]string{}Add a link to your runbook for each error reason, so every alert comes with help attached.

πŸ”½ Namespace / Reason filtering​

# Watch only these namespaces
namespaces:
- default
- production

# Or exclude some (can't mix both)
namespaces:
- !kube-system
- !monitoring

# Filter by event reason
reasons:
- CrashLoopBackOff
- ImagePullBackOff

# Or exclude reasons
reasons:
- !Started
- !Killing

πŸ“± App​

ParameterTypeDefaultDescription
app.clusterNamestring""Name shown in alerts so you know which cluster.
app.proxyURLstring""Outbound HTTP proxy used for all provider calls.
app.disableStartupMessageboolfalseSilence the "kwatch is alive" welcome message.
app.logFormatterstring"text"Log format: text or json.
app.insecureSkipTLSVerifyboolfalseSkip TLS verification for outbound HTTP (providers).
app.caBundlePathstring""Path to a PEM file with custom CA certificates.
app:
clusterName: production-us-east
logFormatter: json

πŸ’“ Health Check​

ParameterTypeDefaultDescription
healthCheck.enabledbooltrueExpose health endpoints.
healthCheck.portint8060HTTP listen port.
healthCheck.pprofboolfalseEnable Go /debug/pprof/* profiling endpoints.
healthCheck.diagnosticsboolfalseEnable /incidents, /test-alert, /deadletters endpoints.
healthCheck.diagnosticsTokenstring""Bearer token; must use ${file:/absolute/path}.

Endpoints:

PathDescriptionRequires
GET /healthzLiveness probeβ€”
GET /readyzReadiness probe (waits for cache sync)β€”
GET /health{"status": "ok"}β€”
GET /metricsPrometheus metrics (incidents, notifications, baseline, graph size)β€”
GET /incidentsActive incidents as JSONdiagnostics: true
POST /test-alertSend a test notificationdiagnostics: true
GET /deadlettersRecent delivery failuresdiagnostics: true
healthCheck:
port: 8060
diagnostics: true

πŸ”„ Upgrader​

ParameterTypeDefaultDescription
upgrader.disableUpdateCheckboolfalseDon't check GitHub for new kwatch releases.

🎯 Severity​

Every alert carries a severity, shown as the colour of its headline. Severity drives urgent channels, escalation, and re-notification.

SeverityMeaning
criticalπŸ”΄ Something users feel right now
high🟠 Needs a person soon
warning / medium🟑 Worth a look
normalπŸ”΅ Informational
ParameterTypeDefaultDescription
severityByOwnerKindmap[string]stringStatefulSet β†’ highSet severity per resource type, e.g. StatefulSet: "high".
severityByReasonmap[string]string{}Set severity per event reason, checked before owner kind.
severityByOwnerKind:
StatefulSet: "high"
DaemonSet: "low"

severityByReason:
OOMKilled: "high"
CrashLoopBackOff: "high"

πŸ”‡ Silences β€” advanced suppression​

Silences suppress an incident that matches any rule β€” no alert, no group, nothing. Build rules from anything on the incident:

FieldTypeDescription
namespaces[]stringSuppress matching namespaces.
reasons[]stringSuppress matching reasons.
podNamePatterns[]stringRegex patterns for pod names.
containerNames[]stringSuppress matching container names.
logPatterns[]stringRegex patterns for log content.
containerMessages[]stringSubstring match on container status message.
eventMessages[]stringSubstring match on an attached Kubernetes Event message.
nodeReasons[]stringSuppress matching node reasons.
nodeMessages[]stringSubstring match on node condition message.
silences:
- namespaces: ["kube-system"]
- reasons: ["BackOff"]
- podNamePatterns: ["my-fancy-pod-.*"]
- eventMessages: ["failed to sync configmap cache"]
- nodeReasons: ["KubeletNotReady"]
nodeMessages: ["kubelet has no node IP"]

eventMessages uses a case-sensitive substring match against Events attached to the affected Pod. It suppresses the whole incident; includeEvents only controls whether those Events are shown in the notification.

Deprecated top-level fields (ignoreContainerNames, ignorePodNames, ignoreLogPatterns, ignoreContainerMessages, ignoreNodeReasons, ignoreNodeMessages) still work but are internally merged into the silence index. Prefer silences for new configs.


🚫 Inhibition β€” no double alerts​

When the node is down, don't also page you about every pod on it β€” you can't fix pods that have no machine.

ParameterTypeDefaultDescription
inhibition.nodeSuppressesPodsbooltrueIf a node has an active incident, pod incidents on that node are suppressed. Lifts as soon as the node recovers.

🧠 Correlation β€” incident lifecycle​

This is kwatch's memory β€” how it remembers that "this crash" and "that crash five minutes ago" are the same problem, when it's allowed to yell again, and when it should escalate a recurring crash.

ParameterTypeDefaultDescription
correlation.windowint (min)10Keep incidents in memory. Outside this β†’ new incident.
correlation.lifecycleIntervalint (min)1How often lifecycle checks (stale, resolve) run.
correlation.resolveHoldDownint (sec)300Wait before sending "resolved". Flap dampening. Must be ≀ window * 60.
correlation.cooldownMinutesint (min)10Min time between identical crash re-alerts. 0 = off.
correlation.maxBaselineint5000Max baseline entries (prevents re-paging after restart).
correlation.escalation.enabledbooltrueEscalate severity when restart count crosses tiers.
correlation.escalation.tiers[]int[3, 10]Crossing the first β†’ high, the second β†’ critical. Must be strictly ascending.
correlation.renotify.intervalBySeveritymap[string]int{}Min minutes between renotifications per severity. "default" is the fallback key. Unset = off.
correlation.renotify.maxPerIncidentint3Max renotifications per incident lifetime.
correlation:
window: 10
resolveHoldDown: 300
cooldownMinutes: 10
escalation:
enabled: true
tiers: [3, 10]
renotify:
intervalBySeverity:
critical: 15
high: 60
default: 120

🧹 Smart Grouping β€” coalesce duplicate notifications​

Many pods failing the same way = one alert, not one per pod. Related failures over a short window are collected and summarized into a single notification, then re-notified on a gentle cooldown instead of every event.

ParameterTypeDefaultDescription
smartGrouping.windowSecondsint (sec)60Grouping window. 0 disables.
smartGrouping.namespaceFanOutThresholdint3Distinct owners failing the same way in one namespace, within one window, before their groups collapse into one alert. 0 disables.
smartGrouping:
windowSeconds: 60
namespaceFanOutThreshold: 3

πŸ“ Custom Templates & Runbooks​

Override the alert message per reason (Go text/template), and attach documentation URLs.

templates:
CrashLoopBackOff: "{{.Incident.Name}} β€” {{.Action}} β€” {{.Incident.Hint}}"
OOMKilled: "πŸ”΄ {{.Incident.Name}} ran out of memory in {{.Incident.Namespace}}"

runbooks:
OOMKilled: "https://wiki.example.com/oom"
CrashLoopBackOff: "https://wiki.example.com/crashloop"

Template variables: {{.Incident.Key}}, {{.Incident.Reason}}, {{.Incident.Name}}, {{.Incident.Namespace}}, {{.Incident.Hint}}, {{.Action}} (create/update/resolved), {{.Message}}.


πŸ“ Audit log​

For every incident transition (created, updated, resolved, skipped), kwatch writes one structured JSON line β€” feed it to your log pipeline for a searchable history.

ParameterTypeDefaultDescription
auditLog.enabledbooltrueWrite one structured JSON entry per incident transition.
auditLog.outputstring"stdout"Destination: stdout or a file path.

🧰 Operations and security​

ParameterTypeDefaultDescription
telemetry.enabledbooltrueSend a weekly adoption heartbeat containing only a random installation ID and the kwatch version.
maintenance.enabledbooltrueHonor maintenance annotations.
maintenance.annotationstringkwatch.io/maintenanceAnnotation used to mark deliberate maintenance.
maintenance.untilAnnotationstringkwatch.io/maintenance-untilOptional annotation containing the maintenance expiry time.

For maintenance behavior and examples, keep the annotations in the Pod template and use the maintenance.annotation and maintenance.untilAnnotation keys above.


πŸ“‹ CRD β€” configuration overlay with automatic restart​

Instead of editing the base config, you can store a non-sensitive overlay in a small custom resource. Provider settings, heartbeat URLs, and diagnostic tokens are forbidden in KwatchConfig; they remain in the mounted Secret. The overlay is applied at startup. When the resource changes, kwatch restarts its Pod so the complete configuration is rebuilt consistently. It is off by default in the generic binary.

ParameterTypeDefaultDescription
crd.enabledboolfalseWatch KwatchConfig custom resources and restart kwatch when the overlay changes.
crd.failureConditionslist[]Extra CRD status rules such as Ready=False or Degraded=True.
crd.graphReferenceslist[]Optional references that add custom CRD edges to dependency analysis.
apiVersion: kwatch.abahmed.dev/v1alpha1
kind: KwatchConfig
metadata:
name: kwatch-config
namespace: kwatch
spec:
maxRecentLogLines: 100
silences:
- namespaces: ["kube-system"]

πŸ“Š Monitors​

All monitors below are on by default unless the table says default: false.

πŸ–₯️ Node Monitor​

ParameterTypeDefaultDescription
nodeMonitor.enabledbooltrueDetect NotReady, Unknown, MemoryPressure, DiskPressure, PIDPressure, NetworkUnavailable.
nodeMonitor.sustainedMinutesint3Minutes a node condition must persist before alerting.

⏳ Pending Pod Monitor​

ParameterTypeDefaultDescription
pendingPodMonitor.enabledbooltrueDetect pods stuck in Pending.
pendingPodMonitor.thresholdint (sec)300Seconds stuck before alerting.

Includes scheduleMonitor.enabled (default true) to add how long the scheduler has been stalling ("unschedulable for 5m30s") to the hint.

🟑 Not Ready Monitor​

ParameterTypeDefaultDescription
notReadyMonitor.enabledbooltrueAlert with ContainersNotReady when a Running pod's Ready condition stays false too long. The budget is derived from the pod's own probes, not a fixed number.

πŸš€ Rollout Monitor (Deployments)​

ParameterTypeDefaultDescription
rolloutMonitor.enabledbooltrueDetect ProgressDeadlineExceeded and stalled rollouts.
rolloutMonitor.sustainedMinutesint5Minutes of unavailability before alerting.

🧩 StatefulSet Monitor​

ParameterTypeDefaultDescription
statefulSetMonitor.enabledbooltrueDetect unavailable StatefulSet pods.
statefulSetMonitor.sustainedMinutesint5Minutes of unavailability before alerting, plus 15-minute rollout grace.

πŸ“‘ DaemonSet Monitor​

ParameterTypeDefaultDescription
daemonSetMonitor.enabledbooltrueDetect unavailable DaemonSet pods.
daemonSetMonitor.sustainedMinutesint5Debounce before alerting.

πŸ§‘β€πŸ’Ό Job Monitor​

ParameterTypeDefaultDescription
jobMonitor.enabledbooltrueDetect failed (JobFailed) or suspended Jobs.

⏰ CronJob Monitor​

ParameterTypeDefaultDescription
cronJobMonitor.enabledbooltrueDetect suspended CronJobs or missed schedules.
cronJobMonitor.sustainedMinutesint5Minutes a CronJob must stay suspended before alerting.

πŸ“ˆ HPA Monitor​

ParameterTypeDefaultDescription
hpaMonitor.enabledbooltrueDetect HPAs stuck at max replicas.
hpaMonitor.sustainedMinutesint20Minutes sustained before alerting.

πŸš€ Cluster Autoscaler Monitor​

ParameterTypeDefaultDescription
clusterAutoscalerMonitor.enabledbooltrueDetect FailedToScaleUp / NotTriggerScaleUp (autoscaler can't add capacity).

πŸ’Ύ PVC Monitor​

ParameterTypeDefaultDescription
pvcMonitor.enabledbooltrueMonitor PersistentVolumeClaim disk usage.
pvcMonitor.intervalint (min)5Check frequency.
pvcMonitor.thresholdfloat (%)80Warn threshold.
pvcMonitor.criticalThresholdfloat (%)90High-severity threshold. Must be β‰₯ threshold.
pvcMonitor.clearThresholdfloat (%)75Resolve below this %. Must be ≀ threshold.

πŸ’“ Heartbeat Monitor (dead man's switch)​

Off by default. Sends periodic HTTP pings to an external health-check URL. If kwatch stops, the external monitor stops getting pings and pages you.

ParameterTypeDefaultDescription
heartbeatMonitor.enabledboolfalseEnable heartbeat pings.
heartbeatMonitor.intervalint (sec)300Seconds between pings.
heartbeatMonitor.urlstring""Secret-backed ${file:/absolute/path} heartbeat URL.

πŸ”’ TLS Certificate Monitor​

Off by default because it requires an additional secrets RBAC permission. Warns with 30 days to go, and raises severity to high with 3 days to go.

ParameterTypeDefaultDescription
tlsMonitor.enabledboolfalseEnable TLS certificate monitoring.
tlsMonitor.thresholdint (days)30Days before expiry to warn.
tlsMonitor.criticalThresholdint (days)3Days before expiry to raise severity to high.

πŸ”— Service Endpoint Monitor​

ParameterTypeDefaultDescription
serviceMonitor.enabledbooltrueDetect Services with zero ready endpoints (60s debounce).

🧩 Admission Webhook Monitor​

ParameterTypeDefaultDescription
admissionWebhookMonitor.enabledbooltrueDetect webhooks whose backing service has no ready endpoints.

πŸ›οΈ Control-Plane Monitor​

ParameterTypeDefaultDescription
controlPlaneMonitor.enabledbooltrueDetect container issues in control-plane pods (apiserver, scheduler, controller-manager, etcd, kube-proxy, coredns).
controlPlaneMonitor.intervalSecondsint30Seconds between API and control-plane health checks.
controlPlaneMonitor.apiServerLatencyWarningMsint1000API server /readyz latency warning threshold in milliseconds.
controlPlaneMonitor.failureThresholdint2Consecutive failures before alerting.
controlPlaneMonitor.recoveryThresholdint2Consecutive successes before resolving.

🌐 Ingress Backend Monitor​

ParameterTypeDefaultDescription
ingressMonitor.enabledbooltrueDetect ingress backends with zero ready endpoints.

🚧 Network Policy Monitor​

ParameterTypeDefaultDescription
networkPolicyMonitor.enabledbooltrueDetect NetworkPolicies that deny all inbound traffic.

πŸ”„ PDB Monitor​

ParameterTypeDefaultDescription
pdbMonitor.enabledbooltrueDetect PDBs blocking voluntary disruptions (disruptionsAllowed=0).
pdbMonitor.sustainedMinutesint5Minutes of blocking before alerting.

🏭 Node Resource Monitor​

ParameterTypeDefaultDescription
nodeResourceMonitor.enabledbooltrueCheck node CPU/memory overcommit levels.
nodeResourceMonitor.intervalSecondsint300How often to check.
nodeResourceMonitor.cpuWarningfloat2.0CPU overcommit ratio for warning.
nodeResourceMonitor.cpuCriticalfloat4.0CPU overcommit ratio for critical.
nodeResourceMonitor.memWarningfloat2.0Memory overcommit ratio for warning.
nodeResourceMonitor.memCriticalfloat4.0Memory overcommit ratio for critical.
nodeResourceMonitor.filesystemWarningPercentfloat90Node filesystem usage warning threshold. 0 disables it.
nodeResourceMonitor.filesystemCriticalPercentfloat95Node filesystem usage critical threshold. 0 disables it.
nodeResourceMonitor.inodeWarningPercentfloat90Node inode usage warning threshold. 0 disables it.
nodeResourceMonitor.inodeCriticalPercentfloat95Node inode usage critical threshold. 0 disables it.

πŸ“Š Optional Metrics Server monitor​

runtimeMetricsMonitor reads the optional metrics.k8s.io API. It is disabled by default and is not required for kwatch's built-in kubelet telemetry.

ParameterTypeDefaultDescription
runtimeMetricsMonitor.enabledboolfalseUse Metrics Server data for workload usage diagnostics.
runtimeMetricsMonitor.intervalSecondsint60Seconds between checks.
runtimeMetricsMonitor.memoryWarningPercentint90Memory usage warning percentage.
runtimeMetricsMonitor.memoryCriticalPercentint100Memory usage critical percentage.
runtimeMetricsMonitor.cpuWarningPercentint90CPU usage warning percentage.
runtimeMetricsMonitor.cpuCriticalPercentint100CPU usage critical percentage.

The shipped RBAC does not grant the extra metrics.k8s.io permission by default. Add it only when this monitor is enabled.

πŸ›οΈ Cluster resource monitor​

ParameterTypeDefaultDescription
clusterResourceMonitor.enabledbooltrueWatch quota, namespace, and node-lease lifecycle failures.
clusterResourceMonitor.sustainedMinutesint10Minutes a terminating namespace or quota condition must persist.
clusterResourceMonitor.nodeLeaseStaleSecondsint90Seconds without a node lease renewal before reporting a stale heartbeat.

🧠 Kubelet telemetry monitor​

This monitor uses built-in kubelet endpoints. It does not need an agent or Prometheus.

ParameterTypeDefaultDescription
kubeletTelemetryMonitor.enabledbooltrueRead built-in kubelet telemetry.
kubeletTelemetryMonitor.intervalSecondsint60Seconds between telemetry sweeps.
kubeletTelemetryMonitor.failureThresholdint2Consecutive failed samples before alerting.
kubeletTelemetryMonitor.recoveryThresholdint2Consecutive healthy samples before resolving.
kubeletTelemetryMonitor.persistStatebooltruePersist telemetry counters across restarts.
kubeletTelemetryMonitor.memoryWarningPercentfloat90Container memory warning threshold.
kubeletTelemetryMonitor.memoryCriticalPercentfloat100Container memory critical threshold.
kubeletTelemetryMonitor.ephemeralStorageWarningPercentfloat90Ephemeral-storage warning threshold.
kubeletTelemetryMonitor.ephemeralStorageCriticalPercentfloat95Ephemeral-storage critical threshold.
kubeletTelemetryMonitor.cpuWarningPercentfloat90CPU usage warning threshold.
kubeletTelemetryMonitor.cpuCriticalPercentfloat100CPU usage critical threshold.
kubeletTelemetryMonitor.cpuThrottlingWarningPercentfloat25CPU throttling warning threshold.
kubeletTelemetryMonitor.cpuThrottlingCriticalPercentfloat50CPU throttling critical threshold.
kubeletTelemetryMonitor.psiWarningPercentfloat20PSI warning threshold.
kubeletTelemetryMonitor.psiCriticalPercentfloat50PSI critical threshold.
kubeletTelemetryMonitor.networkErrorRateWarningfloat1Network errors per second warning threshold.
kubeletTelemetryMonitor.networkErrorRateCriticalfloat10Network errors per second critical threshold.
kubeletTelemetryMonitor.runtimeErrorRateWarningfloat1Runtime errors per second warning threshold.
kubeletTelemetryMonitor.runtimeErrorRateCriticalfloat10Runtime errors per second critical threshold.

🎯 Active probes​

Active probes are disabled by default because they create traffic. Explicit HTTP, TCP, and DNS targets are the recommended low-noise mode. Set autoServices: true only when you want kwatch to probe advertised Service ports automatically.

ParameterTypeDefaultDescription
activeProbeMonitor.enabledboolfalseRun configured application probes.
activeProbeMonitor.intervalSecondsint30Seconds between probe rounds.
activeProbeMonitor.timeoutSecondsint5Timeout for each probe.
activeProbeMonitor.failureThresholdint3Consecutive failures before alerting.
activeProbeMonitor.recoveryThresholdint2Consecutive successes before resolving.
activeProbeMonitor.autoServicesboolfalseProbe discoverable Service ports automatically.
activeProbeMonitor.httplist[]HTTP targets with optional status and latency limits.
activeProbeMonitor.tcplist[]TCP targets.
activeProbeMonitor.dnslist[]DNS targets.
activeProbeMonitor:
enabled: true
http:
- name: api
url: https://api.example.com/ready
expectedStatus: 200
tcp:
- name: postgres
address: postgres.database.svc:5432
dns:
- name: cluster-dns
host: kubernetes.default.svc

πŸ’₯ OOM Pattern Monitor​

ParameterTypeDefaultDescription
oomMonitor.enabledbooltrueTrack repeating OOMs (memory leaks).
oomMonitor.thresholdint3OOM count within window to flag.
oomMonitor.windowMinutesint60Sliding window in minutes.

πŸ” Secret-backed credentials are required​

Provider credentials, diagnostic tokens, and heartbeat URLs must be files mounted from a Kubernetes Secret. Plain values and ${ENV_VAR} substitutions are rejected for sensitive fields:

# config.yaml
alert:
slack:
webhook: "${file:/config/slack-webhook}"
kubectl -n kwatch create secret generic kwatch-config \
--from-file=config.yaml \
--from-file=slack-webhook

Mount kwatch-config at /config, or set the Helm configSecretName value to kwatch-config. ${VAR} remains available for non-sensitive strings only.

The shipped workloads use a non-root user, read-only root filesystem, dropped Linux capabilities, disabled privilege escalation, and the RuntimeDefault seccomp profile. Protect the Secret with least-privilege RBAC, enable API server/etcd encryption at rest, and restart the deployment after rotating it.


🚦 Alert Providers​

kwatch delivers to 56 alert integrations. Configure one or more under alert:. Routing, retry, and fallback are supported by every provider:

alert:
slack:
webhook: "${file:/config/slack-webhook}"
routes:
- namespaces: ["production"]
severities: ["high", "critical"]
retry:
maxAttempts: 5
delay: 5s
fallback: pagerduty

pagerduty:
integrationKey: "${file:/config/pagerduty-integration-key}"

discord:
webhook: "${file:/config/discord-webhook}"

telegram:
token: "${file:/config/telegram-token}"
chatId: <chat>

email:
from: <from>
to: <to>
password: "${file:/config/email-password}"
host: <smtp-host>
port: <smtp-port>

The complete provider reference lists all 56 integrations and every catalog field. The complete configuration reference lists every accepted configuration key, type, default, category, and status. Both pages are generated from the versioned catalogs shipped with kwatch.sh.

Routes​

An incident must match at least one route to be delivered. If no routes are configured, all incidents are delivered.

routes:
- namespaces: ["production"]
severities: ["critical"]
reasons: ["OOMKilled"]

Retry & Fallback​

retry:
maxAttempts: 5 # max send attempts (default: 3)
delay: 5s # delay between attempts

fallback: pagerduty # secondary provider (configured at top level)

Only failures that can succeed on a retry are retried (timeout, 5xx, rate limit). A 4xx or rejected payload is given up on immediately and goes to the dead-letter queue, so it cannot hold up other alerts.


πŸ“‹ Example β€” full config​

apiVersion: v1
kind: Secret
metadata:
name: kwatch
namespace: kwatch
stringData:
slack-webhook: "replace-me"
pagerduty-integration-key: "replace-me"
config.yaml: |
maxRecentLogLines: 50
ignoreFailedGracefulShutdown: true
workers: 2

app:
clusterName: prod-us-east

correlation:
window: 10
resolveHoldDown: 300
escalation:
enabled: true
tiers: [3, 10]

smartGrouping:
windowSeconds: 60
namespaceFanOutThreshold: 3

silences:
- namespaces: ["kube-system"]

nodeMonitor:
enabled: true

pendingPodMonitor:
enabled: true
threshold: 300

healthCheck:
enabled: true
port: 8060

alert:
slack:
webhook: "${file:/config/slack-webhook}"
pagerduty:
integrationKey: "${file:/config/pagerduty-integration-key}"