VictoriaLogs : Et si la gestion des logs devenait simple et performante?

Sommaire

Mieux inspecter nos applications 👁️

Une fois notre application déployée, il est primordial de disposer d'indicateurs permettant d'identifier d'éventuels problèmes ainsi que de suivre les évolutions de performance. Parmi ces éléments, les métriques et les logs jouent un rôle essentiel en fournissant des informations précieuses sur le fonctionnement de l'application. En complément, il est souvent utile de mettre en place un tracing détaillé pour suivre précisément toutes les actions réalisées par l'application.

Dans cette série d'articles, nous allons explorer les différents aspects liés à la supervision applicative. L'objectif étant d'analyser en détail l'état de nos applications, afin d'améliorer leur disponibilité et leurs performances, tout en garantissant une expérience utilisateur optimale.

Trop souvent, la gestion des logs signifie solutions complexes et requêtes lentes. Pourtant les logs sont un pilier incontournable pour comprendre, diagnostiquer et améliorer nos applications.

En effet, si les métriques nous permettent d'observer l'évolution d'indicateurs dans le temps et les traces de suivre le cheminement d'une requête au sein de notre plateforme, les logs nous offrent le contexte détaillé indispensable à la compréhension des événements.

❓ A quoi servent nos logs?

Les logs ne sont pas de simples messages que l'on accumule dans un coin de notre infra: ils constituent la mémoire vivante de nos systèmes. Ils sont essentiels car ils endossent plusieurs rôles critiques dont voici quelques mises en situation concrètes :

  • Diagnostic et Dépannage : Une application e-commerce rencontre des erreurs 500 lors du paiement, les logs permettent de retracer la séquence exacte des appels, d’identifier qu’une dépendance externe (ex: API de paiement) est en cause, et de corriger rapidement le problème.
  • Sécurité et Conformité : Les logs révèlent des tentatives de connexion suspectes en dehors des horaires habituels ; ils permettent de détecter une attaque par brut force et de renforcer la sécurité. Ils sont aussi indispensables pour répondre aux exigences réglementaires (RGPD, PCI DSS, etc.).
  • Monitoring et Alerting Proactif : Des règles d’alerte détectent automatiquement une augmentation anormale du taux d’erreurs dans les logs d’un service critique, permettant d’intervenir avant que la situation ne s'aggrave.
  • Audit et Traçabilité : Lors d’un audit RGPD, les logs d’accès permettent de reconstituer précisément l’historique des actions sur les données personnelles.

Mais pour que ces cas d’usage révèlent toute leur valeur, il ne suffit pas de collecter les logs : il faut pouvoir les rechercher rapidement, formuler des requêtes simples, et garantir leur conservation à long terme sans exploser les coûts ni la complexité.
C'est exactement là que VictoriaLogs entre en scène 🔎

🚀 VictoriaLogs : Une nouvelle réponse à la gestion et l'analyse de logs

Avec l'adoption des architectures distribuées, nos plateformes génèrent des logs en quantité toujours plus importante.

Pour exploiter ces volumes croissants, nous nous sommes traditionnellement tournés vers des solutions comme ELK (Elasticsearch, Logstash, Kibana) ou Grafana Loki, souvent synonymes de complexité opérationnelle.

En 2023, VictoriaLogs est apparu comme une alternative prometteuse qui pourrait bien changer la donne.

Développé par l'équipe derrière la base de données time series VictoriaMetrics, dont la popularité est grandissante, VictoriaLogs hérite des mêmes qualités. Voici ses principales caractéristiques:

  • Simplicité de déploiement et d'opération : Son installation et sa configuration sont plutôt simples et nous allons voir ensemble le mode le plus avancé ci-après (cluster).
  • Haute performance : Optimisé pour une ingestion massive de logs et des requêtes analytiques rapides, même sur de très grands volumes de données.
  • Efficacité des ressources : Faible empreinte CPU et mémoire, et compression efficace des données pour minimiser les coûts de stockage en comparaison avec des solutions similaires.
  • Intégration à l'écosystème VictoriaMetrics : S'intègre naturellement avec VictoriaMetrics pour une solution d'observabilité unifiée, et avec VMAlert pour l'alerting et Grafana pour la visualisation.
  • Recherche Full-Text Rapide et par label : VictoriaLogs permet des recherches à la fois des recherches full-text sur le contenu des logs et des filtrages précis par labels.
🆚 Par rapport à Elasticsearch ou Loki?

Plusieurs sources permettent d'attester de la performance de VictoriaLogs, en comparaison à d'autres solutions de gestion de logs.

Les écarts de performance, en comparaison avec ELK ou Loki, sont assez impressionnants, que ce soit en termes d'utilisation mémoire ou de compression des données.

Concernant la recherche de logs, VictoriaLogs se distingue en combinant efficacement la recherche full-text d'Elasticsearch et le filtrage par labels de Loki, offrant ainsi le meilleur des deux approches tout en conservant une rapidité d'exécution des requêtes.

🗃️ L'ingestion et le stockage

Un log dans VictoriaLogs est typiquement un objet JSON. Chaque log contient forcément des champs suivants :

  • _msg: Le contenu brut du message de log, tel qu'il est produit par l'application.
  • _time: Le timestamp du log.
  • _stream: Un ensemble de labels (clé-valeur) qui identifient de manière unique la source du log.

💡 En plus de ceux-cis, n'importe quel autre champs peut être ajouté au JSON afin de simplifier et d'optimiser la recherche sur des informations pertinentes selon le contexte (Nous verrons quelques exemples par la suite).

L'importance du Stream

Le champs _stream dans VictoriaLogs permet d'optimiser la compression et de garantir une recherche ultra-rapide grâce au stockage contigu des logs partageant les mêmes labels.

L'efficacité dépend d'un choix précautionneux : seuls les champs constants, qui identifient de façon unique une instance d'application (container, namespace, pod), doivent faire partie du stream. Les champs dynamiques (IP, user_id, trace_id) doivent rester dans le message afin d'éviter une cardinalité trop élevée.

Il est possible de stocker un log simplement via la commande curl, ou en utilisant différents agents de collecte et de transport de logs tels que Promtail, FluentBit, OpenTelemetry et j'en passe.

J'ai choisi Vector car il s'agit d'une solution très performante mais aussi car il est proposé par défaut dans le chart Helm que nous allons utiliser 😉.

Parmi les éléments de configuration requis, il faut indiquer la destination mais aussi les champs indispensables dont nous avons parlé précédemment, qui sont ici configurés en utilisant des headers HTTP.

 1    sinks:
 2      vlogs-0:
 3        compression: gzip
 4        endpoints:
 5        - http://<victorialogs_host>:9428/insert/elasticsearch
 6        healthcheck:
 7          enabled: false
 8        inputs:
 9        - parser
10        mode: bulk
11        request:
12          headers:
13            AccountID: "0"
14            ProjectID: "0"
15            VL-Msg-Field: message,msg,_msg,log.msg,log.message,log
16            VL-Stream-Fields: stream,kubernetes.pod_name,kubernetes.container_name,kubernetes.pod_namespace
17            VL-Time-Field: timestamp
18        type: elasticsearch

Les logs sont collectés sur un cluster Kubernetes, et Vector l'enrichit avec de nombreux champs permettant d'identifier de façon précise la source. Voici un exemple concret de log enrichi tel qu'il est stocké dans VictoriaLogs (Ce log a été volontairement tronqué pour le besoin de cet article) :

 1  {
 2    "_time": "2025-07-29T07:25:49.870820279Z",
 3    "_stream_id": "00000000000000006a98e166d58afc9efc6ea35a22d87f1b",
 4    "_stream": "{kubernetes.container_name=\"loggen\",kubernetes.pod_name=\"loggen-loggen-68dc4f9b8b-6mrqj\",kubernetes.pod_namespace=\"observability\",stream=\"stdout\"}",
 5    "_msg": "236.161.251.196 - [07/Jul/2025:08:13:41 ] \"GET /homepage HTTP/2\" 204 4367 \"http://localhost/\" \"curl/7.68.0\" \"DE\" 0.83",
 6    "file": "/var/log/pods/observability_loggen-loggen-68dc4f9b8b-6mrqj_33076791-133a-490f-bd44-97717d242a61/loggen/0.log",
 7    "kubernetes.container_name": "loggen",
 8    "kubernetes.node_labels.beta.kubernetes.io/instance-type": "c5.xlarge",
 9    "kubernetes.node_labels.beta.kubernetes.io/os": "linux",
10    "kubernetes.node_labels.eks.amazonaws.com/capacityType": "SPOT",
11    "kubernetes.pod_ip": "10.0.33.16",
12    "kubernetes.pod_labels.app.kubernetes.io/name": "loggen",
13    "kubernetes.pod_name": "loggen-loggen-68dc4f9b8b-6mrqj",
14    "kubernetes.pod_namespace": "observability",
15    "kubernetes.pod_node_name": "ip-10-0-47-231.eu-west-3.compute.internal",
16    "source_type": "kubernetes_logs",
17    "stream": "stdout"
18    <REDACTED>
19  }

Maintenant que nous avons une vue d'ensemble du fonctionnement de VictoriaLogs, je vous propose ici une méthode d'installation et de configuration qui peut être envisagé pour de la prodution.

🏗️ Installation et configuration

VictoriaLogs peut être installé de 2 façons:

  • Un mode Single qui a l'avantage d'être très simple car un seul binaire se charge de toutes les opérations. C'est le mode à privilégier car il est simple à opérer. Si vous disposez d'une machine puissante, dont les ressources permettent de répondre à votre besoin, ce mode sera toujours plus performant car il ne nécessite pas de transferts réseau entre les différents composants du mode cluster.
    💡 Pour assurer une haute disponibilité, nous pouvons aussi déployer 2 instances Single comme décrit ici.

  • Le mode Cluster sera utilisé pour les très fortes charges et un besoin de scaling horizontal (lorsqu'une seule machine n'est pas suffisante pour répondre au besoin). S'agissant du mode qui donnera le plus de flexibilité pour scaler, nous allons l'explorer dans cet article.

Si vous avez parcouru le précédent article sur VictoriaMetrics, vous remarquerez que l'architecture du mode cluster est très ressemblante:

  • VLStorage: C'est le composant responsable de la persistence des logs sur disque. Il s'agit donc d'un Statefulset et chaque pod dispose d'un volume dédié (Persistent Volume).

  • VLInsert: Ce composant reçoit les logs à partir de différentes sources et différents protocoles et se charge de les répartir sur les VLStorages.

  • Vector: Déployé en DaemonSet Vector se charge de transferer les logs stockés sur les noeuds Kubernetes vers le service VLInsert.

  • VLSelect: Il s'agit du service qui expose l'API nous permettant d'exécuter des requêtes. Les données sont extraites à partir des VLStorages.

  • VMAlert: Afin de pouvoir émettre des alertes basés sur les logs, une instance VMAlert dédiée est déployée.

L'installation se fait en utilisant le chart Helm fournit par VictoriaMetrics, en paramètrant quelques variables. Voici un exemple approprié pour EKS que nous allons décrire ci-après:

observability/base/victoria-logs/helmrelease-vlcluster.yaml

  1    printNotes: false
  2
  3    vlselect:
  4      horizontalPodAutoscaler:
  5        enabled: true
  6        maxReplicas: 10
  7        minReplicas: 2
  8        metrics:
  9          - type: Resource
 10            resource:
 11              name: cpu
 12              target:
 13                type: Utilization
 14                averageUtilization: 70
 15
 16      podDisruptionBudget:
 17        enabled: true
 18        minAvailable: 1
 19
 20      affinity:
 21        podAntiAffinity:
 22          requiredDuringSchedulingIgnoredDuringExecution:
 23            - labelSelector:
 24                matchExpressions:
 25                  - key: "app"
 26                    operator: In
 27                    values:
 28                      - "vlselect"
 29              topologyKey: "kubernetes.io/hostname"
 30      topologySpreadConstraints:
 31        - labelSelector:
 32            matchLabels:
 33              app: vlselect
 34          maxSkew: 1
 35          topologyKey: topology.kubernetes.io/zone
 36          whenUnsatisfiable: ScheduleAnyway
 37
 38      resources:
 39        limits:
 40          cpu: 100m
 41          memory: 200Mi
 42        requests:
 43          cpu: 100m
 44          memory: 200Mi
 45
 46      vmServiceScrape:
 47        enabled: true
 48
 49    vlinsert:
 50      horizontalPodAutoscaler:
 51        enabled: true
 52        maxReplicas: 10
 53        minReplicas: 2
 54        metrics:
 55          - type: Resource
 56            resource:
 57              name: cpu
 58              target:
 59                type: Utilization
 60                averageUtilization: 70
 61
 62      podDisruptionBudget:
 63        enabled: true
 64        minAvailable: 1
 65
 66      affinity:
 67        podAntiAffinity:
 68          requiredDuringSchedulingIgnoredDuringExecution:
 69            - labelSelector:
 70                matchExpressions:
 71                  - key: "app"
 72                    operator: In
 73                    values:
 74                      - "vlinsert"
 75              topologyKey: "kubernetes.io/hostname"
 76      topologySpreadConstraints:
 77        - labelSelector:
 78            matchLabels:
 79              app: vlinsert
 80          maxSkew: 1
 81          topologyKey: topology.kubernetes.io/zone
 82          whenUnsatisfiable: ScheduleAnyway
 83
 84      resources:
 85        limits:
 86          cpu: 100m
 87          memory: 200Mi
 88        requests:
 89          cpu: 100m
 90          memory: 200Mi
 91
 92      vmServiceScrape:
 93        enabled: true
 94
 95    vlstorage:
 96      # -- Enable deployment of vlstorage component. StatefulSet is used
 97      enabled: true
 98      retentionPeriod: 7d
 99      retentionDiskSpaceUsage: "9GiB"
100      replicaCount: 3
101
102      podDisruptionBudget:
103        enabled: true
104        minAvailable: 1
105
106      affinity:
107        podAntiAffinity:
108          requiredDuringSchedulingIgnoredDuringExecution:
109            - labelSelector:
110                matchExpressions:
111                  - key: "app"
112                    operator: In
113                    values:
114                      - "vlstorage"
115              topologyKey: "kubernetes.io/hostname"
116      topologySpreadConstraints:
117        - labelSelector:
118            matchLabels:
119              app: vlstorage
120          maxSkew: 1
121          topologyKey: topology.kubernetes.io/zone
122          whenUnsatisfiable: ScheduleAnyway
123
124      persistentVolume:
125        enabled: true
126        size: 10Gi
127
128      resources:
129        limits:
130          cpu: 500m
131          memory: 512Mi
132        requests:
133          cpu: 500m
134          memory: 512Mi
135
136      vmServiceScrape:
137        enabled: true
138
139    vector:
140      enabled: true
  • Autoscaling: Les composants stateless (VLSelect et VLInsert) sont configurés pour scaler automatiquement au-delà de 70% d'utilisation CPU.

  • Persistence des logs: Pour cet environnement de démo, chaque instance VLStorage dispose d'un volume EBS de 10Gi avec une rétention de 7 jours afin d'éviter la saturation des disques.

  • Haute disponibilité: La configuration garantit une disponibilité maximale grâce à la répartition sur différentes zones (topologySpreadConstraints) et à l'anti-affinité des pods pour chaque composant.

  • Supervision: Les vmServiceScrape exposent automatiquement les métriques de chaque composant pour le monitoring via l'opérateur VictoriaMetrics.

Lorsque le chart Helm est installé, nous pouvons vérifier que tous les pods sont bien démarrés

 1kubectl get po -n observability -l app.kubernetes.io/instance=victoria-logs
 2NAME                                                            READY   STATUS    RESTARTS   AGE
 3victoria-logs-vector-9gww4                                      1/1     Running   0          11m
 4victoria-logs-vector-frj8l                                      1/1     Running   0          10m
 5victoria-logs-vector-jxm95                                      1/1     Running   0          10m
 6victoria-logs-vector-kr6q6                                      1/1     Running   0          12m
 7victoria-logs-vector-pg2fc                                      1/1     Running   0          12m
 8victoria-logs-victoria-logs-cluster-vlinsert-dbd47c5fd-cmqj9    1/1     Running   0          11m
 9victoria-logs-victoria-logs-cluster-vlinsert-dbd47c5fd-mbkwx    1/1     Running   0          12m
10victoria-logs-victoria-logs-cluster-vlselect-7fbfbd9f8f-nmv8t   1/1     Running   0          11m
11victoria-logs-victoria-logs-cluster-vlselect-7fbfbd9f8f-nrhs4   1/1     Running   0          12m
12victoria-logs-victoria-logs-cluster-vlstorage-0                 1/1     Running   0          12m
13victoria-logs-victoria-logs-cluster-vlstorage-1                 1/1     Running   0          11m
14victoria-logs-victoria-logs-cluster-vlstorage-2                 1/1     Running   0          9m39s

Et commencer à utiliser l'interface Web qui est exposée en utilisant Cilium et des ressources Gateway API 🎉

⚙️ Déploiement: où trouver toute la configuration

Toute la configuration utilisée pour l'écriture de cet article se trouve dans le repository Cloud Native Ref.

L'ambition de ce projet est de pouvoir démarrer rapidement une plateforme complète qui applique les bonnes pratiques en terme d'automatisation, de supervision, de sécurité etc.

Les commentaires et contributions sont les bienvenues 🙏

👩‍💻 LogsQL : Un language puissant et facile à apprendre

LogsQL se distingue par sa capacité à effectuer des recherches full-text rapides et l'utilisation des champs exposés par les logs.

Par exemple, nous pouvons rechercher les logs générés par les pods dont le nom commence par loggen, puis filtrer ces résultats en incluant ou excluant (en préfixant par -) certaines chaînes de caractères.

1kubernetes.pod_name: "loggen"* "GET /homepage" -"example.com"

Cette requête retournera donc tous les appels à la homepage avec la méthode GET en excluant les logs contenant le domaine "example.com".

💡 À retenir : La recherche full-text se fait dans le contenu du champ _msg.

Nous allons voir ici quelques exemples de requêtes simples que nous pourrions utiliser dans un environnement Kubernetes.

☸ Événements Kubernetes

Les événements Kubernetes constituent une source d'information précieuse car ils révèlent souvent des problèmes liés aux changements d'état des ressources ou des erreurs qui ne sont pas visibles ailleurs. Il est donc conseillé de les analyser régulièrement.

⚠️ Limitation : ces événements sont éphémères et si l'on veut explorer l'historique, il faut une solution pour persister ces données. En attendant que Vector prenne en charge cette fonctionnalité, j'utilise Kubernetes Event Exporter bien que le projet ne semble pas très actif.

Lorsque la solution est déployée nous pouvons rechercher les événements en utilisant le champs source

  • Utiliser le caractère ~ pour rechercher une chaîne de caractères dans un champ. Ici nous pouvons visualiser les notifications d'erreur de validation d'une politique définie par Kyverno.
1source:"kubernetes-event-exporter" AND type: "Warning" AND message:~"validation error: Privileged mode is disallowed"
  • La requête suivante fait usage des opérateurs logiques AND et NOT pour visualiser les événements de type "Warning" tout en filtrant les erreurs Kyverno.
1source:"kubernetes-event-exporter" AND type: "Warning" AND NOT reason: "PolicyViolation"

🌐 Logs d'un serveur Web

Pour le besoin de cet article, j'ai créé un petit générateur de logs tout simple. Il permet de simuler des logs de type serveur web afin de pouvoir exécuter quelques requêtes.

 1loggen --sleep 1 --error-rate 0.2 --format json
 2
 3{
 4  "remote_addr": "208.175.166.30",
 5  "remote_user": "-",
 6  "time_local": "19/Apr/2025:02:11:56 ",
 7  "request": "PUT /contact HTTP/1.1",
 8  "status": 202,
 9  "body_bytes_sent": 3368,
10  "http_referer": "https://github.com/",
11  "http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15",
12  "country": "AU",
13  "request_time": 0.532
14}

💡 À retenir : Les logs émis par les applications au format JSON permettent d'indexer tous les champs de l'objet JSON. Cela permet de simplifier les recherches et calculs. Cependant, il faut rester attentif à la cardinalité qui peut impacter les performances.

Vector est configuré pour parser les logs JSON et extraire leurs champs. S'il ne s'agit pas d'un log JSON, il conserve le message d'origine sans le modifier.

1    transforms:
2      parser:
3        inputs:
4        - k8s
5        source: |
6          .log = parse_json(.message) ?? .message
7          del(.message)          
8        type: remap

Nous obtenons donc de nouveaux champs préfixés par log dans les logs stockés par VictoriaLogs.

 1{
 2  "log.body_bytes_sent": "4832",
 3  "log.country": "AU",
 4  "log.http_referer": "-",
 5  "log.http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15",
 6  "log.remote_addr": "84.74.62.151",
 7  "log.remote_user": "-",
 8  "log.request": "PUT /products HTTP/1.1",
 9  "log.request_time": "1.191",
10  "log.status": "204",
11  "log.time_local": "27/Jul/2025:10:57:48 ",
12  <REDACTED>
13}

Grâce à cela, nous pouvons maintenant ecrire des requêtes directement sur la valeur des champs. Voici quelques exemples concrets :

  • Compter les codes HTTP et les trier par ordre décroissant :
1kubernetes.pod_name:"loggen"* | stats by (log.status) count() as count | sort by (count desc)

💡 En utilisant stats, il est possible d'effectuer des calculs avancés, de nombreuses fonctions sont disponibles.

  • Nous avons vu précédemment que le caractère ~ permet de rechercher une chaîne de caractères dans un champ. Ce caractère indique que nous utilisons des expressions régulières (regexp), comme le montre cet exemple simple pour rechercher uniquement les requêtes provenant du Japon ou de l'Italie.
1_time:5m kubernetes.pod_name: "loggen"* AND log.country:~"JP|IT"
  • D'autres opérateurs de comparaison peuvent être utilisés. Ici > pour filtrer uniquement les logs dont la durée d'exécution dépasse 1,5 seconde.
1kubernetes.pod_labels.app.kubernetes.io/instance:"loggen" AND log.request_time:>1.5
💻 vlogcli pour lancer des requêtes

Il existe aussi un outil en ligne de commande qui permet d'exécuter des requêtes depuis un terminal: vlogcli.

 1vlogscli -datasource.url='https://vl.priv.cloud.ogenki.io/select/logsql/query'
 2sending queries to -datasource.url=https://vl.priv.cloud.ogenki.io/select/logsql/query
 3type ? and press enter to see available commands
 4;> kubernetes.pod_labels.app.kubernetes.io/instance:"loggen" | stats quantile(0.5, log.request_time) p50, quantile(0.9, log.request_time) p90, quantile(0.99, log.request_time) p99
 5executing ["kubernetes.pod_labels.app.kubernetes.io/instance":loggen | stats quantile(0.5, log.request_time) as p50, quantile(0.9, log.request_time) as p90, quantile(0.99, log.request_time) as p99]...; duration: 2.500s
 6{
 7  "p50": "1.022",
 8  "p90": "1.565",
 9  "p99": "1.686"
10}
11;>

📊 Intégration à Grafana

L'intégration avec Grafana se fait avec la Datasource prévue à cet effet. Celle-ci permet de construire des graphes à partir des données présentes dans VictoriaLogs.

Nous utilisons ici l'opérateur Kubernetes pour Grafana qui permet de déclarer de la configuration par le biais de ressources personnalisées (Custom Resources).

Il y a donc une ressource GrafanaDatasource pour ajouter la connexion à VictoriaLogs en indiquant l'adresse du service VLSelect.

 1apiVersion: grafana.integreatly.org/v1beta1
 2kind: GrafanaDatasource
 3metadata:
 4  name: vl-datasource
 5  namespace: observability
 6spec:
 7  allowCrossNamespaceImport: true
 8  datasource:
 9    access: proxy
10    type: victoriametrics-logs-datasource
11    name: VictoriaLogs
12    url: http://victoria-logs-victoria-logs-cluster-vlselect.observability:9471
13  instanceSelector:
14    matchLabels:
15      dashboards: grafana

Nous pouvons ensuite utiliser cette Datasource pour exécuter des requêtes et construire des graphes.

Il existe également des dashboards prêts à l'usage.

La configuration d'un nouveau dashboard est tout aussi simple grâce à l'operateur Grafana. Nous indiquons l'adresse du dashboards accessible depuis l'API Grafana.com.

 1apiVersion: grafana.integreatly.org/v1beta1
 2kind: GrafanaDashboard
 3metadata:
 4  name: observability-victoria-logs-cluster
 5  namespace: observability
 6spec:
 7  allowCrossNamespaceImport: true
 8  datasources:
 9    - inputName: "DS_VICTORIALOGS"
10      datasourceName: "VictoriaLogs"
11  instanceSelector:
12    matchLabels:
13      dashboards: "grafana"
14  url: "https://grafana.com/api/dashboards/23274/revisions/2/download"

Celui-ci nous perment d'analyser les performances des composants du cluster VictoriaLogs.

Un autre dashboard peut s'avérer utile pour visualiser les logs et donc d'unifier sur une seule adresse métriques et logs.

🚨 Envoyer des alertes

Il est possible de déclencher des alertes basées sur l'analyse des logs.

L'alerting utilise VMAlert, le composant d'alerting de l'écosystème VictoriaMetrics.

Une instance supplémentaire dédiée à l'analyse des logs a été ajoutée (une autre instance étant déjà déployée pour les métriques) :

 1apiVersion: operator.victoriametrics.com/v1beta1
 2kind: VMAlert
 3metadata:
 4  labels:
 5    app.kubernetes.io/component: victoria-logs-vmalert
 6    app.kubernetes.io/instance: victoria-logs
 7  name: victoria-logs
 8  namespace: observability
 9spec:
10  ruleSelector:
11    matchLabels:
12      vmlog: "true"
13  datasource:
14    url: http://victoria-logs-victoria-logs-cluster-vlselect.observability.svc.cluster.local.:9471
15  evaluationInterval: 20s
16  image:
17    tag: v1.122.0
18  notifiers:
19    - url: http://vmalertmanager-victoria-metrics-k8s-stack-0.vmalertmanager-victoria-metrics-k8s-stack.observability.svc.cluster.local.:9093
20  port: "8080"
21  remoteRead:
22    url: http://vmselect-victoria-metrics-k8s-stack.observability.svc.cluster.local.:8481
23  remoteWrite:
24    url: http://vminsert-victoria-metrics-k8s-stack.observability.svc.cluster.local.:8480/api/v1/write
25  resources:
26    limits:
27      cpu: 100m
28      memory: 256Mi
29    requests:
30      cpu: 100m
31      memory: 128Mi
  • Integration AlertManager : Utilise l'instance d'AlertManager déployée avec VictoriaMetrics pour la gestion des notifications
  • Sélecteur de règles : N'évalue que les VMRules avec le label vmlog: "true", permettant de séparer les alertes logs des alertes métriques
  • Stockage des alertes : Les alertes sont stockées comme métriques dans VictoriaMetrics pour l'historique et l'analyse

Voici un exemple concret d'alerte qui détecte un taux d'erreurs HTTP trop élevé :

 1apiVersion: operator.victoriametrics.com/v1beta1
 2kind: VMRule
 3metadata:
 4  name: loggen
 5  namespace: observability
 6  labels:
 7    vmlog: "true"
 8spec:
 9  groups:
10    - name: loggen
11      type: vlogs
12      interval: 10m
13      rules:
14        - alert: LoggenHTTPError500
15          annotations:
16            message: "The application Loggen is throwing too many errors in the last 10 minutes"
17            description: 'The pod `{{ index $labels "kubernetes.pod_name" }}` has `{{ $value }}` server errors in the last 10 minutes'
18          expr: 'kubernetes.pod_labels.app.kubernetes.io/instance:"loggen" AND log.status:"5"* | stats by (kubernetes.pod_name) count() as server_errors | filter server_errors:>100'
19          labels:
20            severity: warning

Si AlertManager est configuré pour envoyer sur slack comme expliqué dans cet article, nous obtenons le résultat suivant:

💭 Dernières remarques

Cette exploration de VictoriaLogs me permet d'affirmer que la solution est simple à installer et configurer. Les concepts sont plutôt simples à appréhender, que ce soit l'architecture modulaire du mode cluster ou le langage logsQL. En effet, ce langage est très intuitif et on s'habitue vite à la syntaxe.

De plus, si l'on se réfère aux tests de performances publiés, les temps d'exécution des requêtes ainsi que la compression efficace des données permettent de se projeter sur des plateformes à large scale.

Vous l'aurez compris, malgré le fait que la solution soit relativement jeune, je recommanderais vivement de l'étudier et d'avoir une approche permettant de comparer avec vos solutions existantes avant d'envisager une bascule 😉

🔖 Références

📚 Documentation et ressources officielles

🔍 Comparaisons et analyses de performance

🛠️ Outils et intégrations

💬 Communauté et support

Articles dans cette série

    Traductions: