bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/chef_linux.go (about)

     1  package collectors
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	"bosun.org/metadata"
    13  	"bosun.org/opentsdb"
    14  )
    15  
    16  type crSummary struct {
    17  	StartTime   string  `json:"start_time"`
    18  	EndTime     string  `json:"end_time"`
    19  	ElapsedTime float32 `json:"elapsed_time"`
    20  	Status      string  `json:"status"`
    21  }
    22  
    23  func init() {
    24  	collectors = append(collectors, &IntervalCollector{F: c_chef_linux, Enable: chefEnable})
    25  }
    26  
    27  const (
    28  	chefRunLog = "/var/chef/reports/run_status_json.log"
    29  )
    30  
    31  func chefEnable() bool {
    32  	_, err := os.Stat(chefRunLog)
    33  	return err == nil
    34  }
    35  
    36  func c_chef_linux() (opentsdb.MultiDataPoint, error) {
    37  	md, err := chef_linux(chefRunLog)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	return md, nil
    42  }
    43  
    44  func chef_linux(logfile string) (opentsdb.MultiDataPoint, error) {
    45  	var md opentsdb.MultiDataPoint
    46  	var cr crSummary
    47  	// Gather stats from the run summary
    48  	s, err := readLastLine(chefRunLog, 4096)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	err = json.Unmarshal([]byte(s), &cr)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	endTime, err := time.Parse("2006-01-02 15:04:05 -0700", cr.EndTime)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	switch cr.Status {
    64  	case "success":
    65  		AddTS(&md, "chef.run_status", endTime.Unix(), 0, nil, metadata.Gauge, metadata.Bool, descChefRunStatus)
    66  	case "failed":
    67  		AddTS(&md, "chef.run_status", endTime.Unix(), 1, nil, metadata.Gauge, metadata.Bool, descChefRunStatus)
    68  	default:
    69  		err := fmt.Errorf("bad chef run status: %s", cr.Status)
    70  		return nil, err
    71  	}
    72  	AddTS(&md, "chef.run_time", endTime.Unix(), cr.ElapsedTime, nil, metadata.Gauge, metadata.Second, descChefRunTime)
    73  
    74  	lastrun_delay := time.Now().Sub(endTime).Seconds()
    75  	Add(&md, "chef.lastrun_delay", lastrun_delay, nil, metadata.Gauge, metadata.Second, descChefLastRunDelay)
    76  
    77  	return md, nil
    78  }
    79  
    80  const (
    81  	descChefRunStatus    = "Status of Chef run."
    82  	descChefRunTime      = "Time which Chef took to run."
    83  	descChefLastRunDelay = "Time passed after last Chef run."
    84  )
    85  
    86  func readLastLines(filepath string, count int, offset int64) ([]string, error) {
    87  	f, err := os.Open(filepath)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	defer f.Close()
    92  
    93  	stat, err := f.Stat()
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	size := stat.Size()
    99  	if size < offset {
   100  		offset = size
   101  	}
   102  
   103  	buf := make([]byte, offset)
   104  	if _, err := f.ReadAt(buf, size-offset); err != nil && err != io.EOF {
   105  		return nil, err
   106  	}
   107  
   108  	scanner := bufio.NewScanner(strings.NewReader(string(buf[:])))
   109  
   110  	scanner.Split(bufio.ScanLines)
   111  	lines := []string{}
   112  	for scanner.Scan() {
   113  		lines = append(lines, scanner.Text())
   114  	}
   115  
   116  	to := len(lines)
   117  	from := len(lines) - count
   118  
   119  	if from < 0 {
   120  		from = 0
   121  	}
   122  
   123  	return lines[from:to], nil
   124  }
   125  
   126  func readLastLine(filepath string, offset int64) (string, error) {
   127  	res, err := readLastLines(filepath, 1, offset)
   128  
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  
   133  	if len(res) != 1 {
   134  		err := fmt.Errorf("wrong slice size")
   135  		return "", err
   136  	}
   137  	return res[0], nil
   138  }