Certains programmes utilisent la modification de leur ligne de commande pour afficher leur activité actuelle. Un utilisateur peut voir l'activité en exécutant les commandes ps
et top
. PostgreSQL, Sendmail, Zabbix sont des exemples de tels programmes.
Voyons un exemple de Linux. Supposons que nous souhaitons surveiller un certain nombre de processus d'agent Zabbix.
La commande ps
montre les processus qui nous intéressent
$ 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]
...
La sélection des processus par nom et utilisateur fait le travail :
Maintenant, renommons l'exécutable zabbix_agentd
en zabbix_agentd_30
et redémarrons-le.
ps
montre maintenant
$ 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]
...
Maintenant, la sélection des processus par nom et utilisateur produit un résultat incorrect :
Pourquoi un simple changement de nom d'exécutable en un nom plus long conduit à un résultat assez différent ?
L'agent Zabbix commence par vérifier le nom du processus. Le fichier /proc/<pid>/status
est ouvert et la ligne Name
est cochée. Dans notre cas, les lignes de Name
sont :
$ 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
Le nom du processus dans le fichier status
est tronqué à 15 caractères.
Un résultat similaire peut être vu avec la commande 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
...
Évidemment, proc.num[]
n'est pas égal à notre valeur de paramètre de name
: zabbix_agentd_30
. N'ayant pas réussi à faire correspondre le nom de processus du fichier status
, l'agent Zabbix se tourne vers le fichier /proc/<pid>/cmdline
.
La manière dont l'agent voit le fichier "cmdline" peut être illustrée avec l'exécution d'une commande
$ 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>...
Les fichiers /proc/<pid>/cmdline
dans notre cas contiennent des octets nuls invisibles et non imprimables, utilisés pour terminer les chaînes en langage C. Les octets nuls sont représentés par "<NUL>" dans cet exemple.
L'agent Zabbix vérifie dans "cmdline" le processus principal et prend zabbix_agentd_30
, qui correspond à la valeur du paramètre name
: zabbix_agentd_30
. Ainsi, le processus principal est compté par l'élément 'proc.num[zabbix_agentd_30,zabbix]
.
Lors de la vérification du processus suivant, l'agent prend zabbix_agentd_30: collector [idle 1 sec]
dans le fichier cmdline
et il ne correspond pas à notre paramètre name
zabbix_agentd_30
. Ainsi, seul le processus principal qui ne modifie pas sa ligne de commande est compté. D'autres processus d'agent modifient leur ligne de commande et sont ignorés.
Cet exemple montre que le paramètre name
ne peut pas être utilisé dans proc.mem[]
et proc.num[]
pour la sélection de processus dans ce cas.
L'utilisation du paramètre cmdline
avec une expression régulière appropriée produit un résultat correct :
Soyez prudent lorsque vous utilisez les éléments proc.mem[]
et proc.num[]
pour surveiller les programmes qui modifient leurs lignes de commande.
Avant de placer les paramètres name
et cmdline
dans les éléments proc.mem[]
et proc.num[]
, vous pouvez tester les paramètres à l'aide de l'élément proc.num[]
et de la commande ps
.
cmdline
dans les éléments proc.mem[]
et proc.num ]
Prenons comme exemple l'un des threads du noyau :
Il peut être sélectionné avec le paramètre name
du processus :
Mais avec la sélection par processus, le paramètre cmdline ne fonctionne pas :
La raison en est que l'agent Zabbix prend l'expression régulière spécifiée dans le paramètre cmdline
et l'applique au contenu du processus /proc/<pid>/cmdline
. Pour les threads du noyau, leurs fichiers /proc/<pid>/cmdline
sont vides. Ainsi, le paramètre cmdline
ne correspond jamais.
proc.mem[]
et proc.num[]
Les threads du noyau Linux sont comptés par l'élément proc.num[]
mais ne signalent pas la mémoire dans l'élément proc.mem[]
. Par exemple :
$ 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.
Mais que se passe-t-il si un processus utilisateur porte le même nom qu'un thread du noyau ? Alors cela pourrait ressembler à ceci :
$ 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[]
compte à la fois le thread du noyau et le processus utilisateur. proc.mem[]
rapporte la mémoire pour le processus utilisateur uniquement et compte la mémoire du thread du noyau comme si elle était à 0. Cela est différent du cas ci-dessus lorsque ZBX_NOTSUPPORTED a été signalé.
Soyez prudent lorsque vous utilisez les éléments proc.mem[]
et proc.num[]
si le nom du programme correspond à l'un des threads.
Avant de mettre des paramètres dans les éléments proc.mem[]
et proc.num[]
, vous pouvez les tester à l'aide de l'élément proc.num[]
et de la commande ps
.