Monitoring: métricas com Prometheus node exporter
1. Introdução ao Monitoramento com Prometheus e Node Exporter
O ecossistema Prometheus é uma solução open-source de monitoramento que coleta métricas de sistemas e aplicações, armazena-as em um banco de dados time-series e permite a criação de alertas baseados em regras. O Node Exporter é um agente oficial que expõe métricas do sistema operacional (CPU, memória, disco, rede) via HTTP no formato texto do Prometheus.
Para aplicações escritas em Linguagem C, o monitoramento nativo é essencial quando se deseja expor métricas internas do processo — como número de requisições processadas, memória alocada, tempo de execução ou estado de conexões. Instrumentar manualmente sua aplicação C com métricas customizadas permite que você integre dados específicos do seu software ao pipeline do Prometheus, indo além das métricas genéricas de sistema.
2. Instalação e Configuração do Node Exporter
O Node Exporter pode ser baixado como binário pré-compilado da página de releases do projeto no GitHub ou compilado a partir do código fonte.
Instalação via binário (Linux x86_64):
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xvf node_exporter-1.8.2.linux-amd64.tar.gz
sudo cp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/
Para executar como serviço systemd, crie o arquivo /etc/systemd/system/node_exporter.service:
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
ExecStart=/usr/local/bin/node_exporter \
--collector.textfile.directory=/var/lib/node_exporter/textfile \
--web.listen-address=:9100
Restart=always
[Install]
WantedBy=multi-user.target
Ative e inicie o serviço:
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
Verifique a coleta básica:
curl http://localhost:9100/metrics | head -20
3. Formatando Métricas no Padrão Prometheus
O formato text exposition do Prometheus segue uma estrutura clara: cada métrica possui seções HELP (descrição), TYPE (tipo) e linhas de valor. Os tipos principais são:
- counter: valor que só aumenta (ex: requisições totais)
- gauge: valor que pode subir e descer (ex: memória atual)
- histogram: distribuição de valores (ex: latência)
- summary: quantis calculados no cliente
Exemplo de função em C para escrever uma métrica gauge formatada:
#include <stdio.h>
#include <string.h>
void write_gauge_metric(char *buffer, size_t size,
const char *name, const char *help,
double value, const char *labels) {
snprintf(buffer, size,
"# HELP %s %s\n"
"# TYPE %s gauge\n"
"%s{%s} %.6f\n",
name, help, name, name, labels, value);
}
// Uso:
char buf[512];
write_gauge_metric(buf, sizeof(buf),
"myapp_memory_rss_bytes",
"Resident Set Size in bytes",
12345678.0, "pid=\"1234\"");
printf("%s", buf);
Saída gerada:
# HELP myapp_memory_rss_bytes Resident Set Size in bytes
# TYPE myapp_memory_rss_bytes gauge
myapp_memory_rss_bytes{pid="1234"} 12345678.000000
4. Criando Métricas Customizadas em C
Para coletar métricas do próprio processo, podemos ler arquivos do sistema de arquivos /proc. Exemplo de leitura de RSS (memória residente) em bytes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long get_rss_bytes() {
FILE *fp = fopen("/proc/self/status", "r");
if (!fp) return -1;
char line[256];
long rss = -1;
while (fgets(line, sizeof(line), fp)) {
if (sscanf(line, "VmRSS: %ld kB", &rss) == 1) {
rss *= 1024; // converte para bytes
break;
}
}
fclose(fp);
return rss;
}
Exemplo de contador de requisições e gauge de conexões ativas:
#include <pthread.h>
static pthread_mutex_t metrics_lock = PTHREAD_MUTEX_INITIALIZER;
static long request_counter = 0;
static int active_connections = 0;
void increment_requests() {
pthread_mutex_lock(&metrics_lock);
request_counter++;
pthread_mutex_unlock(&metrics_lock);
}
void set_active_connections(int n) {
pthread_mutex_lock(&metrics_lock);
active_connections = n;
pthread_mutex_unlock(&metrics_lock);
}
void build_metrics(char *buffer, size_t size) {
pthread_mutex_lock(&metrics_lock);
long reqs = request_counter;
int conns = active_connections;
pthread_mutex_unlock(&metrics_lock);
char tmp[1024];
snprintf(buffer, size,
"# HELP myapp_requests_total Total requests processed\n"
"# TYPE myapp_requests_total counter\n"
"myapp_requests_total %ld\n"
"# HELP myapp_active_connections Current active connections\n"
"# TYPE myapp_active_connections gauge\n"
"myapp_active_connections %d\n",
reqs, conns);
}
5. Expondo Métricas via Servidor HTTP Embutido
Para expor as métricas, implementamos um servidor HTTP mínimo que responde na rota /metrics. Exemplo simplificado:
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#define PORT 9090
#define BUFFER_SIZE 4096
void handle_client(int client_fd) {
char request[1024];
read(client_fd, request, sizeof(request) - 1);
char response[BUFFER_SIZE];
char metrics[2048];
build_metrics(metrics, sizeof(metrics));
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain; charset=utf-8\r\n"
"Content-Length: %zu\r\n\r\n%s",
strlen(metrics), metrics);
write(client_fd, response, strlen(response));
close(client_fd);
}
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(PORT)
};
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 5);
while (1) {
int client = accept(server_fd, NULL, NULL);
handle_client(client);
}
close(server_fd);
return 0;
}
Atenção: este servidor é sequencial e não trata concorrência. Para produção, use threads ou um pool de conexões.
6. Integração com Node Exporter via Textfile Collector
O Node Exporter possui o collector textfile, que lê arquivos .prom de um diretório configurado. Isso permite que sua aplicação C escreva métricas periodicamente sem precisar rodar um servidor HTTP.
Exemplo de escrita segura com rename atômico:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void write_metrics_file(const char *dir) {
char tmp_path[512], final_path[512];
snprintf(tmp_path, sizeof(tmp_path), "%s/metrics.tmp", dir);
snprintf(final_path, sizeof(final_path), "%s/metrics.prom", dir);
FILE *fp = fopen(tmp_path, "w");
if (!fp) return;
char metrics[2048];
build_metrics(metrics, sizeof(metrics));
fputs(metrics, fp);
fclose(fp);
rename(tmp_path, final_path); // atômico no mesmo filesystem
}
Chame essa função periodicamente usando setitimer():
#include <sys/time.h>
void timer_handler(int sig) {
write_metrics_file("/var/lib/node_exporter/textfile");
}
int main() {
signal(SIGALRM, timer_handler);
struct itimerval timer = {
.it_interval = { .tv_sec = 15, .tv_usec = 0 },
.it_value = { .tv_sec = 15, .tv_usec = 0 }
};
setitimer(ITIMER_REAL, &timer, NULL);
// ... resto da aplicação
}
7. Testando e Validando as Métricas
Teste manual com curl:
curl http://localhost:9090/metrics
Valide o formato com promtool:
promtool check metrics < metrics.txt
Configure o Prometheus para fazer scrape da sua aplicação. Adicione ao prometheus.yml:
scrape_configs:
- job_name: 'myapp_c'
static_configs:
- targets: ['localhost:9090']
No Grafana, crie um dashboard simples com consultas como myapp_requests_total e myapp_active_connections.
8. Boas Práticas e Segurança
- Bind em localhost: configure o servidor para escutar apenas em
127.0.0.1e use o Node Exporter como proxy reverso, se necessário. - Firewall: bloqueie portas de métricas com
iptablesouufw. - Evite informações sensíveis: não coloque senhas, tokens ou dados pessoais em labels.
- Cache de métricas: evite ler
/proca cada requisição HTTP. Atualize as métricas em intervalo fixo (ex: a cada 15 segundos) e sirva o buffer cacheado. - Redução de syscalls: agrupe leituras de
/procem uma única chamada por ciclo.
Referências
- Documentação oficial do Prometheus - Exposition formats — Descrição detalhada do formato text exposition e tipos de métricas.
- Node Exporter - Textfile Collector — Documentação do collector textfile e flags de configuração.
- Manual do PromQL - Prometheus Query Language — Guia de consultas para métricas expostas por aplicações C.
- Instrumentação de aplicações em C com métricas Prometheus — Lista de client libraries e dicas para linguagens sem suporte nativo.
- Guia de boas práticas para naming de métricas — Convenções de nomenclatura e labels para métricas customizadas.
- Tutorial: Monitorando processos Linux com Node Exporter e Grafana — Passo a passo para dashboards no Grafana.
- Promtool - Ferramenta de validação de métricas — Como usar promtool para verificar arquivos de métricas.