Diagnósticos usando dotnet-monitor + prometheus + grafana
Tags: dotnet, grafana, prometheus, monitor
Published: 2024-01-03 21:30:00

---
title: Diagnósticos usando dotnet-monitor + prometheus + grafana
published: true
description: 
tags: dotnet, grafana, prometheus, monitor
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvoodpopsovqgb1yg7c9.png
published_at: 2024-01-03 21:30 +0000
---

No meu [último post](https://dev.to/rafaelpadovezi/threadpool-no-aspnet-e-problemas-de-performance-3mao) escrevi sobre o problema de **Threadpool Starvation** e o uso de `dotnet-counters` para obter as métricas de performance de uma aplicação dotnet. Neste artigo, será usado o `dotnet-monitor` como ferramenta para obter diversas informações de diagnóstico de aplicações dotnet. O foco será em métricas de performance da aplicação e para facilitar a visualização será utilizado o conjunto [prometheus](https://prometheus.io/) e [grafana](https://grafana.com/oss/grafana/).

Para o artigo foi criado um laboratório usando docker compose e o código pode ser encontrado no [github](https://github.com/rafaelpadovezi/thread-pool-starvation).

## dotnet-monitor

dotnet-monitor é uma ferramenta de monitoramento em ambiente produtivo capaz de coletar artefatos como dumps, traces, logs e métricas. A ferramenta expõe [uma API](https://github.com/dotnet/dotnet-monitor/blob/main/documentation/api/README.md) que disponibiliza extração de informações de diagnóstico sob demanda.

O runtime do dotnet expõe um endpoint de serviço para comunicação entre processos chamado de [porta de diagnóstico](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnostic-port). A tecnologia usada depende da plataforma. No Linux são utilizados [sockets de domínio Unix](https://twitter.com/b0rk/status/980955984402272257) como transporte. É dessa maneira que o `dotnet-monitor` se comunica com as aplicações dotnet. No laboratório, a aplicação e o monitor são executados em diferentes containers e dessa forma é preciso que o monitor compartilhe um volume com a aplicação.

```yaml
# docker-compose.yml
  app:
    ...
    environment:
      DOTNET_DiagnosticPorts: /app/diag/dotnet-monitor.sock
    volumes:
      - "./:/app/"
  monitor:
    image: mcr.microsoft.com/dotnet/monitor:6
    environment:
      DOTNETMONITOR_Storage__DefaultSharedPath: /diag
      DOTNETMONITOR_DiagnosticPort__ConnectionMode: listen
      DOTNETMONITOR_DiagnosticPort__EndpointName: /diag/dotnet-monitor.sock
    volumes:
      - "./diag:/diag"
    ...
```

É possível executar a aplicação e o monitor com o comando:

```bash
docker compose up app
```

O endpoint de metrics exporta os valores no formato compatível do Prometheus e pode ser acessado no endereço http://localhost:52325/metrics.

## Prometheus

Prometheus é uma ferramenta de monitoramento open source capaz de coletar e armazenar métricas como series de dados temporais.

Para o laboratório é usada a seguinte configuração:

```yaml
# prometheus/prometheus.yml
scrape_configs:
  ...
  - job_name: "monitor"
    scrape_interval: 5s
    metrics_path: "/metrics"
    static_configs:
      - targets: ["monitor:52323"]
```

Dessa forma, ao inicializar o container usando o docker compose o prometheus irá se conectar ao dotnet-monitor para coleta das métricas.

É possível navegar e visualizar as métricas na interface do Prometheus mas vamos usá-lo como fonte de dados para uma outra ferramenta focada em visualização.

## Grafana

Grafana é uma ferramenta open source de visualização e monitoramento que permite a criação de dashboards. É possível usar várias tecnologias como fonte de dados, incluindo Prometheus.

Outro ponto interessante do grafana é a disponibilização de inúmeros [dashboards](https://grafana.com/grafana/dashboards/) pela comunidade que podem ser usados como base para monitoramento de sistemas e aplicações. Para o laboratório vamos usar o [dotnet-monitor dashboard](https://grafana.com/grafana/dashboards/19297-dotnet-monitor-dashboard/).

A configuração do grafana para o laboratório poderia ser feita manualmente via GUI mas para facilitar a reprodução usaremos arquivos de [provisionamento](https://grafana.com/docs/grafana/latest/administration/provisioning/) para automatizar o setup.

A configuração do Prometheus como fonte de dados é feita pelo arquivo:

```yaml
# grafana/provisioning/datasources/default.yaml
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    # Access mode - proxy (server in the UI) or direct (browser in the UI).
    url: http://prometheus:9090
    jsonData:
      httpMethod: POST
      manageAlerts: true
      prometheusType: Prometheus
      prometheusVersion: 2.44.0
      cacheLevel: "High"
      disableRecordingRules: false
      incrementalQueryOverlapWindow: 10m
```

E a configuração para permitir o provisionamento de dashboards é feita no arquivo:

```yaml
# grafana/provisioning/dashboards/default.yaml
providers:
  - name: "default"
    folder: ""
    type: file
    options:
      path: /var/lib/grafana/dashboards
```

Cada dashboard deve ter sua definição em JSON disponibilizado no caminho definido no arquivo anterior.

O arquivo docker-compose mapeia os volumes para os diretórios padrão de configurações esperada pelo grafana.

```yaml
# docker-compose.yml
  grafana:
    image: grafana/grafana-oss
    ports:
      - "3000:3000"
    volumes:
      # https://grafana.com/docs/grafana/latest/administration/provisioning/
      - "./grafana/provisioning/:/etc/grafana/provisioning/"
      - "./grafana/dashboards/:/var/lib/grafana/dashboards/"
```

O próximo comando executa o grafana e o prometheus:

```bash
docker compose up grafana
```

O grafana pode ser acessado no endereço http://localhost:3000 (use admin/admin para login).

## Testes de carga

Por último, podemos executar os testes de carga usando [hey](https://github.com/rakyll/hey).

O comando `docker compose up send-load-async` dispara uma série de requisições em um endpoint que utiliza o async/await do dotnet para reaproveitamento das threads e otimização de aplicações IO bound. Os gráficos abaixo mostram a quantidade se requisições processadas durante a execução do teste bem como as métricas relacionadas ao uso de threads pela aplicação.

![Parte do dashboard: Requisições por segundo e estatísticas de threadpool da carga de testes async. Requisições ficam em 1000 constante e a fila de threadpool se mantém em zero.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4bb2y5u0yl9gsv6vuhn.png)

Por sua vez, o comando `docker compose up send-load-sync` realiza requisições em um endpoint que utiliza não utiliza o async/await e portanto realiza o bloqueio de threads em operações de IO. Os gráficos abaixo mostram o resultado do teste.

![Parte do dashboard: Requisições por segundo e estatísticas de threadpool da carga de testes async. Quantidade de requisições crescem a medida que novas threads são criadas, chegando em 600.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wq7ic905p59e8pvcfyl.png)

## Conclusão

Os testes realizados mostram o potencial do dotnet-monitor para monitoramento de aplicações em ambientes produtivos. Os testes foram feitos usando o docker compose e a [configuração para execução em kubernetes](https://github.com/dotnet/dotnet-monitor/blob/main/documentation%2Fkubernetes.md) é similar, sendo que o monitor seria publicado como um sidecar da aplicação.

Tão importante quanto a extração das métricas é a possibilidade de visualizar e correlacionar esses dados para permitir o diagnóstico de problemas de performance. O par prometheus e grafana foram usados para esse meio por serem ferramentas conhecidas do mercado e facilitarem a reprodução em ambiente local para um laboratório.