diff --git a/docs/.vitepress/sidebar.json b/docs/.vitepress/sidebar.json index c16f74e..e0ab871 100644 --- a/docs/.vitepress/sidebar.json +++ b/docs/.vitepress/sidebar.json @@ -142,8 +142,8 @@ "link": "/guide/alerting" }, { - "text": "Logs (Kibana)", - "link": "/guide/logs-kibana" + "text": "Logs", + "link": "/guide/logs" }, { "text": "Archivage des logs", diff --git a/docs/guide/logs.md b/docs/guide/logs.md new file mode 100644 index 0000000..5b6f190 --- /dev/null +++ b/docs/guide/logs.md @@ -0,0 +1,178 @@ +# Logs + +Les logs sont gérés via la solution [Loki de Grafana](https://grafana.com/oss/loki/) + +Retrouvez ce service dans la console Cloud Pi via le menu `Projet > Mes Projets > Sélectionner un projet > Mes Services` et cliquer sur l'icône Grafana qui vous intéresse. + +## Connexion + +Pour se logguer, cliquer sur le bouton en bas pour utiliser l'authentification par SSO. + +![login](/img/guide/loki/connexion.png) + +## Premiers pas + +Pour explorer vos logs de façon ponctuel, sélectionner **Explore** dans le menu de gauche, puis **Loki** dans la liste déroulante + +![explore](/img/guide/loki/explore.png) + +Dans la liste déroulante *label filters*, sélectionner `namespace` puis dans *select value* choisir le bon namespace. + +Cliquer sur le bouton bleu **Run query** pour retrouver tous les logs générés par votre application dans le namespace choisi: + +![premierspas](/img/guide/loki/premierspas.png) + +Il est aussi possible de filtrer selon le texte contenu dans une ligne de log, pour cela dans le champ de texte **Line contains** mettre la chaîne de caractère recherchée: + +![premierspas_contains](/img/guide/loki/premierspas_contains.png) + +## Filtrage par label + +Loki permet de filtrer les logs via un système de label. + +Certains labels sont statiques (générés par l'équipe CPiN) et il est aussi possible de créer des labels à la volée via le langage LogQL. + +Pour les labels statiques: + +- cluster: nom du cluster où est déployée l'application +- container: +- job: +- namespace: le namespace où est le pod générant les logs +- service_name: +- stream: la sortie des logs, stdout ou stderr +- tenant: + +### Labels dynamiques + +Il est possible de créer des labels à la volée en utilisant les fonctions LogQL suivantes qui permettent de parser la ligne de log: + +- [json](https://grafana.com/docs/loki/latest/query/log_queries/#json): utilisable si la ligne est au format json +- [logfmt](https://grafana.com/docs/loki/latest/query/log_queries/#logfmt): utilisable si la ligne est de la forme *clé=valeur* +- [pattern](https://grafana.com/docs/loki/latest/query/log_queries/#pattern): quand les données forment un pattern régulier (exemple log apache) +- [regexp](https://grafana.com/docs/loki/latest/query/log_queries/#regular-expression): utilise une expression régulière pour parser la ligne de log + +Les parseurs json et logfmt sont à préférer quand cela est possible. Si cela n'est pas possible mais que les données forment un pattern régulier (champs séparés par un espace mais sans clé=valeur par exemple) il vaut mieux utiliser le parseur pattern (plus simple à écrire et plus rapide à exécuter). Pour le reste, il est possible d'écrire une [regex](https://regex101.com/) (format golang) avec le parseur regexp + +Pour les exemples suivants, la sélection des logs se fait via `{namespace="mi-demo"}` + +#### Json + +Pour parser la ligne suivante: + +```json +{ + "protocol": "HTTP/2.0", + "servers": ["129.0.1.1", "10.2.1.3"], + "request": { + "time": "6.032", + "method": "GET", + "host": "foo.grafana.net", + "size": "55", + "headers": { + "Accept": "*/*", + "User-Agent": "curl/7.68.0" + } + }, + "response": { + "status": 401, + "size": "228", + "latency_seconds": "6.031" + } +} +``` + +Avec la ligne LogQL `{namespace="mi-demo"} | json` cela donne (à noter que les tableaux disparaissent): + +```txt +"protocol" => "HTTP/2.0" +"request_time" => "6.032" +"request_method" => "GET" +"request_host" => "foo.grafana.net" +"request_size" => "55" +"response_status" => "401" +"response_size" => "228" +"response_latency_seconds" => "6.031" +``` + +#### logfmt + +Pour parser la ligne suivante: + +```log +at=info method=GET path=/ host=grafana.net fwd="124.133.124.161" service=8ms status=200 +``` + +Avec la ligne LogQL `{namespace="mi-demo"} | logfmt` cela donne: + +```txt +"at" => "info" +"method" => "GET" +"path" => "/" +"host" => "grafana.net" +"fwd" => "124.133.124.161" +"service" => "8ms" +"status" => "200" +``` + +#### Pattern + +Ligne de log: + +```log +0.191.12.2 - - [10/Jun/2021:09:14:29 +0000] "GET /api/plugins/versioncheck HTTP/1.1" 200 2 "-" "Go-http-client/2.0" "13.76.247.102, 34.120.177.193" "TLSv1.2" "US" "" +``` + +LogQL: `{namespace="mi-demo"} | pattern - - <_> " <_>" <_> "" <_>` + +Champs extraits: + +```txt +"ip" => "0.191.12.2" +"method" => "GET" +"uri" => "/api/plugins/versioncheck" +"status" => "200" +"size" => "2" +"agent" => "Go-http-client/2.0" +``` + +## Dashboards + +Loki étant fortement intégré à l'écosystème Grafana, il est possible d'utiliser des requêtes LogQL pour extraire des métriques et en faire des dashboards. + +Pour l'exemple suivant, les logs utilisés sont au format apache: + +```log +10.129.4.2 - - [15/Oct/2024:08:22:34 +0000] "GET / HTTP/1.1" 200 734 "-" "kube-probe/1.26" "-" +10.131.4.226 - blackboxchargement [15/Oct/2024:08:22:05 +0000] "GET /chargement?limit=1&order=id.desc&select=status:status_chargement HTTP/1.1" 200 - "" "Blackbox Exporter/0.24.0" +``` + +Ces lignes représentes les champs suivants (séparé par des espaces): + +- ip +- identité +- utilisateur +- date +- requête +- status http +- taille de la réponse +- en-tête Referer +- en-tête User-Agent + +Pour l'exemple, l'utilisateur va être extrait de la ligne pour voir dans le temps qui fait des requêtes sur l'api: +![dashboard](/img/guide/loki/dashboard.png) + +La requête LogQL utilisée est la suivante: `rate({namespace="mi-demo", service_name="api"} | pattern ' - <_>' | keep user[$__auto])` + +`{namespace="mi-demo", service_name="api"}`: permet de sélectionner la source des logs +`| pattern ' - <_>'`: applique un patter sur la ligne de log, pour ne garder que l'ip et l'utilisateur (_ permet de dire que le champ n'est pas intéressant) +`| keep user`: permet de garder que le label **user** + +`rate( [$ auto])`: calcul le nombre d'appel par utilisateur au fil du temps + +*La représentation graphique dans l'exemple est une heatmap* + +## Aller plus loin + +La documentation de Loki se trouve [ici](https://grafana.com/docs/loki/latest/) + +Plus d'informations concernant la syntaxe de requêtage (LogQL) [ici](https://grafana.com/docs/loki/latest/query/) diff --git a/docs/public/img/guide/loki/connexion.png b/docs/public/img/guide/loki/connexion.png new file mode 100644 index 0000000..7fc9209 Binary files /dev/null and b/docs/public/img/guide/loki/connexion.png differ diff --git a/docs/public/img/guide/loki/dashboard.png b/docs/public/img/guide/loki/dashboard.png new file mode 100644 index 0000000..34d2814 Binary files /dev/null and b/docs/public/img/guide/loki/dashboard.png differ diff --git a/docs/public/img/guide/loki/explore.png b/docs/public/img/guide/loki/explore.png new file mode 100644 index 0000000..54cc65f Binary files /dev/null and b/docs/public/img/guide/loki/explore.png differ diff --git a/docs/public/img/guide/loki/premierspas.png b/docs/public/img/guide/loki/premierspas.png new file mode 100644 index 0000000..2b6ef6b Binary files /dev/null and b/docs/public/img/guide/loki/premierspas.png differ diff --git a/docs/public/img/guide/loki/premierspas_contains.png b/docs/public/img/guide/loki/premierspas_contains.png new file mode 100644 index 0000000..f9da57f Binary files /dev/null and b/docs/public/img/guide/loki/premierspas_contains.png differ