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 }