Skip to content

Commit

Permalink
The big one
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoene committed Jan 23, 2015
1 parent ff982bb commit 3ab1f96
Show file tree
Hide file tree
Showing 13 changed files with 919 additions and 303 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
dist
statsd
statsd_linux_amd64
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM debian:wheezy

ADD statsd_linux_amd64 /usr/bin/statsd

EXPOSE 8125

ENTRYPOINT ["statsd"]
39 changes: 25 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
VERSION=0.1.4
name := statsd
version := $(shell cat main.go | grep VERSION | sed -e 's/\"//g' | head -n1 |cut -d' ' -f4)

default: fmt run
default: fmt build

fmt:
go fmt *.go

debug:
go run main.go -debug -flush=5 -percentiles=90,95,99

build:
go build
go build -o $(name)

build-linux-amd64:
GOOS=linux GOARCH=amd64 go build -o $(name)_linux_amd64

docker-build:
GOOS=linux GOARCH=amd64 go build -o $(name)_linux_amd64
docker build -t jcoene/statsd-librato:latest .

docker-release: docker-build
docker push jcoene/statsd-librato:latest

run: build
./statsd -debug -flush=5 -percentiles=90,95,99

test:
go test -cover

release:
mkdir -p dist

mkdir -p statsd-${VERSION}.darwin-amd64/bin
GOOS=darwin GOARCH=amd64 go build -o statsd-${VERSION}.darwin-amd64/bin/statsd
tar zcvf dist/statsd-${VERSION}.darwin-amd64.tar.gz statsd-${VERSION}.darwin-amd64
rm -rf statsd-${VERSION}.darwin-amd64
mkdir -p statsd-$(version).darwin-amd64/bin
GOOS=darwin GOARCH=amd64 go build -o statsd-$(version).darwin-amd64/bin/statsd
tar zcvf dist/statsd-$(version).darwin-amd64.tar.gz statsd-$(version).darwin-amd64
rm -rf statsd-$(version).darwin-amd64

mkdir -p statsd-${VERSION}.linux-amd64/bin
GOOS=linux GOARCH=amd64 go build -o statsd-${VERSION}.linux-amd64/bin/statsd
tar zcvf dist/statsd-${VERSION}.linux-amd64.tar.gz statsd-${VERSION}.linux-amd64
rm -rf statsd-${VERSION}.linux-amd64
mkdir -p statsd-$(version).linux-amd64/bin
GOOS=linux GOARCH=amd64 go build -o statsd-$(version).linux-amd64/bin/statsd
tar zcvf dist/statsd-$(version).linux-amd64.tar.gz statsd-$(version).linux-amd64
rm -rf statsd-$(version).linux-amd64
158 changes: 158 additions & 0 deletions librato.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math"
"net/http"
"sort"
)

type Measurement struct {
Counters []*Counter `json:"counters"`
Gauges []interface{} `json:"gauges"`
Source string `json:"source,omitempty"`
}

func (m *Measurement) Count() int {
return (len(m.Counters) + len(m.Gauges))
}

type Counter struct {
Name string `json:"name"`
Source string `json:"source,omitempty"`
Value float64 `json:"value"`
}

type Gauge struct {
Name string `json:"name"`
Source string `json:"source,omitempty"`
Value float64 `json:"value"`
}

type ComplexGauge struct {
Name string `json:"name"`
Source string `json:"source,omitempty"`
Count int `json:"count"`
Sum float64 `json:"sum"`
Min float64 `json:"min"`
Max float64 `json:"max"`
SumSquares float64 `json:"sum_squares"`
}

func submitLibrato() (err error) {
m := buildMeasurement()

if m.Count() == 0 {
return
}

payload, err := json.MarshalIndent(m, "", " ")
if err != nil {
return
}

if *debug {
log.Printf("sending payload:\n%s\n", string(payload))
}

req, err := http.NewRequest("POST", "https://metrics-api.librato.com/v1/metrics", bytes.NewBuffer(payload))
if err != nil {
return
}

req.Header.Add("Content-Type", "application/json")
req.Header.Set("User-Agent", "statsd/1.0")
req.SetBasicAuth(*libratoUser, *libratoToken)
req.Close = true

resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
raw, _ := ioutil.ReadAll(resp.Body)
return fmt.Errorf("%s: %s", resp.Status, string(raw))
}

log.Printf("%d measurements sent to librato\n", m.Count())

resetTimers()

return
}

func buildMeasurement() (m *Measurement) {
m = &Measurement{}
if libratoSource != nil {
m.Source = *libratoSource
}

m.Counters = make([]*Counter, len(counters))
m.Gauges = make([]interface{}, len(gauges))

n := 0
for k, v := range counters {
c := &Counter{}
c.Name, c.Source = parseSource(k)
c.Value = v
m.Counters[n] = c
n++
}

n = 0
for k, v := range gauges {
g := &Gauge{}
g.Name, g.Source = parseSource(k)
g.Value = v
m.Gauges[n] = g
n++
}

for k, t := range timers {
for _, pct := range tiles {
if g := buildComplexGauge(k, t, pct); g != nil {
m.Gauges = append(m.Gauges, g)
}
}
}

return
}

func buildComplexGauge(k string, t []float64, pct float64) *ComplexGauge {
threshold := ((100.0 - pct) / 100.0) * float64(len(t))
threshold = math.Floor(threshold + 0.5)

count := len(t) - int(threshold)
if count <= 0 {
return nil
}

g := &ComplexGauge{}
g.Name, g.Source = parseSource(k)
if pct != 100.0 {
if float64(int(pct)) != pct {
rem := int(math.Ceil((pct - float64(int(pct))) * 10))
g.Name += fmt.Sprintf(".%d_%d", int(pct), rem)
} else {
g.Name += fmt.Sprintf(".%d", int(pct))
}
}
g.Count = count

sort.Float64s(t)
g.Min = t[0]
g.Max = t[count-1]
for i := 0; i < count; i++ {
g.Sum += t[i]
g.SumSquares += (t[i] * t[i])
}

return g
}
Loading

0 comments on commit 3ab1f96

Please sign in to comment.