No mundo do desenvolvimento, é necessário saber como a aplicação que estamos trabalhando está se comportando e a maneira mais conhecida de realizarmos isso é por meio de métricas. Elas podem ser de diversos tipos, como, por exemplo, de desempenho, de produto ou de saúde. Atualmente, o Prometheus é amplamente utilizado pelo mercado a fim de coletar essas métricas.
Ele é um serviço open-source mantido pela CNCF, a Cloud Native Computing Foundation. Ele funciona da seguinte maneira: um endpoint é exposto na aplicação. Esse endpoint retorna um texto no formato esperado, e o Prometheus acessa esse endpoint de tempos em tempos coletando as informações dali.
# HELP failure_rate The total number of failed events # TYPE failure_rate counter failure_rate 3280
O formato é bem simples, para cada métrica, você vai ter pelo menos três entradas:
- O #HELP mostra a descrição da métrica.
- O #TYPE define o tipo da métrica.
- A terceira linha mostra o valor da métrica.
Em aplicações escritas com Go, temos uma biblioteca que facilita ainda mais a exposição dessas métricas. Ela implementa um handler que expõe por padrão as principais métricas relacionadas ao software, como, por exemplo, goroutines, memória, heap, etc. O exemplo abaixo demonstra melhor como se usa:
package main import ( "fmt" "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { fmt.Println("Monitoring service...") http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":8080", nil) }
Pode-se notar que com poucas linhas temos o endpoint de métricas e um servidor web funcionando! Agora, como configurar um Prometheus para coletá-las? O primeiro passo é subir ambas as aplicações, para isso o melhor é utilizar o docker compose
.
services: myapp: image: myapp build: . container_name: myapp ports: - 8080:8080 restart: unless-stopped prometheus: image: prom/prometheus container_name: prometheus command: - '--config.file=/etc/prometheus/prometheus.yaml' ports: - 9090:9090 restart: unless-stopped volumes: - ./prometheus:/etc/prometheus - prom_data:/prometheus volumes: prom_data:
No arquivo compose, é definida que a aplicação vai escutar na porta 8080
e o Prometheus na porta 9090
. Ele também espera um arquivo de configuração. Este arquivo define onde e com qual frequência ele deve fazer a varredura.
global: scrape_interval: 15s scrape_timeout: 10s evaluation_interval: 15s scrape_configs: - job_name: myapp honor_timestamps: true scrape_interval: 15s scrape_timeout: 10s metrics_path: /metrics scheme: http static_configs: - targets: - 'myapp:8080'
Também definimos o Dockerfile da nossa aplicação falsa:
# copied from the internet # syntax=docker/dockerfile:1 FROM golang:1.23 # Set destination for COPY WORKDIR /app # Download Go modules COPY go.mod go.sum ./ RUN go mod download # Copy the source code. Note the slash at the end, as explained in # https://docs.docker.com/reference/dockerfile/#copy COPY ./ ./ # Build RUN CGO_ENABLED=0 GOOS=linux go build -o /myapp # Optional: # To bind to a TCP port, runtime parameters must be supplied to the docker command. # But we can document in the Dockerfile what ports # the application is going to listen on by default. # https://docs.docker.com/reference/dockerfile/#expose EXPOSE 8080 # Run CMD ["/myapp"]
Se quiser verificar se tudo está funcionando, é só acessar http://localhost:9090
e ver se deu certo a configuração. Contudo, muitas vezes as métricas padrões não são suficientes para representar o comportamento da nossa aplicação e é necessário definir métricas customizadas. Ao utilizar a biblioteca padrão do Prometheus para Go, essa tarefa se torna trivial e simples, como o exemplo abaixo:
successRate := promauto.NewCounter(prometheus.CounterOpts{ Name: "success_rate", Help: "The total number of succeded events", }) successRate.Inc()
Desta forma, uma nova métrica será retornada ao acessar o endpoint /metrics
. Porém, nem sempre é possível ter um servidor web para ter as métricas expostas dessa forma. A partir dessa premissa, foi desenvolvido o Pushgateway. Ele funciona da seguinte forma: você envia suas métricas por chamadas HTTP e ele armazena e expõe o endpoint /metrics
para a coleta do Prometheus. Todavia, nem sempre é uma boa ideia utilizar esta estratégia, pois, segundo a própria documentação oficial:
- Quando se monitora múltiplas instâncias por meio de um único Pushgateway, ele se torna um ponto único de falha e um potencial gargalo.
- Você perde o monitoramento automático da saúde da sua aplicação, gerada em cada varredura.
- O Pushgateway nunca esquece nenhum dado que foi enviado para ele e vai sempre os expor para o Prometheus, exceto caso seja manualmente deletado.
Para mais informações, recomendo a leitura dessa documentação. Mas, como existem casos de uso, vamos ver como podemos usar a biblioteca do Prometheus para fazer um Push. O exemplo abaixo demonstra que muda muito pouco do exemplo anterior. Só adicionamos a instrução referente ao Push e para onde ele deve ser realizado.
successRate := promauto.NewCounter(prometheus.CounterOpts{ Name: "success_rate_pg", Help: "The total number of succeded events", }) p.successRate.Inc() err := push.New("http://pushgateway:9091", "pg"). Collector(p.successRate). Grouping("myapp", "success_rate_pg"). Push() if err != nil { fmt.Println("Could not push completion time to Pushgateway:", err) }
Também é necessário configurar o compose para iniciar o Pushgateway.
services: # ... myapp and prometheus already exposed pushgateway: image: prom/pushgateway container_name: pushgateway restart: unless-stopped expose: - 9091 ports: - "9091:9091"
E por fim, vamos dizer ao Prometheus que ele deve varrer o Pushgateway também.
global: scrape_interval: 15s scrape_timeout: 10s evaluation_interval: 15s scrape_configs: - job_name: pushgateway honor_timestamps: true scrape_interval: 15s scrape_timeout: 10s metrics_path: /metrics scheme: http static_configs: - targets: - 'pushgateway:9091'
Vale a pena mencionar que, para o exemplo, eu utilizei somente o tipo de métrica Counter, ou em português Contador. Contudo, existem diversos outros tipos que podem ser encontrados aqui! Para mais exemplos utilizando o Prometheus com Go, você pode checar os exemplos oficiais da biblioteca ou a PoC onde implemento um simulador de monitoramento sintético e gero métricas através do endpoint e do Pushgateway.
Se você gostou do post, me diz: quais métricas você geralmente monitora na sua aplicação? Elas são métricas padrões ou customizadas?
Top comments (0)