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

     1  package collectors
     2  
     3  import (
     4  	"encoding/json"
     5  	"os/exec"
     6  	"strings"
     7  	"time"
     8  
     9  	"bosun.org/metadata"
    10  	"bosun.org/opentsdb"
    11  	"bosun.org/slog"
    12  	"bosun.org/util"
    13  )
    14  
    15  func init() {
    16  	if _, err := exec.LookPath("varnishstat"); err == nil {
    17  		collectors = append(collectors, &IntervalCollector{F: c_varnish_unix})
    18  	}
    19  }
    20  
    21  func c_varnish_unix() (opentsdb.MultiDataPoint, error) {
    22  	var md opentsdb.MultiDataPoint
    23  	const metric = "varnish."
    24  
    25  	r, err := util.Command(5*time.Second, nil, "varnishstat", "-j")
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	var stats varnishStats
    31  	if err := json.NewDecoder(r).Decode(&stats); err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	for name, raw := range stats {
    36  		if name == "timestamp" {
    37  			continue
    38  		}
    39  
    40  		var v varnishStat
    41  		if err := json.Unmarshal(raw, &v); err != nil {
    42  			slog.Errorln("varnish parser error:", name, err)
    43  			continue
    44  		}
    45  
    46  		ts := opentsdb.TagSet{}
    47  
    48  		// special case for backend stats. extract backend name, host and port, put
    49  		// them in tags and remove them in name.
    50  		// the format is like "name(host,,port)" for the "ident" field of "VBE" type
    51  		if v.Type == "VBE" {
    52  			subtype := v.SubType
    53  
    54  			name = strings.Replace(name, "."+subtype, "", -1)
    55  
    56  			idx := strings.Index(subtype, "(")
    57  			if idx < 0 || len(subtype)-idx < 4 {
    58  				// output format changed, ignore
    59  				continue
    60  			}
    61  
    62  			ss := strings.Split(subtype[idx+1:len(subtype)-1], ",")
    63  			if len(ss) != 3 {
    64  				// output format changed, ignore
    65  				continue
    66  			}
    67  
    68  			ts.Merge(opentsdb.TagSet{"backend": subtype[:idx]})
    69  			ts.Merge(opentsdb.TagSet{"endpoint": ss[0] + "_" + ss[2]})
    70  		}
    71  
    72  		rate := metadata.RateType(metadata.Gauge)
    73  		if flag := v.Flag; flag == "a" || flag == "c" {
    74  			rate = metadata.Counter
    75  		}
    76  
    77  		unit := metadata.Unit(metadata.Count)
    78  		if v.Format == "B" {
    79  			unit = metadata.Bytes
    80  		}
    81  
    82  		Add(&md, metric+strings.ToLower(name), v.Value, ts, rate, unit, v.Desc)
    83  	}
    84  	return md, nil
    85  }
    86  
    87  /*
    88  {
    89    "timestamp": "YYYY-MM-DDTHH:mm:SS",
    90    "FIELD NAME": {
    91      "description": "FIELD DESCRIPTION",
    92      "type": "FIELD TYPE", "ident": "FIELD IDENT", "flag": "FIELD SEMANTICS", "format": "FIELD DISPLAY FORMAT",
    93      "value": FIELD VALUE
    94    },
    95    "FIELD2 NAME": {
    96      "description": "FIELD2 DESCRIPTION",
    97      "type": "FIELD2 TYPE", "ident": "FIELD2 IDENT", "flag": "FIELD2 SEMANTICS", "format": "FIELD2 DISPLAY FORMAT",
    98      "value": FIELD2 VALUE
    99    },
   100    [..]
   101  }
   102  */
   103  type varnishStats map[string]json.RawMessage
   104  
   105  type varnishStat struct {
   106  	Desc    string `json:"description"`
   107  	Type    string `json:"type"`
   108  	SubType string `json:"ident"`
   109  	// for older version, flag can be either 'a', 'c', 'g' or 'i'
   110  	// for newer version 'a' become 'c' and 'i' become 'g', which means
   111  	// counter and gauge, see:
   112  	// https://github.com/varnish/Varnish-Cache/commit/5cceef815
   113  	Flag string `json:"flag"`
   114  	// newer version add a format field
   115  	// currently there are 'i' for integer and 'B' for bytes
   116  	Format string `json:"format"`
   117  	Value  int64  `json:"value"`
   118  }