[comment]: # ({b3f6bc92-c42d1f48})
# 8 Notas sobre a seleção de processos em itens proc.mem e proc.num

[comment]: # ({/b3f6bc92-c42d1f48})

[comment]: # ({e9ff6ad6-93778d6f})
#### Processos que modificam sua linha de comando

Alguns programas usam a modificação de sua linha de comando como um método para exibir sua atividade atual. Um usuário pode ver a atividade executando os comandos `ps` e `top`. Exemplos de tais programas incluem *PostgreSQL*, *Sendmail*, *Zabbix*.

Vamos ver um exemplo no Linux. Suponha que queremos monitorar o número de processos do agent Zabbix.

O comando `ps` mostra os processos de interesse como

    $ ps -fu zabbix
    UID        PID  PPID  C STIME TTY          TIME CMD
    ...
    zabbix    6318     1  0 12:01 ?        00:00:00 sbin/zabbix_agentd -c /home/zabbix/zabbix_agentd.conf               
    zabbix    6319  6318  0 12:01 ?        00:00:01 sbin/zabbix_agentd: collector [idle 1 sec]                          
    zabbix    6320  6318  0 12:01 ?        00:00:00 sbin/zabbix_agentd: listener #1 [waiting for connection]            
    zabbix    6321  6318  0 12:01 ?        00:00:00 sbin/zabbix_agentd: listener #2 [waiting for connection]            
    zabbix    6322  6318  0 12:01 ?        00:00:00 sbin/zabbix_agentd: listener #3 [waiting for connection]            
    zabbix    6323  6318  0 12:01 ?        00:00:00 sbin/zabbix_agentd: active checks #1 [idle 1 sec]                   
    ...

Selecionar processos por nome e usuário resolve o problema:

    $ zabbix_get -s localhost -k 'proc.num[zabbix_agentd,zabbix]'
    6

Agora vamos renomear o executável `zabbix_agentd` para `zabbix_agentd_30` e reiniciá-lo.

O `ps` agora mostra

    $ ps -fu zabbix
    UID        PID  PPID  C STIME TTY          TIME CMD
    ...
    zabbix    6715     1  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30 -c /home/zabbix/zabbix_agentd.conf               
    zabbix    6716  6715  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30: collector [idle 1 sec]                          
    zabbix    6717  6715  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30: listener #1 [waiting for connection]            
    zabbix    6718  6715  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30: listener #2 [waiting for connection]            
    zabbix    6719  6715  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30: listener #3 [waiting for connection]            
    zabbix    6720  6715  0 12:53 ?        00:00:00 sbin/zabbix_agentd_30: active checks #1 [idle 1 sec]                   
    ...

Agora, selecionar processos por nome e usuário produz um resultado incorreto:

    $ zabbix_get -s localhost -k 'proc.num[zabbix_agentd_30,zabbix]'
    1

Por que uma simples renomeação do executável para um nome mais longo levou a um resultado tão diferente?

O agent Zabbix começa verificando o nome do processo. O arquivo `/proc/<pid>/status` é aberto e a linha `Name` é verificada. No nosso caso, as linhas `Name` são:

    $ grep Name /proc/{6715,6716,6717,6718,6719,6720}/status
    /proc/6715/status:Name:   zabbix_agentd_3
    /proc/6716/status:Name:   zabbix_agentd_3
    /proc/6717/status:Name:   zabbix_agentd_3
    /proc/6718/status:Name:   zabbix_agentd_3
    /proc/6719/status:Name:   zabbix_agentd_3
    /proc/6720/status:Name:   zabbix_agentd_3

O nome do processo no arquivo `status` é truncado para 15 caracteres.

Um resultado semelhante pode ser visto com o comando `ps`:

    $ ps -u zabbix
      PID TTY          TIME CMD
    ...
     6715 ?        00:00:00 zabbix_agentd_3
     6716 ?        00:00:01 zabbix_agentd_3
     6717 ?        00:00:00 zabbix_agentd_3
     6718 ?        00:00:00 zabbix_agentd_3
     6719 ?        00:00:00 zabbix_agentd_3
     6720 ?        00:00:00 zabbix_agentd_3
     ...

Obviamente, isso não é igual ao valor do parâmetro `name` do nosso `proc.num[]`, `zabbix_agentd_30`. Não conseguindo corresponder ao nome do processo do arquivo `status`, o agent Zabbix recorre ao arquivo `/proc/<pid>/cmdline`.

Como o agent vê o arquivo "cmdline" pode ser ilustrado executando um comando

    $ for i in 6715 6716 6717 6718 6719 6720; do cat /proc/$i/cmdline | awk '{gsub(/\x0/,"<NUL>"); print};'; done
    sbin/zabbix_agentd_30<NUL>-c<NUL>/home/zabbix/zabbix_agentd.conf<NUL>
    sbin/zabbix_agentd_30: collector [idle 1 sec]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
    sbin/zabbix_agentd_30: listener #1 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
    sbin/zabbix_agentd_30: listener #2 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
    sbin/zabbix_agentd_30: listener #3 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
    sbin/zabbix_agentd_30: active checks #1 [idle 1 sec]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...

Os arquivos `/proc/<pid>/cmdline` em nosso caso contêm bytes nulos invisíveis e não imprimíveis, usados para terminar strings na linguagem *C*. Os bytes nulos são mostrados como "<NUL>" neste exemplo.

O agent Zabbix verifica o "cmdline" para o processo principal e pega um `zabbix_agentd_30`, que corresponde ao valor do nosso parâmetro `name` `zabbix_agentd_30`. Portanto, o processo principal é contado pelo item `proc.num[zabbix_agentd_30,zabbix]`.

Ao verificar o próximo processo, o agent pega `zabbix_agentd_30: collector [idle 1 sec]` do arquivo `cmdline` e ele não corresponde ao nosso parâmetro `name` `zabbix_agentd_30`. Assim, apenas o processo principal que não modifica sua linha de comando é contado. Outros processos do agent modificam sua linha de comando e são ignorados.

Este exemplo mostra que o parâmetro `name` não pode ser usado em `proc.mem[]` e `proc.num[]` para selecionar processos neste caso.

:::noteclassic
Para o item `proc.get[]`, quando o agent Zabbix verifica o "cmdline" para o nome do processo, ele usará apenas parte do nome começando a partir da última barra até o primeiro espaço ou sinal de dois pontos. O nome do processo recebido do arquivo cmdline só será usado se seu início corresponder completamente ao nome do processo encurtado no arquivo `status`. O algoritmo é o mesmo tanto para o nome do processo no filtro quanto na saída JSON.
:::


Usar o parâmetro `cmdline` com uma expressão regular adequada produz um resultado correto:

    $ zabbix_get -s localhost -k 'proc.num[,zabbix,,zabbix_agentd_30[ :]]'
    6

Tenha cuidado ao usar os itens `proc.get[]`, `proc.mem[]` e `proc.num[]` para monitorar programas que modificam suas linhas de comando.

Antes de colocar os parâmetros `name` e `cmdline` nos itens `proc.get[]`, `proc.mem[]` e `proc.num[]`, você pode querer testar os parâmetros usando o item `proc.num[]` e o comando `ps`.

[comment]: # ({/e9ff6ad6-93778d6f})

[comment]: # ({0ff11097-0ff11097})
#### Threads do kernel do Linux

[comment]: # ({/0ff11097-0ff11097})

[comment]: # ({7212f400-3588d8df})
##### Threads não podem ser selecionados com o parâmetro `cmdline` em itens `proc.get[]`, `proc.mem[]` e `proc.num[]`

Vamos tomar como exemplo uma das threads do kernel:

    $ ps -ef| grep kthreadd
    root         2     0  0 09:33 ?        00:00:00 [kthreadd]

Ela pode ser selecionada com o parâmetro `name` do processo:

    $ zabbix_get -s localhost -k 'proc.num[kthreadd,root]'
    1

Mas a seleção pelo parâmetro `cmdline` do processo não funciona:

    $ zabbix_get -s localhost -k 'proc.num[,root,,kthreadd]'
    0

A razão é que o agent do Zabbix pega a expressão regular especificada
no parâmetro `cmdline` e a aplica ao conteúdo do processo
`/proc/<pid>/cmdline`. Para threads do kernel, seus arquivos `/proc/<pid>/cmdline`
estão vazios. Portanto, o parâmetro `cmdline` nunca corresponde.

[comment]: # ({/7212f400-3588d8df})

[comment]: # ({8d1ef0a6-8d1ef0a6})
##### Contagem de threads em itens `proc.mem[]` e `proc.num[]`

Threads do kernel do Linux são contadas pelo item `proc.num[]`, mas não relatam
memória no item `proc.mem[]`. Por exemplo:

    $ ps -ef | grep kthreadd
    root         2     0  0 09:51 ?        00:00:00 [kthreadd]

    $ zabbix_get -s localhost -k 'proc.num[kthreadd]'
    1

    $ zabbix_get -s localhost -k 'proc.mem[kthreadd]'
    ZBX_NOTSUPPORTED: Cannot get amount of "VmSize" memory.

Mas o que acontece se houver um processo de usuário com o mesmo nome de uma
thread do kernel? Então poderia ser assim:

    $ ps -ef | grep kthreadd
    root         2     0  0 09:51 ?        00:00:00 [kthreadd]
    zabbix    9611  6133  0 17:58 pts/1    00:00:00 ./kthreadd

    $ zabbix_get -s localhost -k 'proc.num[kthreadd]'
    2

    $ zabbix_get -s localhost -k 'proc.mem[kthreadd]'
    4157440

`proc.num[]` contou tanto a thread do kernel quanto o processo de usuário.
`proc.mem[]` relata a memória apenas para o processo de usuário e conta a
memória da thread do kernel como se fosse 0. Isso é diferente do caso
acima, quando ZBX\_NOTSUPPORTED foi relatado.

Tenha cuidado ao usar os itens `proc.mem[]` e `proc.num[]` se o nome do programa
coincidir com o de uma thread.

Antes de colocar parâmetros nos itens `proc.mem[]` e `proc.num[]`, você
pode querer testar os parâmetros usando o item `proc.num[]` e o comando `ps`.

[comment]: # ({/8d1ef0a6-8d1ef0a6})
