Prima di ricominciare il lavoro direi che è necessario scaldarsi un pochino. Ho pensato quindi di implementare un giro (molto tranquillo) di una roba che ho sempre desiderato fare. Monitorare alcuni dei miei servizi “teknoludici” tra cui https://accolli.it.

Lo scopo è molto semplice, vorrei una notifica qualora qualcuno creasse una carta di accollo al fine di capire se mi stanno dossando (non è vero, per quello uso altri strumenti ma mi serve una scusa per impostare il tutto).

Siccome espongo i miei servizi con HaProxy direi che potrei usare le loggate per individuare le chiamate POST che creano le card. Il Grok Exporter è un progetto molto utile: trasforma in metriche per Prometheus il parsing dei log.

Per prima cosa lo installo in /opt/grok e gli do un file di configurazione molto semplice…

global:
  config_version: 3
input:
  type: file
  path: /var/log/haproxy.log
  readall: true
imports:
- type: grok_patterns
  dir: ./logstash-patterns-core/patterns
metrics:
- type: counter
  name: grok_post_cartadiaccollo_lines_total
  help: Counter metric example with labels.
  match: '.*302.*POST /cartadiaccollo.*'
server:
  port: 9144

Poi creo una unit Systemd di tipo service per trattarlo come un servizio Linux (file grok_exporter.service)

[Unit]
Description=Grok Exporter Service
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/opt/grok_exporter
ExecStart=/opt/grok_exporter -config /opt/config.yml
Restart=on-failure

[Install]
WantedBy=multi-user.target

Lo avvio con systemctl start grok_exporter e controllo se il servizio è running.

$ root@ns304365 (~) > systemctl status grok_exporter.service 
● grok_exporter.service - Grok Exporter Service
     Loaded: loaded (/etc/systemd/system/grok_exporter.service; disabled; preset: enabled)
     Active: active (running) since Sun 2024-09-01 08:20:53 UTC; 1 day 10h ago
   Main PID: 4039639 (grok_exporter)
      Tasks: 13 (limit: 19100)
     Memory: 9.4M
        CPU: 7min 1.362s
     CGroup: /system.slice/grok_exporter.service
             └─4039639 /opt/grok_exporter -config /root/grok_exporter/config.yml

Sep 01 08:20:53 ns304365 systemd[1]: Started grok_exporter.service - Grok Exporter Service.
Sep 01 08:20:53 ns304365 grok_exporter[4039639]: Starting server on http://ns304365:9144/metrics

Per provare il suo funzionamento basta un curl verso localhost su porta 9144

$ root@ns304365 (~) > curl http://localhost:9144/metrics -s | grep accollo
grok_exporter_line_processing_errors_total{metric="grok_post_cartadiaccollo_lines_total"} 0
grok_exporter_lines_matching_total{metric="grok_post_cartadiaccollo_lines_total"} 8
grok_exporter_lines_processing_time_microseconds_total{metric="grok_post_cartadiaccollo_lines_total"} 169
# HELP grok_post_cartadiaccollo_lines_total Counter metric example with labels.
# TYPE grok_post_cartadiaccollo_lines_total counter
grok_post_cartadiaccollo_lines_total 8

Al cambiamento di stato, ovvero all’aggiunta di una nuova riga di log in haproxy.log intercettata da Grok, la metrica grok_post_cartadiaccollo_lines_total cambia per cui mi basta confrontarla con quella ottenuta in un controllo precedente.

Non ho voglia di scrivere troppo codice, basteranno un po’ di righe di bash

$ root@ns304365 (~) > cat telegram_notifications/notify.sh 
#!/bin/bash

# Set the API token and chat ID
API_TOKEN="***"
CHAT_ID="***"

check_cartadiaccollo=$(curl -s http://localhost:9144/metrics | grep '^grok_post_cartadiaccollo_lines_total\ [0-9]*')
ls check_cartadiaccollo.lock || echo $check_cartadiaccollo > check_cartadiaccollo.lock
check_cartadiaccollo_lock=$(cat check_cartadiaccollo.lock)

while true
do
  if [ "$check_cartadiaccollo" != "$check_cartadiaccollo_lock" ]; then
    echo "Metrica grok_post_cartadiaccollo_lines_total cambiata, inviare notifica Telegram"
    MESSAGE='Warning, a new carta di accollo has just been issued!'
    curl -s -X POST https://api.telegram.org/bot$API_TOKEN/sendMessage -d chat_id=$CHAT_ID -d text="$MESSAGE"
    echo $check_cartadiaccollo > check_cartadiaccollo.lock
  fi
  sleep 2
done

A questo punto creo una unit Systemd anche per il mio script bash per gestire il servizio notify_telegram.service

$ root@ns304365 (~) > cat /etc/systemd/system/notify_telegram.service
[Unit]
Description=My Telegram Notifications
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/root/telegram_notifications
ExecStart=/root/telegram_notifications/notify.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
$ root@ns304365 (~) > systemctl status notify_telegram.service 
● notify_telegram.service - My Telegram Notifications
     Loaded: loaded (/etc/systemd/system/notify_telegram.service; disabled; preset: enabled)
     Active: active (running) since Sun 2024-09-01 20:16:28 UTC; 22h ago
   Main PID: 376330 (notify.sh)
      Tasks: 2 (limit: 19100)
     Memory: 1.1M
        CPU: 32min 52.345s
     CGroup: /system.slice/notify_telegram.service
             ├─ 376330 /bin/bash /opt/telegram_notifications/notify.sh
             └─1255329 sleep 2