From 469ec2747b6f7c53600f2b6df40cf3e46e582eb1 Mon Sep 17 00:00:00 2001 From: sbookworm Date: Sat, 10 Oct 2020 16:37:17 +0800 Subject: [PATCH] add the NewPidFileFn to helper Signed-off-by: sbookworm --- prometheus/process_collector.go | 21 +++++++++ prometheus/process_collector_test.go | 64 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/prometheus/process_collector.go b/prometheus/process_collector.go index 9b80979..c46702d 100644 --- a/prometheus/process_collector.go +++ b/prometheus/process_collector.go @@ -15,7 +15,11 @@ package prometheus import ( "errors" + "fmt" + "io/ioutil" "os" + "strconv" + "strings" ) type processCollector struct { @@ -149,3 +153,20 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) } ch <- NewInvalidMetric(desc, err) } + +// NewPidFileFn returns a function that retrieves a pid from the specified file. +// It is meant to be used for the PidFn field in ProcessCollectorOpts. +func NewPidFileFn(pidFilePath string) func() (int, error) { + return func() (int, error) { + content, err := ioutil.ReadFile(pidFilePath) + if err != nil { + return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err) + } + pid, err := strconv.Atoi(strings.TrimSpace(string(content))) + if err != nil { + return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err) + } + + return pid, nil + } +} diff --git a/prometheus/process_collector_test.go b/prometheus/process_collector_test.go index 8651d4f..7b19c5e 100644 --- a/prometheus/process_collector_test.go +++ b/prometheus/process_collector_test.go @@ -18,8 +18,11 @@ package prometheus import ( "bytes" "errors" + "fmt" "os" + "path/filepath" "regexp" + "strings" "testing" "github.com/prometheus/common/expfmt" @@ -101,3 +104,64 @@ func TestProcessCollector(t *testing.T) { t.Errorf("%d metrics collected, want 1", n) } } + +func TestNewPidFileFn(t *testing.T) { + folderPath, err := os.Getwd() + if err != nil { + t.Error("failed to get current path") + } + mockPidFilePath := filepath.Join(folderPath, "mockPidFile") + defer os.Remove(mockPidFilePath) + + testCases := []struct { + mockPidFile func() + expectedErrPrefix string + expectedPid int + desc string + }{ + { + mockPidFile: func() { + os.Remove(mockPidFilePath) + }, + expectedErrPrefix: "can't read pid file", + expectedPid: 0, + desc: "no existed pid file", + }, + { + mockPidFile: func() { + os.Remove(mockPidFilePath) + f, _ := os.Create(mockPidFilePath) + f.Write([]byte("abc")) + f.Close() + }, + expectedErrPrefix: "can't parse pid file", + expectedPid: 0, + desc: "existed pid file, error pid number", + }, + { + mockPidFile: func() { + os.Remove(mockPidFilePath) + f, _ := os.Create(mockPidFilePath) + f.Write([]byte("123")) + f.Close() + }, + expectedErrPrefix: "", + expectedPid: 123, + desc: "existed pid file, correct pid number", + }, + } + + for _, tc := range testCases { + fn := NewPidFileFn(mockPidFilePath) + if fn == nil { + t.Error("Should not get nil PidFileFn") + } + + tc.mockPidFile() + + if pid, err := fn(); pid != tc.expectedPid || (err != nil && !strings.HasPrefix(err.Error(), tc.expectedErrPrefix)) { + fmt.Println(err.Error()) + t.Error(tc.desc) + } + } +}