1// 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/coreos/etcd/Godeps/_workspace/src/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) *processCollector { 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) *processCollector { 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} 143