Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add processes exporter #950

Merged
merged 3 commits into from
Jun 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions collector/fixtures/e2e-64k-page-output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions collector/fixtures/e2e-output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions collector/fixtures/proc/10/stat
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions collector/fixtures/proc/sys/kernel/pid_max
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
123
1 change: 1 addition & 0 deletions collector/fixtures/proc/sys/kernel/threads-max
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7801
1 change: 1 addition & 0 deletions collector/fixtures/proc/sys/pid_max
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
123
1 change: 1 addition & 0 deletions collector/fixtures/proc/sys/threads-max
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7801
109 changes: 109 additions & 0 deletions collector/processes_linux.go
Original file line number Diff line number Diff line change
@@ -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
}
47 changes: 47 additions & 0 deletions collector/processes_linux_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
1 change: 1 addition & 0 deletions end-to-end-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enabled_collectors=$(cat << COLLECTORS
wifi
xfs
zfs
processes
COLLECTORS
)
disabled_collectors=$(cat << COLLECTORS
Expand Down