diff --git a/alerting-create-silence-lj/create-silence/content.json b/alerting-create-silence-lj/create-silence/content.json index 55dedadc..d11e3842 100644 --- a/alerting-create-silence-lj/create-silence/content.json +++ b/alerting-create-silence-lj/create-silence/content.json @@ -5,12 +5,12 @@ "blocks": [ { "type": "markdown", - "content": "You'll open the silence form, set a time window, add label matchers that select which alerts to suppress, verify the affected instances, and submit.\n\nIn this milestone, you create a silence from start to finish." + "content": "You'll open the **Silences** page, set a time window, add label matchers that select which alerts to suppress, verify the affected instances, and submit.\n\nIn this milestone, you create a silence from start to finish." }, { "type": "section", "id": "open-silence-form", - "title": "Open the silence form", + "title": "Start a new silence", "blocks": [ { "type": "interactive", @@ -22,8 +22,8 @@ { "type": "interactive", "action": "highlight", - "reftarget": "a[href*='/alerting/silence/new']", - "content": "Click **Add silence** to open the silence creation form.", + "reftarget": "a[href*='alerting/silence/new']", + "content": "Click **Create silence** to start a new silence.", "requirements": ["on-page:/alerting/silences"], "verify": "on-page:/alerting/silence/new" } @@ -35,18 +35,31 @@ "title": "Set the silence time window", "requirements": ["section-completed:open-silence-form"], "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "label:contains('Silence start and end')", + "content": "The **Silence start and end** field shows two timestamps: when the silence starts and when it ends. By default, the start is now and the end is two hours from now, so the silence lasts two hours.", + "doIt": false, + "requirements": ["on-page:/alerting/silence/new"] + }, { "type": "interactive", "action": "noop", - "content": "In the **Silence start and end** picker, set when the silence begins and ends. For a maintenance window, set the start to now and the end to when the work finishes." + "content": "If you need custom times, click the field to open an **Absolute time range** menu, set **From** and **To**, then click **Apply time range**. Otherwise, skip to the **Duration** field." }, { "type": "interactive", "action": "highlight", "reftarget": "#duration", - "content": "Alternatively, set the **Duration** field and Grafana calculates the end time for you.\n\nUse a duration that matches the work, for example, `2h` for a short maintenance window or `1d` for a longer migration. Valid units: `y`, `M`, `w`, `d`, `h`, `m`, `s`.", + "content": "Set the **Duration** field to how long you want the silence to last, and Grafana calculates the end time for you.", "doIt": false, "requirements": ["on-page:/alerting/silence/new"] + }, + { + "type": "interactive", + "action": "noop", + "content": "The default `2h` works for a short deployment. Use `1d` for a longer migration. Valid units are years (y), months (M), weeks (w), days (d), hours (h), minutes (m), and seconds (s)." } ] }, @@ -60,7 +73,7 @@ "type": "interactive", "action": "highlight", "reftarget": "#matcher-0-label", - "content": "Under **Refine affected alerts**, enter the label name to match in the **Label** field, for example, `severity` or `team`.", + "content": "Under **Refine affected alerts**, enter a label that's on one of your alerts. If you followed the first-rule journey, copy `severity` and paste it into the **Label** field.", "doIt": false, "requirements": ["on-page:/alerting/silence/new"] }, @@ -68,15 +81,20 @@ "type": "interactive", "action": "highlight", "reftarget": "#matcher-0-value", - "content": "Enter the matching value in the **Value** field, for example, `warning` or `database`. The operator defaults to equals (`=`); change it if you need a regex or not-equals match.\n\nOnly alerts whose labels match every matcher you add are silenced. The more matchers you add, the narrower the silence.", + "content": "Copy `critical` and paste it into the **Value** field so the matcher becomes `severity=critical`. The operator defaults to equals (`=`). Change it if you need a regex or not-equals match.", "doIt": false, "requirements": ["on-page:/alerting/silence/new"] }, + { + "type": "interactive", + "action": "noop", + "content": "Only alerts whose labels match every matcher you add are silenced. The more matchers you add, the narrower the silence." + }, { "type": "interactive", "action": "highlight", "reftarget": "button:contains('Add matcher')", - "content": "Click **Add matcher** to add another label matcher if you need to narrow the silence further.", + "content": "Click **Add matcher** if you want to narrow the silence further, for example, adding `team=platform` alongside `severity=critical` silences only critical alerts owned by the platform team.", "doIt": false, "requirements": ["on-page:/alerting/silence/new"], "skippable": true @@ -92,13 +110,13 @@ { "type": "interactive", "action": "noop", - "content": "Review the **Affected alert instances** preview below the matchers. It lists the alert instances your matchers currently select.\n\nIf the preview is empty or includes alerts you didn't intend to silence, adjust your matchers before submitting." + "content": "Review the **Affected alert instances** preview below the matchers. It lists any alert instances currently firing that match your matchers.\n\nWith `severity=critical`, you should see the alerts you created in the previous sections. If the preview is empty, the silence still catches alerts that start firing during the window." }, { "type": "interactive", "action": "highlight", "reftarget": "#comment", - "content": "Enter a **Comment** describing why you're creating the silence, for example, `Database upgrade maintenance window`. This helps your team understand the silence later.", + "content": "Replace the auto-populated text in the **Comment** field with a short reason, for example, `Database upgrade in progress`. Grafana records the creation time separately, so the timestamp isn't needed here.", "doIt": false, "requirements": ["on-page:/alerting/silence/new"] }, diff --git a/alerting-first-rule-lj/build-query/content.json b/alerting-first-rule-lj/build-query/content.json index 88ff5e45..7c4dca8a 100644 --- a/alerting-first-rule-lj/build-query/content.json +++ b/alerting-first-rule-lj/build-query/content.json @@ -5,7 +5,7 @@ "blocks": [ { "type": "markdown", - "content": "The query defines what data Grafana monitors. You point the rule at a data source, choose a metric, filter it down to what matters, and apply operations that transform the raw data into something useful.\n\nThis milestone uses the **grafanacloud-play-prom** Prometheus data source from the QuickPizza tutorial data sources. You build the query in **Builder** mode, targeting a real HTTP request counter from the QuickPizza demo service." + "content": "You'll build an alert that watches the QuickPizza app for server errors. You'll use Builder mode instead of using a query language." }, { "type": "section", @@ -15,20 +15,34 @@ "has-datasource:grafanacloud-play-prom" ], "blocks": [ - { - "type": "markdown", - "content": "You'll point the alert rule at the Prometheus data source that came with the QuickPizza tutorial data sources." - }, { "type": "interactive", "action": "formfill", "reftarget": "input[data-testid='data-testid Select a data source']", "targetvalue": "grafanacloud-play-prom", - "content": "In the **Define query and alert condition** section, open the data source picker and select **grafanacloud-play-prom**.", - "tooltip": "Pick the Prometheus data source from the QuickPizza tutorial data sources.", + "content": "Choose the data source that holds the metric you want to alert on. For this tutorial, `grafanacloud-play-prom` is filled in for you — it's the Prometheus data source from the QuickPizza tutorial data sources.", + "tooltip": "Prometheus data source from the QuickPizza tutorial data sources.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] + } + ] + }, + { + "type": "section", + "id": "toggle-explain", + "title": "Turn on Explain (optional)", + "skippable": true, + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='data-testid prometheus explain switch wrapper']", + "content": "Toggle **Explain** on. Grafana narrates what each part of your query does in plain English — a fast way to learn what you're clicking without knowing PromQL syntax.", "requirements": [ "on-page:/alerting/new/alerting" ], + "skippable": true, "doIt": false } ] @@ -37,19 +51,12 @@ "type": "section", "id": "use-builder-mode", "title": "Confirm Builder mode", - "requirements": [ - "section-completed:select-data-source" - ], "blocks": [ - { - "type": "markdown", - "content": "The Prometheus query editor has two modes: **Builder** (visual, point-and-click) and **Code** (write PromQL by hand). Builder is the fastest way in when you're new to Prometheus, and it's the default for new queries." - }, { "type": "interactive", "action": "highlight", "reftarget": "div[data-testid='data-testid QueryEditorModeToggle']", - "content": "Above the query field, confirm **Builder** is selected. If you're on **Code**, click **Builder** to switch.", + "content": "Make sure **Builder** mode is selected. This mode lets you build the query without using PromQL.", "requirements": [ "on-page:/alerting/new/alerting" ], @@ -62,81 +69,100 @@ "type": "section", "id": "choose-metric", "title": "Choose the metric", - "requirements": [ - "section-completed:use-builder-mode" - ], "blocks": [ - { - "type": "markdown", - "content": "The **Metric** field is where you tell Prometheus which time series to query. QuickPizza exposes an HTTP request counter you can alert on." - }, { "type": "interactive", "action": "highlight", - "reftarget": "button[aria-label='Open metrics explorer']", - "content": "Click the **Metric** drop-down and select `quickpizza_server_http_request_duration_seconds_count`.\n\nIf you can't find the Metric from the dropdown, Click the **Open metric explorer** button and search for the metric.\n\nThis is a counter that increments every time QuickPizza handles an HTTP request. It's exactly the kind of counter you'd alert on in production.", + "reftarget": "[data-testid='data-testid metric select']", + "content": "Copy `quickpizza_server_http_requests_total` from this step, paste it into the **Metric** drop-down, then select it from the list. This counter tracks every HTTP request QuickPizza's services handle, labeled with the response `status`. It's the raw material for the alert.", + "tooltip": "Paste the metric name here, then pick it from the list.", + "doIt": false, "requirements": [ "on-page:/alerting/new/alerting" - ], - "doIt": false + ] } ] }, { "type": "section", "id": "add-label-filter", - "title": "Narrow down with a label filter", - "requirements": [ - "section-completed:choose-metric" - ], + "title": "Filter to server errors", "blocks": [ { - "type": "markdown", - "content": "QuickPizza has multiple services. A label filter narrows the query to just the one you care about — the public API, which handles customer traffic." + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='data-testid Select label']", + "content": "In the **Label filters** row, open the **Label** drop-down and select `status`. The raw metric covers *all* requests — the `status` label lets you narrow it down.", + "tooltip": "Pick status from the list.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] }, { "type": "interactive", "action": "highlight", - "reftarget": "[data-testid='data-testid Select label']", - "content": "Below the metric picker, in the **Label filters** row, open the **Label** drop-down and select `service_name`.", + "reftarget": "[data-testid='data-testid Select match operator']", + "content": "Open the operator drop-down and change `=` to `=~`. The `=~` operator does a regex match, so one filter catches every 5xx code at once (500, 502, 503, and so on).", + "tooltip": "=~ is Prometheus regex-match; = is exact-match.", + "doIt": false, "requirements": [ "on-page:/alerting/new/alerting" - ], - "doIt": false + ] }, { "type": "interactive", "action": "highlight", "reftarget": "[data-testid='data-testid Select value']", - "content": "In the value picker next to `service_name`, select `quickpizza-public-api`.\n\nYour query now returns only the HTTP request counter for QuickPizza's public API.", + "content": "In the **Select value** box, enter `5..`, then press Enter. That regex matches any three-digit status starting with 5, so the query now returns only server errors.", + "tooltip": "Enter 5.. and press Enter.", + "doIt": false, "requirements": [ "on-page:/alerting/new/alerting" - ], - "doIt": false + ] } ] }, { "type": "section", - "id": "add-rate-operation", - "title": "Convert the counter to a rate", - "requirements": [ - "section-completed:add-label-filter" - ], + "id": "add-increase-operation", + "title": "Add Increase (5m)", "blocks": [ { - "type": "markdown", - "content": "Counters only ever go up, so the raw value isn't useful for alerting. Applying **Rate** turns the counter into a per-second rate — how many requests QuickPizza is currently serving. That's what you actually want to compare against a threshold." + "type": "interactive", + "action": "button", + "reftarget": "Operations", + "content": "The metric is a *counter* that only goes up, so its raw value doesn't tell you whether errors just happened. `increase()` fixes that. Click **+ Operations** to open the picker.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] }, + { + "type": "interactive", + "action": "noop", + "content": "Select **Range functions**, then **Increase**. Set the range to `5m` — the query now counts new errors in the last 5 minutes." + } + ] + }, + { + "type": "section", + "id": "add-sum-operation", + "title": "Sum across services (optional)", + "skippable": true, + "blocks": [ { "type": "interactive", "action": "button", "reftarget": "Operations", - "content": "Click **+ Operations** to add a function to your query. In the picker, select **Range > Rate** and `$__rate_interval`.\n\nGrafana wraps your query with `rate(...[$__rate_interval])` under the hood — but you never touched PromQL.", + "content": "Without `Sum`, you get one number per QuickPizza service — noisier, harder to read. Summing gives one total so the alert answers \"is QuickPizza having errors *anywhere*?\" Click **+ Operations** again to open the picker.", "requirements": [ "on-page:/alerting/new/alerting" ], - "doIt": false + "skippable": true + }, + { + "type": "interactive", + "action": "noop", + "content": "Select **Aggregations**, then **Sum**. Grafana wraps your `increase()` result in a single total across all services." } ] }, @@ -144,22 +170,19 @@ "type": "section", "id": "preview-query", "title": "Preview the query", - "requirements": [ - "section-completed:add-rate-operation" - ], "blocks": [ { "type": "interactive", "action": "button", "reftarget": "Run queries", - "content": "Click **Run queries** to preview the data your query returns.\n\nYou should see a line that fluctuates in the low single digits — the real-time HTTP request rate for QuickPizza's public API. If the preview is empty, double-check that you selected `grafanacloud-play-prom` and the metric name is correct.", + "content": "Click **Run queries** to preview the data. You should see `0` while QuickPizza is healthy, jumping above zero when 5xx errors happen in the last 5-minute window. If the preview is empty, double-check the data source, metric name, and label filter.", "requirements": [ "on-page:/alerting/new/alerting" ] }, { "type": "markdown", - "content": "Your query now returns a real per-second request rate from QuickPizza. In the next milestone, you set the condition that decides when this rate is high enough to fire an alert." + "content": "Your query now counts QuickPizza's 5xx errors over the last 5 minutes. In the next milestone, you set the condition that fires the alert the moment that count goes above zero." } ] } diff --git a/alerting-first-rule-lj/build-query/website.yaml b/alerting-first-rule-lj/build-query/website.yaml index 97562062..ba4954a1 100644 --- a/alerting-first-rule-lj/build-query/website.yaml +++ b/alerting-first-rule-lj/build-query/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - query weight: 400 -step: 4 +step: 5 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/business-value/content.json b/alerting-first-rule-lj/business-value/content.json index a3121cb6..33eaa484 100644 --- a/alerting-first-rule-lj/business-value/content.json +++ b/alerting-first-rule-lj/business-value/content.json @@ -5,11 +5,15 @@ "blocks": [ { "type": "markdown", - "content": "An alert rule turns your telemetry into action. It watches a query, decides when something is wrong, and notifies the right people through the right channel — so you find out about problems before your users do.\n\nEvery alert rule is built from the same pieces: a query that defines what to watch, a condition that decides when to fire, labels and a folder that organize and route it, evaluation settings that control timing, and notification settings that decide who hears about it. In this path, you build all of them in order." + "content": "An alert rule watches your data, fires when something looks wrong, and notifies the right people. You hear about problems before your users do." }, { "type": "markdown", - "content": "This path uses the QuickPizza tutorial data sources, which you install as a prerequisite before you begin. In the next milestone, you open the alert rule form and give your rule a clear name." + "content": "In this path, you build every part of an alert rule in order:\n\n- A query that picks what to watch\n- A condition that decides when to fire\n- A folder and labels that organize and route it\n- Evaluation settings that control how often it runs and how long it must be wrong before firing\n- A contact point and message that decide who hears about it and what they see" + }, + { + "type": "markdown", + "content": "You'll use the QuickPizza tutorial data sources. The next milestone installs them, then the one after opens the new alert rule page so you can name your rule." } ] } diff --git a/alerting-first-rule-lj/business-value/manifest.json b/alerting-first-rule-lj/business-value/manifest.json index 66c46c52..efac4b03 100644 --- a/alerting-first-rule-lj/business-value/manifest.json +++ b/alerting-first-rule-lj/business-value/manifest.json @@ -11,7 +11,7 @@ "tier": "cloud" }, "depends": [], - "recommends": ["alerting-first-rule-navigate-to-form"], + "recommends": ["alerting-first-rule-install-datasources"], "suggests": [], "provides": [] } diff --git a/alerting-first-rule-lj/configure-handling/content.json b/alerting-first-rule-lj/configure-handling/content.json index 8abf2b3b..7850bc35 100644 --- a/alerting-first-rule-lj/configure-handling/content.json +++ b/alerting-first-rule-lj/configure-handling/content.json @@ -5,7 +5,7 @@ "blocks": [ { "type": "markdown", - "content": "No-data and error handling controls what your rule does when a query returns no data or fails.\n\nIn this milestone, you configure how the rule handles missing data and query errors." + "content": "No-data and error handling controls what your rule does when a query returns no data or fails. In this milestone, you'll set these." }, { "type": "section", @@ -15,11 +15,21 @@ "blocks": [ { "type": "interactive", - "action": "highlight", - "reftarget": "button:contains('Configure no data and error handling')", - "content": "In the evaluation behavior area, expand **Configure no data and error handling** to control what happens when a query returns no data or errors.\n\nThe defaults are usually fine, but change the behavior for queries that legitimately return no data at times — for example, set **No data** to **Normal** so a quiet log stream doesn't fire an alert.", - "doIt": false, + "action": "button", + "reftarget": "Configure no data and error handling", + "content": "In the **Set evaluation behavior** section, click **Configure no data and error handling** to expand the options.", + "doIt": true, "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Leave both dropdown menus at their defaults. **Alert state if no data or all values are null** stays on **No Data**. **Alert state if execution error or timeout** stays on **Error**. That way, empty results and query failures each surface as their own alert instead of going unnoticed." + }, + { + "type": "interactive", + "action": "noop", + "content": "Your rule now handles empty results and query errors safely. Next, you'll choose the contact point that receives the notification." } ] } diff --git a/alerting-first-rule-lj/configure-handling/website.yaml b/alerting-first-rule-lj/configure-handling/website.yaml index 6e9cf01c..1ceb028b 100644 --- a/alerting-first-rule-lj/configure-handling/website.yaml +++ b/alerting-first-rule-lj/configure-handling/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - handling weight: 800 -step: 8 +step: 9 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/configure-labels-evaluation/content.json b/alerting-first-rule-lj/configure-labels-evaluation/content.json index be1466c0..37c06168 100644 --- a/alerting-first-rule-lj/configure-labels-evaluation/content.json +++ b/alerting-first-rule-lj/configure-labels-evaluation/content.json @@ -1,24 +1,29 @@ { "schemaVersion": "1.1.0", "id": "alerting-first-rule-configure-labels-evaluation", - "title": "Select a folder and add labels", + "title": "Create a folder and add labels", "blocks": [ { "type": "markdown", - "content": "You'll organize your alert into a folder and add labels that control routing.\n\nIn this milestone, you select a folder, then add rule-level labels." + "content": "You'll organize your alert into a folder and add labels that control how notifications get routed.\n\nFolders organize alerts by team, service, or purpose, and control who can manage them.\n\nIn this milestone, you create a folder, then add rule-level labels." }, { "type": "section", "id": "select-folder", - "title": "Select a folder", + "title": "Create a folder", "blocks": [ { "type": "interactive", "action": "button", - "reftarget": "Select folder", - "content": "In the **Set evaluation behavior** section, click **Select folder** to choose or create a folder for your alert rule.\n\nFolders organize alert rules by team, service, or purpose, and they determine who has permission to manage the rules inside them.", + "reftarget": "New folder", + "content": "In the **Add folder and labels** section, click **New folder** to open the create dialog.", "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Give your folder a name \u2014 **Alerts** works for this tutorial, or pick something meaningful to your team \u2014 then click **Create**. Grafana saves the folder and selects it for your rule." } ] }, @@ -28,30 +33,22 @@ "title": "Add labels", "requirements": ["section-completed:select-folder"], "blocks": [ - { - "type": "markdown", - "content": "Labels can come from two places: the query itself (your QuickPizza query already carries `service_name`, `service_namespace`, and other labels straight from the Prometheus metric) or the rule-level **Add labels** section. Use rule-level labels for higher-level routing metadata that doesn't belong on the data, like team, severity, or environment." - }, { "type": "interactive", "action": "button", "reftarget": "Add labels", - "content": "Scroll to the **Add labels** section and click **Add labels** to add a rule-level label.", + "content": "Click **Add labels** to open the labels editor. Labels are simple key-value tags you attach to the alert. Grafana uses them to decide who to notify.", "requirements": ["on-page:/alerting/new/alerting"] }, { "type": "interactive", "action": "noop", - "content": "Your query already carries `service_name=\"quickpizza-public-api\"` and `service_namespace=\"quickpizza\"` from the metric. Add higher-level labels here to control routing without touching the query.\n\n| Key | Example values | Purpose |\n|-----|----------------|--------|\n| `severity` | `critical`, `warning`, `info` | Controls urgency and routing |\n| `team` | `platform`, `database`, `frontend` | Routes to the right responders |\n| `environment` | `production`, `staging` | Distinguishes alert context |\n| `runbook` | `payments-runbook` | Points on-call to a runbook |" + "content": "Add a label with the key **severity** and the value **critical**, then click **Save**.\n\nA server returning 5xx errors is significant, so this alert deserves the critical tag." }, { "type": "interactive", "action": "noop", - "content": "Labels drive notification routing. For example, notification policies can:\n\n- Route `severity=\"critical\"` to PagerDuty for immediate response\n- Route `severity=\"warning\"` to a Slack channel for awareness\n- Route `team=\"platform\"` to the platform team's on-call\n- Route by `service_name` (already on the query) to service owners\n\nChoose labels that match your notification policy matchers." - }, - { - "type": "markdown", - "content": "Your alert now has a folder and routing labels.\n\nNext, you set how often Grafana evaluates the rule and how long a problem must persist before it fires." + "content": "Your alert now has a folder and a label. Next, you'll tell Grafana how often to check the query and how long the problem must last before the alert fires." } ] } diff --git a/alerting-first-rule-lj/configure-labels-evaluation/website.yaml b/alerting-first-rule-lj/configure-labels-evaluation/website.yaml index 66792584..21fc06f2 100644 --- a/alerting-first-rule-lj/configure-labels-evaluation/website.yaml +++ b/alerting-first-rule-lj/configure-labels-evaluation/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - labels weight: 600 -step: 6 +step: 7 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/configure-notification/content.json b/alerting-first-rule-lj/configure-notification/content.json new file mode 100644 index 00000000..196fb5ae --- /dev/null +++ b/alerting-first-rule-lj/configure-notification/content.json @@ -0,0 +1,48 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-first-rule-configure-notification", + "title": "Configure the notification message", + "blocks": [ + { + "type": "markdown", + "content": "When your alert fires, the notification includes a **Summary** and a **Description**. In this milestone, you complete both so anyone who gets the alert can tell what happened and what to check." + }, + { + "type": "section", + "id": "add-summary", + "title": "Add a summary", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "[data-testid='annotation-value-0']", + "targetvalue": "QuickPizza returned {{ $value }} server errors in the last 5 minutes", + "content": "The **Summary** is the first line people see in the email or Slack message, so keep it short. The `{{ $value }}` piece gets replaced with the live number from your query when the alert fires.", + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "add-description", + "title": "Add a description", + "requirements": ["section-completed:add-summary"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "[data-testid='annotation-value-1']", + "targetvalue": "Fires when the 5-minute rate of QuickPizza HTTP 5xx responses stays above the threshold. Check the app dashboard and recent deploys first.", + "content": "The **Description** gives more detail than the Summary. Use it to explain what the alert is watching and where to start looking if it goes off.", + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your notification now says what happened and what to check. Next, you'll save and activate the rule." + } + ] + } + ] +} diff --git a/alerting-first-rule-lj/content.json b/alerting-first-rule-lj/content.json index c9d0106a..9d7b25e9 100644 --- a/alerting-first-rule-lj/content.json +++ b/alerting-first-rule-lj/content.json @@ -9,11 +9,11 @@ }, { "type": "markdown", - "content": "## Here's what to expect\n\nWhen you complete this path, you'll be able to:\n\n- Navigate to the alert rule form and give your rule a clear name\n- Build a Prometheus query using the visual query builder\n- Set a comparison operator and threshold for the alert condition\n- Select a folder and add labels that control routing\n- Configure the evaluation group and pending period\n- Configure no-data and error handling\n- Select a contact point and add a summary annotation\n- Save and activate your alert rule" + "content": "## Here's what to expect\n\nWhen you complete this path, you'll be able to:\n\n- Open the new alert rule page and give your rule a clear name\n- Build a Prometheus query using the visual query builder\n- Set a comparison operator and threshold for the alert condition\n- Select a folder and add labels that control routing\n- Configure the evaluation group and pending period\n- Configure no-data and error handling\n- Select a contact point\n- Add a summary and description to your notification\n- Save and activate your alert rule" }, { "type": "markdown", - "content": "## Before you begin\n\nBefore you build your alert rule, ensure you have:\n\n- A Grafana Cloud account. To create one, refer to [Grafana Cloud](https://grafana.com/signup/cloud/connect-account).\n- Admin permissions to create and manage alert rules.\n- The QuickPizza tutorial data sources installed on your stack. To install them, refer to [Work with demo data in Grafana Cloud](https://grafana.com/docs/grafana-cloud/get-started/connect-send/explore-demo-data/). This path uses `grafanacloud-play-prom`, and querying it does not count toward your Grafana Cloud usage." + "content": "## Before you begin\n\nBefore you build your alert rule, ensure you have:\n\n- A Grafana Cloud account. To create one, refer to [Grafana Cloud](https://grafana.com/signup/cloud/connect-account).\n- Admin permissions to create and manage alert rules.\n\nThe path installs the QuickPizza tutorial data sources for you in the next milestone. This path uses `grafanacloud-play-prom`, and querying it does not count toward your Grafana Cloud usage." }, { "type": "markdown", diff --git a/alerting-first-rule-lj/end-journey/content.json b/alerting-first-rule-lj/end-journey/content.json index 26e0247c..a3f465c4 100644 --- a/alerting-first-rule-lj/end-journey/content.json +++ b/alerting-first-rule-lj/end-journey/content.json @@ -5,7 +5,7 @@ "blocks": [ { "type": "markdown", - "content": "Congratulations on completing this path! Job well done!\n\nWe hope you've enjoyed traveling with us as you:\n\n- Opened and named your alert rule\n- Built a Prometheus query with the visual query builder\n- Set the alert condition and threshold\n- Selected a folder and added routing labels\n- Configured the evaluation group and pending period\n- Configured no-data and error handling\n- Selected a contact point and added a summary annotation\n- Saved and activated your alert rule" + "content": "Congratulations on completing this path! Job well done!\n\nWe hope you've enjoyed traveling with us as you:\n\n- Opened and named your alert rule\n- Built a Prometheus query with the visual query builder\n- Set the alert condition and threshold\n- Selected a folder and added routing labels\n- Configured the evaluation group and pending period\n- Configured no-data and error handling\n- Selected a contact point\n- Added a summary and description to your notification\n- Saved and activated your alert rule" }, { "type": "markdown", diff --git a/alerting-first-rule-lj/end-journey/website.yaml b/alerting-first-rule-lj/end-journey/website.yaml index b0b6f036..548772fb 100644 --- a/alerting-first-rule-lj/end-journey/website.yaml +++ b/alerting-first-rule-lj/end-journey/website.yaml @@ -4,7 +4,7 @@ description: You created a complete alert rule from query to notification. keywords: - alerting weight: 1100 -step: 11 +step: 12 layout: single-journey cta: type: conclusion diff --git a/alerting-first-rule-lj/install-datasources/content.json b/alerting-first-rule-lj/install-datasources/content.json new file mode 100644 index 00000000..3dad4abb --- /dev/null +++ b/alerting-first-rule-lj/install-datasources/content.json @@ -0,0 +1,47 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-first-rule-install-datasources", + "title": "Install the tutorial data sources", + "blocks": [ + { + "type": "markdown", + "content": "This path uses the QuickPizza tutorial data sources, which include a Prometheus data source named **grafanacloud-play-prom** that carries real metrics from a running demo service. Querying these data sources does not count toward your Grafana Cloud usage.\n\nThe install runs from the **Demo Data Dashboards** app in the left nav. After the install finishes, Grafana refreshes the page and the alerting flow picks up in the next milestone." + }, + { + "type": "section", + "id": "install-tutorial-datasources", + "title": "Install QuickPizza", + "objectives": [ + "has-datasource:grafanacloud-play-prom" + ], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "a[data-testid='data-testid Nav menu item'][href='/a/grafana-demodashboards-app']", + "content": "In the left nav, click **Demo Data Dashboards**.", + "tooltip": "Opens the app that installs the tutorial data sources.", + "requirements": [ + "navmenu-open", + "exists-reftarget" + ] + }, + { + "type": "interactive", + "action": "highlight", + "reftarget": "button[data-testid='install-quickpizza']", + "content": "Click **Install the Quick Pizza SRE demo**. This deploys the tutorial data sources and refreshes the page.", + "tooltip": "Installs grafanacloud-play-prom and the other tutorial data sources.", + "requirements": [ + "exists-reftarget" + ], + "completeEarly": true + } + ] + }, + { + "type": "markdown", + "content": "The `grafanacloud-play-prom` data source is now available. In the next milestone, you open the new alert rule page and give your rule a clear name." + } + ] +} diff --git a/alerting-first-rule-lj/install-datasources/manifest.json b/alerting-first-rule-lj/install-datasources/manifest.json new file mode 100644 index 00000000..7210b3b4 --- /dev/null +++ b/alerting-first-rule-lj/install-datasources/manifest.json @@ -0,0 +1,17 @@ +{ + "id": "alerting-first-rule-install-datasources", + "type": "guide", + "description": "Install the QuickPizza tutorial data sources so the alert rule has real data to query.", + "category": "take-action", + "author": { + "name": "JohnnyK-Grafana", + "team": "Grafana Documentation" + }, + "testEnvironment": { + "tier": "cloud" + }, + "depends": ["alerting-first-rule-business-value"], + "recommends": ["alerting-first-rule-navigate-to-form"], + "suggests": [], + "provides": [] +} diff --git a/alerting-first-rule-lj/install-datasources/website.yaml b/alerting-first-rule-lj/install-datasources/website.yaml new file mode 100644 index 00000000..90ad9c11 --- /dev/null +++ b/alerting-first-rule-lj/install-datasources/website.yaml @@ -0,0 +1,12 @@ +menuTitle: Install data sources +title: Install the tutorial data sources +description: Install the QuickPizza tutorial data sources so the alert rule has real data to query. +keywords: + - alerting + - datasource + - quickpizza +weight: 200 +step: 3 +layout: single-journey +cta: + type: continue diff --git a/alerting-first-rule-lj/manifest.json b/alerting-first-rule-lj/manifest.json index 1f5de15e..61b945bc 100644 --- a/alerting-first-rule-lj/manifest.json +++ b/alerting-first-rule-lj/manifest.json @@ -9,6 +9,7 @@ "testEnvironment": { "tier": "cloud" }, "milestones": [ "alerting-first-rule-business-value", + "alerting-first-rule-install-datasources", "alerting-first-rule-navigate-to-form", "alerting-first-rule-build-query", "alerting-first-rule-set-condition", @@ -16,6 +17,7 @@ "alerting-first-rule-set-evaluation-behavior", "alerting-first-rule-configure-handling", "alerting-first-rule-select-contact-point", + "alerting-first-rule-configure-notification", "alerting-first-rule-save-rule", "alerting-first-rule-end-journey" ], diff --git a/alerting-first-rule-lj/navigate-to-form/content.json b/alerting-first-rule-lj/navigate-to-form/content.json index 19126f47..7ec67dc6 100644 --- a/alerting-first-rule-lj/navigate-to-form/content.json +++ b/alerting-first-rule-lj/navigate-to-form/content.json @@ -1,16 +1,16 @@ { "schemaVersion": "1.1.0", "id": "alerting-first-rule-navigate-to-form", - "title": "Navigate to the alert rule form", + "title": "Open the new alert rule page", "blocks": [ { "type": "markdown", - "content": "A clear, descriptive name is the first thing responders see when an alert fires. A good name tells them immediately what's wrong without opening the alert details.\n\nIn this milestone, you'll open the alert rule creation form and give your rule a name." + "content": "A clear, descriptive name is the first thing responders see when an alert fires. A good name tells them immediately what's wrong without opening the alert details.\n\nIn this milestone, you'll open the new alert rule page and give your rule a name." }, { "type": "section", "id": "open-alert-form", - "title": "Open the alert rule form", + "title": "Open the new alert rule page", "blocks": [ { "type": "interactive", @@ -23,13 +23,13 @@ "type": "interactive", "action": "highlight", "reftarget": "a[href*='alerting/new/alerting']", - "content": "Click **+ New alert rule** to open the alert rule creation form.", + "content": "Click **+ New alert rule** to open the new alert rule page.", "requirements": ["on-page:/alerting/list"], "verify": "on-page:/alerting/new/alerting" }, { "type": "markdown", - "content": "You're now on the alert rule creation form." + "content": "You're now on the new alert rule page." } ] }, @@ -39,27 +39,18 @@ "title": "Set the alert rule name", "requirements": ["section-completed:open-alert-form"], "blocks": [ - { - "type": "markdown", - "content": "You'll enter a descriptive name for your alert rule that tells responders exactly what triggered it." - }, { "type": "interactive", - "action": "highlight", + "action": "formfill", "reftarget": "input#name", - "content": "Enter a descriptive name in the **Alert rule name** field.\n\nA good alert name clearly identifies what's being monitored and what condition triggers the alert.", + "targetvalue": "QuickPizza server errors", + "content": "Enter a descriptive name for your alert rule that tells responders triage alerts quickly, especially when multiple alerts fire at once. In the **Alert rule name** field, `QuickPizza server errors` is filled in for you.", "tooltip": "Responders see this name first when the alert fires.", - "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] }, - { - "type": "interactive", - "action": "noop", - "content": "Use a naming pattern that includes the signal, the scope, and the condition:\n\n| Pattern | Example |\n|---------|--------|\n| Signal + scope | `High CPU usage - Linux servers` |\n| Signal + service | `Error rate spike - API gateway` |\n| Signal + threshold | `Disk space critical - Database servers` |\n| Log pattern + scope | `OOM errors - Production pods` |" - }, { "type": "markdown", - "content": "A descriptive name helps responders triage alerts quickly, especially when multiple alerts fire at once.\n\nIn the next milestone, you learn how to build the query that defines what your alert monitors." + "content": "In the next milestone, you learn how to build the query that defines what your alert monitors." } ] } diff --git a/alerting-first-rule-lj/navigate-to-form/manifest.json b/alerting-first-rule-lj/navigate-to-form/manifest.json index 3b8b9adb..2beba10f 100644 --- a/alerting-first-rule-lj/navigate-to-form/manifest.json +++ b/alerting-first-rule-lj/navigate-to-form/manifest.json @@ -1,7 +1,7 @@ { "id": "alerting-first-rule-navigate-to-form", "type": "guide", - "description": "Open the alert rule creation form and give your rule a clear name.", + "description": "Open the new alert rule page and give your rule a clear name.", "category": "take-action", "author": { "name": "JohnnyK-Grafana", @@ -10,7 +10,7 @@ "testEnvironment": { "tier": "cloud" }, - "depends": ["alerting-first-rule-business-value"], + "depends": ["alerting-first-rule-install-datasources"], "recommends": ["alerting-first-rule-build-query"], "suggests": [], "provides": [] diff --git a/alerting-first-rule-lj/navigate-to-form/website.yaml b/alerting-first-rule-lj/navigate-to-form/website.yaml index d5bb9165..81d08193 100644 --- a/alerting-first-rule-lj/navigate-to-form/website.yaml +++ b/alerting-first-rule-lj/navigate-to-form/website.yaml @@ -1,11 +1,11 @@ menuTitle: Name your rule -title: Navigate to the alert rule form -description: Open the alert rule creation form and give your rule a clear name. +title: Open the new alert rule page +description: Open the new alert rule page and give your rule a clear name. keywords: - alerting - alert rule weight: 300 -step: 3 +step: 4 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/save-rule/content.json b/alerting-first-rule-lj/save-rule/content.json index c1d7640b..13b181de 100644 --- a/alerting-first-rule-lj/save-rule/content.json +++ b/alerting-first-rule-lj/save-rule/content.json @@ -5,43 +5,29 @@ "blocks": [ { "type": "markdown", - "content": "The last steps are the notification message and saving.\n\nIn this milestone, you add a summary annotation, then save and activate your rule." - }, - { - "type": "section", - "id": "add-annotation", - "title": "Add a summary annotation", - "requirements": ["on-page:/alerting/new/alerting"], - "blocks": [ - { - "type": "interactive", - "action": "highlight", - "reftarget": "[data-testid='annotation-value-0']", - "content": "In the **Configure notification message** section, locate the **Summary** field. The summary is the first line responders see in Slack, PagerDuty, email, and other channels. Keep it brief and use template variables to reference labels from your query.\n\nFor the QuickPizza alert you built, use:\n\n```\nHigh request rate on {{ $labels.service_name }}\n```\n\nOther examples for real alerts:\n\n| If alerting on | Example summary |\n|----------------|------------------|\n| CPU usage | `CPU usage is high on {{ $labels.instance }}` |\n| Error rate | `Error rate elevated for {{ $labels.job }}` |\n| Disk space | `Disk space low on {{ $labels.instance }}` |", - "doIt": false, - "requirements": ["on-page:/alerting/new/alerting"] - } - ] + "content": "The rule is ready. In this milestone, you save it and Grafana starts evaluating it on the schedule you set." }, { "type": "section", "id": "save-rule", "title": "Save and activate the rule", - "requirements": ["section-completed:add-annotation"], + "requirements": ["on-page:/alerting/new/alerting"], "blocks": [ { "type": "interactive", "action": "highlight", - "reftarget": "button[data-testid='save-rule']", - "content": "Click **Save** to save and activate your alert rule.\n\nYour alert rule is now saved and active. Grafana immediately begins evaluating it at your specified interval.", + "reftarget": "[data-testid='save-rule']", + "content": "Click **Save** in the action bar at the bottom of the page to save and activate your alert rule. Grafana immediately begins evaluating it at the interval you set.", "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] }, { - "type": "markdown", - "content": "**Your alert rule is saved and actively monitoring.** When the condition is met and persists past your pending period, the alert fires and notifications are sent to your contact point.\n\nYou've created a complete alert rule from query to notification." + "type": "interactive", + "action": "noop", + "content": "Your alert rule is saved and running. When the condition holds past your pending period, the alert fires and notifications go to your contact point." } ] } ] } + diff --git a/alerting-first-rule-lj/save-rule/website.yaml b/alerting-first-rule-lj/save-rule/website.yaml index 840b960b..72380bd2 100644 --- a/alerting-first-rule-lj/save-rule/website.yaml +++ b/alerting-first-rule-lj/save-rule/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - save weight: 1000 -step: 10 +step: 11 layout: single-journey cta: type: success diff --git a/alerting-first-rule-lj/select-contact-point/content.json b/alerting-first-rule-lj/select-contact-point/content.json index 26b86873..e0ffd840 100644 --- a/alerting-first-rule-lj/select-contact-point/content.json +++ b/alerting-first-rule-lj/select-contact-point/content.json @@ -5,7 +5,7 @@ "blocks": [ { "type": "markdown", - "content": "A contact point is where notifications go, like email, Slack, or PagerDuty.\n\nIn this milestone, you select the contact point that receives notifications for this rule." + "content": "A contact point tells Grafana where to send notifications, like email, Slack, or PagerDuty. In this milestone, you pick the contact point that receives notifications when this rule fires." }, { "type": "section", @@ -17,18 +17,14 @@ "type": "interactive", "action": "highlight", "reftarget": "[data-testid='contact-point-picker']", - "content": "In the **Configure notifications** section, locate the **Contact point** picker. Select the contact point where you want alert notifications delivered.\n\nNotifications for firing alerts are routed to the selected contact point.", + "content": "In the **Configure notifications** section, open the **Contact point** picker and choose **grafana-default-email**. Every Grafana Cloud stack includes it, and it delivers notifications to the email on your account.", "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] }, { "type": "interactive", - "action": "highlight", - "reftarget": "a[aria-label='View or create contact points']", - "content": "If you don't have a contact point yet, click **View or create contact points** to create one.\n\nChoose the integration that matches your team's workflow:\n\n| Integration | Setup |\n|-------------|-------|\n| **Email** | Enter your email address — simplest option |\n| **Slack** | Provide a webhook URL for your channel |\n| **PagerDuty** | Add your routing key for on-call escalation |\n| **Microsoft Teams** | Provide a webhook URL for your team channel |", - "doIt": false, - "requirements": ["on-page:/alerting/new/alerting"], - "skippable": true + "action": "noop", + "content": "Your rule now knows where to send notifications. Next, you'll write the notification message and save the rule." } ] } diff --git a/alerting-first-rule-lj/select-contact-point/website.yaml b/alerting-first-rule-lj/select-contact-point/website.yaml index 0c0540ef..f97f7810 100644 --- a/alerting-first-rule-lj/select-contact-point/website.yaml +++ b/alerting-first-rule-lj/select-contact-point/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - notifications weight: 900 -step: 9 +step: 10 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/set-condition/content.json b/alerting-first-rule-lj/set-condition/content.json index eb3d8c6f..9391cbc4 100644 --- a/alerting-first-rule-lj/set-condition/content.json +++ b/alerting-first-rule-lj/set-condition/content.json @@ -5,58 +5,49 @@ "blocks": [ { "type": "markdown", - "content": "You'll configure the condition that determines when your alert fires using the simplified alert condition editor.\n\nIn this milestone, you set a comparison operator and threshold that fire when QuickPizza's request rate exceeds a target value, then preview the result." + "content": "You'll set the rule that decides when your alert fires: which comparison to make, and what value to compare against.\n\nYour query counts QuickPizza's 5xx errors in the last 5 minutes. In this milestone, you tell Grafana to fire the moment that count goes above zero, then preview the result." }, { "type": "section", "id": "choose-operator", - "title": "Choose the comparison operator", + "title": "Choose when the alert fires", "requirements": ["has-datasource:grafanacloud-play-prom"], "blocks": [ { "type": "interactive", "action": "highlight", - "reftarget": "[data-testid='data-testid alert-rule step-2'] button:contains('Is above')", - "content": "Below the query editor, locate the **Alert condition** area. It reads \"WHEN QUERY\" followed by a condition dropdown.\n\nLeave the operator on **Is above**. You want the alert to fire when QuickPizza's request rate climbs above your target — the classic \"traffic surge\" pattern.", + "reftarget": "label:contains('WHEN QUERY')", + "content": "Notice the **Alert condition** section. This is where you tell Grafana when to fire the alert.", "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] }, { - "type": "markdown", - "content": "> **Other operators.** For real alerts, you might pick a different operator: `Is below` for low disk space or memory, `Is equal to` for exact matches, or `Is within range` and `Is outside range` for band checks. For this course, `Is above` matches the traffic-surge pattern." + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='data-testid alert-rule step-2'] button:contains('Is above')", + "content": "**Is above** is already selected. Leave it — any 5xx error in the last 5 minutes puts your query result above zero, which fires the alert.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] } ] }, { "type": "section", "id": "set-threshold", - "title": "Set the threshold value", + "title": "Preview rule", "requirements": ["section-completed:choose-operator"], "blocks": [ - { - "type": "interactive", - "action": "formfill", - "reftarget": "[data-testid='data-testid alert-rule step-2'] input[type='number']", - "targetvalue": "1", - "content": "In the number field next to the condition operator, enter `1`.\n\nThat threshold represents one request per second. QuickPizza's public API typically serves a low, fluctuating rate of demo traffic, so a threshold around `1` will fire during busy periods and resolve during quiet ones — a useful pattern to watch in real time.", - "doIt": false, - "requirements": ["on-page:/alerting/new/alerting"] - }, { "type": "interactive", "action": "button", "reftarget": "Preview alert rule condition", - "content": "Click **Preview alert rule condition** to test the threshold against your query.\n\nThe preview shows a firing state during traffic spikes above `1` req/s and a normal state during quieter periods.", + "content": "Click **Preview alert rule condition** to test the value against your query.\n\nThe preview shows a normal state while QuickPizza is healthy and a firing state as soon as any 5xx error appears in the 5-minute window.", "requirements": ["on-page:/alerting/new/alerting"] }, { "type": "interactive", "action": "noop", - "content": "For real-world alerts, pick a threshold that gives you time to respond before things break — for example, `80` for CPU percentage, `10` for errors per minute, or a p95 latency ceiling for a user-facing endpoint.\n\nFor more control over how the condition is evaluated, enable **Advanced options** at the top of this section to access the full Reduce and Threshold expression editors." - }, - { - "type": "markdown", - "content": "Your alert condition is configured. Grafana evaluates the threshold at every interval and fires the alert when QuickPizza's request rate exceeds `1` req/s.\n\nIn the next milestone, you organize your rule with labels and control evaluation timing." + "content": "Your alert condition is set. Next, you organize the rule with labels and control how often Grafana evaluates it." } ] } diff --git a/alerting-first-rule-lj/set-condition/website.yaml b/alerting-first-rule-lj/set-condition/website.yaml index f231820d..48eeb51f 100644 --- a/alerting-first-rule-lj/set-condition/website.yaml +++ b/alerting-first-rule-lj/set-condition/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - condition weight: 500 -step: 5 +step: 6 layout: single-journey cta: type: continue diff --git a/alerting-first-rule-lj/set-evaluation-behavior/content.json b/alerting-first-rule-lj/set-evaluation-behavior/content.json index 3ebc904b..01d8aaa1 100644 --- a/alerting-first-rule-lj/set-evaluation-behavior/content.json +++ b/alerting-first-rule-lj/set-evaluation-behavior/content.json @@ -5,31 +5,26 @@ "blocks": [ { "type": "markdown", - "content": "Evaluation behavior controls how often Grafana runs your rule and how long a problem must persist before the alert fires.\n\nIn this milestone, you configure the evaluation group and set the pending period." + "content": "Evaluation behavior sets how often Grafana runs your query, how long a problem must last before the alert fires, and how long the alert keeps firing after the condition resolves.\n\nIn this milestone, you create an evaluation group, set a pending period, and set keep firing for." }, { "type": "section", "id": "configure-evaluation-group", - "title": "Configure the evaluation group", + "title": "Create an evaluation group", "requirements": ["on-page:/alerting/new/alerting"], "blocks": [ { "type": "interactive", - "action": "highlight", - "reftarget": "[data-testid='group-picker']", - "content": "Locate the evaluation group picker. Evaluation groups batch rules that share the same evaluation interval.\n\nIf the picker is disabled, select a folder first.", + "action": "button", + "reftarget": "New evaluation group", + "content": "In the **Set evaluation behavior** section, click **New evaluation group** to open the dialog.", "doIt": false, - "requirements": ["on-page:/alerting/new/alerting"], - "skippable": true + "requirements": ["on-page:/alerting/new/alerting"] }, { "type": "interactive", - "action": "highlight", - "reftarget": "[data-testid='data-testid alert-rule new-evaluation-group-button']", - "content": "If you don't have an existing group, click **New evaluation group** to create one. Choose a name and set the **Evaluation interval** — how often Grafana runs your query.\n\n| Urgency | Interval | Use case |\n|---------|----------|----------|\n| Critical | `1m` | Host down, service unavailable |\n| Standard | `5m` | CPU high, error rate elevated |\n| Low priority | `10m` | Disk trending full, memory creeping up |\n\nShorter intervals detect issues faster but increase query load on your data sources.", - "doIt": false, - "requirements": ["on-page:/alerting/new/alerting"], - "skippable": true + "action": "noop", + "content": "Give the group a name, such as **Alerts group**, set the **Evaluation interval** to **1m**, then click **Create**." } ] }, @@ -43,13 +38,30 @@ "type": "interactive", "action": "highlight", "reftarget": "#eval-for-input", - "content": "Locate the **Pending period** field. This controls how long the condition must be true before the alert fires, which prevents brief spikes from triggering notifications.\n\n| Alert type | Pending period | Why |\n|------------|----------------|-----|\n| CPU spike | `5m` | Filters brief spikes during deployments |\n| Error burst | `2m` | Catches sustained patterns, not single errors |\n| Disk full | `10m` | Disk usage changes slowly, longer window is fine |\n| Service down | `1m` | Outages need fast detection |", + "content": "Find the **Pending period** field. This is how long the condition must stay true before the alert fires. Set it to **1m** \u2014 brief spikes get filtered out, but a real problem fires quickly.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "set-keep-firing-for", + "title": "Set keep firing for", + "requirements": ["section-completed:set-pending-period"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "#keep-firing-for-input", + "content": "Find the **Keep firing for** field. This is how long the alert keeps firing after the condition resolves, so a metric bouncing across the threshold doesn't flap. Leave it at **None** for this rule \u2014 you can raise it later if you see the alert flip on and off.", "doIt": false, "requirements": ["on-page:/alerting/new/alerting"] }, { - "type": "markdown", - "content": "Your alert now has a folder, routing labels, an evaluation schedule, and a pending period.\n\nIn the next milestone, you configure no-data handling, select a contact point, and save your rule." + "type": "interactive", + "action": "noop", + "content": "Your alert now has a folder, a label, and an evaluation schedule. Next, you'll pick who gets notified when the alert fires." } ] } diff --git a/alerting-first-rule-lj/set-evaluation-behavior/website.yaml b/alerting-first-rule-lj/set-evaluation-behavior/website.yaml index ad70c031..099e6c20 100644 --- a/alerting-first-rule-lj/set-evaluation-behavior/website.yaml +++ b/alerting-first-rule-lj/set-evaluation-behavior/website.yaml @@ -5,7 +5,7 @@ keywords: - alerting - evaluation weight: 700 -step: 7 +step: 8 layout: single-journey cta: type: continue diff --git a/alerting-query-language-lj/build-query/content.json b/alerting-query-language-lj/build-query/content.json new file mode 100644 index 00000000..4fffc02e --- /dev/null +++ b/alerting-query-language-lj/build-query/content.json @@ -0,0 +1,94 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-build-query", + "title": "Write your query in Code mode", + "blocks": [ + { + "type": "markdown", + "content": "Your alert watches how often QuickPizza's server fails. Every request either works or doesn't. You want the alert to fire when **too many** fail, say, more than 5 in every 100.\n\nTo express \"5 in every 100,\" your query has to divide the number of failed requests by the number of *all* requests. Builder mode can't divide two numbers in one query, so you switch to Code mode and write it in PromQL." + }, + { + "type": "section", + "id": "select-data-source", + "title": "Select the QuickPizza Prometheus data source", + "requirements": [ + "has-datasource:grafanacloud-play-prom" + ], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "input[data-testid='data-testid Select a data source']", + "targetvalue": "grafanacloud-play-prom", + "content": "Choose **grafanacloud-play-prom** as the data source. That's the Prometheus data source with QuickPizza's metrics.", + "tooltip": "QuickPizza's Prometheus data source.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] + } + ] + }, + { + "type": "section", + "id": "switch-to-code-mode", + "title": "Switch to Code mode", + "requirements": ["section-completed:select-data-source"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "div[data-testid='data-testid QueryEditorModeToggle']", + "content": "Click **Code** on the mode toggle to switch away from Builder mode. The dropdowns collapse, and a text field appears where you type PromQL.", + "tooltip": "Switches the query editor from Builder to Code.", + "doIt": false, + "requirements": [ + "on-page:/alerting/new/alerting" + ] + } + ] + }, + { + "type": "section", + "id": "write-promql", + "title": "Write the PromQL error-rate query", + "requirements": ["section-completed:switch-to-code-mode"], + "blocks": [ + { + "type": "code-block", + "reftarget": "div[data-testid='data-testid Query field']", + "language": "promql", + "code": "100 * sum(rate(quickpizza_server_http_requests_total{status=~\"5..\"}[5m])) / sum(rate(quickpizza_server_http_requests_total[5m]))", + "content": "Add this query to the editor. Click **Insert** to drop it in.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] + }, + { + "type": "markdown", + "content": "Here's what the query does, one piece at a time:\n\n- `quickpizza_server_http_requests_total` counts every request QuickPizza has ever handled.\n- `rate(...[5m])` turns that ever-growing count into a per-second speed, smoothed over the last 5 minutes.\n- `{status=~\"5..\"}` narrows to just the failed requests (anything with a status code starting with `5`, like `500` or `503`).\n- Dividing failed requests by all requests, then multiplying by 100, gives you a percentage." + } + ] + }, + { + "type": "section", + "id": "preview-query", + "title": "Preview the query", + "requirements": ["section-completed:write-promql"], + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "Run queries", + "content": "Click **Run queries** to see what the query returns. You'll see a low percentage while QuickPizza is healthy, and spikes when errors happen. If the preview is empty, double-check that **grafanacloud-play-prom** is selected as the data source.", + "requirements": [ + "on-page:/alerting/new/alerting" + ] + }, + { + "type": "markdown", + "content": "The query now reports QuickPizza's error rate as a percentage. Next, you decide how high that percentage has to go before the alert fires." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/business-value/content.json b/alerting-query-language-lj/business-value/content.json new file mode 100644 index 00000000..f72d2212 --- /dev/null +++ b/alerting-query-language-lj/business-value/content.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-business-value", + "title": "Why write your alert in query language?", + "blocks": [ + { + "type": "markdown", + "content": "**Builder mode** lets you build a query by picking things from menus: one metric, a filter or two, done. **Code mode** lets you type the query yourself, and that opens up patterns the menus can't build.\n\nIn this path, you use Code mode to alert on QuickPizza's **error rate**: the percentage of requests that fail. To get a percentage, the query has to divide one number by another, something Builder mode can't do in a single query." + }, + { + "type": "markdown", + "content": "## When to reach for Code mode\n\nCode mode is worth it when your alert needs:\n\n- **A percentage or ratio.** For example, failed requests as a share of all requests.\n- **To detect silence.** Alert when a metric stops reporting. The menus don't offer this.\n- **To compare two metrics.** For example, current usage against a capacity limit on a different series.\n- **A query you already trust.** Paste one in from a dashboard or a teammate." + }, + { + "type": "markdown", + "content": "## What you'll build\n\nStep by step, you build every part of the rule:\n\n- The PromQL query that measures error rate\n- The threshold that decides when to fire\n- A folder and labels so the alert is easy to find and route\n- How often Grafana checks the rule, and how long the problem must last before firing\n- Rules for handling missing data\n- The contact point and message that tell someone what's wrong" + }, + { + "type": "markdown", + "content": "You'll use **QuickPizza**, a demo pizza shop that ships with Grafana Cloud. The next milestone installs it." + } + ] +} diff --git a/alerting-query-language-lj/configure-handling/content.json b/alerting-query-language-lj/configure-handling/content.json new file mode 100644 index 00000000..9a07ec1e --- /dev/null +++ b/alerting-query-language-lj/configure-handling/content.json @@ -0,0 +1,55 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-configure-handling", + "title": "Configure no-data, error handling, and recovery", + "blocks": [ + { + "type": "markdown", + "content": "No-data and error handling controls what your rule does when a query returns no data or fails.\n\nA **recovery threshold** is a second boundary that stops the alert from flapping. It fires above your threshold, but only returns to normal when the value drops below the recovery boundary. Ratio queries can hover near the trigger point, so a recovery threshold matters here.\n\nIn this milestone, you configure both." + }, + { + "type": "section", + "id": "configure-handling", + "title": "Configure no-data and error handling", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "Configure no data and error handling", + "content": "In the **Set evaluation behavior** section, click **Configure no data and error handling** to expand the options.", + "doIt": true, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Leave both dropdowns at their defaults. **Alert state if no data or all values are null** stays on **No Data**. **Alert state if execution error or timeout** stays on **Error**. That way, empty results and query failures each surface as their own alert instead of going unnoticed." + } + ] + }, + { + "type": "section", + "id": "set-recovery-threshold", + "title": "Set a recovery threshold", + "requirements": ["section-completed:configure-handling"], + "skippable": true, + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='data-testid alert-rule step-2']", + "content": "Scroll back to the **Set alert condition** section and turn on the **Custom recovery threshold** toggle. Set the recovery value to **3**. The alert now fires when the error rate crosses 5%, and only returns to normal when it drops below 3%. That gap prevents the alert from flapping when the rate hovers around 5%.", + "doIt": false, + "skippable": true, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your rule now handles empty results, query errors, and recovery. Next, you choose the contact point that receives the notification." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/configure-labels-evaluation/content.json b/alerting-query-language-lj/configure-labels-evaluation/content.json new file mode 100644 index 00000000..f4813fd6 --- /dev/null +++ b/alerting-query-language-lj/configure-labels-evaluation/content.json @@ -0,0 +1,57 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-configure-labels-evaluation", + "title": "Create a folder and add labels", + "blocks": [ + { + "type": "markdown", + "content": "You'll organize your alert into a folder and add labels that control how notifications get routed. Folders group alerts by team, service, or purpose, and control who can manage them.\n\nIn this milestone, you create a folder, then add rule-level labels." + }, + { + "type": "section", + "id": "select-folder", + "title": "Create a folder", + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "New folder", + "content": "In the **Add folder and labels** section, click **New folder** to open the create dialog.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Name the folder **Alerts** (or something meaningful to your team), then click **Create**. Grafana saves the folder and selects it for your rule." + } + ] + }, + { + "type": "section", + "id": "add-labels", + "title": "Add labels", + "requirements": ["section-completed:select-folder"], + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "Add labels", + "content": "Click **Add labels** to open the labels editor. Labels are key-value tags that route this alert. A sustained 5% error rate deserves a `severity=critical` tag.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "In the **Choose key** dropdown, type or select **severity**. In **Choose value**, type **critical**. Click **Save**." + }, + { + "type": "interactive", + "action": "noop", + "content": "Your alert now has a folder and a label. Next, you tell Grafana how often to check the query and how long the problem must last before the alert fires." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/configure-notification/content.json b/alerting-query-language-lj/configure-notification/content.json new file mode 100644 index 00000000..edfbce36 --- /dev/null +++ b/alerting-query-language-lj/configure-notification/content.json @@ -0,0 +1,48 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-configure-notification", + "title": "Configure the notification message", + "blocks": [ + { + "type": "markdown", + "content": "When your alert fires, the notification includes a **Summary** and a **Description**. In this milestone, you complete both so anyone who gets the alert can tell what happened and what to check.\n\nYour first alert reported a raw count of 5xx responses. This alert reports a **percentage**, because the query returns a ratio. The Summary uses `printf \"%.1f\"` to format `$value` as a one-decimal number, and the Description names the ratio explicitly so the on-call reader knows what 5% means." + }, + { + "type": "section", + "id": "add-summary", + "title": "Add a summary", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "[data-testid='annotation-value-0']", + "targetvalue": "QuickPizza error rate at {{ $value | printf \"%.1f\" }}% over the last 5 minutes", + "content": "The **Summary** is the first line people see. The `{{ $value }}` template renders the live percentage when the alert fires.", + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "add-description", + "title": "Add a description", + "requirements": ["section-completed:add-summary"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "[data-testid='annotation-value-1']", + "targetvalue": "Fires when the ratio of QuickPizza 5xx responses to total requests exceeds 5% over 5 minutes. Check recent deploys and the app dashboard first.", + "content": "The **Description** gives more detail than the Summary. Use it to explain what the alert is watching and where to start looking if it goes off.", + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your notification now says what happened and what to check. Next, you save and activate the rule." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/content.json b/alerting-query-language-lj/content.json new file mode 100644 index 00000000..182c93c5 --- /dev/null +++ b/alerting-query-language-lj/content.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-lj", + "title": "Create an alert rule with query language", + "blocks": [ + { + "type": "markdown", + "content": "Welcome! In this learning path, you build a Grafana alert rule by writing the query yourself in **Code mode**, instead of picking it from menus.\n\nYou'll open a new alert rule, write a PromQL query that measures QuickPizza's error rate, set a threshold, add labels and a folder, choose a contact point, and save." + }, + { + "type": "markdown", + "content": "## What you'll learn\n\nBy the end of this path, you can:\n\n- Tell when Code mode is a better fit than Builder mode\n- Write a PromQL query that calculates a percentage\n- Set a threshold that decides when the alert fires\n- Organize an alert with a folder and labels\n- Control how often Grafana checks the rule\n- Handle no-data and error cases so the alert stays useful\n- Send the alert to a contact point with a helpful message" + }, + { + "type": "markdown", + "content": "## Before you begin\n\nYou need:\n\n- A Grafana Cloud account. To sign up, refer to [Grafana Cloud](https://grafana.com/signup/cloud/connect-account).\n- Permission to create alert rules.\n- Some familiarity with PromQL. If PromQL is new to you, try [Create your first alert rule](https://grafana.com/docs/learning-paths/alerting-first-rule/) first. It uses Builder mode, so you don't need to write any query.\n\nThe next milestone installs **QuickPizza**, a demo pizza shop that generates real metrics. Querying it doesn't count toward your Grafana Cloud usage." + }, + { + "type": "markdown", + "content": "## Troubleshooting\n\nIf you get stuck, we've got your back! Where appropriate, troubleshooting information is just a click away." + }, + { + "type": "markdown", + "content": "## More to explore\n\nAfter you save your first rule, explore silences to suppress notifications during planned maintenance, and learn how to configure contact points and notification policies in depth." + } + ] +} diff --git a/alerting-query-language-lj/end-journey/content.json b/alerting-query-language-lj/end-journey/content.json new file mode 100644 index 00000000..c31de5dc --- /dev/null +++ b/alerting-query-language-lj/end-journey/content.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-end-journey", + "title": "Destination reached!", + "blocks": [ + { + "type": "markdown", + "content": "Congratulations on completing this path! Job well done!\n\nWe hope you've enjoyed traveling with us as you:\n\n- Opened and named your alert rule\n- Switched the query editor to Code mode\n- Wrote a PromQL error-rate query using two `rate()` calls and a ratio\n- Set the alert condition and threshold\n- Created a folder and added a routing label\n- Configured the evaluation group and pending period\n- Configured no-data and error handling, and set a recovery threshold\n- Selected a contact point\n- Added a summary and description to your notification\n- Saved and activated your alert rule" + }, + { + "type": "markdown", + "content": "You now have a working alert rule that reaches for a pattern the visual builder can't compose in one query. That's the real power of Code mode." + }, + { + "type": "markdown", + "content": "---\n\n### More to explore (optional)\n\nRead more about how you can:\n\n- [Build alert queries and conditions](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/)\n- [Write PromQL expressions](https://grafana.com/docs/grafana/latest/fundamentals/intro-to-promql/)\n- [Configure contact points](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/)\n- [Write effective alert annotations](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/annotation-label/)" + }, + { + "type": "markdown", + "content": "---\n\n### Related paths\n\nConsider taking the following path next:\n\n- [Create a silence](https://grafana.com/docs/learning-paths/alerting-create-silence/)" + } + ] +} diff --git a/alerting-query-language-lj/install-datasources/content.json b/alerting-query-language-lj/install-datasources/content.json new file mode 100644 index 00000000..3202f809 --- /dev/null +++ b/alerting-query-language-lj/install-datasources/content.json @@ -0,0 +1,43 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-install-datasources", + "title": "Install the tutorial data sources", + "blocks": [ + { + "type": "markdown", + "content": "**QuickPizza** is a demo pizza-shop app that runs inside Grafana Cloud. It generates real metrics, so your queries have something interesting to see. Querying it doesn't count toward your Grafana Cloud usage.\n\nYou install QuickPizza from the **Demo Data Dashboards** app in the left nav. When it's done, Grafana refreshes the page and you're ready to build the alert." + }, + { + "type": "section", + "id": "install-tutorial-datasources", + "title": "Install QuickPizza", + "objectives": [ + "has-datasource:grafanacloud-play-prom" + ], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "a[data-testid='data-testid Nav menu item'][href='/a/grafana-demodashboards-app']", + "content": "In the left nav, click **Demo Data Dashboards**.", + "tooltip": "Opens the app that installs QuickPizza.", + "requirements": [ + "navmenu-open" + ] + }, + { + "type": "interactive", + "action": "highlight", + "reftarget": "button[data-testid='install-quickpizza']", + "content": "Click **Install the Quick Pizza SRE demo**. Grafana adds QuickPizza's data sources and refreshes the page.", + "tooltip": "Adds QuickPizza's metrics data source.", + "completeEarly": true + } + ] + }, + { + "type": "markdown", + "content": "QuickPizza is installed. Next, you open the alert rule form and give your rule a name." + } + ] +} diff --git a/alerting-query-language-lj/manifest.json b/alerting-query-language-lj/manifest.json new file mode 100644 index 00000000..cd7eb25a --- /dev/null +++ b/alerting-query-language-lj/manifest.json @@ -0,0 +1,28 @@ +{ + "id": "alerting-query-language-lj", + "type": "path", + "description": "Step-by-step guide: open and name an alert rule, switch to Code mode and write a PromQL error-rate query, set the condition, add a folder and labels, configure evaluation and handling, select a contact point, and save.", + "category": "take-action", + "author": { "name": "JohnnyK-Grafana", "team": "Grafana Documentation" }, + "startingLocation": "/alerting", + "targeting": { "match": { "and": [ { "urlPrefix": "/alerting" }, { "targetPlatform": "cloud" } ] } }, + "testEnvironment": { "tier": "cloud" }, + "milestones": [ + "alerting-query-language-business-value", + "alerting-query-language-install-datasources", + "alerting-query-language-navigate-to-form", + "alerting-query-language-build-query", + "alerting-query-language-set-condition", + "alerting-query-language-configure-labels-evaluation", + "alerting-query-language-set-evaluation-behavior", + "alerting-query-language-configure-handling", + "alerting-query-language-select-contact-point", + "alerting-query-language-configure-notification", + "alerting-query-language-save-rule", + "alerting-query-language-end-journey" + ], + "depends": [], + "recommends": [], + "suggests": ["alerting-create-silence-lj"], + "provides": [] +} diff --git a/alerting-query-language-lj/navigate-to-form/content.json b/alerting-query-language-lj/navigate-to-form/content.json new file mode 100644 index 00000000..51904cec --- /dev/null +++ b/alerting-query-language-lj/navigate-to-form/content.json @@ -0,0 +1,58 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-navigate-to-form", + "title": "Open the new alert rule page", + "blocks": [ + { + "type": "markdown", + "content": "When an alert fires, the name is the first thing responders see, so give the rule a name that says exactly what's wrong.\n\nIn this milestone, you open a fresh alert rule form and name the rule." + }, + { + "type": "section", + "id": "open-alert-form", + "title": "Open the new alert rule page", + "blocks": [ + { + "type": "interactive", + "action": "navigate", + "reftarget": "/alerting/list", + "content": "Open the **Alert rules** page. It's in the main menu under **Alerting > Alert rules**.", + "verify": "on-page:/alerting/list" + }, + { + "type": "interactive", + "action": "highlight", + "reftarget": "a[href*='alerting/new/alerting']", + "content": "Click **+ New alert rule** to start a fresh rule.", + "requirements": ["on-page:/alerting/list"], + "verify": "on-page:/alerting/new/alerting" + }, + { + "type": "markdown", + "content": "You're on the new alert rule page. Any draft you had open before is now cleared." + } + ] + }, + { + "type": "section", + "id": "set-alert-name", + "title": "Name the rule", + "requirements": ["section-completed:open-alert-form"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "input#name", + "targetvalue": "QuickPizza high error rate", + "content": "In the **Alert rule name** field, use **QuickPizza high error rate**. It says exactly what the rule watches.", + "tooltip": "This name shows up first when the alert fires.", + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "markdown", + "content": "Next, you write the query that measures the error rate." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/save-rule/content.json b/alerting-query-language-lj/save-rule/content.json new file mode 100644 index 00000000..02726e2e --- /dev/null +++ b/alerting-query-language-lj/save-rule/content.json @@ -0,0 +1,32 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-save-rule", + "title": "Save your alert rule", + "blocks": [ + { + "type": "markdown", + "content": "The rule is ready. In this milestone, you save it and Grafana starts evaluating it on the schedule you set." + }, + { + "type": "section", + "id": "save-rule", + "title": "Save and activate the rule", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='save-rule']", + "content": "Click **Save** in the action bar at the bottom of the page to save and activate your alert rule. Grafana immediately begins evaluating it at the interval you set.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your alert rule is saved and running. When the error rate holds above 5% past the pending period, the alert fires and notifications go to your contact point." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/select-contact-point/content.json b/alerting-query-language-lj/select-contact-point/content.json new file mode 100644 index 00000000..cb3b0b8e --- /dev/null +++ b/alerting-query-language-lj/select-contact-point/content.json @@ -0,0 +1,32 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-select-contact-point", + "title": "Select a contact point", + "blocks": [ + { + "type": "markdown", + "content": "A contact point tells Grafana where to send notifications, like email, Slack, or PagerDuty.\n\nIn this milestone, you pick the contact point that receives notifications when this rule fires." + }, + { + "type": "section", + "id": "select-contact-point", + "title": "Select a contact point", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='contact-point-picker']", + "content": "In the **Configure notifications** section, open the **Contact point** picker and choose **grafana-default-email**. Every Grafana Cloud stack includes it, and it delivers notifications to the email on your account.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your rule now knows where to send notifications. Next, you write the notification message and save the rule." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/set-condition/content.json b/alerting-query-language-lj/set-condition/content.json new file mode 100644 index 00000000..0f7ffd5d --- /dev/null +++ b/alerting-query-language-lj/set-condition/content.json @@ -0,0 +1,72 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-set-condition", + "title": "Set the alert condition", + "blocks": [ + { + "type": "markdown", + "content": "Your query returns a percentage. Now you tell Grafana *when* that percentage counts as \"too high\" and the alert should fire.\n\nIn this milestone, you set the threshold to **5**, meaning the alert fires when the error rate goes above 5%." + }, + { + "type": "section", + "id": "choose-operator", + "title": "Check when the alert fires", + "requirements": ["has-datasource:grafanacloud-play-prom"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "label:contains('WHEN QUERY')", + "content": "This is the **Alert condition** section. It's where you say: \"Fire the alert when the query result goes above this number.\"", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "highlight", + "reftarget": "[data-testid='data-testid alert-rule step-2'] button:contains('Is above')", + "content": "**Is above** is already selected. Leave it. The alert fires when the error rate goes above your threshold.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "set-threshold", + "title": "Set the threshold", + "requirements": ["section-completed:choose-operator"], + "blocks": [ + { + "type": "interactive", + "action": "formfill", + "reftarget": "[data-testid='data-testid alert-rule step-2'] input[type='number']", + "targetvalue": "5", + "content": "Set the threshold to **5**. Because the query returns a percentage, `5` means 5%.", + "tooltip": "The query returns a percentage, so 5 means 5%.", + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "preview-condition", + "title": "Preview the rule", + "requirements": ["section-completed:set-threshold"], + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "Preview alert rule condition", + "content": "Click **Preview alert rule condition** to test it. You'll see a **Normal** result when the error rate is under 5%, and **Firing** when it goes over.", + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "The condition is set. Next, you pick a folder and add labels so the alert is easy to find and route." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/set-evaluation-behavior/content.json b/alerting-query-language-lj/set-evaluation-behavior/content.json new file mode 100644 index 00000000..afb5f006 --- /dev/null +++ b/alerting-query-language-lj/set-evaluation-behavior/content.json @@ -0,0 +1,69 @@ +{ + "schemaVersion": "1.1.0", + "id": "alerting-query-language-set-evaluation-behavior", + "title": "Set evaluation behavior", + "blocks": [ + { + "type": "markdown", + "content": "Evaluation behavior sets how often Grafana runs your query, how long a problem must last before the alert fires, and how long the alert keeps firing after the condition resolves.\n\nYou saw these settings in the first alert rule. This milestone walks through them again for the ratio query." + }, + { + "type": "section", + "id": "configure-evaluation-group", + "title": "Create an evaluation group", + "requirements": ["on-page:/alerting/new/alerting"], + "blocks": [ + { + "type": "interactive", + "action": "button", + "reftarget": "New evaluation group", + "content": "In the **Set evaluation behavior** section, click **New evaluation group** to open the create dialog.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Name the group **QuickPizza alerts** (groups share an evaluation interval, so the name should describe what's grouped). Set the **Evaluation interval** to **1m**, then click **Create**." + } + ] + }, + { + "type": "section", + "id": "set-pending-period", + "title": "Set the pending period", + "requirements": ["section-completed:configure-evaluation-group"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "#eval-for-input", + "content": "Find the **Pending period** field. This is how long the condition must stay true before the alert fires. Set it to **1m**. Brief spikes get filtered out, but a real problem fires quickly.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + } + ] + }, + { + "type": "section", + "id": "set-keep-firing-for", + "title": "Set keep firing for", + "requirements": ["section-completed:set-pending-period"], + "blocks": [ + { + "type": "interactive", + "action": "highlight", + "reftarget": "#keep-firing-for-input", + "content": "Find the **Keep firing for** field. This is how long the alert keeps firing after the condition resolves, so a metric bouncing across the threshold doesn't flap. Leave it at **None** \u2014 the recovery threshold you set in the next milestone handles flapping for this ratio query.", + "doIt": false, + "requirements": ["on-page:/alerting/new/alerting"] + }, + { + "type": "interactive", + "action": "noop", + "content": "Your alert now has a folder, a label, and an evaluation schedule. Next, you handle missing data and query errors, then set a recovery threshold to stop flapping." + } + ] + } + ] +} diff --git a/alerting-query-language-lj/website.yaml b/alerting-query-language-lj/website.yaml new file mode 100644 index 00000000..1bb622b2 --- /dev/null +++ b/alerting-query-language-lj/website.yaml @@ -0,0 +1,40 @@ +menuTitle: First alert rule with query language +title: Create an alert rule with query language +description: Build a Grafana alert rule in Code mode — write a PromQL error-rate query, set a condition, add labels, configure evaluation and notifications, and save. +weight: 750 +journey: + group: take-action + skill: Intermediate + source: Docs & blog posts + logo: + src: /static/img/menu/grafana2.svg + background: '#0068FF' + width: 46 + height: 55 +step: 1 +layout: single-journey +cascade: + layout: single-journey +cta: + type: start + title: Are you ready? + cta_text: Let's go! +keywords: + - alerting + - alert rule + - PromQL + - code mode + - query language + - notifications + - save +related_journeys: + title: Related paths + heading: Consider taking the following paths before you start this path. + items: + - title: Create your first alert rule + url: /docs/learning-paths/alerting-first-rule/ + description: Learn the alerting workflow using Builder mode. Recommended before this path if you're new to PromQL. +source_docs: + - /docs/grafana/latest/alerting/fundamentals/alert-rules/ + - /docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/ + - /docs/grafana/latest/alerting/fundamentals/notifications/contact-points/