---
title: Scripts externos para alertas
url: https://doc2.pstreamer.tv/pt/manual/extras/alert_scripts.html
lang: pt-BR
product: Perfect Streamer
version: 2.0.2.415
---

# Scripts externos para alertas

O canal «Processo» da entrega externa de alertas executa no nó o seu programa ou script a cada evento de alerta: a geração de um incidente e a sua resolução. Assim, os alertas chegam a qualquer sistema que possa ser chamado a partir de um script: um gateway de SMS, um mensageiro, um webhook, o seu próprio monitoramento ou um sistema de chamados. Esta página descreve como o nó executa o comando, o que ele recebe e como o resultado é tratado, e traz dois modelos prontos: em `/bin/sh` e em Python 3.

O funcionamento geral da entrega externa e os outros dois canais, Telegram e e-mail, estão descritos em [Entrega externa de alertas](../meshwork/alerts.md#meshwork-alert-delivery); a janela de configuração, em [Destinos de alerta](../webui/administration.md#webui-alert-destinations).

## Configuração do canal

O canal é configurado na aba «Processo» da janela «Destinos de alerta». A janela é aberta pelo botão «Destinos de alerta…» nas configurações do alertador ([Destinos de alerta](../webui/administration.md#webui-alert-destinations)). Os mesmos valores ficam na seção `alerter` do arquivo de configuração.

| Campo | Chave | Finalidade |
| --- | --- | --- |
| «Ativar destino de processo» | `process-enable` | Ativa o canal. Desativado por padrão. |
| «Comando» | `process-command` | Linha de comando: o programa e os seus argumentos. Vazia por padrão; um canal ativado com o comando vazio não executa nada. |
| «Severidade mínima» | `process-min-severity` | Limiar inferior de severidade do evento: `Info` (3), `Warning` (4, padrão), `Error` (5), `Critical` (6), `AdminAction` (7). |
| «Timeout, ms» | `process-timeout-ms` | Tempo em milissegundos concedido a cada execução: de 100 a 600000, padrão 5000. |

Os quatro valores são lidos a cada evento, por isso uma alteração vale a partir do próximo alerta, sem reiniciar o serviço.

## Como o comando é executado

**Sem shell.** A linha «Comando» é dividida em palavras pelas regras do shell, mas o shell em si não é iniciado. As palavras são separadas por espaços; o texto entre aspas simples é tomado como está; entre aspas duplas, a barra invertida escapa apenas `"` e `\`; fora das aspas, a barra invertida escapa o caractere seguinte; aspas vazias `''` geram um argumento vazio. A primeira palavra é o programa, as demais são os seus argumentos. Pipes `|`, redirecionamentos `>`, substituição de variáveis `$VAR`, `~` e padrões de nomes de arquivo não funcionam: chegam ao programa como texto comum. Tudo isso deve ser feito dentro do script.

**Busca do programa.** Se a primeira palavra contém `/`, ela é o caminho de um arquivo: o arquivo deve existir e ser executável; caso contrário, cada evento termina com o erro `process-command not executable`. Um nome sem `/` é procurado no `PATH` do serviço. O mais seguro é indicar sempre o caminho completo.

**Ambiente de execução.**

- Usuário e grupo: os mesmos do serviço, `pss`.
- Diretório de trabalho: a raiz `/`; no script, indique os caminhos completos.
- As variáveis de ambiente são herdadas do serviço (inclusive o seu `PATH`), e a elas se somam as variáveis `PSS_ALERT_*`.
- Os arquivos e sockets abertos do serviço não são passados ao script: ele tem apenas a entrada padrão, a saída padrão e a saída de erro padrão.
- A saída padrão do script vai para o registro do sistema do serviço, ou seja, para a saída de `journalctl -u pss` ([Registro do serviço](../support/index.md#support-logs)). A saída de erro padrão é lida pelo próprio nó, depois que o script termina (Resultado, tempo limite e registro).

## O que o script recebe

Cada evento é passado de duas formas ao mesmo tempo: em campos nas variáveis de ambiente e por inteiro em formato JSON na entrada padrão. O nó não passa argumentos: há apenas os que estão escritos em «Comando».

**Variáveis de ambiente**

| Variável | Valor |
| --- | --- |
| `PSS_ALERT_ID` | Identificador estável do incidente, o mesmo na sua geração e na sua resolução, por exemplo `2:12:3`. |
| `PSS_ALERT_STATE` | `raised` — o incidente foi gerado, `cleared` — foi resolvido. |
| `PSS_ALERT_SEVERITY` | Severidade em número: 3–7 (veja «Severidade mínima» acima). |
| `PSS_ALERT_SEVERITY_STR` | Severidade por extenso: `Info`, `Warning`, `Error`, `Critical`, `AdminAction`. |
| `PSS_ALERT_CODE` | Código numérico do tipo de incidente ([Catálogo de códigos de alerta](../meshwork/alerts.md#meshwork-alert-codes)). |
| `PSS_ALERT_CODE_STR` | O mesmo código como designação textual, por exemplo `no-data`, `io-error`. |
| `PSS_ALERT_SRC_TYPE` | Tipo de fonte: `System`, `Stream`, `Cluster`, `EPG`, `Mosaic`, `DVB` ou `CS`. |
| `PSS_ALERT_SRC_ID` | Identificador da fonte, por exemplo o número do fluxo. |
| `PSS_ALERT_NODE` | Nome do nó em que o incidente foi gerado. Em um alerta recebido de um vizinho do domínio Meshwork, é o nome desse vizinho. |
| `PSS_ALERT_DISPLAY_NAME` | Nome legível do objeto, por exemplo o nome do fluxo. |
| `PSS_ALERT_MESSAGE` | Texto do alerta. |
| `PSS_ALERT_TS` | Horário deste evento, em segundos Unix (UTC). |
| `PSS_ALERT_RAISED_TS` | Horário da geração do incidente. |
| `PSS_ALERT_CLEARED_TS` | Horário da resolução; `0` enquanto o incidente está ativo. |

As variáveis são práticas em `/bin/sh`: textos com espaços e quebras de linha passam por elas sem distorção, e elas não aparecem na lista de processos (`ps`).

**JSON na entrada padrão.** Uma única linha sem quebra de linha final; depois dela, a entrada é fechada. O JSON traz as mesmas informações, mas a severidade e o tipo de fonte vêm apenas como números (tipo de fonte: 1 — `System`, 2 — `Stream`, 3 — `Cluster`, 4 — `EPG`, 5 — `Mosaic`, 6 — `DVB`, 7 — `CS`), e não há designações textuais do código e da severidade. Campos:

- sempre: `id`, `state`, `ts`, `raised_ts`, `cleared_ts`, `severity`, `src_type`, `src_id`, `node`, `display_name`, `code`, `message`;
- nos incidentes de uma entrada ou saída específica: `io_id` e `io_kind` (`input` ou `output`);
- nos alertas `AdminAction`: `admin_action_src`;
- em um incidente «oscilante»: `flapping` (`true`) e `flap_cycles`, o número dos seus ciclos (Quando o script é executado).

O script não é obrigado a ler a entrada padrão: tudo o que é necessário também está nas variáveis. Mas, se ele lê a entrada, deve lê-la até o fim, e não apenas uma linha.

Exemplo: no nó `edge-1`, o fluxo `Sport HD` (número 12) está há 15 segundos sem dados. Geração:

```json
{"id":"2:12:3","state":"raised","ts":1761134400,"raised_ts":1761134400,
 "cleared_ts":0,"severity":4,"src_type":2,"src_id":12,"node":"edge-1",
 "display_name":"Sport HD","code":3,
 "message":"[Sport HD] no data 15s (no-data threshold 15s)"}
```

Resolução do mesmo incidente dois minutos depois:

```json
{"id":"2:12:3","state":"cleared","ts":1761134520,"raised_ts":1761134400,
 "cleared_ts":1761134520,"severity":4,"src_type":2,"src_id":12,"node":"edge-1",
 "display_name":"Sport HD","code":3,
 "message":"[Sport HD] no data 15s (no-data threshold 15s)"}
```

Aqui o JSON foi dividido em linhas para facilitar a leitura; o nó o passa em uma única linha. A resolução mantém a severidade e o texto do incidente; não existe um texto «restabelecido», e quem indica a resolução é o campo `state`. As variáveis de ambiente da mesma geração:

```sh
PSS_ALERT_ID=2:12:3
PSS_ALERT_STATE=raised
PSS_ALERT_SEVERITY=4
PSS_ALERT_SEVERITY_STR=Warning
PSS_ALERT_CODE=3
PSS_ALERT_CODE_STR=no-data
PSS_ALERT_SRC_TYPE=Stream
PSS_ALERT_SRC_ID=12
PSS_ALERT_NODE=edge-1
PSS_ALERT_DISPLAY_NAME=Sport HD
PSS_ALERT_MESSAGE=[Sport HD] no data 15s (no-data threshold 15s)
PSS_ALERT_TS=1761134400
PSS_ALERT_RAISED_TS=1761134400
PSS_ALERT_CLEARED_TS=0
```

## Quando o script é executado

- **Geração e resolução.** O script é executado uma vez quando o incidente é gerado e uma vez quando ele é resolvido. As atualizações intermediárias de um incidente ativo (repetição, novo texto, mudança de severidade) não são passadas ao script.
- **Limiar de severidade.** A «Severidade mínima» se aplica ao incidente, e não a cada evento. Um incidente abaixo do limiar não é passado. Se a sua severidade subiu depois até o limiar, o script recebe `raised` uma única vez, no momento desse aumento. `cleared` chega se e somente se `raised` foi passado, qualquer que seja a severidade no momento da resolução. Considera-se passado o evento entregue ao canal: se a entrega falhou, o incidente continua sendo considerado aberto, e a sua resolução será passada.
- **Interruptor principal.** Com o alertador do nó desativado ([Alertador](../webui/administration.md#webui-alerter)), o script não é executado em nenhum caso, nem mesmo para a resolução de um incidente já comunicado.
- **Alertas do domínio.** Com a replicação de alertas pelo domínio Meshwork, o script também recebe os alertas dos vizinhos; o nó de origem é indicado em `PSS_ALERT_NODE` ([Replicação de alertas em todo o domínio](../meshwork/alerts.md#meshwork-alert-replication)). Se o canal estiver ativado em vários nós do domínio, cada um deles comunicará o mesmo incidente. Para evitar duplicatas, ative o canal em um único nó.
- **Incidentes oscilantes.** Se um incidente é gerado e resolvido repetidamente (por padrão, três ciclos seguidos com intervalos de no máximo 600 segundos), o nó deixa de resolvê-lo a cada ciclo: o incidente permanece ativo, e uma única resolução chega quando a condição se mantiver restabelecida por pelo menos 600 segundos. O script recebe uma geração e uma resolução, em vez de um par a cada ciclo. Os valores são definidos pelas chaves `flap-suppress`, `flap-cycles`, `flap-window-sec` e `flap-settle-sec` da seção `alerter` do arquivo de configuração ([O arquivo de configuração pss.json](config_file.md#extras-config-file)).
- **Alertas persistentes,** que só são resolvidos manualmente, enviam a resolução quando o operador resolve o alerta ([Visualização e resolução de alertas](../meshwork/alerts.md#meshwork-alerts-view)).
- **Reinício do serviço.** A lista de incidentes ativos fica na memória e se perde no reinício do serviço, sem resoluções. Uma condição que ainda persiste é gerada de novo, e o script recebe um segundo `raised` com o mesmo `PSS_ALERT_ID`.

Por isso, é melhor tratar o evento por `PSS_ALERT_ID` e `PSS_ALERT_STATE`: um `raised` repetido atualiza um incidente já conhecido em vez de abrir um novo.

## Fila e ordem

- O script é executado estritamente um de cada vez: a execução seguinte começa depois que a anterior termina, e os eventos seguem a ordem de chegada.
- As execuções são conduzidas por uma thread em segundo plano própria do canal. Um script lento não atrasa os outros canais nem o funcionamento do nó, mas atrasa os eventos seguintes do mesmo canal.
- Enquanto o script está em execução, os novos eventos aguardam na fila do canal, com capacidade para 512 eventos. Quando a fila está cheia, os eventos mais novos são descartados, e o registro do serviço recebe a linha `delivery queue full, dropped alert(s)`.
- Na parada e no reinício do serviço, os eventos da fila são descartados; o serviço aguarda apenas a execução que já está em andamento.

Faça as contas: em uma tempestade de cem eventos, um script que leva dois segundos fica mais de três minutos atrás dos eventos. Mova a entrega demorada para segundo plano (veja a próxima seção).

## Resultado, tempo limite e registro

- **Código de saída 0:** o evento foi entregue.
- **Código diferente de zero:** falha na entrega. No registro do serviço ([Registro do serviço](../support/index.md#support-logs)) é gravada uma linha como `[alert:process] deliver failed: process-command '/usr/local/bin/pss-alert.sh' exit 1: <texto do stderr>` com os últimos 4 KB da saída de erro.
- **A saída de erro** é lida pelo nó enquanto o script é executado e só é exibida junto com um código diferente de zero. A saída no stderr com o código 0 não é considerada erro e não afeta nada; uma saída abundante no stderr não deixa o script mais lento e não leva ao tempo limite.
- **Tempo limite.** Se o script não terminar dentro do «Timeout, ms», o nó o encerra à força (`SIGKILL`) e grava `timed out after <N> ms`. Só o próprio script é encerrado; os processos iniciados por ele continuam em execução.
- **Não há novas tentativas.** Um evento que falhou não é reenviado; o canal passa ao seguinte.
- **Limitação da frequência de registros.** O primeiro erro do canal é gravado imediatamente; os seguintes, no máximo uma vez por minuto, com o número de erros desse período no fim da linha (`(x12)`).

> **Nota**
>
> **Processos em segundo plano.** Um processo que o script deixa em segundo plano não atrasa os próximos eventos do canal, mesmo que tenha herdado a saída de erro. Nas versões anteriores à 2.0.2.415, esse processo parava o canal até terminar; por isso, nos nós onde podem funcionar versões anteriores, e em geral por cuidado, inicie trabalhos em segundo plano com a entrada e a saída fechadas:
>
> ```sh
> some-command </dev/null >/dev/null 2>&1 &
> ```
>
> ou com redirecionamento para um arquivo de registro próprio:
>
> ```sh
> setsid some-command </dev/null >>/var/log/pss-alerts/bg.log 2>&1 &
> ```

## Segurança

- O script é executado com os privilégios do serviço, do usuário `pss`. Defina `root` como dono do arquivo do script e dê ao usuário `pss` apenas leitura e execução (modo `750`, grupo `pss`): assim, o serviço não consegue alterar o script que ele mesmo executa.
- Não passe segredos nos argumentos do «Comando». Os argumentos ficam visíveis para todos os usuários do sistema na lista de processos (`ps`), são armazenados no arquivo de configuração e aparecem na interface web para o papel Admin (para os papéis Restricted admin e Viewer, a linha de comando é exibida oculta). Guarde tokens e senhas no próprio script ou em um arquivo separado que só o usuário `pss` possa ler.
- O texto do alerta (o nome do fluxo, a mensagem) vem das configurações e das fontes. Não o insira em comandos de shell sem aspas e não o passe para `eval`. Os modelos abaixo passam os valores somente entre aspas.

## Modelo em /bin/sh

O script grava uma linha no registro a cada evento e termina com o código 0. O lugar da entrega real está marcado com um comentário.

```sh
#!/bin/sh
# Receptor de alertas do Perfect Streamer (canal «Processo»).
# O nó executa o script a cada geração e resolução de um incidente.
# Os campos do evento estão nas variáveis PSS_ALERT_*, o JSON inteiro - na entrada padrão.

LOG=/var/log/pss-alerts/alerts.log

# JSON da entrada padrão: uma linha sem quebra de linha no fim,
# por isso lemos com cat, e não com read.
json=$(cat)

# Uma linha no registro. Erro de gravação - código diferente de zero: o nó o grava
# no próprio registro junto com o texto do stderr.
printf '%s %s %s %s [%s] %s: %s\n' \
    "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$PSS_ALERT_STATE" "$PSS_ALERT_SEVERITY_STR" \
    "$PSS_ALERT_NODE" "$PSS_ALERT_CODE_STR" "$PSS_ALERT_DISPLAY_NAME" \
    "$PSS_ALERT_MESSAGE" >> "$LOG" || exit 1

# Aqui entra a entrega real, por exemplo um webhook.
# A chamada síncrona deve caber no «Timeout, ms» (padrão 5 s):
#
# printf '%s' "$json" | curl -sS -m 3 -X POST \
#     -H 'Content-Type: application/json' --data-binary @- \
#     https://hooks.example.com/pss >/dev/null || exit 1
#
# Entrega demorada - só em segundo plano e só com entrada e saída fechadas,
# senão o canal para (veja «Resultado, tempo limite e registro»):
#
# ( printf '%s' "$json" | curl -sS -m 30 -X POST \
#     -H 'Content-Type: application/json' --data-binary @- \
#     https://hooks.example.com/pss ) </dev/null >/dev/null 2>&1 &

exit 0
```

## Modelo em Python 3

O mesmo em Python 3, apenas com a biblioteca padrão (Python 3.6 ou mais recente).

```python
#!/usr/bin/env python3
# Receptor de alertas do Perfect Streamer (canal «Processo»).
# O nó executa o script a cada geração e resolução de um incidente.
# Os campos do evento estão nas variáveis PSS_ALERT_*, o JSON inteiro - na entrada padrão.

import json
import os
import sys
import time

LOG = "/var/log/pss-alerts/alerts.log"

def main():
    # Toda a entrada padrão: uma linha de JSON sem quebra de linha no fim.
    raw = sys.stdin.read()
    alert = json.loads(raw) if raw else {}
    env = os.environ

    line = "{} {} {} {} [{}] {}: {}\n".format(
        time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
        alert.get("state", env.get("PSS_ALERT_STATE", "")),
        env.get("PSS_ALERT_SEVERITY_STR", ""),
        alert.get("node", ""),
        env.get("PSS_ALERT_CODE_STR", ""),
        alert.get("display_name", ""),
        alert.get("message", ""),
    )
    # Um erro de gravação encerra o script com código diferente de zero, e o texto
    # do erro vai para o stderr - o nó o grava no próprio registro.
    with open(LOG, "a", encoding="utf-8") as f:
        f.write(line)

    # Aqui entra a entrega real, por exemplo um webhook.
    # A chamada deve caber no «Timeout, ms» (padrão 5 s):
    #
    # import urllib.request
    # req = urllib.request.Request(
    #     "https://hooks.example.com/pss",
    #     data=raw.encode("utf-8"),
    #     headers={"Content-Type": "application/json"},
    # )
    # urllib.request.urlopen(req, timeout=3).close()
    #
    # Inicie processos em segundo plano (subprocess.Popen) com
    # stdin/stdout/stderr=subprocess.DEVNULL e start_new_session=True
    # (veja «Resultado, tempo limite e registro»).

    return 0

if __name__ == "__main__":
    sys.exit(main())
```

## Instalação e verificação

1. Crie o diretório de registro com permissão de escrita para o usuário `pss`:

   ```sh
   sudo install -d -o pss -g pss -m 750 /var/log/pss-alerts
   ```
2. Salve o modelo, por exemplo como `/usr/local/bin/pss-alert.sh` (ou `pss-alert.py`), e defina o dono e as permissões:

   ```sh
   sudo chown root:pss /usr/local/bin/pss-alert.sh
   sudo chmod 750 /usr/local/bin/pss-alert.sh
   ```
3. Teste o script manualmente como usuário `pss`, com um evento de exemplo:

   ```sh
   echo '{"id":"2:12:3","state":"raised","severity":4,"node":"edge-1","display_name":"Sport HD","code":3,"message":"test"}' | \
     sudo -u pss env PSS_ALERT_ID=2:12:3 PSS_ALERT_STATE=raised \
       PSS_ALERT_SEVERITY=4 PSS_ALERT_SEVERITY_STR=Warning \
       PSS_ALERT_CODE=3 PSS_ALERT_CODE_STR=no-data \
       PSS_ALERT_NODE=edge-1 PSS_ALERT_DISPLAY_NAME='Sport HD' \
       PSS_ALERT_MESSAGE=test \
       /usr/local/bin/pss-alert.sh
   echo "exit=$?"
   tail -n 1 /var/log/pss-alerts/alerts.log
   ```

   Espera-se `exit=0` e uma nova linha no registro. Aproveite para medir o tempo: ele deve ser bem menor que o «Timeout, ms».
4. Na aba «Processo» da janela «Destinos de alerta», informe em «Comando» o caminho completo `/usr/local/bin/pss-alert.sh`, defina a «Severidade mínima», ative o destino e salve.
5. Verifique a entrega em um fluxo de teste: interrompa o envio de dados para a entrada dele (por exemplo, pare o transmissor). Após o tempo limite de ausência de dados (padrão 15 segundos, [Configurações do alerter](../meshwork/alerts.md#meshwork-alerts-settings)), será gerado um alerta `no-data` com severidade `Warning` e, quando os dados voltarem, a sua resolução. No registro do script devem aparecer as linhas `raised` e, depois, `cleared`.

## Problemas comuns

- **O script não é executado em nenhum caso.** Verifique o interruptor principal do alertador e «Ativar destino de processo», se o «Comando» não está vazio e se a severidade do evento não está abaixo do limiar. Por padrão, o limiar é `Warning`: eventos `Info` não são enviados para fora.
- **No registro do serviço:** `process-command not executable`. O arquivo no caminho indicado não existe ou o usuário `pss` não tem permissão de execução. Verifique com `ls -l`, incluindo as permissões de todos os diretórios do caminho.
- **No registro do serviço:** `posix_spawnp failed`. Não foi possível iniciar o programa: na maioria das vezes, o nome foi indicado sem caminho e não foi encontrado no `PATH` do serviço, ou a primeira linha do script (`#!`) está errada. Indique o caminho completo.
- **No registro do serviço:** `exit <N>`. O script terminou com erro, e o texto do stderr aparece na mesma linha. Uma causa frequente é a falta de permissão de escrita no diretório de registro ou nos arquivos de trabalho: o script é executado como `pss`, e não como `root`, e no diretório `/`.
- **No registro do serviço:** `timed out after <N> ms`. O script não terminou dentro do tempo limite: acelere a entrega (com um tempo limite da chamada de rede menor que o «Timeout, ms»), aumente o «Timeout, ms» ou mova a parte demorada para segundo plano com a saída fechada.
- **Os alertas chegam com grande atraso ou se perdem; no registro,** `delivery queue full`. O script é lento demais para o volume de eventos: a fila do canal está cheia. Acelere o script ou aumente a «Severidade mínima».
- **O canal ficou mudo sem nenhum erro no registro** (versões anteriores à 2.0.2.415). O mais provável é que o script tenha deixado um processo em segundo plano com a saída de erro herdada e que o nó esteja aguardando o término dele. Encontre o processo (`ps -u pss -f`), encerre-o e corrija a forma de iniciar o segundo plano: com `</dev/null >/dev/null 2>&1` ou com redirecionamento para um arquivo. A partir da versão 2.0.2.415, esse processo não para o canal.
- **O script funciona manualmente, mas não a partir do nó.** A causa está no ambiente: outro usuário (`pss`), o diretório de trabalho `/`, outro `PATH`, a ausência das variáveis da sua sessão. Teste com o comando do passo 3 da seção Instalação e verificação, via `sudo -u pss`.
- **Chegou um segundo** `raised` **com o mesmo** `PSS_ALERT_ID`. O serviço foi reiniciado, e o incidente ativo foi detectado novamente (veja Quando o script é executado).
- **Não chegou** `cleared`. O alertador do nó foi desativado enquanto o incidente estava ativo, ou o serviço foi reiniciado antes da resolução (veja Quando o script é executado).
- **O mesmo alerta chega de vários nós.** O canal está ativado em vários nós do domínio que replicam alertas. Deixe-o ativado em apenas um.
- **A saída do script não aparece.** A saída padrão vai para `journalctl -u pss`, e a saída de erro só chega ao registro do serviço com um código de saída diferente de zero. Grave o diagnóstico em um arquivo de registro próprio.
