├── .gitignore ├── README.md ├── config.go ├── falcon.go ├── falcon_test.go └── tags.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-metrics-falcon 2 | [falcon-plus](https://github.com/open-falcon/falcon-plus) support for [go-metrics](https://github.com/rcrowley/go-metrics) 3 | 4 | 5 | ## Usage 6 | ---- 7 | Create and update metrics: 8 | 9 | ```go 10 | c := metrics.NewCounter() 11 | metrics.Register("foo", c) 12 | c.Inc(47) 13 | 14 | g := metrics.NewGauge() 15 | metrics.Register("bar", g) 16 | g.Update(47) 17 | 18 | s := metrics.NewExpDecaySample(1028, 0.015) // or metrics.NewUniformSample(1028) 19 | h := metrics.NewHistogram(s) 20 | metrics.Register("baz", h) 21 | h.Update(47) 22 | 23 | m := metrics.NewMeter() 24 | metrics.Register("quux", m) 25 | m.Mark(47) 26 | 27 | t := metrics.NewTimer() 28 | metrics.Register("bang", t) 29 | t.Time(func() {}) 30 | t.Update(47) 31 | 32 | ``` 33 | 34 | Periodically report every metric to open falcon. 35 | ```go 36 | import falconmetrics "github.com/g4zhuj/go-metrics-falcon" 37 | 38 | go falconmetrics.ReportRegistry(metrics.DefaultRegistry) 39 | ``` 40 | 41 | Json of open falcon 42 | 43 | ```json 44 | { 45 | "endpoint": "$endpoint", 46 | "metric": "$name", 47 | "value": 2.2, 48 | "step": 60, 49 | "counterType": "GAUGE", 50 | "tags": "project=$projectName,metricType=meter,valueType=ratemean", 51 | "timestamp": 1524724608 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package falconmetrics 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "strings" 7 | ) 8 | 9 | //FalconConfig config of open-falcon 10 | type FalconConfig struct { 11 | Debug bool `json:""` 12 | EndPoint string `json:"endpoint"` 13 | HostName string `json:"hostname"` //hostname of agent default is http://127.0.0.1:1988/v1/push 14 | Step int64 `json:"interval"` // interval to report metrics (s) 15 | BaseTags string `json:"basetags"` // base tags 16 | } 17 | 18 | //DefaultFalconConfig default config 19 | var DefaultFalconConfig = FalconConfig{ 20 | HostName: "http://127.0.0.1:1988/v1/push", 21 | Step: 60, 22 | EndPoint: defaultHostname(), 23 | } 24 | 25 | func defaultProjectName() string { 26 | s, _ := exec.LookPath(os.Args[0]) 27 | psName := "" 28 | if strings.Contains(s, "/") { 29 | ss := strings.Split(s, "/") 30 | psName = ss[len(ss)-1] 31 | } else { 32 | psName = s 33 | } 34 | return psName 35 | } 36 | 37 | func defaultHostname() string { 38 | hostname, _ := os.Hostname() 39 | return hostname 40 | } 41 | -------------------------------------------------------------------------------- /falcon.go: -------------------------------------------------------------------------------- 1 | package falconmetrics 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "time" 9 | 10 | gometrics "github.com/rcrowley/go-metrics" 11 | ) 12 | 13 | //DefaultFalcon default falcon created by default config 14 | var DefaultFalcon = NewFalcon(&DefaultFalconConfig) 15 | 16 | type FalconMetric struct { 17 | Endpoint string `json:"endpoint"` 18 | Metric string `json:"metric"` 19 | Value interface{} `json:"value"` 20 | Step int64 `json:"step"` 21 | Type string `json:"counterType"` 22 | Tags string `json:"tags"` 23 | Timestamp int64 `json:"timestamp"` 24 | } 25 | 26 | type Falcon struct { 27 | cfg *FalconConfig 28 | } 29 | 30 | func NewFalcon(cfg *FalconConfig) *Falcon { 31 | return &Falcon{ 32 | cfg: cfg, 33 | } 34 | } 35 | 36 | //NewFalconMetric create open-falcon metric with args 37 | func NewFalconMetric(metricType, valueType, name, endpoint string, step int64, value interface{}) *FalconMetric { 38 | tags := NewDefaultTags() 39 | MetricType.Set(tags, metricType) 40 | ValueType.Set(tags, valueType) 41 | return &FalconMetric{ 42 | Endpoint: endpoint, 43 | Metric: name, 44 | Value: value, 45 | Step: step, 46 | Type: "GAUGE", 47 | Tags: tags.ToStr(), 48 | Timestamp: time.Now().Unix(), 49 | } 50 | } 51 | 52 | func ReportRegistry(r gometrics.Registry) { 53 | DefaultFalcon.ReportRegistry(r) 54 | } 55 | 56 | func (f *Falcon) post(ms []*FalconMetric) error { 57 | mb, err := json.Marshal(ms) 58 | if err != nil { 59 | return err 60 | } 61 | bodyReader := bytes.NewBuffer(mb) 62 | _, err = http.Post(f.cfg.HostName, "application/json", bodyReader) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func (f *Falcon) print(ms []*FalconMetric) error { 71 | for _, m := range ms { 72 | mb, err := json.Marshal(m) 73 | if err != nil { 74 | return err 75 | } 76 | fmt.Printf("falcon metric: %v\n", string(mb)) 77 | } 78 | return nil 79 | } 80 | 81 | func (f *Falcon) ReportRegistry(r gometrics.Registry) { 82 | for _ = range time.Tick(time.Duration(f.cfg.Step) * time.Second) { 83 | r.Each(func(name string, i interface{}) { 84 | var fmetrics []*FalconMetric 85 | switch metric := i.(type) { 86 | case gometrics.Counter: 87 | mcount := NewFalconMetric(MetricCounter, ValueCount, name, f.cfg.EndPoint, f.cfg.Step, metric.Count()) 88 | fmetrics = append(fmetrics, mcount) 89 | 90 | case gometrics.GaugeFloat64: 91 | mcount := NewFalconMetric(MetricGaugeFloat64, Value, name, f.cfg.EndPoint, f.cfg.Step, metric.Value()) 92 | fmetrics = append(fmetrics, mcount) 93 | 94 | case gometrics.Histogram: 95 | h := metric.Snapshot() 96 | ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99}) 97 | mcount := NewFalconMetric(MetricGaugeFloat64, ValueCount, name, f.cfg.EndPoint, f.cfg.Step, h.Count()) 98 | fmetrics = append(fmetrics, mcount) 99 | mmin := NewFalconMetric(MetricGaugeFloat64, ValueMin, name, f.cfg.EndPoint, f.cfg.Step, h.Min()) 100 | fmetrics = append(fmetrics, mmin) 101 | mmax := NewFalconMetric(MetricGaugeFloat64, ValueMax, name, f.cfg.EndPoint, f.cfg.Step, h.Max()) 102 | fmetrics = append(fmetrics, mmax) 103 | mmean := NewFalconMetric(MetricGaugeFloat64, ValueMean, name, f.cfg.EndPoint, f.cfg.Step, h.Mean()) 104 | fmetrics = append(fmetrics, mmean) 105 | mmedian := NewFalconMetric(MetricGaugeFloat64, ValueMedian, name, f.cfg.EndPoint, f.cfg.Step, ps[0]) 106 | fmetrics = append(fmetrics, mmedian) 107 | m75 := NewFalconMetric(MetricGaugeFloat64, Value75, name, f.cfg.EndPoint, f.cfg.Step, ps[1]) 108 | fmetrics = append(fmetrics, m75) 109 | m95 := NewFalconMetric(MetricGaugeFloat64, Value95, name, f.cfg.EndPoint, f.cfg.Step, ps[2]) 110 | fmetrics = append(fmetrics, m95) 111 | m99 := NewFalconMetric(MetricGaugeFloat64, Value99, name, f.cfg.EndPoint, f.cfg.Step, ps[3]) 112 | fmetrics = append(fmetrics, m99) 113 | 114 | case gometrics.Meter: 115 | m := metric.Snapshot() 116 | mcount := NewFalconMetric(MetricMeter, ValueCount, name, f.cfg.EndPoint, f.cfg.Step, m.Count()) 117 | fmetrics = append(fmetrics, mcount) 118 | mrate1 := NewFalconMetric(MetricMeter, ValueRate1, name, f.cfg.EndPoint, f.cfg.Step, m.Rate1()) 119 | fmetrics = append(fmetrics, mrate1) 120 | mrate5 := NewFalconMetric(MetricMeter, ValueRate5, name, f.cfg.EndPoint, f.cfg.Step, m.Rate5()) 121 | fmetrics = append(fmetrics, mrate5) 122 | mrate15 := NewFalconMetric(MetricMeter, ValueRate15, name, f.cfg.EndPoint, f.cfg.Step, m.Rate15()) 123 | fmetrics = append(fmetrics, mrate15) 124 | mratemean := NewFalconMetric(MetricMeter, ValueRateMean, name, f.cfg.EndPoint, f.cfg.Step, m.RateMean()) 125 | fmetrics = append(fmetrics, mratemean) 126 | 127 | case gometrics.Timer: 128 | du := float64(time.Millisecond) 129 | t := metric.Snapshot() 130 | ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99}) 131 | mcount := NewFalconMetric(MetricTimer, ValueCount, name, f.cfg.EndPoint, f.cfg.Step, t.Count()) 132 | fmetrics = append(fmetrics, mcount) 133 | mmin := NewFalconMetric(MetricTimer, ValueMin, name, f.cfg.EndPoint, f.cfg.Step, float64(t.Min())/du) 134 | fmetrics = append(fmetrics, mmin) 135 | mmax := NewFalconMetric(MetricTimer, ValueMax, name, f.cfg.EndPoint, f.cfg.Step, float64(t.Max())/du) 136 | fmetrics = append(fmetrics, mmax) 137 | mmean := NewFalconMetric(MetricTimer, ValueMean, name, f.cfg.EndPoint, f.cfg.Step, t.Mean()/du) 138 | fmetrics = append(fmetrics, mmean) 139 | mmedian := NewFalconMetric(MetricTimer, ValueMedian, name, f.cfg.EndPoint, f.cfg.Step, ps[0]/du) 140 | fmetrics = append(fmetrics, mmedian) 141 | m75 := NewFalconMetric(MetricTimer, Value75, name, f.cfg.EndPoint, f.cfg.Step, ps[1]/du) 142 | fmetrics = append(fmetrics, m75) 143 | m95 := NewFalconMetric(MetricTimer, Value95, name, f.cfg.EndPoint, f.cfg.Step, ps[2]/du) 144 | fmetrics = append(fmetrics, m95) 145 | m99 := NewFalconMetric(MetricTimer, Value99, name, f.cfg.EndPoint, f.cfg.Step, ps[3]/du) 146 | fmetrics = append(fmetrics, m99) 147 | mrate1 := NewFalconMetric(MetricTimer, ValueRate1, name, f.cfg.EndPoint, f.cfg.Step, metric.Rate1()) 148 | fmetrics = append(fmetrics, mrate1) 149 | mrate5 := NewFalconMetric(MetricTimer, ValueRate5, name, f.cfg.EndPoint, f.cfg.Step, metric.Rate5()) 150 | fmetrics = append(fmetrics, mrate5) 151 | mrate15 := NewFalconMetric(MetricTimer, ValueRate15, name, f.cfg.EndPoint, f.cfg.Step, metric.Rate15()) 152 | fmetrics = append(fmetrics, mrate15) 153 | mratemean := NewFalconMetric(MetricTimer, ValueRateMean, name, f.cfg.EndPoint, f.cfg.Step, metric.RateMean()) 154 | fmetrics = append(fmetrics, mratemean) 155 | } 156 | 157 | if f.cfg.Debug { 158 | f.print(fmetrics) 159 | } 160 | f.post(fmetrics) 161 | }) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /falcon_test.go: -------------------------------------------------------------------------------- 1 | package falconmetrics 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | metrics "github.com/rcrowley/go-metrics" 9 | ) 10 | 11 | func TestRegistry(t *testing.T) { 12 | c := metrics.NewCounter() 13 | metrics.Register("counter_name", c) 14 | c.Inc(47) 15 | 16 | g := metrics.NewGauge() 17 | err := metrics.Register("gauge_name", g) 18 | if err != nil { 19 | fmt.Printf("Register Gauge %v\n", err) 20 | return 21 | } 22 | g.Update(47) 23 | 24 | s := metrics.NewExpDecaySample(1028, 0.015) // or metrics.NewUniformSample(1028) 25 | h := metrics.NewHistogram(s) 26 | metrics.Register("histogram_name", h) 27 | h.Update(47) 28 | for i := 0; i < 100; i++ { 29 | h.Update(int64(i)) 30 | } 31 | 32 | m := metrics.NewMeter() 33 | metrics.Register("meter_name", m) 34 | m.Mark(47) 35 | for i := 0; i < 10; i++ { 36 | m.Mark(int64(1)) 37 | time.Sleep(time.Millisecond * 1) 38 | } 39 | 40 | timer := metrics.NewTimer() 41 | metrics.Register("timer_name", t) 42 | timer.Time(func() { time.Sleep(time.Millisecond * 10) }) 43 | timer.Update(47) 44 | 45 | //report to open falcon 46 | cfg := DefaultFalconConfig 47 | cfg.Debug = true 48 | //report for each 5 seconds 49 | cfg.Step = 5 50 | falcon := NewFalcon(&cfg) 51 | falcon.ReportRegistry(metrics.DefaultRegistry) 52 | } 53 | -------------------------------------------------------------------------------- /tags.go: -------------------------------------------------------------------------------- 1 | package falconmetrics 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | var ( 8 | //ProjectName name of project 9 | ProjectName = stringTagName("project") 10 | MetricType = stringTagName("metricType") 11 | ValueType = stringTagName("valueType") 12 | 13 | MetricCounter = "counter" 14 | MetricGaugeFloat64 = "gaugeFloat64" 15 | MetricHistogram = "histogram" 16 | MetricMeter = "meter" 17 | MetricTimer = "timer" 18 | 19 | ValueCount = "count" 20 | ValueMin = "min" 21 | ValueMax = "max" 22 | ValueMean = "mean" 23 | ValueMedian = "median" 24 | Value75 = "75%" 25 | Value95 = "95%" 26 | Value99 = "99%" 27 | ValueRate1 = "rate1" 28 | ValueRate5 = "rate5" 29 | ValueRate15 = "rate15" 30 | ValueRateMean = "ratemean" 31 | Value = "value" 32 | ) 33 | 34 | type stringTagName string 35 | 36 | func (tag stringTagName) Set(t *Tags, value string) { 37 | t.SetTag(string(tag), value) 38 | } 39 | 40 | type Tags struct { 41 | tags map[string]string 42 | } 43 | 44 | func NewDefaultTags() *Tags { 45 | t := &Tags{ 46 | tags: make(map[string]string), 47 | } 48 | ProjectName.Set(t, defaultProjectName()) 49 | return t 50 | } 51 | 52 | func (t *Tags) SetTag(k, v string) { 53 | t.tags[k] = v 54 | } 55 | 56 | func (t *Tags) ToStr() string { 57 | var ts []string 58 | for k, v := range t.tags { 59 | ts = append(ts, k+"="+v) 60 | } 61 | return strings.Join(ts, ",") 62 | } 63 | --------------------------------------------------------------------------------