Zum Inhalt springen

Monitoring as Code

Mit Monitoring as Code definieren Sie Ihr LoadFocus-Monitoring-Setup als versionierte Dateien und wenden es von der Kommandozeile oder aus CI an, genauso, wie Sie Infrastruktur mit Terraform oder Pulumi verwalten. Sie beschreiben die Monitore, Gruppen, Benachrichtigungen, Wartungsfenster, Dashboards und Statusseiten, die Sie haben möchten; die @loadfocus/monitoring CLI ermittelt den Unterschied zum Live-Zustand und gleicht ihn ab (erstellen, aktualisieren, löschen).

Es ist deklarativ und idempotent: Wenn Sie deploy zweimal ausführen, ändert sich beim zweiten Mal nichts. Ihre Dateien sind die einzige Quelle der Wahrheit, sodass Änderungen über Pull Requests laufen und Ihr Monitoring-Verlauf in Git lebt.

Alles läuft in Ihrem Konto und Ihrem aktiven Team, wobei Ihre Plan-Limits vom LoadFocus-Backend genauso durchgesetzt werden wie im Dashboard. Die CLI tut nur, was Sie auch selbst in der Oberfläche tun könnten.

Sie pflegen einen Ordner mit kleinen YAML- (oder JavaScript-) Dateien, eine Ressource pro Datei, sowie eine loadfocus.config.yaml, die auf sie verweist. Die CLI sendet diese Definitionen an LoadFocus, das sie auf Live-Ressourcen abbildet, vergleicht und einen Plan zurückgibt. Sie prüfen den Plan und wenden ihn dann an.

  • Verfassen: Beschreiben Sie Ressourcen als Dateien (YAML- oder JS-Konstrukte).
  • Planen: deploy --dry-run zeigt genau, was erstellt, aktualisiert, übernommen oder gelöscht wird.
  • Anwenden: deploy gleicht Ihr Konto so ab, dass es den Dateien entspricht.
  • Identität abgleichen: jede Ressource trägt eine stabile, von Ihnen gewählte logicalId. So verfolgt die CLI eine Ressource über Umbenennungen hinweg, sodass das Ändern des Anzeigenamens eines Checks ihn nie neu erstellt.

Die CLI ist ein Node-Paket (Node 18+). Führen Sie es bei Bedarf mit npx aus:

Terminal-Fenster
npx @loadfocus/monitoring --help

…oder installieren Sie es global, um den Befehl loadfocus-monitoring zu erhalten:

Terminal-Fenster
npm install -g @loadfocus/monitoring
loadfocus-monitoring --help

Die CLI authentifiziert sich mit einem LoadFocus-API-Schlüssel und einer Team-ID. Beides finden Sie auf der Entwicklerseite, die Ihren API-Schlüssel und Ihre Team-ID zusammen anzeigt, samt MCP-Einrichtung.

Melden Sie sich einmal an, und die Anmeldedaten werden in ~/.loadfocus/config.json gespeichert:

Terminal-Fenster
loadfocus-monitoring login --apikey <your-api-key> --teamid <your-team-id>
loadfocus-monitoring whoami # confirm who you are and which team you're targeting

Für CI sind Umgebungsvariablen vorzuziehen (sie überschreiben die gespeicherte Konfiguration und werden nie auf die Festplatte geschrieben):

Terminal-Fenster
export LOADFOCUS_API_KEY="apikey_xxxxxxxx"
export LOADFOCUS_TEAM_ID="team_xxxxxxxx"
# optional: export LOADFOCUS_API_URL="https://apimonitor.loadfocus.com"

Um später einen gespeicherten Wert zu ändern, verwenden Sie config set mit --apikey, --teamid oder --api-url. config show zeigt die Anmeldedaten, die die CLI tatsächlich verwendet, Umgebungsvariablen eingeschlossen; vom API-Schlüssel sind nur die letzten vier Zeichen sichtbar. logout entfernt den gespeicherten API-Schlüssel und die Team-ID aus ~/.loadfocus/config.json.

Terminal-Fenster
loadfocus-monitoring config set --teamid <your-team-id> # change one saved value
loadfocus-monitoring config show # credentials in use, API key masked
loadfocus-monitoring logout # remove the saved API key and team id

Erzeugen Sie ein Gerüst aus Konfigurationsdatei und Beispielmonitor in Ihrem Repository:

Terminal-Fenster
loadfocus-monitoring init

Dies schreibt loadfocus.config.yaml:

project: my-project # a namespace for this set of resources
checkMatch:
- "monitors/**/*.{check,group,alertRule,maintenanceWindow,dashboard,statusPage,alertChannel,variable}.{yaml,yml,js}"
defaults:
schedule: "300" # applied to checks that omit a schedule
locations: [us-east-1]
  • project grenzt alles ein, was die CLI verwaltet. Ressourcen in einem Projekt werden gemeinsam abgeglichen; alles im Projekt, was nicht mehr in Ihren Dateien steht, wird bei deploy gelöscht. Nutzen Sie separate Projekte, um unabhängige Monitor-Sets zu verwalten.
  • checkMatch ist das Glob (bzw. die Globs) für Ihre Verfassungs-Dateien.
  • defaults füllt schedule, locations und alertChannels für Checks aus, die sie weglassen.

init überspringt Dateien, die bereits existieren. Mit --force werden sie überschrieben.

Terminal-Fenster
loadfocus-monitoring validate # compile locally + server-side dry-run; great as a PR gate
loadfocus-monitoring deploy --dry-run # show the plan (created / updated / adopted / deleted)
loadfocus-monitoring deploy # apply it
loadfocus-monitoring list # inventory of what's deployed in the project
loadfocus-monitoring list --status # …with each check's latest up/down/degraded status
loadfocus-monitoring get <logicalId> # show one deployed resource
loadfocus-monitoring trigger --id <logicalId> # run a check now (no --id runs every deployed check)
loadfocus-monitoring destroy # delete everything managed in the project

deploy ist standardmäßig sicher: Es zeigt den Plan und fragt bei interaktiver Ausführung nach, bevor es etwas löscht. In CI (nicht-interaktiv) verweigert es das Löschen ohne --yes und beendet sich mit einem klaren Code, statt an einer Eingabeaufforderung zu hängen. Fügen Sie Lese-/Ergebnisbefehlen --json hinzu, um maschinenlesbare Ausgaben zu erhalten.

validate --no-server kompiliert Ihre Dateien nur lokal: Es braucht keine Anmeldedaten und überspringt den Server-Probelauf, eignet sich also für einen Pre-Commit-Hook. deploy verweigert außerdem die Anwendung, wenn checkMatch überhaupt keine Dateien lädt, denn dieser Plan würde jede vom Projekt verwaltete Ressource löschen; meist steckt ein falscher Ordner oder ein Tippfehler in checkMatch dahinter. deploy --dry-run zeigt diesen Plan trotzdem an. Um bewusst alles zu löschen, führen Sie destroy aus oder übergeben --allow-empty an deploy.

Terminal-Fenster
loadfocus-monitoring test
loadfocus-monitoring test --json # machine-readable results

test führt jeden Check aus Ihren Dateien einmal aus, direkt aus den Dateien, und meldet für jeden, ob er bestanden hat oder fehlgeschlagen ist. Dabei wird nichts gespeichert: Kein Check wird in Ihrem Konto angelegt oder geändert. Schlägt ein Check fehl oder endet er mit einem Fehler, beendet sich der Befehl mit Exit-Code 1, sodass ein CI-Job einen Pull Request blockieren kann, bis die Checks gegen die echten Endpunkte bestehen; ein beeinträchtigtes (degraded) Ergebnis lässt den Lauf nicht scheitern. Projekte mit vielen Checks werden in Paketen zu je 20 gesendet.

Sie haben bereits Monitore im Dashboard? Holen Sie sie in Dateien, statt sie neu zu erstellen:

Terminal-Fenster
loadfocus-monitoring import --project my-project --out monitors

Dies schreibt eine Datei pro Ressource und eine loadfocus.config.yaml. Prüfen, committen und dann deploy --dry-run ausführen: übereinstimmende Ressourcen werden an Ort und Stelle übernommen (unter Verwaltung gestellt), statt dupliziert zu werden.

import überspringt Dateien, die im Ausgabeordner bereits existieren. Mit --force werden sie durch die Version vom Server ersetzt.

Jede Ressource ist eine Datei mit einem kind, einer logicalId (Ihr stabiler Bezeichner) und den Feldern für dieses kind. Verweise zwischen Ressourcen nutzen logicalIds (oder Namen für Benachrichtigungskanäle), der Server löst sie auf, und die Deploy-Reihenfolge wird für Sie geregelt.

Ein check-kind deckt jeden Check-Typ über type ab: api, browser, multistep, tcp, heartbeat (in JavaScript leistet das Konstrukt Monitor dasselbe).

kind: check
type: api
logicalId: home
name: Home API
schedule: "300" # seconds between runs
locations: [us-east-1, eu-west-1]
tags: [production, payments] # optional labels
request:
url: "https://example.com/health"
method: GET
assertions:
- { type: statusCode, comparison: equals, value: 200 }
- { type: responseTime, comparison: less-than, value: 1000 }
  • api: HTTP-Anfrage mit Assertions zu Statuscode, Antwortzeit und Body. Die Vergleiche sind equals, not-equals, greater-than, less-than, equals-or-greater-than, equals-or-less-than, contains und not-contains.
  • browser: ein Playwright-User-Flow-Skript mit Screenshots und Zeiten pro Schritt (kostenpflichtig).
  • multistep: eine geordnete Folge von API-Anfragen, die Daten zwischen den Schritten weitergeben (kostenpflichtig).
  • tcp: eine Port-/Erreichbarkeitsprüfung aus mehreren Regionen (kostenpflichtig).
  • heartbeat: ein Totmannschalter: Ein externer Job pingt eine URL nach Zeitplan, und LoadFocus benachrichtigt, wenn ein Ping ausbleibt.

Ein Check kann außerdem tags tragen, dieselben Labels, die Sie in der App neben dem Check-Namen setzen (siehe Tags von Checks). Deployen Sie eine Check-Datei ohne tags, werden die Tags dieses Checks entfernt. In JavaScript behält das Monitor-Konstrukt tags ab CLI-Version 1.0.2; ältere Versionen haben sie verworfen.

Teilen Sie Standorte, Benachrichtigungskanäle, Frequenz und Aktivierung über viele Checks hinweg. Ein Check tritt einer Gruppe mit group: <logicalId> bei.

kind: group
logicalId: web
name: Web services
locations: [us-east-1, eu-west-1]

Benachrichtigen, wenn die Metrik eines Checks einen Schwellenwert überschreitet.

kind: alertRule
logicalId: home-latency
name: Home API latency
check: home # reference a check by logicalId
metric: responseTime # responseTime | statusCode | duration
condition: above
conditionValue: 1500 # milliseconds

Verwalten Sie Benachrichtigungskanäle als Code und referenzieren Sie sie per Name aus einem Check, einer Gruppe oder einer Benachrichtigungsregel. Unterstützte types: email, slack, microsoftteams, webhook, discord, pagerduty, opsgenie. E-Mail-, Slack-, Teams- und Webhook-Kanäle gibt es in jedem Tarif; Discord, PagerDuty und Opsgenie sind kostenpflichtig. Geheime Felder (webhookUrl, routingKey, apiKey) nehmen eine {{secrets.NAME}}-Referenz entgegen, der Wert wird mit env set-secret gespeichert und beim Senden einer Benachrichtigung aufgelöst, niemals in Ihre Dateien committet.

kind: alertChannel
logicalId: oncall # the name checks / groups / alert rules reference
type: pagerduty
routingKey: "{{secrets.PAGERDUTY_KEY}}"

Unterdrücken Sie Benachrichtigungen während geplanter Arbeiten. Zeiten sind in UTC. startsAt / endsAt akzeptieren einen ISO-8601-String (z. B. "2026-07-01T00:00:00Z") oder Unix-Millisekunden.

kind: maintenanceWindow
logicalId: weekly-deploy
name: Weekly deploy window
enabled: true
startsAt: "2026-07-01T00:00:00Z" # ISO-8601 or unix ms
endsAt: "2026-07-01T02:00:00Z"
repeat: weekly # none | daily | weekly | monthly
weekdays: [2] # 0=Sun … 6=Sat
targets:
allChecks: false
checkIds: [home] # by logicalId

Eine gemeinsame Ansicht ausgewählter Checks, optional öffentlich über einen Slug.

kind: dashboard
logicalId: status-overview
name: Status overview
visibility: private # private | public
checks: [home] # by logicalId
window: 24h # 24h | 7d | 30d

Eine öffentliche Statusseite unter <slug>.loadfoc.us, optional auf Ihrer eigenen, benutzerdefinierten Domain.

kind: statusPage
logicalId: public-status
title: Acme Status
slug: acme # -> acme.loadfoc.us (globally unique)
enabled: true
customDomain: status.acme.com # optional, paid; point a CNAME at cname.loadfoc.us
groups:
- { id: core, name: Core Services, order: 0 }
components:
- id: api
name: API
groupId: core
monitors: [home] # checks shown on this component, by logicalId
branding:
brandColor: "#5353a4"
colorTheme: dark

Eine benutzerdefinierte Domain geht live, sobald Sie den CNAME erstellen und das Zertifikat ausgestellt ist, deploy deklariert sie; die Verifizierung erfolgt außerhalb des Ablaufs.

Nicht geheime Werte (Basis-URLs, IDs), die API-Checks zur Laufzeit in URL, Headern, Query-Parametern und Body als ${{NAME}} referenzieren, mit demselben Platzhalter wie Secrets. Die logicalId ist der Variablenschlüssel. (Für Secrets verwenden Sie env set-secret, legen Sie sie niemals in Dateien ab.)

kind: variable
logicalId: BASE_URL
value: "https://api.example.com"

Wenn Sie Code statt YAML bevorzugen, erstellen Sie dieselben Definitionen programmatisch und exportieren Sie sie, die Konstrukte erzeugen identische Ressourcen:

const { Monitor, Group, AlertRule, Maintenance, Dashboard, StatusPage, AlertChannel, Variable } = require('@loadfocus/monitoring');
module.exports = [
new Monitor({
type: 'api', logicalId: 'home', name: 'Home API', schedule: '300',
locations: ['us-east-1'],
request: { url: 'https://example.com/health', method: 'GET' },
assertions: [{ type: 'statusCode', comparison: 'equals', value: 200 }],
}),
new Group({ logicalId: 'web', name: 'Web services', locations: ['us-east-1'] }),
];

Exportieren Sie die Konstrukte aus der Datei (ein Array, wie oben) und benennen Sie sie so, dass checkMatch sie findet, zum Beispiel monitors/home.check.js. Die CLI lädt sie wie jede andere Ressource.

Referenzieren Sie Werte aus Ihren Checks, ohne sie zu committen. Secrets (Tokens, Passwörter) werden ausschließlich imperativ verwaltet und in Check-Feldern (URL, Header, Body) als ${{NAME}} und in geheimen Feldern von Benachrichtigungskanälen als {{secrets.NAME}} referenziert. Variablen (nicht geheim) können als Dateien deklariert (kind: variable, siehe oben) oder imperativ gesetzt werden und werden in den Feldern eines API-Checks genauso als ${{NAME}} referenziert; dort wird ein Platzhalter ohne Dollarzeichen, etwa {{NAME}}, als normaler Text gesendet. Ein Multistep-Check gibt Werte stattdessen zwischen den Schritten weiter: Sein Setup-Skript liest die Variable als ${{NAME}} und legt sie in ctx.vars ab, und die Schritte verwenden sie als {{name}} (siehe Setup- und Teardown-Skripte).

Terminal-Fenster
loadfocus-monitoring env set-secret API_TOKEN "s3cr3t"
loadfocus-monitoring env set-var BASE_URL "https://example.com"
loadfocus-monitoring env ls # list secret + variable keys (values never shown)
loadfocus-monitoring env rm-secret API_TOKEN # delete a secret
loadfocus-monitoring env rm-var BASE_URL # delete a variable

Eine typische Pipeline validiert bei jedem Pull Request und deployt beim Merge in den Main-Branch.

.github/workflows/monitoring.yml
name: monitoring
on:
pull_request:
push:
branches: [main]
jobs:
monitoring:
runs-on: ubuntu-latest
env:
LOADFOCUS_API_KEY: ${{ secrets.LOADFOCUS_API_KEY }}
LOADFOCUS_TEAM_ID: ${{ secrets.LOADFOCUS_TEAM_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npx @loadfocus/monitoring validate
- if: github.ref == 'refs/heads/main'
run: npx @loadfocus/monitoring deploy --yes
  • logicalId ist die Identität. Halten Sie sie stabil. Sie können name oder title eines Checks beliebig ändern; das Ändern der logicalId wird so behandelt, als würde eine Ressource gelöscht und eine andere erstellt.
  • Löschungen sind auf das Projekt beschränkt. deploy entfernt nur Ressourcen im aktuellen project, die nicht mehr in Ihren Dateien stehen, niemals etwas in einem anderen Projekt oder außerhalb von Monitoring as Code Erstelltes (bis Sie es übernehmen).
  • Statusseiten-Slugs sind global. slug wird zu einer Subdomain, muss also über alle LoadFocus-Kunden hinweg eindeutig sein.
  • Kostenpflichtige Funktionen brauchen einen kostenpflichtigen Tarif. Ein kostenloses Team, das eine benutzerdefinierte Statusseiten-Domain deklariert, erhält bei deploy einen klaren Fehler. Das Entfernen des "Powered by"-Badges wird in einem kostenlosen Tarif nicht angewendet: Das Feld bleibt aus.
  • Plan-Limits gelten. Das Erstellen von Ressourcen über die CLI unterliegt denselben Plan-Kontingenten wie das Dashboard. Eine Ressource, die ein Kontingent überschreiten würde, wird als abgelehnt gemeldet, und der Rest des Deployments läuft weiter.