blob: e31e62e78d0d12903facc726498c44bf1d48ff68 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// Copyright 2015 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package prometheus
15
16import "github.com/prometheus/procfs"
17
18type processCollector struct {
19 pid int
20 collectFn func(chan<- Metric)
21 pidFn func() (int, error)
22 cpuTotal Counter
23 openFDs, maxFDs Gauge
24 vsize, rss Gauge
25 startTime Gauge
26}
27
28// NewProcessCollector returns a collector which exports the current state of
29// process metrics including cpu, memory and file descriptor usage as well as
30// the process start time for the given process id under the given namespace.
31func NewProcessCollector(pid int, namespace string) Collector {
32 return NewProcessCollectorPIDFn(
33 func() (int, error) { return pid, nil },
34 namespace,
35 )
36}
37
38// NewProcessCollectorPIDFn returns a collector which exports the current state
39// of process metrics including cpu, memory and file descriptor usage as well
40// as the process start time under the given namespace. The given pidFn is
41// called on each collect and is used to determine the process to export
42// metrics for.
43func NewProcessCollectorPIDFn(
44 pidFn func() (int, error),
45 namespace string,
46) Collector {
47 c := processCollector{
48 pidFn: pidFn,
49 collectFn: func(chan<- Metric) {},
50
51 cpuTotal: NewCounter(CounterOpts{
52 Namespace: namespace,
53 Name: "process_cpu_seconds_total",
54 Help: "Total user and system CPU time spent in seconds.",
55 }),
56 openFDs: NewGauge(GaugeOpts{
57 Namespace: namespace,
58 Name: "process_open_fds",
59 Help: "Number of open file descriptors.",
60 }),
61 maxFDs: NewGauge(GaugeOpts{
62 Namespace: namespace,
63 Name: "process_max_fds",
64 Help: "Maximum number of open file descriptors.",
65 }),
66 vsize: NewGauge(GaugeOpts{
67 Namespace: namespace,
68 Name: "process_virtual_memory_bytes",
69 Help: "Virtual memory size in bytes.",
70 }),
71 rss: NewGauge(GaugeOpts{
72 Namespace: namespace,
73 Name: "process_resident_memory_bytes",
74 Help: "Resident memory size in bytes.",
75 }),
76 startTime: NewGauge(GaugeOpts{
77 Namespace: namespace,
78 Name: "process_start_time_seconds",
79 Help: "Start time of the process since unix epoch in seconds.",
80 }),
81 }
82
83 // Set up process metric collection if supported by the runtime.
84 if _, err := procfs.NewStat(); err == nil {
85 c.collectFn = c.processCollect
86 }
87
88 return &c
89}
90
91// Describe returns all descriptions of the collector.
92func (c *processCollector) Describe(ch chan<- *Desc) {
93 ch <- c.cpuTotal.Desc()
94 ch <- c.openFDs.Desc()
95 ch <- c.maxFDs.Desc()
96 ch <- c.vsize.Desc()
97 ch <- c.rss.Desc()
98 ch <- c.startTime.Desc()
99}
100
101// Collect returns the current state of all metrics of the collector.
102func (c *processCollector) Collect(ch chan<- Metric) {
103 c.collectFn(ch)
104}
105
106// TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the
107// client allows users to configure the error behavior.
108func (c *processCollector) processCollect(ch chan<- Metric) {
109 pid, err := c.pidFn()
110 if err != nil {
111 return
112 }
113
114 p, err := procfs.NewProc(pid)
115 if err != nil {
116 return
117 }
118
119 if stat, err := p.NewStat(); err == nil {
120 c.cpuTotal.Set(stat.CPUTime())
121 ch <- c.cpuTotal
122 c.vsize.Set(float64(stat.VirtualMemory()))
123 ch <- c.vsize
124 c.rss.Set(float64(stat.ResidentMemory()))
125 ch <- c.rss
126
127 if startTime, err := stat.StartTime(); err == nil {
128 c.startTime.Set(startTime)
129 ch <- c.startTime
130 }
131 }
132
133 if fds, err := p.FileDescriptorsLen(); err == nil {
134 c.openFDs.Set(float64(fds))
135 ch <- c.openFDs
136 }
137
138 if limits, err := p.NewLimits(); err == nil {
139 c.maxFDs.Set(float64(limits.OpenFiles))
140 ch <- c.maxFDs
141 }
142}