Um pipeline de CI/CD que falha sem avisar ninguém é pior do que não ter pipeline. A automação cria uma falsa sensação de segurança: o time assume que, se nada foi dito, tudo correu bem. Quando a falha finalmente é descoberta — geralmente por um cliente reclamando de algo que não funciona — o tempo de resposta é muito maior do que seria se o alerta tivesse chegado imediatamente.
Monitoramento de pipeline não é um detalhe de acabamento. É parte integral do sistema de entrega. Um bom sistema de notificações garante que a pessoa certa recebe a informação certa no momento certo, sem criar ruído que leve a equipe a ignorar os alertas.
Este artigo cobre três dimensões complementares: como estruturar notificações úteis, como interpretar e centralizar logs de pipeline, e como monitorar a saúde do pipeline como um sistema em si.
O Problema do Alerta Genérico
Antes de configurar qualquer notificação, vale refletir sobre o que torna um alerta útil versus um alerta que se torna ruído.
Um alerta genérico do tipo "pipeline falhou" obriga o receptor a abrir o GitHub, encontrar o workflow, identificar qual job falhou, ler os logs e então entender o que aconteceu. Se esse processo acontece dezenas de vezes por semana, a equipe começa a ignorar os alertas.
Um alerta útil responde imediatamente a quatro perguntas: o quê falhou, onde falhou, quem causou a falha e o que fazer a seguir. Com essa informação disponível diretamente na notificação, o tempo de resposta cai drasticamente e a equipe mantém o hábito de agir sobre os alertas.
Notificações no Slack
O Slack é a ferramenta de comunicação mais comum em equipes de tecnologia. A integração com GitHub Actions pode ser feita de diferentes formas, com diferentes níveis de riqueza de informação.
A forma mais simples usa webhooks do Slack diretamente:
- name: Notifica falha no Slack
if: failure()
uses: slackapi/slack-github-action@v1.26.0
with:
payload: |
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "❌ Pipeline Falhou"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repositório:*\n${{ github.repository }}"
},
{
"type": "mrkdwn",
"text": "*Branch:*\n${{ github.ref_name }}"
},
{
"type": "mrkdwn",
"text": "*Job Falhou:*\n${{ github.job }}"
},
{
"type": "mrkdwn",
"text": "*Autor do Commit:*\n${{ github.actor }}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Mensagem do Commit:*\n${{ github.event.head_commit.message }}"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Ver Pipeline"
},
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
Para notificações mais sofisticadas que incluem o diff de cobertura de testes, o tamanho do PR ou métricas de build, usa-se a API do Slack diretamente com um token de bot:
- name: Notifica resultado completo do pipeline
if: always()
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: 'deploys'
slack-message: |
${{ job.status == 'success' && '✅' || '❌' }} *${{ github.repository }}*
*Status:* ${{ job.status }}
*Branch:* `${{ github.ref_name }}`
*Commit:* `${{ github.sha }}`
*Autor:* ${{ github.actor }}
*Duração:* ${{ steps.duracao.outputs.tempo }}
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Ver detalhes>
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
Notificações por Email e Microsoft Teams
Para equipes que usam email como canal principal de comunicação:
- name: Envia notificação por email
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
secure: true
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: "❌ Pipeline falhou — ${{ github.repository }} (${{ github.ref_name }})"
to: time-devops@empresa.com
from: pipeline@empresa.com
html_body: |
<h2>Pipeline Falhou</h2>
<table>
<tr><td><strong>Repositório</strong></td><td>${{ github.repository }}</td></tr>
<tr><td><strong>Branch</strong></td><td>${{ github.ref_name }}</td></tr>
<tr><td><strong>Commit</strong></td><td>${{ github.sha }}</td></tr>
<tr><td><strong>Autor</strong></td><td>${{ github.actor }}</td></tr>
<tr><td><strong>Job</strong></td><td>${{ github.job }}</td></tr>
</table>
<p>
<a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}">
Ver detalhes do pipeline
</a>
</p>
Para Microsoft Teams, o formato usa Adaptive Cards:
- name: Notifica no Microsoft Teams
if: failure()
uses: jdcargile/ms-teams-notification@v1.4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
ms-teams-webhook-uri: ${{ secrets.TEAMS_WEBHOOK_URL }}
notification-summary: "Pipeline falhou em ${{ github.repository }}"
notification-color: "FF0000"
timezone: America/Sao_Paulo
Estratégia de Notificação por Contexto
Notificar sempre e para todos é tão ruim quanto não notificar. A estratégia mais eficiente diferencia o contexto:
jobs:
testes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
# Notifica o autor do commit diretamente quando os testes falham
- name: Notifica autor sobre falha nos testes
if: failure() && github.event_name == 'pull_request'
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{ secrets.SLACK_CHANNEL_DEVS }}
slack-message: |
<@${{ github.actor }}> seus testes falharam no PR #${{ github.event.pull_request.number }}.
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Ver logs>
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
deploy-producao:
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy
run: ./scripts/deploy.sh
# Deploy bem-sucedido — notifica canal geral
- name: Anuncia deploy bem-sucedido
if: success()
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{ secrets.SLACK_CHANNEL_GERAL }}
slack-message: |
🚀 *Deploy em produção concluído*
Versão `${{ github.sha }}` está no ar.
Autor: ${{ github.actor }}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
# Deploy falhou — acorda o plantão
- name: Alerta crítico de falha em produção
if: failure()
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{ secrets.SLACK_CHANNEL_ALERTAS }}
slack-message: |
🚨 *ALERTA: Deploy em produção FALHOU*
<!channel> verificar imediatamente.
Commit: `${{ github.sha }}`
Autor: ${{ github.actor }}
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Ver pipeline>
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
Logs Estruturados no Pipeline
Logs são o principal instrumento de diagnóstico quando algo dá errado. A diferença entre logs úteis e logs inúteis é a estrutura e a consistência.
O GitHub Actions oferece comandos especiais chamados workflow commands que permitem estruturar a saída dos logs:
# Agrupa linhas relacionadas em uma seção recolhível
echo "::group::Instalando dependências"
npm ci
echo "::endgroup::"
# Marca uma linha como aviso — aparece destacado nos logs
echo "::warning::Cobertura de testes abaixo de 85%"
# Marca uma linha como erro — aparece em vermelho
echo "::error::Falha na conexão com o banco de dados"
# Adiciona uma anotação vinculada a um arquivo e linha específica
echo "::error file=src/auth.js,line=42::Token de autenticação não validado"
# Define uma variável disponível nos steps seguintes
echo "BUILD_VERSION=1.2.3" >> $GITHUB_ENV
# Define um output do step disponível nos jobs seguintes
echo "image-tag=sha-abc1234" >> $GITHUB_OUTPUT
# Mascara um valor para que não apareça nos logs
echo "::add-mask::$SENHA_SECRETA"
Exemplo de um script de deploy com logs bem estruturados:
#!/bin/bash
set -euo pipefail
# Funções de log com timestamp e nível
log_info() {
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [INFO] $*"
}
log_warn() {
echo "::warning::[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [WARN] $*"
}
log_error() {
echo "::error::[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [ERROR] $*"
}
log_group() {
echo "::group::$1"
}
log_endgroup() {
echo "::endgroup::"
}
# Uso no script de deploy
log_group "Verificando pré-requisitos"
log_info "Verificando Docker..."
docker version || { log_error "Docker não está acessível"; exit 1; }
log_info "Verificando conectividade com o servidor..."
nc -zv "$DEPLOY_HOST" 22 || { log_error "Servidor inacessível na porta 22"; exit 1; }
log_endgroup
log_group "Executando deploy"
log_info "Imagem: $IMAGE"
log_info "Servidor: $DEPLOY_HOST"
docker pull "$IMAGE" && log_info "Imagem baixada com sucesso" || {
log_error "Falha ao baixar imagem $IMAGE"
exit 1
}
log_endgroup
log_group "Verificando saúde pós-deploy"
for i in $(seq 1 10); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"http://$DEPLOY_HOST:3000/health" || echo "000")
if [ "$STATUS" = "200" ]; then
log_info "Aplicação saudável após ${i}s"
break
fi
if [ "$i" = "10" ]; then
log_error "Aplicação não ficou saudável após 10s — status $STATUS"
exit 1
fi
log_warn "Aguardando... tentativa $i/10 — status atual: $STATUS"
sleep 1
done
log_endgroup
Calculando e Reportando Métricas do Pipeline
Acompanhar métricas do pipeline ao longo do tempo permite identificar degradações de performance antes que se tornem problemas críticos.
Um step que calcula a duração do pipeline e a reporta:
jobs:
pipeline:
runs-on: ubuntu-latest
steps:
- name: Registra hora de início
id: inicio
run: echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT
# ... steps do pipeline ...
- name: Calcula e reporta métricas
if: always()
run: |
INICIO=${{ steps.inicio.outputs.timestamp }}
FIM=$(date +%s)
DURACAO=$((FIM - INICIO))
MINUTOS=$((DURACAO / 60))
SEGUNDOS=$((DURACAO % 60))
echo "::notice::Duração total do pipeline: ${MINUTOS}m ${SEGUNDOS}s"
# Alerta se o pipeline demorou mais que 10 minutos
if [ $DURACAO -gt 600 ]; then
echo "::warning::Pipeline acima de 10 minutos — considere otimização"
fi
# Envia métrica para o Datadog (se disponível)
if [ -n "${{ secrets.DD_API_KEY }}" ]; then
curl -s -X POST "https://api.datadoghq.com/api/v2/series" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: ${{ secrets.DD_API_KEY }}" \
-d "{
\"series\": [{
\"metric\": \"ci.pipeline.duration\",
\"points\": [[$(date +%s), $DURACAO]],
\"tags\": [
\"repo:${{ github.repository }}\",
\"branch:${{ github.ref_name }}\",
\"status:${{ job.status }}\"
]
}]
}"
fi
Monitoramento do Pipeline como Sistema
Além de monitorar execuções individuais, é valioso monitorar o pipeline como um sistema — identificar padrões de falha, jobs lentos e tendências ao longo do tempo.
O GitHub fornece uma API para consultar dados históricos de workflows:
#!/bin/bash
# scripts/analise-pipeline.sh
# Analisa as últimas 50 execuções do workflow de CI
REPO="meu-usuario/meu-repositorio"
WORKFLOW="ci.yml"
TOKEN="$GITHUB_TOKEN"
# Busca as últimas execuções
RUNS=$(curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$REPO/actions/workflows/$WORKFLOW/runs?per_page=50")
# Calcula taxa de sucesso
TOTAL=$(echo "$RUNS" | jq '.workflow_runs | length')
SUCESSO=$(echo "$RUNS" | jq '[.workflow_runs[] | select(.conclusion == "success")] | length')
FALHA=$(echo "$RUNS" | jq '[.workflow_runs[] | select(.conclusion == "failure")] | length')
TAXA=$(echo "scale=1; $SUCESSO * 100 / $TOTAL" | bc)
echo "=== Análise do Pipeline: últimas $TOTAL execuções ==="
echo "Sucesso: $SUCESSO ($TAXA%)"
echo "Falha: $FALHA"
# Calcula duração média das execuções bem-sucedidas
MEDIA=$(echo "$RUNS" | jq '
[.workflow_runs[]
| select(.conclusion == "success")
| (.updated_at | fromdateiso8601) - (.created_at | fromdateiso8601)
] | add / length | . / 60 | floor')
echo "Duração média (sucesso): ${MEDIA} minutos"
# Identifica os jobs que mais falham
echo ""
echo "=== Analisando jobs com maior taxa de falha ==="
for RUN_ID in $(echo "$RUNS" | jq -r '.workflow_runs[].id' | head -20); do
curl -s \
-H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/$REPO/actions/runs/$RUN_ID/jobs" \
| jq -r '.jobs[] | select(.conclusion == "failure") | .name'
done | sort | uniq -c | sort -rn | head -10
Dashboard de Status com GitHub Badges
Uma forma simples e eficaz de tornar o status do pipeline visível para toda a equipe é adicionar badges ao README do repositório:
# Minha API
[](https://github.com/usuario/minha-api/actions/workflows/ci.yml)
[](https://github.com/usuario/minha-api/actions/workflows/deploy.yml)
[](https://codecov.io/gh/usuario/minha-api)
Esses badges atualizam automaticamente e são visíveis para qualquer pessoa que abrir o repositório — sem precisar entrar na aba de Actions.
Integrando com Ferramentas de Observabilidade
Para times com ferramentas de APM como Datadog ou New Relic, integrar os eventos de deploy ao sistema de observabilidade cria uma linha do tempo unificada que correlaciona deploys com mudanças de performance:
- name: Registra evento de deploy no Datadog
if: success()
run: |
curl -s -X POST "https://api.datadoghq.com/api/v1/events" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: ${{ secrets.DD_API_KEY }}" \
-d '{
"title": "Deploy em produção",
"text": "Versão ${{ github.sha }} implantada por ${{ github.actor }}",
"alert_type": "info",
"tags": [
"env:production",
"service:minha-api",
"version:${{ github.sha }}"
],
"source_type_name": "github"
}'
Com esse evento registrado, qualquer anomalia de performance que ocorra após um deploy fica visualmente correlacionada no dashboard do Datadog — simplificando enormemente a investigação de regressões.
Encerrando o Módulo 4
Com este artigo conclui-se o Módulo 4. Foram cobertos os fundamentos conceituais do CI/CD, a construção de pipelines completos com GitHub Actions, testes automatizados em suas diferentes camadas, gerenciamento seguro de secrets, deploy automático com zero downtime e rollback, e o monitoramento do próprio pipeline como sistema.
O Módulo 5 entra no território da Infraestrutura como Código — a disciplina que aplica os mesmos princípios de versionamento, revisão e automação que foram aplicados ao código da aplicação à própria infraestrutura que a sustenta.
Referências para Aprofundamento
Documentação oficial - GitHub Actions — Workflow Commands — Referência completa de todos os comandos especiais disponíveis nos runners do GitHub Actions para estruturar logs e outputs. - GitHub Actions — API de Workflows — Documentação da API REST do GitHub para consultar dados históricos de execuções de workflows.
Ferramentas de notificação - Slack Block Kit Builder — Ferramenta visual do Slack para criar e testar layouts de mensagens antes de implementá-los no pipeline. - slackapi/slack-github-action — GitHub — Repositório oficial da action do Slack com documentação de todos os modos de uso disponíveis. - dawidd6/action-send-mail — GitHub — Action para envio de emails com suporte a HTML, anexos e múltiplos destinatários.
Observabilidade e métricas - Datadog CI Visibility — Documentação do módulo de visibilidade de CI/CD do Datadog, que agrega métricas de múltiplos pipelines em dashboards unificados. - Codecov Documentation — Documentação do Codecov para integração de relatórios de cobertura de testes ao pipeline do GitHub Actions.