process_exporterがあまり使えなかった件


#はじめに
皆さん、プロセス監視はどのように行なっていますか？？
prometheusには、process_exporterというexporterがあるのですが、検証した結果を備忘録として残しておきます。

このexporterを実運用で使っていて、効果的に使えているという方はぜひ、教えてください！！！

#検証
検証環境は、vagrantを使用しローカルに構築し、少し古いですがUbuntu 14.04.6 LTSを使用しております。

##導入
以下の記事を参考に頑張りました。
https://qiita.com/nekoneck/items/a9deab623da277afc4be

githubのリポジトリは以下になります。
https://github.com/ncabatoff/process-exporter/blob/master/README.md

今回はdockerではなく、バイナリで導入しています。

まずは手動ダウンロードをして、展開しましょう。

```
$ curl -LO https://github.com/ncabatoff/process-exporter/releases/download/v0.2.11/process-exporter_0.2.11_linux_amd64.tar.gz 
$ tar xvf process-exporter_0.2.11_linux_amd64.tar.gz
```

そうすると、以下のファイルが展開されます。

```
$ ls
LICENSE  README.md  process-exporter  process-exporter_0.2.11_linux_amd64.tar.gz
```

##起動
process-exporterが実行ファイルになります。実際はflagをつけて、実行することになりますがどのようなオプションがあるか確認してみましょう。

```
$ ./process-exporter -h
Usage of ./process-exporter:
  -children
    	if a proc is tracked, track with it any children that aren't part of their own group (default true)
  -config.path string
    	path to YAML config file
  -man
    	print manual
  -namemapping string
    	comma-seperated list, alternating process name and capturing regex to apply to cmdline
  -once-to-stdout
    	Don't bind, instead just print the metrics once to stdout and exit
  -procfs string
    	path to read proc data from (default "/proc")
  -procnames string
    	comma-seperated list of process names to monitor
  -recheck
    	recheck process names on each scrape
  -threads
    	report on per-threadname metrics as well
  -web.listen-address string
    	Address on which to expose metrics and web interface. (default ":9256")
  -web.telemetry-path string
    	Path under which to expose metrics. (default "/metrics")
```

基本的には外だししたconfigファイルを読みに行くか、-procnamesを指定して実行するかの二択かなと思われます。

でこの設定が地味によくわからないのが、今回微妙だと思った理由です。

まずは、今回対象にするプロセスをみていきましょう。postgresqlのプロセスを対象として見ます。

```
$ ps -ef |grep -v grep | grep postgres
postgres 21127     1  0 Apr15 ?        00:00:00 /usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf
postgres 21129 21127  0 Apr15 ?        00:00:00 postgres: checkpointer process
postgres 21130 21127  0 Apr15 ?        00:00:00 postgres: writer process
postgres 21131 21127  0 Apr15 ?        00:00:00 postgres: wal writer process
postgres 21132 21127  0 Apr15 ?        00:00:00 postgres: autovacuum launcher process
postgres 21133 21127  0 Apr15 ?        00:00:01 postgres: stats collector process
```

configファイルは以下のようにしました。commはgithubの説明では以下のようになっています。/proc/{pid}/statの2列目を取ってきているようですね。

```
  # comm is the second field of /proc/<pid>/stat minus parens.
  # It is the base executable name, truncated at 15 chars.  
  # It cannot be modified by the program, unlike exe.
  - comm:
    - bash
```


```
$ cat config.yaml
process_names:
  - comm:
    - postgresql
```

それでは、起動して見ましょう。

```
$ ./process-exporter -config.path config.yaml
2019/04/16 05:02:48 Reading metrics from /proc based on "config.yaml"
```

エンドポイントを叩いて見ましょう。

```
$ curl http://192.168.33.31:9256/metrics |grep postgresql
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7215  100  7215    0     0  1081k      0 --:--:-- --:--:-- --:--:-- 1174k
```

・・・おう。取れていない。そしたら、configを少し変えてみよう。


```
$ cat config.yaml
process_names:
  - comm:
    - postgres
```

エンドポイントを叩いて見ます。

```
$ curl http://192.168.33.31:9256/metrics |grep postgres
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: writer process   "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: writer process   "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: writer process   "} 0
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="resident"} 1.2640256e+07
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: autovacuum launcher process   ",memtype="resident"} 2.822144e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: autovacuum launcher process   ",memtype="virtual"} 2.5337856e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: checkpointer process   ",memtype="resident"} 3.244032e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: checkpointer process   ",memtype="virtual"} 2.52628992e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: stats collector process   ",memtype="resident"} 1.794048e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: stats collector process   ",memtype="virtual"} 1.04841216e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: wal writer process   ",memtype="resident"} 1.695744e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: wal writer process   ",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: writer process   ",memtype="resident"} 2.506752e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: writer process   ",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_minor_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: writer process   "} 0
namedprocess_namegroup_num_procs{groupname="postgres"} 1
namedprocess_namegroup_num_procs{groupname="postgres: autovacuum launcher process   "} 1
namedprocess_namegroup_num_procs{groupname="postgres: checkpointer process   "} 1
namedprocess_namegroup_num_procs{groupname="postgres: stats collector process   "} 1
namedprocess_namegroup_num_procs{groupname="postgres: wal writer process   "} 1
namedprocess_namegroup_num_procs{groupname="postgres: writer process   "} 1
namedprocess_namegroup_num_threads{groupname="postgres"} 1
namedprocess_namegroup_num_threads{groupname="postgres: autovacuum launcher process   "} 1
namedprocess_namegroup_num_threads{groupname="postgres: checkpointer process   "} 1
namedprocess_namegroup_num_threads{groupname="postgres: stats collector process   "} 1
namedprocess_namegroup_num_threads{groupname="postgres: wal writer process   "} 1
namedprocess_namegroup_num_threads{groupname="postgres: writer process   "} 1
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres"} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: autovacuum launcher process   "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: checkpointer process   "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: stats collector process   "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: wal writer process   "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: writer process   "} 1.55536655e+09
namedprocess_namegroup_open_filedesc{groupname="postgres"} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: writer process   "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: writer process   "} 0
namedprocess_namegroup_states{groupname="postgres",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process   ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process   ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process   ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process   ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process   ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process   ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process   ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process   ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: checkpointer process   ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process   ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process   ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process   ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process   ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: stats collector process   ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process   ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process   ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process   ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process   ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: wal writer process   ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process   ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: writer process   ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: writer process   ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: writer process   ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: writer process   ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: writer process   ",state="Zombie"} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres"} 0
100 18856  100 18856    0     0  1769k      0 --:--:-- --:--:-- --:--:-- 1841k
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: writer process   "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: autovacuum launcher process   "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: checkpointer process   "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: stats collector process   "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: wal writer process   "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: writer process   "} 0
```

おお！なんか取れましたね。どうやら、postgresql系のパラメータはgroupnameというパラメータでそれぞれ分けられているようですね。
これだとまあ、使えそう。

続いて、-procnamesオプションを指定して起動して見ましょう。

```
$ ./process-exporter -procnames postgres
2019/04/16 05:15:46 Reading metrics from /proc for procnames: [postgres]
```

エンドポイントを叩いて見ます。

```
$ curl http://192.168.33.31:9256/metrics |grep postgres
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres"} 0.010000000000000009
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="resident"} 2.4702976e+07
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="virtual"} 1.368317952e+09
namedprocess_namegroup_minor_page_faults_total{groupname="postgres"} 61
namedprocess_namegroup_num_procs{groupname="postgres"} 6
namedprocess_namegroup_num_threads{groupname="postgres"} 6
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres"} 1.55536655e+09
namedprocess_namegroup_open_filedesc{groupname="postgres"} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_states{groupname="postgres",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres",state="Running"} 0
100 10261  100 10261    0     0  1126k      0 --:--:-- --:--:-- --:--:-- 1252k
namedprocess_namegroup_states{groupname="postgres",state="Sleeping"} 6
namedprocess_namegroup_states{groupname="postgres",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres",state="Zombie"} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres"} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres"} 0
```

お。出力が変わりました。どうやら、これは先ほど出力されていたものがまとめられて表示されているようです。
groupnameの表示名を変えたければ、以下のようにconfigを書き直します。

```
$ cat config.yaml
process_names:
  - name: aaaaaa
    comm:
      - 'postgres'
```

またまた、エンドポイントをたたいてみます。

```
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="aaaaaa"} 6
100 10009  100 10009    0     0  1094k      0 --:--:-- --:--:-- --:--:-- 1221k
```

さてここからです。
exeというselecorを使ってみます。ちなみにgithubの説明では、以下のようにあります。

```
# exe is argv[0]. If no slashes, only basename of argv[0] need match.
  # If exe contains slashes, argv[0] must match exactly.
  - exe: 
    - postgres
    - /usr/local/bin/prometheus
```

ということで、以下のようにconfigを設定してみました。プログラム名を取ってくるイメージですね。

```
process_names:
  - name: postgres master process
    exe:
      - '/usr/lib/postgresql/9.3/bin/postgres'
```

エンドポイントをたたいてみる。あれ？6つ取れている。子プロセスもカウントされるのかな。そうするとcommとの違いがよくわからない。。

```
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="postgres process"} 6
100 10180  100 10180    0     0  1145k      0 --:--:-- --:--:-- --:--:-- 1242k
```

最後、cmdlineについて。これは正規表現が使えまっせというもの。

```
  # cmdline is a list of regexps applied to argv.
  # Each must match, and any captures are added to the .Matches map.
  - name: "{{.ExeFull}}:{{.Matches.Cfgfile}}"
    exe: 
    - /usr/local/bin/process-exporter
    cmdline: 
    - -config.path\s+(?P<Cfgfile>\S+)
```

こんな感じで設定しました。

```
process_names:
 # - name: postgres process
 -  exe:
      - '/usr/lib/postgresql/9.3/bin/postgres'
    cmdline:
    - .*postgresql.conf
```

エンドポイントをたたいてみます。以下見るとわかるのですが、nameをしてしなければ、デフォルトでは、Commの値で名前が入ります。

```
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="postgres"} 6
100 10239  100 10239    0     0  1225k      0 --:--:-- --:--:-- --:--:-- 1249k
```

んー変わらないですね。

# 結論
使えそうなメトリクスとしては、namedprocess_namegroup_num_procs、namedprocess_namegroup_statesかなと思いますが、どちらもグルーピングされたもののカウントが表示されるだけになります。

プロセスの全死などの検知をしたい場合には使えるというところでしょうか。
例えば、特定のjavaのプロセスを監視したい場合などは全て、javaというグルーピングになると思われるため、厳しいかもしれないです。

もし、使い方間違っているなど、ご指摘ありましたら教えてください！

## 2019/5/16 追記
この記事を投稿後、もう少し触っていたら、異なる使い方を見つけたので、追記します。

configファイルにcommとcmdlineの合わせ技を使うと異なるプロセスidを持っていれば、異なるプロセスとして認識させることができました。

サンプルでportをリッスンするjavaアプリケーションを作り、起動させておきます。

```
$ ps -ef |grep java
vagrant   4136  4060  0 05:14 pts/1    00:00:00 java -jar Sample1.jar 8080
vagrant   4148  4060  1 05:14 pts/1    00:00:00 java -jar Sample2.jar 8081
vagrant   4161  4060  0 05:14 pts/1    00:00:00 grep --color=auto java
```

以下configファイルとなります。

```
$ cat config.yaml
process_names:
  - name: test1
    comm:
    - java
    cmdline:
    - Sample1.jar
  - name: test2
    comm:
    - java
    cmdline:
    - Sample2.jar
```
それぞれの説明をします。
name でgroupnameを指定します。今回だと、test1,test2となります。
commで/proc/{pid}/stateの2列目にある文字列を指定します。
これだけだと、javaという文字列全てで引っかかってしまうとため、cmdlineを使用します。このパラメータでは引っ掛ける文字列を指定します。正規表現も使えます。ここにはプロセスを一意に判定できるような文字列を指定すると良いと思います。（例えばjarファイル名など）

エンドポイントを叩いてみましょう。

```
$ curl http://192.168.33.31:9256/metrics | grep namedprocess_namegroup_num_procs
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="test1"} 1
namedprocess_namegroup_num_procs{groupname="test2"} 1
100 11500  100 11500    0     0  1169k      0 --:--:-- --:--:-- --:--:-- 1247k
```

javaのプロセスを分けて取得することができました。

※注意点
postgresのような親プロセスから子プロセスがフォークされるようなものでは、子プロセスでは、この方法で判別することができますが、親プロセスに対してはこの方法が効かないです。（子プロセスの分までカウントされる。）