alloy

alloy

  • As métricas do nginx no grafana

    Seguindo o artigo expondo as métricas do nginx pro prometheus, aqui está o resultado olhado no grafana.

    Como os valores server_accepts_total, server_handled_total e server_requests_total são do tipo counter, eu usei um irate(__variável__[5m]) pra mostrar no gráfico da forma acima.

    E como coletei esses dados? Eu já tinha comentado no artigo configurando o grafana alloy pra monitorar VMs que uso o alloy. Então foi adicionando uma entrada extra nele.

      
    [...]
    discovery.relabel "metrics_agent" {
            targets = array.concat(
                    [{
                            __address__ = "localhost:9090",
                    }],
            )
    
            rule {
                    source_labels = ["__address__"]
                    target_label  = "instance"
            }
    }
    [...]
    prometheus.scrape "nginx_metrics" {
            targets    = discovery.relabel.metrics_agent.output
            forward_to = [prometheus.remote_write.prod.receiver]
    }
     
    

    Agora fica mais fácil entender o que acontece com as páginas servidas e se tem realmente alguma lentidão.

  • Configurando o grafana alloy pra monitorar VMs

    Estou inaugurando uma categoria nova, observability, ou... observabilidade na língua pátria. Nunca comentei nada por aqui, mas nos últimos anos em que trabalhei na Ericsson, o fiz dentro do time que mantinha o Prometheus. Prometheus é um conhecido sistema de monitoração dentro de clusters Kubernetes, ou k8s pros já iniciados.

    Não era um trabalho glorioso que contribuia pro projeto. Não diretamente. Era mais sobre compilar a partir dos fontes com o sistema oficial da empresa, que era Suse (e talvez ainda seja) e passar por alguns testes em cima dos helm charts que construíamos. Além de algumas verificações de segurança.

    Segurança aliás foi uma das poucas coisas que contribuí pro projeto open source. Reportei algumas vulnerabilidades encontradas pelos nossos scanners em alguns pacotes usados. Geralmente em javascript/npm.

    O tempo passou, fui demitido, e acabei em outro emprego.

    No emprego atual não existe tanta demanda assim por k8s. Até tem alguma coisa, mas o negócio mesmo gira em torno de VMs com Linux. Então nada de Prometheus pra esses casos. Mas existem alternativas. Uma delas é usar um programa "agente" rodando nessas VMs e enviar pra um "Prometheus" os dados ao invés de esperar que um Prometheus real busque o dado, como é o caso dentro de um cluster k8s.

    Pra isso instalei o mimir do Grafana. Mimir, aquele deus que cortam a cabeça e Odin a preserva pra ouvir seus conselhos, funciona como um remote write de Prometheus. Em linguagem mais simples, é onde os dados ficam guardados. Um DB dos dados coletados. E é possível fazer o Grafana, aquele dos dashboards, ler esses dados dele.

    Eu segui os passos de instalação em VM ao invés de usar k8s pro mimir. É mais fácil pra gerenciar o espaço em disco e aumentar se necessário. E também no cloud provider que usamos, custa mais barato assim. A configuração que fiz é assim em /etc/grafana/mimir.yaml:

      multitenancy_enabled: false
    no_auth_tenant: <token>
    
    blocks_storage:
      backend: filesystem
      bucket_store:
        sync_dir: /var/mimir/tsdb-sync
      filesystem:
        dir: /var/mimir/data/tsdb
      tsdb:
        dir: /var/mimir/tsdb
    
    compactor:
      data_dir: /var/mimir/compactor
      sharding_ring:
        kvstore:
          store: memberlist
    
    distributor:
      ring:
        instance_addr: 127.0.0.1
        kvstore:
          store: memberlist
    
    ingester:
      ring:
        instance_addr: 127.0.0.1
        kvstore:
          store: memberlist
        replication_factor: 1
    
    ruler_storage:
      backend: filesystem
      filesystem:
        dir: /var/mimir/rules
    
    server:
      http_listen_address: localhost
      http_listen_port: 9009
      log_level: warn
      grpc_server_max_recv_msg_size: 2147483647
      grpc_server_max_send_msg_size: 2147483647
    
    store_gateway:
      sharding_ring:
        replication_factor: 1
    
    usage_stats:
      enabled: true
    
    limits:
      ingestion_burst_size: 3500000
      ingestion_rate: 100000
      max_global_series_per_user: 100000000
      max_label_names_per_series: 50
      max_query_parallelism: 224
      out_of_order_time_window: "5m"
    

    Essa é a maneira mais simples possível. O token é que será usado em todo lugar pra validar as conexões. De grafana aos cliente alloy. E usando nginx pra gerenciar os certificados SSL e conectar a port 443 com a interna 9009, onde roda o mimir.

    Falando dos clientes, esses eu instalei primeiro o grafana-agent, que faz a mesma coisa. Mas a página de configuração já avisava que estava defasado e que era pra migrar pro alloy. Então resolvi fazer isso logo ao invés de esperar parar de funcionar.

    A primeira configuração que fiz pro grafana-agent em /etc/grafana-agent.yaml era a seguinte:

      server:
      log_level: info
    
    metrics:
      global:
        scrape_interval: 1m
      wal_directory: '/var/lib/grafana-agent'
      configs:
        # Example Prometheus scrape configuration to scrape the agent itself for metrics.
        # This is not needed if the agent integration is enabled.
        - name: agent
          host_filter: false
          scrape_configs:
            - job_name: agent
              static_configs:
                - targets: ['localhost:9090']
              relabel_configs:
                - source_labels: [__address__]
                  replacement: <nome do servidor>
                  target_label: instance
                  action: replace
          remote_write:
            - url: https://<endereço do mimir>/api/v1/push
              headers:
                X-Scope-OrgID: <token>
    
    integrations:
      agent:
        enabled: true
      node_exporter:
        enabled: true
        include_exporter_metrics: true
        disable_collectors:
          - "mdadm"
    

    É possível ver que dentro de remote_write eu coloco o endereço do mimir em url com REQUEST_URI apontando pra /api/v1/push e que adiciono um header X-Scope-OrgID com o mesmo token pra validar. E isso funcionava.

    Mas tive de mudar pro alloy. E a configuração, que usa uma sintaxe própria (e bastante bizarra), é a seguinte:

      root@heliotest1:~# cat /etc/alloy/config.alloy
    
        prometheus.exporter.unix "company" {
            enable_collectors = ["cpu", "disk", "filesystem", "systemd"]
            cpu  {
                    guest = true
                    info = true
    
            }
            disk { }
            filesystem {
                    mount_timeout = "3s"
            }
            systemd {
                    enable_restarts = true
                    start_time = true
            }
    
    
    }
    
    prometheus.remote_write "production" {
            endpoint {
                    url = "http://<endereço do mimir>/api/v1/push"
                    headers = {
                            "X-Scope-OrgID" = "<token>",
                    }
                    queue_config { }
                    metadata_config { }
            }
    }
    
    // Collect metrics from Kubernetes pods and send them to prod.
    prometheus.scrape "first" {
            targets    = prometheus.exporter.unix.company.targets
            forward_to = [prometheus.remote_write.production.receiver]
    }
    

    Eu copiei alguns valores do manual de configuração, como o que é visto em filesystem. Efetivamente não vi se faz muita diferença isso ou não.

    Feito isso, os agentes alloy começam a enviar os dados pro mimir. Na configuração do mimir é possível ver que eu aumentei alguns parâmetros pra aguentar a quantidade de dados recebidos como grpc_server_max_recv_msg_size/grpc_server_max_send_msg_size.

    O passo final é adicionar essa origem no grafana pra gerar as dashboards. A origem tem de escolher como se fosse um prometheus.

    Em seguida a configuração.

    Note que o endereço do mimir [1] passa a usar a REQUEST_URI /prometheus e que o é preciso adicionar um campo de header X-Org-ID [2] onde estará o valor do token configurado no mimir. Feito isso, basta usar o mimir como se fosse um Prometheus e gerar seus dashboards.

    Boa diversão!

  • Expondo as métricas do nginx pro prometheus

    Esses dias eu peguei um problema no servidor web, nginx. Não nele especificamente. Mas um usuário estava reclamando que estava super lento pra carregar as páginas.

    A questão então é como ver como e quanto está o nginx. Infelizmente a versão open source não fornece muita coisa. Só uma versão texto de estatísticas.

    Não é grande coisa mas pelo menos já é ALGUMA COISA.

    Agora como monitorar isso no Grafana?

    A resposta são open metrics. E isso não tem.

    Não tinha.

    Fiz um programa em Go que converte essas estatísticas em open metrics e expõe na porta 9090 no endpoint /metrics.

    Pra ter isso funcionando, é preciso primeiro subir a configuração de estatísticas no nginx.

    
    server {
        listen 127.0.0.1:8080;
        location /api {
            stub_status;
            allow 127.0.0.1;
            deny all;
        }
    }  
    
    

    Eu salvei no arquivo statistics.conf e coloquei em /etc/nginx/conf.d. E bastou um reload pra ter funcionado.

      
    ❯ curl localhost:8080/api
    Active connections: 2 
    server accepts handled requests
     21 21 322 
    Reading: 0 Writing: 1 Waiting: 1   
     
    

    Agora é rodar o programa e apontar pra esse endpoint.

      
    ❯ ./nginx-openmetrics/nginx-openmetrics --service=http://localhost:8080/api
    [2025-08-22T14:11:45] (INFO): 🚚 fetching data from:http://localhost:8080/api
    [2025-08-22T14:11:45] (INFO): 🎬 starting service at port:9090    
     
    

    E a porta fica exposta pras métricas serem coletadas pelo prometheus ou grafana alloy. Ou qualquer outro programa que faça scrape de dados no padrão open metrics.

      
    ❯ curl localhost:9090/metrics
    # HELP active_connections The number of active connections
    # TYPE active_connections gauge
    active_connections 1
    # HELP reading_connections The number of active reading connections
    # TYPE reading_connections gauge
    reading_connections 0
    # HELP server_accepts_total The total number of server accepted connections
    # TYPE server_accepts_total counter
    server_accepts_total 22
    # HELP server_handled_total The total number of server handled connections
    # TYPE server_handled_total counter
    server_handled_total 22
    # HELP server_requests_total The total number of server requests
    # TYPE server_requests_total counter
    server_requests_total 333
    # HELP waiting_connections The number of waiting connections
    # TYPE waiting_connections gauge
    waiting_connections 0
    # HELP writing_connections The number of active writing connections
    # TYPE writing_connections gauge
    writing_connections 1  
     
    

    E fica exposto em todas as interfaces.

      
    ❯ netstat -nat | grep 9090 | grep -i listen
    tcp6       0      0 :::9090                 :::*                    LISTEN         
     
    

    O programa faz o update dos dados a cada 15 segundos. Pra não sobrecarregar.

    E ainda falta dar uma melhorada com a entrada como serviço do systemd. Devo fazer isso hoje.

    Próximo passo será gerar um pacote debian dele pra instalar fácil.

    Update: Fri Aug 22 04:23:45 PM CEST 2025
    Tá lá o arquivo pro systemd. E está funcionando no sistema que estou testando.

      
    root@server:/# systemctl status nginx-openmetrics.service 
    ● nginx-openmetrics.service - nginx open metrics service
         Loaded: loaded (/etc/systemd/system/nginx-openmetrics.service; enabled; vendor preset: enabled)
         Active: active (running) since Fri 2025-08-22 14:08:17 UTC; 16min ago
       Main PID: 314061 (nginx-openmetri)
          Tasks: 7 (limit: 19076)
         Memory: 4.0M
            CPU: 47ms
         CGroup: /system.slice/nginx-openmetrics.service
                 └─314061 /usr/sbin/nginx-openmetrics --service=http://localhost:8080/api
    
    Aug 22 14:08:17 internal systemd[1]: Started nginx open metrics service.
    Aug 22 14:08:17 internal nginx-openmetrics[314061]: [2025-08-22T14:08:17.78433] (INFO): nginx-open-metrics-service (1.0-9)
    Aug 22 14:08:17 internal nginx-openmetrics[314061]: [2025-08-22T14:08:17.78441] (INFO): 🚚 fetching data from:http://localhost:8080/api
    Aug 22 14:08:17 internal nginx-openmetrics[314061]: [2025-08-22T14:08:17.78442] (INFO): 🎬 starting service at port:9090    
     
    
  • Monitorando a temperatura da sala dos servidores

    Por motivos que não cabem aqui, temos alguns servidores instalados em uma sala na empresa. E essa sala tem um ar-condicionado pra manter a temperatura sob controle.

    Um belo dia estou olhando os dados no Grafana e noto que essas máquinas não reportaram dados (não temos alertas enviados pelo Grafana, mas o porquê disso fica pra um outro dia). Entro na sala e a temperatura estava simplemente... 32°C. Era verão na Suécia, que é curto mas tem seus dias bem quentes. E o hardware das máquinas desligaram pra proteção.

    Entre entrar em contato com técnico do ar-condicionado e deixar a sala aberta pra ventilar, ficamos com aquele gosto amargo de não ter nenhum dado sobre a temperatura.

    A solução? raspberrypi!

    Ele tem um sensor que é vendido na Internet.

    O sensor já chegou mas não o raspberrypi. O motivo deve ser porque compramos um modelo que funciona como KVM e tem algumas coisas a mais.

    Então aqui a descrição de como botar o serviço pra funcionar em Linux.

    Dados via python

    Existe um software descrito na página do produto que aponta pro seguinte repositório no GitHub:

    Mas o repositório parece abandonado. Já faz 7 anos que ninguém manda nenhum commit. E o código não funciona com a versão mais moderna do sensor.

    O que fazer? Patch!

    Então corrigi o programa e criei um fork do repo original.

    Então temos o software pronto pra funcionar. Ou quase.

    Antes é preciso corrigir as permissões de leitura e escrita do dispositivo. E pra isso eu criei uma pequena regra no udev em /etc/udev/rules.d/90-temperature-sensor.rules

        
    KERNEL=="hidraw[0-9]*", SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="3553", ATTRS{idProduct}=="a001", MODE="0666", SYMLINK+="temper"      
       
     

    Pegando a saída do kernel:

        
    # dmesg | grep -i temper
    [    5.152423] usb 1-10.4: Product: TEMPer2
    [    6.769788] input: PCsensor TEMPer2 as /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10.4/1-10.4:1.0/0003:3553:A001.0005/input/input14
    [    6.826541] hid-generic 0003:3553:A001.0005: input,hidraw4: USB HID v1.11 Keyboard [PCsensor TEMPer2] on usb-0000:00:14.0-10.4/input0
    [    6.826720] input: PCsensor TEMPer2 as /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10.4/1-10.4:1.1/0003:3553:A001.0006/input/input15
    [    6.827067] hid-generic 0003:3553:A001.0006: input,hidraw5: USB HID v1.10 Device [PCsensor TEMPer2] on usb-0000:00:14.0-10.4/input1
    [  939.507362] usb 1-10.4: Product: TEMPer2
    [  939.521617] input: PCsensor TEMPer2 as /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10.4/1-10.4:1.0/0003:3553:A001.000B/input/input26
    [  939.580825] hid-generic 0003:3553:A001.000B: input,hidraw4: USB HID v1.11 Keyboard [PCsensor TEMPer2] on usb-0000:00:14.0-10.4/input0
    [  939.581808] input: PCsensor TEMPer2 as /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10.4/1-10.4:1.1/0003:3553:A001.000C/input/input27
    [  939.582035] hid-generic 0003:3553:A001.000C: input,hidraw5: USB HID v1.10 Device [PCsensor TEMPer2] on usb-0000:00:14.0-10.4/input1
       
     

    É possível ver que o dispositivo aparece como dois devices: /dev/hidraw4 e /dev/hidraw5.

    Eu tentei usar a permissão 0644 primeiro, mas essa não funcionou pra ler os dados. Então tive de mudar pra 0666 mesmo sendo algo que só lê informação.

    Feita essa etapa, ainda não estamos prontos pra rodar o programa temper.py. Ainda é preciso instalar a dependência: serial.

    Se seu sistema é baseado em debian/ubuntu:

        
    > sudo apt install -y python3-serial
       
     

    Se não for, talvez seja mais fácil fazer com virtualenv. E pra isso eu atualmente uso o uv

       
    > uv venv venv
    > source venv/bin/activate     
    (venv)> uv pip install serial
      
    

    Tendo tudo pronto, chegamos ao momento da verdade:

       
    (venv)> ./temper.py 
    Bus 001 Dev 011 3553:a001 TEMPer2_V4.1 25.6C 78.0F - 22.8C 73.1F -
      
    

    Pegando a saída como JSON permite ver melhor o que é cada um desses resultados.

       
    (venv)>  ./temper.py --json
    [
        {
            "vendorid": 13651,
            "productid": 40961,
            "manufacturer": "PCsensor",
            "product": "TEMPer2",
            "busnum": 1,
            "devnum": 11,
            "devices": [
                "hidraw4",
                "hidraw5"
            ],
            "firmware": "TEMPer2_V4.1",
            "hex_firmware": "54454d506572325f56342e3100000000",
            "hex_data": "808009f64e200000800108e94e200000",
            "internal temperature": 25.5,
            "external temperature": 22.81
        }
    ]     
      
    

    Então a primeira temperatura lida, de /dev/hidraw4, é 25.5°C interna do dispositivo. A segunda, /dev/hidraw5, é de 22.81°C e externa, do cabo.

    Temos as leituras e os dados. Como mandar isso pro Grafana?

    Exportando as métricas pro Grafana

    Eu primeiramente tentei fazer em shell script e mandar o dados pro mimir, que é onde eu agrego as métricas.

    Fracassei miseravelmente.

    Não existe uma forma muito fácil de enviar um dados pro lá. O formato que o alloy usa é protobuf, que é um dado comprimido em snappy, etc.

    Qual outra alternativa?

    Expor o dado como open metric pro alloy pegar e enviar.

    Pode parecer simples mas... precisamos de um servidor web pra isso. Algo que temos fácil em python. Então usando uvicorn e fastapi podemos ter tudo funcionando. E é possível importar o temper.py como módulo.

    E é preciso incrementar nosso virtualenv (ou pacotes) com esses pacotes:

      
    > sudo apt install -y python3-uvicorn python3-fastapi
     
    
    ou
      
    (venv)> uv pip install uvicorn
    (venv)> uv pip install fastapi
     
    

    Sem mais delongas, eis aqui o código do monitor.py:

       
    #! /usr/bin/env python3
    
    import subprocess
    import argparse
    import logging
    import threading
    import time
    
    try:
        import temper
    except ImportError as e:
        print(f"Error importing temper module: {e}")
        print("Make sure python3-serial is installed: sudo apt-get install python3-serial")
        exit(1)
    
    import uvicorn
    from fastapi import FastAPI
    from fastapi.responses import PlainTextResponse
    
    
    CELSIUS = "\u2103"
    DEFAULT_PORT = 8000
    TEMPERATURE_MAX = 25.0
    
    logger = logging.getLogger(__file__)
    consoleOutputHandler = logging.StreamHandler()
    formatter = logging.Formatter(
        fmt="[%(asctime)s] (%(levelname)s) %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    consoleOutputHandler.setFormatter(formatter)
    logger.addHandler(consoleOutputHandler)
    logger.setLevel(logging.INFO)
    
    def shellExec(command: str) -> str:
        'run a command and return its output'
        try:
            return subprocess.getoutput(command)
        except Exception as e:
            logger.error(f"Error executing shell command '{command}': {e}")
            return f"Error: {e}"
    
    app = FastAPI()
    
    # Global temperature monitor instance (will be set in main)
    temperature_monitor = None
    
    @app.get("/metrics", response_class=PlainTextResponse)
    async def metrics():
        if temperature_monitor is None or temperature_monitor.temperature_current is None:
            return ""
            
        temperature_current = temperature_monitor.temperature_current
        logger.info(f"/metrics: {temperature_current}{CELSIUS}")
        data_lines = list()
        data_lines.append("#HELP server_room_temperature_celsius the room with servers current temperature")
        data_lines.append("#TYPE server_room_temperature_celsius gauge")
        data_lines.append(f"server_room_temperature_celsius {temperature_current}")
        data_lines.append("")
        return "\n".join(data_lines)
    
    class TemperatureMonitor:
        'A class that handle the temperature monitoring'
        port: int = DEFAULT_PORT
        temperature_max: float = TEMPERATURE_MAX
        temperature_current: float|None = None
        alert_lock: bool = False
    
        def __init__(self, port=None, temperature_max=None) -> None:
            if port:
                self.port = port
            if temperature_max:
                self.temperature_max = temperature_max
    
        def monitor(self) -> None:
            th = threading.Thread(target=self.webserver)
            th.daemon = True  # Make it a daemon thread
            th.start()
            try:
                while True:
                    self.update()
                    time.sleep(15)
            except KeyboardInterrupt:
                logger.info("Monitoring stopped by user")
            except Exception as e:
                logger.error(f"Error in monitoring loop: {e}")
                raise
         
        def webserver(self) -> None:
            uvicorn.run(app, host="127.0.0.1", port=self.port)
    
        def update(self) -> None:
            'Read the output from the command'
            try:
                tp = temper.Temper().read()
                if not tp or len(tp) == 0:
                    logger.warning("No temperature devices found")
                    self.temperature_current = None
                    return
                
                self.temperature_current = tp[0].get('external temperature')
                if self.temperature_current is not None:
                    logger.info(f"🌡️ current temperature: {self.temperature_current}{CELSIUS}")
                else:
                    logger.warning("External temperature reading is None")
            except Exception as e:
                logger.error(f"Error reading temperature sensor: {e}")
                self.temperature_current = None
    
    if __name__ == '__main__':
        parse = argparse.ArgumentParser(description="script to monitor temperature")
        parse.add_argument("--loglevel", default="info", help="the logging level (default=info)")
        parse.add_argument("--tempmax", type=float, default=TEMPERATURE_MAX, help="maximum temperature before raising alert")
        parse.add_argument("--port", type=int, default=DEFAULT_PORT, help="port to listen the service")
        args = parse.parse_args()
    
        # Validate log level
        valid_log_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
        if args.loglevel.upper() not in valid_log_levels:
            print(f"Invalid log level: {args.loglevel}. Valid options: {', '.join(valid_log_levels)}")
            exit(1)
            
        if args.loglevel.upper() != "INFO":
            logger.setLevel(args.loglevel.upper())
    
        # Validate temperature threshold
        if args.tempmax <= 0:
            print("Temperature threshold must be greater than 0")
            exit(1)
            
        # Validate port number
        if not (1 <= args.port <= 65535):
            print("Port must be between 1 and 65535")
            exit(1)
    
        # Create temperature monitor instance
        temperature_monitor = TemperatureMonitor(args.port, args.tempmax)
        temperature_monitor.monitor()     
      
    

    Eu tenho integrado uma parte de alerta que usa outro sistema, mas removi pra deixar o código fazendo somente o que é preciso.

    No alloy, adicionei as seguintes linhas:

      
    discovery.relabel "temperature_sensor" {
            targets = array.concat(
                    [{
                    __address__ = "localhost:8000",
                    }],
            )
    
            rule {
                    source_labels = ["__address__"]
                    target_label  = "instance"
                    replacement   = "temper"
            }
    }
    
    prometheus.scrape "temperature_sensor" {
            targets    = discovery.relabel.temperature_sensor.output
            forward_to = [prometheus.remote_write.prod.receiver]
            job_name   = "agent"
    }    
     
    

    Tudo pronto. Ou quase. Falta rodar o monitor.py que mostrei acima como serviço. E pra isso usamos o systemd. Basta criar o arquivo /etc/systemd/system/temperature-monitor.service e iniciar.

    Serviço no systemd

      
    [Unit]
    Description=Temperature monitoring service
    After=network.target
    
    [Service]
    User=helio
    Group=helio
    WorkingDirectory=/home/helio/temperature-sensor
    ExecStart=/home/helio/temperature-sensor/monitor.sh
    Restart=always
    
    [Install]
    WantedBy=multi-user.target    
     
    

    O script monitor.sh é pra somente ler o virtualenv corretamente:

      
    #! /usr/bin/env bash
    
    die() {
    	echo "ERROR: $@" >&2
    	echo "[$(date)] exiting with error"
    	exit 1
    }
    
    program="$0"
    root_dir=$(readlink -f $program)
    root_dir=$(dirname $root_dir)
    
    cd $root_dir
    
    source venv/bin/activate || \
        die "failed to read virtualenv"
    exec ./monitor.py    
     
    

    E iniciando o serviço:

      
    > sudo systemctl daemon-reload
    > sudo systemctl enable --now temperature-monitor    
     
    

    O que resta é criar um gráfico pra métrica server_room_temperature_celsius e partir pro abraço.

    Update: [Fri Sep 12 05:30:00 PM CEST 2025] acabo de perceber que o repositório que fiz fork é na verdade um fork de outro, que parece ser bem mais completo.

We use cookies

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.