1// Copyright 2018 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 14// +build linux 15 16package prometheus 17 18import ( 19 "bytes" 20 "errors" 21 "os" 22 "regexp" 23 "testing" 24 25 "github.com/prometheus/common/expfmt" 26 "github.com/prometheus/procfs" 27 28 dto "github.com/prometheus/client_model/go" 29) 30 31func TestProcessCollector(t *testing.T) { 32 if _, err := procfs.Self(); err != nil { 33 t.Skipf("skipping TestProcessCollector, procfs not available: %s", err) 34 } 35 36 registry := NewRegistry() 37 if err := registry.Register(NewProcessCollector(ProcessCollectorOpts{})); err != nil { 38 t.Fatal(err) 39 } 40 if err := registry.Register(NewProcessCollector(ProcessCollectorOpts{ 41 PidFn: func() (int, error) { return os.Getpid(), nil }, 42 Namespace: "foobar", 43 ReportErrors: true, // No errors expected, just to see if none are reported. 44 })); err != nil { 45 t.Fatal(err) 46 } 47 48 mfs, err := registry.Gather() 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 var buf bytes.Buffer 54 for _, mf := range mfs { 55 if _, err := expfmt.MetricFamilyToText(&buf, mf); err != nil { 56 t.Fatal(err) 57 } 58 } 59 60 for _, re := range []*regexp.Regexp{ 61 regexp.MustCompile("\nprocess_cpu_seconds_total [0-9]"), 62 regexp.MustCompile("\nprocess_max_fds [1-9]"), 63 regexp.MustCompile("\nprocess_open_fds [1-9]"), 64 regexp.MustCompile("\nprocess_virtual_memory_max_bytes (-1|[1-9])"), 65 regexp.MustCompile("\nprocess_virtual_memory_bytes [1-9]"), 66 regexp.MustCompile("\nprocess_resident_memory_bytes [1-9]"), 67 regexp.MustCompile("\nprocess_start_time_seconds [0-9.]{10,}"), 68 regexp.MustCompile("\nfoobar_process_cpu_seconds_total [0-9]"), 69 regexp.MustCompile("\nfoobar_process_max_fds [1-9]"), 70 regexp.MustCompile("\nfoobar_process_open_fds [1-9]"), 71 regexp.MustCompile("\nfoobar_process_virtual_memory_max_bytes (-1|[1-9])"), 72 regexp.MustCompile("\nfoobar_process_virtual_memory_bytes [1-9]"), 73 regexp.MustCompile("\nfoobar_process_resident_memory_bytes [1-9]"), 74 regexp.MustCompile("\nfoobar_process_start_time_seconds [0-9.]{10,}"), 75 } { 76 if !re.Match(buf.Bytes()) { 77 t.Errorf("want body to match %s\n%s", re, buf.String()) 78 } 79 } 80 81 brokenProcessCollector := NewProcessCollector(ProcessCollectorOpts{ 82 PidFn: func() (int, error) { return 0, errors.New("boo") }, 83 ReportErrors: true, 84 }) 85 86 ch := make(chan Metric) 87 go func() { 88 brokenProcessCollector.Collect(ch) 89 close(ch) 90 }() 91 n := 0 92 for m := range ch { 93 n++ 94 pb := &dto.Metric{} 95 err := m.Write(pb) 96 if err == nil { 97 t.Error("metric collected from broken process collector is unexpectedly valid") 98 } 99 } 100 if n != 1 { 101 t.Errorf("%d metrics collected, want 1", n) 102 } 103} 104