diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index 30152623..f2f660f8 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -2094,6 +2094,21 @@ node_nfsd_server_rpcs_total 18628 # HELP node_nfsd_server_threads Total number of NFSd kernel threads that are running. # TYPE node_nfsd_server_threads gauge node_nfsd_server_threads 8 +# HELP node_processes_max_processes Number of max PIDs limit +# TYPE node_processes_max_processes gauge +node_processes_max_processes 123 +# HELP node_processes_max_threads Limit of threads in the system +# TYPE node_processes_max_threads gauge +node_processes_max_threads 7801 +# HELP node_processes_pids Number of PIDs +# TYPE node_processes_pids gauge +node_processes_pids 1 +# HELP node_processes_state Number of processes in each state. +# TYPE node_processes_state gauge +node_processes_state{state="S"} 1 +# HELP node_processes_threads Allocated threads in system +# TYPE node_processes_threads gauge +node_processes_threads 1 # HELP node_procs_blocked Number of processes blocked waiting for I/O to complete. # TYPE node_procs_blocked gauge node_procs_blocked 0 @@ -2149,6 +2164,7 @@ node_scrape_collector_success{collector="netdev"} 1 node_scrape_collector_success{collector="netstat"} 1 node_scrape_collector_success{collector="nfs"} 1 node_scrape_collector_success{collector="nfsd"} 1 +node_scrape_collector_success{collector="processes"} 1 node_scrape_collector_success{collector="qdisc"} 1 node_scrape_collector_success{collector="sockstat"} 1 node_scrape_collector_success{collector="stat"} 1 diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index 4eb1dd0e..218aaf56 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2094,6 +2094,21 @@ node_nfsd_server_rpcs_total 18628 # HELP node_nfsd_server_threads Total number of NFSd kernel threads that are running. # TYPE node_nfsd_server_threads gauge node_nfsd_server_threads 8 +# HELP node_processes_max_processes Number of max PIDs limit +# TYPE node_processes_max_processes gauge +node_processes_max_processes 123 +# HELP node_processes_max_threads Limit of threads in the system +# TYPE node_processes_max_threads gauge +node_processes_max_threads 7801 +# HELP node_processes_pids Number of PIDs +# TYPE node_processes_pids gauge +node_processes_pids 1 +# HELP node_processes_state Number of processes in each state. +# TYPE node_processes_state gauge +node_processes_state{state="S"} 1 +# HELP node_processes_threads Allocated threads in system +# TYPE node_processes_threads gauge +node_processes_threads 1 # HELP node_procs_blocked Number of processes blocked waiting for I/O to complete. # TYPE node_procs_blocked gauge node_procs_blocked 0 @@ -2149,6 +2164,7 @@ node_scrape_collector_success{collector="netdev"} 1 node_scrape_collector_success{collector="netstat"} 1 node_scrape_collector_success{collector="nfs"} 1 node_scrape_collector_success{collector="nfsd"} 1 +node_scrape_collector_success{collector="processes"} 1 node_scrape_collector_success{collector="qdisc"} 1 node_scrape_collector_success{collector="sockstat"} 1 node_scrape_collector_success{collector="stat"} 1 diff --git a/collector/fixtures/proc/10/stat b/collector/fixtures/proc/10/stat new file mode 100644 index 00000000..1451c8a4 --- /dev/null +++ b/collector/fixtures/proc/10/stat @@ -0,0 +1 @@ +17 (khungtaskd) S 2 0 0 0 -1 2129984 0 0 0 0 14 0 0 0 20 0 1 0 24 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/collector/fixtures/proc/sys/kernel/pid_max b/collector/fixtures/proc/sys/kernel/pid_max new file mode 100644 index 00000000..190a1803 --- /dev/null +++ b/collector/fixtures/proc/sys/kernel/pid_max @@ -0,0 +1 @@ +123 diff --git a/collector/fixtures/proc/sys/kernel/threads-max b/collector/fixtures/proc/sys/kernel/threads-max new file mode 100644 index 00000000..0ccbf457 --- /dev/null +++ b/collector/fixtures/proc/sys/kernel/threads-max @@ -0,0 +1 @@ +7801 \ No newline at end of file diff --git a/collector/fixtures/proc/sys/pid_max b/collector/fixtures/proc/sys/pid_max new file mode 100644 index 00000000..190a1803 --- /dev/null +++ b/collector/fixtures/proc/sys/pid_max @@ -0,0 +1 @@ +123 diff --git a/collector/fixtures/proc/sys/threads-max b/collector/fixtures/proc/sys/threads-max new file mode 100644 index 00000000..0ccbf457 --- /dev/null +++ b/collector/fixtures/proc/sys/threads-max @@ -0,0 +1 @@ +7801 \ No newline at end of file diff --git a/collector/processes_linux.go b/collector/processes_linux.go new file mode 100644 index 00000000..fd6ddb1f --- /dev/null +++ b/collector/processes_linux.go @@ -0,0 +1,109 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !noprocesses + +package collector + +import ( + "fmt" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/procfs" +) + +type processCollector struct { + threadAlloc *prometheus.Desc + threadLimit *prometheus.Desc + procsState *prometheus.Desc + pidUsed *prometheus.Desc + pidMax *prometheus.Desc +} + +func init() { + registerCollector("processes", defaultDisabled, NewProcessStatCollector) +} + +func NewProcessStatCollector() (Collector, error) { + subsystem := "processes" + return &processCollector{ + threadAlloc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "threads"), + "Allocated threads in system", + nil, nil, + ), + threadLimit: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "max_threads"), + "Limit of threads in the system", + nil, nil, + ), + procsState: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "state"), + "Number of processes in each state.", + []string{"state"}, nil, + ), + pidUsed: prometheus.NewDesc(prometheus.BuildFQName(namespace, subsystem, "pids"), + "Number of PIDs", nil, nil, + ), + pidMax: prometheus.NewDesc(prometheus.BuildFQName(namespace, subsystem, "max_processes"), + "Number of max PIDs limit", nil, nil, + ), + }, nil +} +func (t *processCollector) Update(ch chan<- prometheus.Metric) error { + pids, states, threads, err := getAllocatedThreads() + if err != nil { + return fmt.Errorf("Unable to retrieve number of allocated threads %v\n", err) + } + + ch <- prometheus.MustNewConstMetric(t.threadAlloc, prometheus.GaugeValue, float64(threads)) + maxThreads, err := readUintFromFile(procFilePath("sys/kernel/threads-max")) + if err != nil { + return fmt.Errorf("Unable to retrieve limit number of threads %v\n", err) + } + ch <- prometheus.MustNewConstMetric(t.threadLimit, prometheus.GaugeValue, float64(maxThreads)) + + for state := range states { + ch <- prometheus.MustNewConstMetric(t.procsState, prometheus.GaugeValue, float64(states[state]), state) + } + + pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) + if err != nil { + return fmt.Errorf("Unable to retrieve limit number of maximum pids alloved %v\n", err) + } + ch <- prometheus.MustNewConstMetric(t.pidUsed, prometheus.GaugeValue, float64(pids)) + ch <- prometheus.MustNewConstMetric(t.pidMax, prometheus.GaugeValue, float64(pidM)) + + return nil +} + +func getAllocatedThreads() (int, map[string]int32, int, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return 0, nil, 0, err + } + p, err := fs.AllProcs() + if err != nil { + return 0, nil, 0, err + } + thread := 0 + procStates := make(map[string]int32) + for _, pid := range p { + stat, err := pid.NewStat() + if err != nil { + return 0, nil, 0, err + } + procStates[stat.State] += 1 + thread += stat.NumThreads + } + return len(p), procStates, thread, nil +} diff --git a/collector/processes_linux_test.go b/collector/processes_linux_test.go new file mode 100644 index 00000000..1cf9e4f0 --- /dev/null +++ b/collector/processes_linux_test.go @@ -0,0 +1,47 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !noprocesses + +package collector + +import ( + "testing" + + "gopkg.in/alecthomas/kingpin.v2" +) + +func TestReadProcessStatus(t *testing.T) { + if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "fixtures/proc"}); err != nil { + t.Fatal(err) + } + want := 1 + pids, states, threads, err := getAllocatedThreads() + if err != nil { + t.Fatalf("Cannot retrieve data from procfs getAllocatedThreads function: %v ", err) + } + if threads < want { + t.Fatalf("Current threads: %d Shouldn't be less than wanted %d", threads, want) + } + if states == nil { + + t.Fatalf("Process states cannot be nil %v:", states) + } + maxPid, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) + if err != nil { + t.Fatalf("Unable to retrieve limit number of maximum pids alloved %v\n", err) + } + if uint64(pids) > maxPid || pids == 0 { + t.Fatalf("Total running pids cannot be greater than %d or equals to 0", maxPid) + } +} diff --git a/end-to-end-test.sh b/end-to-end-test.sh index ec99cae5..469d2441 100755 --- a/end-to-end-test.sh +++ b/end-to-end-test.sh @@ -36,6 +36,7 @@ enabled_collectors=$(cat << COLLECTORS wifi xfs zfs + processes COLLECTORS ) disabled_collectors=$(cat << COLLECTORS