Ξαναπιάσε το ταμπλό του αυτοκινήτου από το μάθημα 01. Ο χιλιομετρητής μόνο αυξάνεται: είναι ένας μετρητής (counter), όπως το http_requetes_total. Ο δείκτης βενζίνης ανεβαίνει στο γέμισμα και κατεβαίνει στην οδήγηση: είναι ένας δείκτης στιγμιαίας τιμής (gauge), όπως το requetes_en_cours. Το βιβλίο συντήρησης που σημειώνει «12 διαδρομές κάτω από 10 km, 30 κάτω από 50 km, 3 πάνω από 100 km» ταξινομεί κάθε διαδρομή σε μια ζώνη: είναι ένα ιστόγραμμα, όπως το http_duree_requete_seconds. Και το μαύρο κουτί, που γράφει μια γραμμή ανά συμβάν με την ακριβή ώρα, είναι το log JSON του API. Ο Prometheus δεν λαμβάνει τίποτα: είναι αυτός που έρχεται να διαβάσει τους μετρητές κάθε 15 δευτερόλεπτα, όπως ένας ελεγκτής που περνά να καταγράψει τους μετρητές κάθε αυτοκινήτου του στόλου.
Μια μετρική Prometheus έχει πάντα ένα όνομα, ενδεχομένως labels, και μια αριθμητική τιμή. Ο τύπος λέει πώς να διαβάσεις αυτή την τιμή στον χρόνο. Ο Prometheus γνωρίζει τέσσερις: τον μετρητή, το gauge, το ιστόγραμμα και την περίληψη (summary). Οι τρεις πρώτοι χρησιμοποιούνται από το API καταλόγου· ο τέταρτος όχι, και ο λόγος είναι διδακτικός. Όλες οι παρακάτω γραμμές έχουν αντιγραφεί από το http://localhost:8000/metrics στο μηχάνημα του μαθήματος· οι τιμές θα είναι διαφορετικές σε σένα.
Μετρητής (counter). Ένας μετρητής μόνο αυξάνεται, ή ξαναρχίζει από το μηδέν αν η υπηρεσία επανεκκινήσει. Μετρά συσσωρευμένα συμβάντα. Το API εκθέτει το http_requetes_total, με τρία labels: τον κωδικό απόκρισης, τη μέθοδο HTTP και τη διαδρομή:
# HELP http_requetes_total Nombre de requêtes HTTP reçues, par méthode, route normalisée et code de réponse.
# TYPE http_requetes_total counter
http_requetes_total{code="200",methode="GET",route="/cours"} 3247.0
http_requetes_total{code="201",methode="POST",route="/inscriptions"} 855.0
http_requetes_total{code="404",methode="GET",route="/cours/{id}"} 210.0
http_requetes_total{code="500",methode="GET",route="/cours"} 32.0Αυτό που δεν κάνεις ποτέ με έναν μετρητή: να διαβάσεις την ακατέργαστη τιμή του για να πεις «υπάρχουν 3247 αιτήματα αυτή τη στιγμή». Ένας μετρητής δεν κατεβαίνει ποτέ· αυτό που σε ενδιαφέρει είναι η ταχύτητα αύξησής του, υπολογισμένη με τη συνάρτηση rate() (ενότητα 2). Τεκμηρίωση: Prometheus — Metric types, Counter.
Gauge. Ένα gauge ανεβαίνει και κατεβαίνει ελεύθερα: μια τιμή σε μια δεδομένη στιγμή. Το API εκθέτει το requetes_en_cours, τον αριθμό αιτημάτων που βρίσκονται υπό επεξεργασία την ακριβή στιγμή της καταγραφής:
# HELP requetes_en_cours Nombre de requêtes HTTP en cours de traitement à cet instant.
# TYPE requetes_en_cours gauge
requetes_en_cours 1.0Ένα αίτημα είναι σε εξέλιξη τη στιγμή της καταγραφής· την επόμενη στιγμή, αυτός ο αριθμός μπορεί να είναι 0 ή 4. Το API εκθέτει επίσης gauges ρύθμισης, των οποίων η τιμή είναι περισσότερο πληροφορία παρά μέτρηση: api_info{version="1.0.0"} 1.0 (η έκδοση βρίσκεται στο label, η τιμή είναι πάντα 1) και api_panne_taux_erreurs 0.01 (το μερίδιο αιτημάτων που το API κάνει επίτηδες να αποτύχουν: 1 % σε κανονική λειτουργία). Τεκμηρίωση: Prometheus — Metric types, Gauge.
Ιστόγραμμα (histogram). Ένα ιστόγραμμα μετρά την κατανομή μιας τιμής, όπως τη διάρκεια ενός αιτήματος HTTP: πόσα αιτήματα πήραν λιγότερο από 5 ms, λιγότερο από 10 ms, λιγότερο από 25 ms…; Το API εκθέτει το http_duree_requete_seconds. Αντίθετα με έναν μετρητή ή ένα gauge, ένα ιστόγραμμα δημοσιεύει πολλές γραμμές για μια μόνο μετρική: έναν μετρητή ανά ζώνη (bucket), πλέον ένα συνολικό πλήθος και ένα άθροισμα. Εδώ είναι οι δώδεκα γραμμές της διαδρομής /cours:
# HELP http_duree_requete_seconds Durée de traitement des requêtes HTTP, en secondes, par route normalisée.
# TYPE http_duree_requete_seconds histogram
http_duree_requete_seconds_bucket{le="0.005",route="/cours"} 32.0
http_duree_requete_seconds_bucket{le="0.01",route="/cours"} 74.0
http_duree_requete_seconds_bucket{le="0.025",route="/cours"} 1566.0
http_duree_requete_seconds_bucket{le="0.05",route="/cours"} 3248.0
http_duree_requete_seconds_bucket{le="0.1",route="/cours"} 3276.0
http_duree_requete_seconds_bucket{le="0.25",route="/cours"} 3278.0
http_duree_requete_seconds_bucket{le="0.5",route="/cours"} 3279.0
http_duree_requete_seconds_bucket{le="1.0",route="/cours"} 3279.0
http_duree_requete_seconds_bucket{le="2.0",route="/cours"} 3279.0
http_duree_requete_seconds_bucket{le="+Inf",route="/cours"} 3279.0
http_duree_requete_seconds_count{route="/cours"} 3279.0
http_duree_requete_seconds_sum{route="/cours"} 85.42293146001248Κάθε _bucket{le="…"} (le για less or equal) μετρά τα αιτήματα ταχύτερα ή ίσα με αυτό το κατώφλι, με σωρευτικό τρόπο: τα 32 αιτήματα κάτω από 5 ms μετριούνται και στα 74 κάτω από 10 ms, και στα 3279 του κάδου +Inf (όλα). Το _count είναι ο συνολικός αριθμός παρατηρήσεων (3279, ίσος με τον κάδο +Inf), το _sum το άθροισμα όλων των διαρκειών (85,4 δευτερόλεπτα συνολικά, δηλαδή 26 ms κατά μέσο όρο ανά αίτημα). Αυτό είναι που επιτρέπει να ανακατασκευάσεις ένα ποσοστημόριο εκ των υστέρων, με το histogram_quantile() (ενότητα 2). Άμεση ανάγνωση: 3248 αιτήματα από τα 3279 πήραν λιγότερο από 50 ms, δηλαδή 99 %. Τεκμηρίωση: Prometheus — Metric types, Histogram.
Περίληψη (summary), και γιατί το εργαστήριο δεν τη χρησιμοποιεί. Μια περίληψη μετρά επίσης μια κατανομή, αλλά υπολογίζει τα ποσοστημόριά της απευθείας μέσα στο παρατηρούμενο πρόγραμμα, πριν τα δημοσιεύσει: μια γραμμή {quantile="0.5"}, μια γραμμή {quantile="0.9"}, πλέον _sum και _count. Το πρόβλημα: ένα ποσοστημόριο υπολογισμένο στην πλευρά του πελάτη δεν μπορεί να ανασυνδυαστεί με αυτό μιας άλλης instance. Αν το εργαστήριο έτρεχε τρία αντίγραφα του API, δεν θα μπορούσες να πάρεις τον μέσο όρο των τριών quantile="0.9" για να πάρεις το πραγματικό 90ό εκατοστημόριο του συνόλου. Ένα ιστόγραμμα δημοσιεύει ακατέργαστους μετρητές ανά ζώνη: ο Prometheus μπορεί να τους προσθέσει μεταξύ instances πριν υπολογίσει το ποσοστημόριο. Δεν υπάρχει λοιπόν καμία γραμμή summary στο /metrics του API του εργαστηρίου. Τεκμηρίωση: Prometheus — Histograms and summaries.
| Τύπος | Τι μετρά | Στο εργαστήριο | Ερώτηση στην οποία απαντά |
|---|---|---|---|
| Μετρητής | Μια συσσώρευση που μόνο αυξάνεται | http_requetes_total, inscriptions_total, cours_consultes_total | «Πόσα αιτήματα ανά δευτερόλεπτο;» (με rate) |
| Gauge | Μια στιγμιαία τιμή που ανεβαίνει και κατεβαίνει | requetes_en_cours, api_disque_libre_octets, api_info | «Πόσα αυτή τη στιγμή;» |
| Ιστόγραμμα | Μια κατανομή, σε σωρευτικές ζώνες | http_duree_requete_seconds | «Το 95 % των αιτημάτων παίρνει λιγότερο από πόσο;» |
| Περίληψη | Μια κατανομή, ποσοστημόρια υπολογισμένα στην πλευρά του πελάτη | καμία | Η ίδια, αλλά χωρίς δυνατότητα συνάθροισης μεταξύ instances |
Κάθε μοναδικός συνδυασμός ονόματος μετρικής και labels σχηματίζει μια χρονοσειρά: μια ακολουθία ζευγών (χρονοσφραγίδα, τιμή) που ο Prometheus αποθηκεύει και ερωτά. Το http_requetes_total{code="200",methode="GET",route="/cours"} είναι μια σειρά· το http_requetes_total{code="201",methode="POST",route="/inscriptions"} είναι μια άλλη. Στο μηχάνημα του μαθήματος, το http_requetes_total αριθμεί 14 σειρές (14 συνδυασμοί κωδικού, μεθόδου και διαδρομής που εμφανίστηκαν από την εκκίνηση). Τα labels επιτρέπουν να φιλτράρεις και να ομαδοποιείς χωρίς να αλλάζεις το όνομα: «τα σφάλματα διακομιστή, μόνο στο /inscriptions» γράφεται http_requetes_total{route="/inscriptions",code=~"5.."}. Τεκμηρίωση: Prometheus — Data model.
Η πληθικότητα (cardinality) μιας μετρικής είναι ο αριθμός διακριτών σειρών που παράγει. Το http_requetes_total{code,methode,route}, με πέντε κωδικούς, δύο μεθόδους και επτά διαδρομές σε πρότυπο, δίνει το πολύ μερικές δεκάδες σειρές. Κοίτα το log του βήματος 2 του μαθήματος 01: το αίτημα κάλεσε το /cours/C0038, αλλά η μετρική φέρει route="/cours/{id}", το πρότυπο της διαδρομής όπως το δήλωσε το FastAPI. Αν το label περιείχε το πραγματικό αναγνωριστικό, κάθε μάθημα που θα ανοιγόταν θα δημιουργούσε μια σειρά: 64 μαθήματα × 5 κωδικοί × 2 μέθοδοι. Σε έναν πραγματικό κατάλογο δεκάδων χιλιάδων μαθημάτων, η μετρική θα εκρηγνυόταν και ο Prometheus θα επιβραδυνόταν. Ο κανόνας: ένα label πρέπει να έχει έναν φραγμένο και λογικό αριθμό τιμών· ένα μοναδικό αναγνωριστικό, μια διεύθυνση IP ή μια χρονοσφραγίδα δεν έχουν καμία θέση σε ένα label. Μια διαδρομή που δεν υπάρχει μετριέται κάτω από route="inconnue", ποτέ κάτω από την πραγματική της διαδρομή, για τον ίδιο λόγο.
Το εργαστήριο περιέχει επίτηδες μια διδακτική εξαίρεση: το inscriptions_total{cours_id="C0028"} και το cours_consultes_total{cours_id="…"} έχουν ένα label ανά μάθημα. Με 64 μαθήματα, παραμένει φραγμένο (64 σειρές το καθένα). Με ένα εκατομμύριο μαθήματα, θα ήταν λάθος. Το εργαστήριο έχει άλλωστε μια ειδοποίηση PrometheusTropDeSeries που ηχεί πάνω από 100 000 σειρές. Τεκμηρίωση: Prometheus — Instrumentation, cardinality.
Ο Prometheus λειτουργεί σε pull (πηγαίνει να πάρει): ερωτά ο ίδιος, κάθε 15 δευτερόλεπτα στο εργαστήριο (scrape_interval: 15s στο prometheus/prometheus.yml), το URL /metrics κάθε υπηρεσίας που επιτηρεί. Είναι το αντίστροφο ενός συστήματος push, όπου η παρατηρούμενη υπηρεσία στέλνει τις μετρικές της σε έναν συλλέκτη. Το pull έχει ένα άμεσο πλεονέκτημα: αν μια υπηρεσία δεν απαντά πλέον, ο Prometheus το ξέρει αμέσως, η μετρική up περνά σε 0, χωρίς να εξαρτάται από την υπηρεσία που έχει βλάβη για να σηματοδοτήσει η ίδια την απουσία της. Αυτό ακριβώς σε κάνει να προκαλέσεις η πρακτική αυτής της ενότητας με το casser api.
| Όρος | Τι είναι | Στο εργαστήριο |
|---|---|---|
| scrape | Μια ανάγνωση του /metrics από τον Prometheus | Κάθε 15 s, σε καθέναν από τους 8 στόχους |
| target (στόχος) | Ένα URL /metrics που διαβάζει ο Prometheus | http://api:8000/metrics, http://node-exporter:9100/metrics… |
| exporter | Ένα πρόγραμμα που εκθέτει σε μορφή Prometheus τις μετρικές ενός συστήματος που δεν τη μιλά εγγενώς | node-exporter (το μηχάνημα-οικοδεσπότης), cadvisor (τα containers) |
| job | Μια ομάδα στόχων που κάνουν την ίδια δουλειά | job="api", job="prometheus", job="loki"… 8 jobs |
| instance | Ένας μεμονωμένος στόχος μέσα σε ένα job | instance="api:8000" |
up | Η μετρική που κατασκευάζει ο ίδιος ο Prometheus σε κάθε scrape: 1 αν ο στόχος απάντησε, 0 αλλιώς | Το up{job="api"} ισούται με 1 σε κανονική λειτουργία |
Τα ονόματα api:8000, node-exporter:9100 είναι αυτά του εσωτερικού δικτύου του Docker Compose: είναι ο Prometheus, μέσα στο container του, που μιλά στο API μέσα στο δικό του. Από τον υπολογιστή σου, η ίδια σελίδα είναι http://localhost:8000/metrics. Τεκμηρίωση: Prometheus — Configuration, scrape_config και Prometheus — Jobs and instances.
Ένα δομημένο log γράφεται σε μια μορφή που η μηχανή τεμαχίζει χωρίς να μαντεύει (JSON, τις περισσότερες φορές), αντί για μια ελεύθερη φράση. Το API γράφει στην τυπική έξοδό του μια γραμμή JSON ανά επεξεργασμένο αίτημα. Εδώ είναι μια πραγματική γραμμή, διαβασμένη με .\labo.ps1 journal api στο μηχάνημα του μαθήματος:
{"horodatage": "2026-09-15T19:33:25.839+00:00", "niveau": "INFO", "id_requete": "46bb533b33e9", "methode": "GET", "route": "/cours/{id}", "code": 200, "duree_ms": 13.9, "message": "GET /cours/C0038 -> 200"}| Πεδίο | Παράδειγμα | Τι είναι |
|---|---|---|
horodatage | 2026-09-15T19:33:25.839+00:00 | Η ακριβής στιγμή του συμβάντος, σε μορφή ISO 8601, σε UTC (+00:00) |
niveau | INFO | Η σοβαρότητα: INFO (2xx), WARNING (404, 422), ERROR (500). Τρεις τιμές στο εργαστήριο |
id_requete | 46bb533b33e9 | Ένα μοναδικό αναγνωριστικό 12 χαρακτήρων που παράγεται για αυτό το αίτημα, επιστρέφεται στον πελάτη στην κεφαλίδα HTTP x-id-requete |
methode | GET | Η μέθοδος HTTP |
route | /cours/{id} | Το πρότυπο της διαδρομής, το ίδιο με αυτό της μετρικής |
code | 200 | Ο κωδικός απόκρισης HTTP |
duree_ms | 13.9 | Η διάρκεια επεξεργασίας, σε χιλιοστά του δευτερολέπτου |
message | GET /cours/C0038 -> 200 | Η αναγνώσιμη φράση: εδώ, και μόνο εδώ, εμφανίζεται το πραγματικό αναγνωριστικό του μαθήματος |
Τι πρέπει να δεις: το route κρατά το πρότυπο /cours/{id} (όπως η μετρική), αλλά το message περιέχει C0038, το πραγματικό αναγνωριστικό. Ένα log μπορεί να επιτρέψει στον εαυτό του αυτή τη λεπτομέρεια: το Loki δεν ευρετηριάζει το κείμενο του μηνύματος, ευρετηριάζει μόνο τέσσερα labels (service, conteneur, niveau, code) που εξάγει το Alloy. Η ενότητα 5 σου δείχνει πώς το Alloy διαβάζει το JSON και κατασκευάζει αυτά τα labels. Τεκμηρίωση: Grafana Loki — Labels.
Οι άλλες υπηρεσίες του εργαστηρίου δεν γράφουν όλες JSON. Το webhook, στην εκκίνηση, γράφει ελεύθερο κείμενο: INFO: Uvicorn running on http://0.0.0.0:8090 (Press CTRL+C to quit). Η υπηρεσία charge γράφει JSON, αλλά με άλλα πεδία: κάθε 30 δευτερόλεπτα, μια περίληψη {"niveau": "INFO", "message": "résumé des 30 dernières secondes", "requetes": {"200": 214, "total": 262, "201": 26, "500": 4, "404": 16, "422": 2}}. Ένα δομημένο log δεν είναι μια παγκόσμια μορφή: είναι μια απόφαση που λαμβάνεται υπηρεσία προς υπηρεσία.
Ένα trace ακολουθεί ένα μοναδικό αίτημα μέσα από πολλές υπηρεσίες: κάθε βήμα (ένα span) καταγράφει το όνομά του, τη διάρκειά του, και τη σχέση γονέα-παιδιού με τα άλλα. Απαντά στο «το αίτημα πήρε 800 ms, σε ποια υπηρεσία δαπανήθηκε αυτός ο χρόνος;». Το εργαστήριο δεν εγκαθιστά κανένα εργαλείο ιχνηλάτησης: το API καταλόγου και η γεννήτρια φορτίου είναι οι δύο μόνες εφαρμογές, συνδεδεμένες με μια απλή κλήση HTTP, γεγονός που περιορίζει το παιδαγωγικό ενδιαφέρον ενός κατανεμημένου trace εδώ. Το id_requete του log είναι ήδη το πρώτο κομμάτι ενός trace: αυτό θα το έλεγε το OpenTelemetry trace id. Η ενότητα 7 λέει μια λέξη παραπάνω. Τεκμηρίωση: OpenTelemetry — Traces.
| Υπηρεσία | Ρόλος | Θύρα | URL από τον υπολογιστή σου |
|---|---|---|---|
prometheus | Διαβάζει τους στόχους, αποθηκεύει τις σειρές, αξιολογεί τους κανόνες | 9090 | http://localhost:9090 |
alertmanager | Λαμβάνει τις ειδοποιήσεις του Prometheus, τις ομαδοποιεί και τις δρομολογεί | 9093 | http://localhost:9093 |
grafana | Εξερευνά και οπτικοποιεί Prometheus, Loki και Alertmanager | 3000 (GRAFANA_PORT) | http://localhost:3000 (admin / aiopsatlas2026) |
loki | Αποθηκεύει τα logs, ευρετηριασμένα με labels | 3100 | http://localhost:3100/ready |
alloy | Ανακαλύπτει τα containers και μεταφέρει τα logs τους στο Loki | 12345 | http://localhost:12345 |
node-exporter | Μετρικές του μηχανήματος-οικοδεσπότη | 9100 | http://localhost:9100/metrics |
cadvisor | Μετρικές κάθε container | 8080 | http://localhost:8080 |
api | Η παρατηρούμενη υπηρεσία | 8000 | http://localhost:8000/cours · http://localhost:8000/metrics |
webhook | Λαμβάνει και εμφανίζει τις ειδοποιήσεις | 8090 | http://localhost:8090 |
charge | Παράγει κίνηση προς το API | καμία | καμία: δεν έχει διεπαφή, μόνο ένα ημερολόγιο (journal) |
Εννέα θύρες, δέκα υπηρεσίες: το charge δεν ακούει σε τίποτα. Οκτώ στόχοι Prometheus, δέκα υπηρεσίες: το charge και το webhook δεν εκθέτουν /metrics.
Αυτό το βήμα προς βήμα υποθέτει ότι το εργαστήριο έχει ξεκινήσει (μάθημα 04). Αν διαβάζεις αυτό το μάθημα πριν, κράτησέ το για αργότερα: κάθε βήμα γίνεται στον περιηγητή ή σε ένα τερματικό, μόνο για ανάγνωση.
Άνοιξε το http://localhost:8000/metrics στον περιηγητή. Είναι η ακατέργαστη σελίδα που ο Prometheus διαβάζει κάθε 15 δευτερόλεπτα: κείμενο, μια γραμμή ανά σειρά, με τις γραμμές # HELP και # TYPE πριν από αυτήν. Στο μηχάνημα του μαθήματος, αριθμεί 271 γραμμές. Σύγκρινε με το http://localhost:9100/metrics (node-exporter: 1578 γραμμές) και το http://localhost:8080/metrics (cAdvisor: 3444 γραμμές, για δέκα containers).
Τι πρέπει να δεις: οι γραμμές που αρχίζουν με python_ και process_ στην κορυφή της σελίδας του API δεν γράφονται από το εργαστήριο. Η βιβλιοθήκη prometheus_client τις προσθέτει από μόνη της (μνήμη της διεργασίας, συλλέκτης απορριμμάτων Python). Οι μετρικές του μαθήματος αρχίζουν στο http_requetes_total.
Ψάξε τα τέσσερα # TYPE του API. Στη σελίδα, ψάξε (Ctrl+F) # TYPE http_: βρίσκεις counter για το http_requetes_total και histogram για το http_duree_requete_seconds. Ψάξε # TYPE requetes_en_cours: gauge. Ψάξε summary: κανένα αποτέλεσμα.
Τι πρέπει να δεις: οι τρεις τύποι που χρησιμοποιούνται, και η εκούσια απουσία του τέταρτου.
Μέτρησε τις σειρές του http_requetes_total στον Prometheus. Άνοιξε το http://localhost:9090, πληκτρολόγησε http_requetes_total στο πεδίο ερωτήματος και εκτέλεσε. Στο μηχάνημα του μαθήματος, ο πίνακας εμφανίζει 14 γραμμές, ανάμεσά τους:
http_requetes_total{code="200", instance="api:8000", job="api", methode="GET", route="/cours", service="api"} 3241
http_requetes_total{code="500", instance="api:8000", job="api", methode="GET", route="/cours", service="api"} 32Τι πρέπει να δεις: ο Prometheus πρόσθεσε τρία labels σε αυτά της σελίδας /metrics: job="api" και instance="api:8000" (που ταυτοποιούν τον στόχο) και service="api" (που προστίθεται από τη ρύθμιση του job στο prometheus.yml). Η τιμή 3241 είναι λίγο μικρότερη από το 3247 που διαβάστηκε στο βήμα 1: ο Prometheus δείχνει το τελευταίο scrape, που είναι 0 έως 15 δευτερόλεπτα πριν.
Διάβασε μια γραμμή log του API στο τερματικό. Από τον φάκελο lab3:
.\labo.ps1 journal apiΣτο μηχάνημα του μαθήματος, οι τελευταίες γραμμές μοιάζουν με:
labo-api | {"horodatage": "2026-09-15T19:33:25.916+00:00", "niveau": "INFO", "id_requete": "5ccaee4d1a2a", "methode": "GET", "route": "/sante", "code": 200, "duree_ms": 1.0, "message": "GET /sante -> 200"}
labo-api | {"horodatage": "2026-09-15T19:33:26.217+00:00", "niveau": "INFO", "id_requete": "e64206564a68", "methode": "GET", "route": "/cours/{id}", "code": 200, "duree_ms": 8.2, "message": "GET /cours/C0043 -> 200"}Τι πρέπει να δεις: το GET /sante κάθε λίγα δευτερόλεπτα είναι το Docker που ελέγχει την υγεία του container (το healthcheck)· τα υπόλοιπα είναι η υπηρεσία charge. Το πρόθεμα labo-api | προστίθεται από το Docker Compose, δεν ανήκει στο JSON.
Έλεγξε τα labels που γνωρίζει το Loki. Άνοιξε το http://localhost:3100/loki/api/v1/labels:
{"status":"success","data":["code","conteneur","niveau","service"]}Μετά το http://localhost:3100/loki/api/v1/label/niveau/values:
{"status":"success","data":["ERROR","INFO","WARNING"]}Τι πρέπει να δεις: τέσσερα labels, όχι οκτώ. Το Loki δεν ευρετηριάζει ούτε το id_requete, ούτε το duree_ms, ούτε το message: αυτά τα πεδία μένουν στο κείμενο της γραμμής, όπου η LogQL μπορεί να τα εξαγάγει κατά παραγγελία με | json (ενότητα 5). Οι τρεις τιμές του niveau επιβεβαιώνουν τον πίνακα παραπάνω.
Τα παρακάτω μηνύματα προκλήθηκαν στα αλήθεια στον Prometheus, στο μηχάνημα του μαθήματος. Θα επανέλθουν στην ενότητα 2· καλύτερα να τα αναγνωρίζεις από τώρα.
Να ξεχάσεις τα εισαγωγικά γύρω από μια τιμή label: το up{job=api} επιστρέφει
invalid parameter "query": 1:8: parse error: unexpected identifier "api" in label matching, expected stringΜια τιμή label είναι πάντα μια συμβολοσειρά μέσα σε εισαγωγικά: up{job="api"}. Ακόμη και για έναν αριθμό: το http_requetes_total{code=500} επιστρέφει parse error: unexpected character inside braces: '5'· πρέπει να γράψεις code="500".
Να καλέσεις το rate() χωρίς χρονικό παράθυρο: το rate(http_requetes_total) επιστρέφει
invalid parameter "query": 1:6: parse error: expected type range vector in call to function "rate", got instant vectorΤο rate() χρειάζεται ένα διάστημα μέσα σε αγκύλες: rate(http_requetes_total[1m]). Χωρίς αγκύλες, του δίνεις την τελευταία τιμή (ένα instant vector) ενώ χρειάζεται μια ακολουθία τιμών (ένα range vector).
Να καλέσεις το rate() σε ένα gauge: το rate(requetes_en_cours[1m]) δεν προκαλεί σφάλμα, αλλά ο Prometheus εμφανίζει μια προειδοποίηση:
PromQL info: metric might not be a counter, name does not end in _total/_sum/_count/_bucket: "requetes_en_cours" (1:6)Το αποτέλεσμα (0.017… στο μηχάνημα του μαθήματος) δεν έχει κανένα νόημα: η ταχύτητα αύξησης μιας τιμής που ανεβαίνει και κατεβαίνει δεν είναι πληροφορία. Το rate() προορίζεται για μετρητές.
Να κάνεις λάθος στο όνομα μιας μετρικής: το http_request_total (στον ενικό, χωρίς το γαλλικό e) επιστρέφει κενό αποτέλεσμα, χωρίς μήνυμα σφάλματος. Ο Prometheus δεν γνωρίζει αυτή τη μετρική, δεν τη διορθώνει. Το ακριβές όνομα είναι http_requetes_total. Ομοίως, το http_requetes_total{route="/inexistant"} επιστρέφει κενό αποτέλεσμα: η άγνωστη διαδρομή μετριέται κάτω από route="inconnue", όχι κάτω από την πραγματική της διαδρομή.
Οι τέσσερις τύποι μετρικών Prometheus είναι ο μετρητής (http_requetes_total, που αυξάνεται μόνο προς μία κατεύθυνση και διαβάζεται με rate()), το gauge (requetes_en_cours, που ανεβαίνει και κατεβαίνει), το ιστόγραμμα (http_duree_requete_seconds, δώδεκα γραμμές ανά διαδρομή: δέκα σωρευτικά _bucket, _count, _sum) και η περίληψη (απούσα από το εργαστήριο, γιατί τα ποσοστημόριά της δεν συναθροίζονται μεταξύ instances). Μια χρονοσειρά είναι ένας μοναδικός συνδυασμός ονόματος και labels· το http_requetes_total έχει 14 στο μηχάνημα του μαθήματος. Η πληθικότητα εξηγεί γιατί η μετρική φέρει route="/cours/{id}" ενώ το log περιέχει C0038 στο μήνυμά του. Ο Prometheus λειτουργεί σε pull: διαβάζει (scrape) οκτώ στόχους (targets) κάθε 15 δευτερόλεπτα, ομαδοποιημένους ανά job, ταυτοποιημένους ανά instance, και κατασκευάζει ο ίδιος τη μετρική up. Ένα δομημένο log του εργαστηρίου είναι μια γραμμή JSON με οκτώ πεδία, ανάμεσά τους το id_requete, που επιστρέφεται επίσης στην κεφαλίδα x-id-requete· το Loki ευρετηριάζει από αυτό μόνο τέσσερα labels: service, conteneur, niveau, code. Δέκα υπηρεσίες, εννέα θύρες (το charge δεν έχει), οκτώ στόχοι Prometheus (το charge και το webhook δεν εκθέτουν /metrics).
/metrics που άνοιξες στο βήμα 1 (οι γραμμές # HELP, # TYPE, η διαφυγή των labels)._total για έναν μετρητή, _seconds για μια διάρκεια, _bytes για ένα μέγεθος· το API του εργαστηρίου σέβεται αυτές τις συμβάσεις, με μία εξαίρεση: τα ονόματα είναι στα γαλλικά.histogram_quantile.api/app.py για να εκθέσει τις μετρικές· η ενότητα 3 σε κάνει να προσθέσεις τη δική σου μετρική με αυτήν.up, να φιλτράρεις ανά label, να υπολογίσεις ένα rate(), να διαβάσεις ένα ιστόγραμμα με histogram_quantile().