[comment]: # ({d793bcb9-75dc9168})
# 9 Observações sobre seleção de processos nos itens proc.mem e proc.num

[comment]: # ({/d793bcb9-75dc9168})

[comment]: # ({fe795704-93778d6f})
#### Processos modificando sua própria linha de comando

Alguns programas utilizam sua própria linha de comando como uma forma de
apresentar sua atividade atual. Um usuário pode ver a atividade através
dos comandos `ps` e `top`. Exemplos destes programas incluem
*PostgreSQL*, *Sendmail*, *Zabbix*.

Vamos ver um exemplo no Linux. Digamos que vamos monitorar a quantidade
de processos do Zabbix Agent.

O comando `ps` mostra os processos de interesse desta forma

    $ 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/ZBXNEXT-1078/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]                   
    ...

Podemos contar estes processos através de seu nome e do usuário:

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

Vamos modificar o executável `zabbix_agentd` para `zabbix_agentd_30` e
reiniciá-lo.

`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/ZBXNEXT-1078/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 selecionando os processos pelo nome e pelo usuário irá retornar um
valor incorreto:

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

Por que o simples renomear de um executável fez com que tivéssemos um
resultado diferente ?

O Zabbix Agent começa com a verificação pelo nome do processos. O
arquivo aberto é `/proc/<pid>/status` 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 de `status` é truncado em 15 characteres.

Um resultado similar 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 nosso valor de parâmetro utilizado em
`proc.num[]` `name` (`zabbix_agentd_30`). Quando a verificação do nome
do processo a partir do arquivo de `status` falha o Zabbix Agent
modifica para o arquivo `/proc/<pid>/cmdline`.

Agora o agente vê a o arquivo "cmdline" o que pode ser entendido como o
funcionamento de 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/ZBXNEXT-1078/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 invisíveis,
não apresentáveis e nulos, utilizados para terminar strings na linguagem
*C*. Os bytes nulos estão sendo apresentados como "<NUL>" aqui
neste exemplo.

O agente verifica "cmdline" buscando o processo principal e encontra um
`zabbix_agentd_30`, que corresponde com o valor informado no parâmetro
`name` (`zabbix_agentd_30`). Logo, o processo principal é contado pelo
item `proc.num[zabbix_agentd_30,zabbix]`.

Quando vai verificar o próximo processo o agente encontra
`zabbix_agentd_30: collector [idle 1 sec]` no arquivo `cmdline` e isso
não confere com o valor proposto (`zabbix_agentd_30`). Logo, apenas o
processo principal, que não modifica a sua própria linha de comando,
será contabilizado. Os outros processos do agente serão ignorados.

Este exemplo mostro o que parâmetro `name` não pode ser utilizado neste
caso para os itens `proc.mem[]` e `proc.num[]`.

Usando o comando `cmdline` com uma expressão recular apropriada,
obteremos o resultado correto:

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

Cuidado ao utilizar os itens `proc.mem[]` e `proc.num[]` para monitorar
programas que modificam sua própria linha de comando.

Antes de utilizar os parâmetros `name` e `cmdline` com os itens
`proc.mem[]` e `proc.num[]`, pode ser uma boa prática testar o resultado
destes usando o comando `ps`.

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

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

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

[comment]: # ({a7d7bd85-3588d8df})
##### Threads não podem ser selecionadas com o parâmetro `cmdline` nos itens `proc.mem[]` e `proc.num[]`

Vamos ver um exemplo das threads do kernel:

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

Ela pode ser selecionada através do parâmetro `name`:

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

Mas selecionado pelo parâmetro `cmdline` não irá funcionar:

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

A razão disso é que o agente utiliza a expressão regular definida no
parametro `cmdline` e aplica seu conteúdo ao conteúdo do processo
`/proc/<pid>/cmdline`. Mas para as threads do kernel os arquivos
`/proc/<pid>/cmdline` estarão vazios. Logo, o parâmetro `cmdline` nunca
irá funcionar para elas.

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

[comment]: # ({3cb3c072-8d1ef0a6})
##### Contando threads com os itens `proc.mem[]` e `proc.num[]`

As threads do kernel Linux são contadas pelo item `proc.num[]` mas não
pelo `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 existir um processo com o mesmo nome de uma thread
do kernel? Pode ocorrer algo similar a isso:

    $ 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[]` irá contar tanto o processo de usuário quanto a thread de
kernel. `proc.mem[]` irá apresentar o uso de memória para o processo de
usuário e contará a memória da thread como 0. É diferente neste caso
pois gerará um status de ZBX\_NOTSUPPORTED.

Cuidado ao usar os itens `proc.mem[]` e `proc.num[]` se o programa for
similar à alguma das threads.

Antes de colocar os parâmetros nos itens `proc.mem[]` e `proc.num[]` é
sempre interessante testar os parâmetros através de um comando `ps`.

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