How to read this page. Ten steps, one gesture at a time. For each: where to click, what Grafana displays word for word, and what to look at. The interface labels are in English in Grafana 13.2.2 (the kit's version); they are quoted as they are, in bold. The numbers will be different on your machine; the shapes (number of series, panel value, messages) must be the same. The "To understand better" blocks are optional. If the lab is not started, go back to the guided practice: the In short section gives the commands, kit included (
https://github.com/hrhouma2/aiopsatlas-observabilite-labo-fr). Everything you create here is destroyed in step 10: the three dashboards shipped with the kit are not touched.
In the guided practice, you typed eight queries in Explore and looked at three ready-made dashboards. So you know how to read Grafana. But if you are asked to add a number to a dashboard, do you know where to start? Here, you start from scratch and assemble yourself the three objects of Grafana, from the smallest to the largest: a data source (Grafana stores nothing, it queries Prometheus), a panel (a query plus a way to draw it), a dashboard (panels arranged on a grid, with a name and an address). One step is a deliberate trap: you break a query to see how the Prometheus error passes through Grafana. At the end, you read the JSON Grafana wrote for you and find the three objects in it, then you delete everything.
Grafana is a digital photo frame. It takes no photos: it goes and fetches them from a photographer (the data source: Prometheus, Loki) and displays them. Each photo is a panel: a question asked to the photographer (the query) and a display format (a number, a curve, a gauge). The frame itself, with its photos laid out on a grid, is the dashboard: it has a name, an address, and it is saved in Grafana's database as a JSON document.
| Grafana | Classic SQL database | In this workshop |
|---|---|---|
| data source | the connection to the database | Prometheus (http://prometheus:9090) |
| query | SELECT … | count(up) |
| panel | a saved view | Cibles surveillées (monitored targets) |
| visualization | the way to display the result | Stat (a big number) |
| dashboard | a report that assembles several views | Atelier M1 - Cibles Prometheus |
uid | primary key | adc947c (yours will be different) |
| dashboard JSON | the exported schema of the report | step 9 |
| folder | database schema | Dashboards (the root); Labo observabilite for the kit's three |
Open http://localhost:3000. The main menu is the three-line icon at the top left: it gives access to Dashboards, Explore and Connections. The breadcrumb at the top (for example Dashboards › New dashboard) always says where you are. When an action succeeds, Grafana displays for a few seconds a banner at the bottom right (a toast): Dashboard saved, Dashboard deleted. When a query fails, it displays a red box under the query field, with Prometheus's message copied as is.
Once the dashboard is saved, you will re-read it as JSON through Grafana's API. In PowerShell or in a Linux terminal, the same command:
curl -s -u admin:aiopsatlas2026 http://localhost:3000/api/dashboards/uid/<uid><uid> is the identifier Grafana gave your dashboard; you will read it in the page address in step 8.
Main menu → Connections → Data sources. Three sources are listed: Alertmanager, Loki and Prometheus (marked default). Click Prometheus. The Settings page opens, with Prometheus server URL filled in: http://prometheus:9090. Change nothing. Scroll to the very bottom and click Save & test.
Successfully queried the Prometheus API.
Next, you can start to visualize data by building a dashboard from scratch or by querying data in the Explore view.What to look at: the green banner. Grafana has just sent a query to Prometheus and Prometheus answered. This is the first object: a data source is an address and a type. The address is http://prometheus:9090 and not http://localhost:9090: Grafana runs in a container, and from that container, Prometheus is called prometheus. Your browser, for its part, reaches it through localhost:9090. Two names for the same machine, depending on who is talking.
Not you. The kit describes them in grafana/provisioning/datasources/sources.yml and Grafana reads them at startup: this is provisioning. The file is short, open it: name: Prometheus, uid: prometheus, type: prometheus, url: http://prometheus:9090, isDefault: true. Without this file, the first thing to do in a fresh Grafana would be Add new data source, and you would type these four lines by hand. The uid: prometheus will serve you again in step 9: it is through it that your panel will designate its source.
Main menu → Explore. At the top, the source selector displays Prometheus. To the right of the field, switch to Code (and not Builder). Type:
upthen Run query (or Shift+Enter).
up{instance="alertmanager:9093", job="alertmanager"}
up{instance="alloy:12345", job="alloy"}
up{instance="api:8000", job="api", service="api"}
up{instance="cadvisor:8080", job="cadvisor"}
up{instance="grafana:3000", job="grafana"}
up{instance="localhost:9090", job="prometheus"}
up{instance="loki:3100", job="loki"}
up{instance="node-exporter:9100", job="node-exporter"}What to look at: eight lines in the legend under the graph, the eight series of step 2 of workshop 1, in alphabetical order of instance. The query is exactly the one you typed in Prometheus; Grafana forwarded it and drew the answer. Explore is a scratchpad: nothing is saved there, it is where you fine-tune a query before putting it on a panel.
Still in Explore, replace the query with a wrong version, on purpose:
count(upRun query:
bad_data: invalid parameter "query": 1:9: parse error: unclosed left parenthesisWhat to look at: a red box under the field, and No data in the graph. The message is not from Grafana: parse error and the position 1:9 are Prometheus's, which you learned to read in workshop 1. Grafana only prefixes bad_data:, the error category returned by Prometheus's API. Rule: when a Grafana panel displays a PromQL error, fix it in Prometheus first (http://localhost:9090), then copy it back into Grafana. Close the parenthesis, Run query: a single line in the legend, which Grafana names count(up) for lack of labels (Prometheus, for its part, wrote {}), at 8. This is the query you are going to put on your panel.
Main menu → Dashboards. The page lists a single folder, Labo observabilite, which contains the kit's three dashboards. At the top right, New → New dashboard.
New dashboard
Add a panel to visualize your dataWhat to look at: the breadcrumb says Dashboards › New dashboard, the page is empty, and the Save button is already there at the top right. Nothing is saved yet: if you close the tab now, nothing remains. A dashboard only exists from the moment it is saved (step 8). On the right, an Add side panel offers Panel ("Drag or click to add a panel").
In the Add side panel, click Panel. A frame appears on the grid, titled New panel, with the text No visualization configured. On the right, the Title field contains New panel: replace it with:
Cibles surveilléesWhat to look at: the frame's title changes live. You have a panel, but it is empty: neither query nor visualization. This is the second object, reduced to its minimum: a slot on the grid and a name. Click Edit visualization in the side panel: the Edit panel page opens, with the Queries 1 tab at the bottom and, on the right, Suggestions / All visualizations.
In Queries, line A is already linked to Data source: Prometheus (the default source). Switch to Code, type in the Enter a PromQL query… field:
count(up)then Run queries (or Shift+Enter).
Suggestions
Time series · Stat · Gauge · Bar gauge · Table · State timeline · Heatmap · HistogramWhat to look at: the right-hand pane changes: under Suggestions, Grafana offers a dozen visualizations, and each thumbnail already displays your data: count(up) and 8. The top panel, for its part, still says "Run a query to visualize it here or go to all visualizations": it has the query, it has not yet chosen how to draw it. Query and visualization are two separate settings of the same panel.
Builder builds the query with menus (choose the metric, add a label, stack a function). Code lets you type it. Both produce the same PromQL string, and you can switch from one to the other. In this course, we stay in Code: the query you type here is word for word Prometheus's, and you will find it as is in the JSON of step 9 ("editorMode": "code").
In Suggestions, click the Stat thumbnail.
Stat
Value options
Calculate | All values
Calculation: Last *
Thresholds
80 (rouge)
Base (vert)What to look at: the top panel now displays a big green 8, with the small background curve. The right-hand pane lists the Stat options, two of which are worth knowing: under Value options, Calculate is checked and Calculation is Last * (the panel shows the last value of the series, not an average); under Thresholds, two steps, Base in green and 80 in red: the value would turn red from 80 upwards. These thresholds are the ones Grafana puts by default on every new panel; they make no sense for a target count (you would see red at 80 targets), you would read and change them in a real dashboard. Here, leave them: what matters is recognizing them in the JSON.
At the top right, Save. The Save dashboard dialog opens, with two tabs, Details and Changes 3, and three fields: Title (New dashboard), Description, Folder (Dashboards).
What to look at first: clear the title and click Save: the word Required appears in red under Title and the Save button grays out. A dashboard must have a name. Type:
Atelier M1 - Cibles PrometheusThe button becomes active again. Click Save.
Dashboard savedWhat to look at next: the Dashboard saved banner, then the page address:
http://localhost:3000/d/adc947c/atelier-m1-cibles-prometheus?orgId=1&from=now-6h&to=now&timezone=browserThree things in this address. adc947c is the uid, drawn at random by Grafana: it is the identity of the dashboard, note it down. atelier-m1-cibles-prometheus is the title formatted as an address; it is only there for readability. from=now-6h&to=now is the period displayed, Last 6 hours by default for a new dashboard. The pencil at the top right (Edit) has replaced Save: you are in read mode. Main menu → Dashboards: your dashboard is in the list, at the root, next to the Labo observabilite folder.
Before clicking Save, open Changes 3: Grafana shows, as JSON, the difference between a fresh dashboard and the one you are saving. The number is the count of modifications it tallied; on an empty dashboard just opened, the tab says Changes 1. This is the first time you see the JSON that will be written; step 9 has you re-read it in full.
In a terminal, with your uid instead of adc947c:
curl -s -u admin:aiopsatlas2026 http://localhost:3000/api/dashboards/uid/adc947cThe answer is a JSON document. Its meta part:
"meta": {
"slug": "atelier-m1-cibles-prometheus",
"url": "/d/adc947c/atelier-m1-cibles-prometheus",
"created": "2026-09-15T21:21:02Z",
"version": 1,
"folderTitle": "General"
}And in dashboard, the panels array contains a single element, your panel (shortened to the fields that matter):
{
"type": "stat",
"title": "Cibles surveillées",
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"editorMode": "code",
"expr": "count(up)",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": 0 },
{ "color": "red", "value": 80 }
]
}
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
"id": 1,
"pluginVersion": "13.2.2"
}What to look at: the three objects of the workshop, written in black and white. The source: "datasource": { "type": "prometheus", "uid": "prometheus" }, the uid from the provisioning file of step 1. The query: "expr": "count(up)", in targets, with "refId": "A" (the letter of the line in Queries) and "editorMode": "code". The visualization: "type": "stat", and its settings from step 7: "calcs": ["lastNotNull"] is the Last * of the screen, steps are the two Thresholds, green at the base and red at 80. gridPos says where the frame is on the grid: top left, 12 columns wide out of 24, 8 rows high. A Grafana dashboard is nothing but that: this document, saved under a uid. This is your deliverable: this block, with stat, count(up) and prometheus circled.
On the dashboard page, Edit (the pencil) → in the right sidebar, Options (the gear) → View all settings → JSON Model tab. It is the same document, without the meta part, and you can modify it there then Save. It is also this document that the kit ships for its three dashboards, in grafana/provisioning/dashboards/*.json: open api-catalogue.json and search for "expr": you will read queries from the guided practice there, exactly in the format above. A dashboard is shared by sending this file.
On the dashboard page, Edit → Options → View all settings. The Settings page opens (tabs General, Annotations, Variables, Links, Versions, Permissions, JSON Model). At the very bottom, the red Delete dashboard button.
Delete
Do you want to delete this dashboard?
Atelier M1 - Cibles Prometheus
Type "Delete" to confirmWhat to look at: the dialog's Delete button is grayed out as long as you have not typed the word Delete in the field. Type it, click Delete.
Dashboard deleted
View deleted dashboardsGrafana takes you back to the home page. Proof through the API, with your uid:
curl -s -u admin:aiopsatlas2026 http://localhost:3000/api/dashboards/uid/adc947c{"message":"Dashboard not found"}And the complete list of dashboards:
curl -s -u admin:aiopsatlas2026 "http://localhost:3000/api/search?type=dash-db"Three entries, the kit's three, all in the Labo observabilite folder: api-catalogue (« API catalogue — signaux dorés », catalog API — golden signals), hote-conteneurs (« Hôte et conteneurs », host and containers), journaux-api (« Journaux de l'API », API logs). Yours is no longer there. The deletion dialog said so: Grafana keeps deleted dashboards in a history for up to twelve months (Recently deleted on the Dashboards page), from where they can be restored; for what you do in this course, deleted means deleted.
Redo the ten gestures from memory, in order, and tick:
Successfully queried the Prometheus API.up in Code mode returns 8 series.count(up returns a red box bad_data: … parse error: unclosed left parenthesis; count(up) returns {} and 8.count(up) then Run queries fills Suggestions with the value 8 on every thumbnail.8; Calculation is Last *; Thresholds: Base green, 80 red.Atelier M1 - Cibles Prometheus: Dashboard saved banner and a uid in the address.curl … /api/dashboards/uid/<uid> contains "type": "stat", "expr": "count(up)", "uid": "prometheus".curl returns {"message":"Dashboard not found"} and /api/search?type=dash-db lists exactly three dashboards.On the lab side, nothing has moved: etat still displays 10/10 services, 8/8 cibles up, 0 alertes actives. Grafana wrote then erased one row in its own database; Prometheus saw nothing go by.
The login page appears and admin / admin is refused. The kit's password is aiopsatlas2026 (set in docker-compose.yml, GF_SECURITY_ADMIN_PASSWORD variable). On the command line, the same pair: -u admin:aiopsatlas2026; with a wrong password, the API returns {"message":"Invalid username or password", …, "statusCode":401}.
Save & test returns an error instead of the green banner. Prometheus is stopped or restarting: etat, then wait for labo-prometheus to be healthy and retry. If you changed the URL by mistake, restore http://prometheus:9090 (not localhost: from the Grafana container, localhost is Grafana itself).
Explore returns No data on up without a red box. Look at the source selector at the top: you may be on Loki (the guided practice left you there). Switch back to Prometheus. Also check the period at the top right: it must end at now.
The query field refuses what I type, or the text appears twice. You are in Builder: the free field only exists in Code. Switch, clear, retype.
The panel stays on "Run a query to visualize it here". The query is written but has not been run: Run queries or Shift+Enter. If the Suggestions pane stays empty after that, the query has an error: the red box is under the field, scroll down.
The dialog's Save stays grayed out, with Required under the title. The title is empty. Type one. If you already saved a dashboard with the same name in a previous attempt, Grafana accepts it anyway: two dashboards can bear the same title, they have different uids. You will then have two entries in the list; delete the extra one (step 10).
I cannot find the uid. It is in the address, right after /d/: http://localhost:3000/d/adc947c/…. Otherwise, curl -s -u admin:aiopsatlas2026 "http://localhost:3000/api/search?query=Atelier" returns the "uid" field of every dashboard whose title contains Atelier.
curl returns {"message":"Dashboard not found"} in step 9 while the dashboard is on screen. The uid is miscopied (capitals, extra character). Copy it again from the address.
I deleted a kit dashboard by mistake. It is in Dashboards → Recently deleted: restore it. Otherwise, docker compose restart grafana: provisioning re-reads grafana/provisioning/dashboards/ at startup and recreates the three dashboards from their JSON files (tableaux-de-bord.yml, updateIntervalSeconds: 30).
I modified a kit dashboard and Save refuses. Normal: allowUiUpdates: false in tableaux-de-bord.yml. The kit's three dashboards are read, not overwritten; save your version under another name.