func BenchmarkRequests(b *testing.B) { c, _ := statsd.NewNoop() SpadeHandler := &SpadeHandler{ EdgeLogger: &testEdgeLogger{}, Assigner: Assigner, StatLogger: c, } reqGet, err := http.NewRequest("GET", "http://spade.twitch.tv/?data=blah", nil) if err != nil { b.Fatalf("Failed to build request error: %s\n", err) } reqGet.Header.Add("X-Forwarded-For", "222.222.222.222") reqPost, err := http.NewRequest("POST", "http://spade.twitch.tv/", strings.NewReader("data=blah")) if err != nil { b.Fatalf("Failed to build request error: %s\n", err) } reqPost.Header.Add("X-Forwarded-For", "222.222.222.222") testrecorder := httptest.NewRecorder() b.ResetTimer() isProd = true for i := 0; i < b.N; i++ { if i%2 == 0 { SpadeHandler.ServeHTTP(testrecorder, reqPost) } else { SpadeHandler.ServeHTTP(testrecorder, reqGet) } } b.ReportAllocs() }
func TestEndPoints(t *testing.T) { c, _ := statsd.NewNoop() SpadeHandler := &SpadeHandler{ EdgeLogger: &testEdgeLogger{}, Assigner: &testUUIDAssigner{}, StatLogger: c, } var expectedEvents []spade.Event fixedIP := net.ParseIP("222.222.222.222") fixedTime, _ := time.Parse(time.RFC3339, "2014-05-02T19:34:01+00:00") uuidCounter := 1 for _, tt := range testRequests { testrecorder := httptest.NewRecorder() req, err := http.NewRequest( tt.Request.Verb, "http://spade.twitch.tv/"+tt.Request.Endpoint, strings.NewReader(tt.Request.Body), ) if err != nil { t.Fatalf("Failed to build request: %s error: %s\n", tt.Request.Endpoint, err) } req.Header.Add("X-Forwarded-For", "222.222.222.222") req.Header.Add("X-Original-Msec", "1399059241.000") if tt.Request.ContentType != "" { req.Header.Add("Content-Type", tt.Request.ContentType) } SpadeHandler.ServeHTTP(testrecorder, req) if testrecorder.Code != tt.Response.Code { t.Fatalf("%s expected code %d not %d\n", tt.Request.Endpoint, tt.Response.Code, testrecorder.Code) } if testrecorder.Body.String() != tt.Response.Body { t.Fatalf("%s expected body %s not %s\n", tt.Request.Endpoint, tt.Response.Body, testrecorder.Body.String()) } if tt.Expectation != "" { expectedEvents = append(expectedEvents, spade.Event{ ReceivedAt: fixedTime.UTC(), ClientIp: fixedIP, Uuid: fmt.Sprintf("%d", uuidCounter), Data: tt.Expectation, Version: 2, }) uuidCounter++ } } for idx, byteLog := range SpadeHandler.EdgeLogger.(*testEdgeLogger).events { var ev spade.Event err := spade.Unmarshal(byteLog, &ev) if err != nil { t.Errorf("Expected Unmarshal to work, input: %s, err:%s", byteLog, err) } if !reflect.DeepEqual(ev, expectedEvents[idx]) { t.Errorf("Event processed incorrectly: expected:%s got:%s", expectedEvents[idx], ev) } } }
func initStatsd(statsPrefix, statsdHostport string) (stats statsd.Statter, err error) { if statsdHostport == "" { stats, _ = statsd.NewNoop() } else { if stats, err = statsd.New(statsdHostport, *stats_prefix); err != nil { log.Fatalf("Statsd configuration error: %v", err) } } return }
// NewService creates a new service given a unique name. // If no configuration is specified (nil), defaults values are used. func NewService(name string, c *ServiceConfig) (*Service, error) { var err error if c == nil { c = new(ServiceConfig) } if c.PrespawnConns == 0 { c.PrespawnConns = DefaultPrespawnConns } if c.GetAttempts == 0 { c.GetAttempts = DefaultGetAttempts } if c.CloseDeadline == 0 { c.CloseDeadline = DefaultCloseDeadline } if c.DecayDuration == 0 { c.DecayDuration = DefaultDecayDuration } if c.MemoizeScoreDuration == 0 { c.MemoizeScoreDuration = DefaultMemoizeScoreDuration } if c.BanditStrategy == nil { c.BanditStrategy = NewRoundRobin() } s := &Service{ ServiceConfig: c, name: name, hosts: make(map[string]*Host), add: make(chan string), rm: make(chan string), stop: make(chan struct{}), } if _, ok := s.BanditStrategy.(*RoundRobin); !ok { s.decay = time.NewTicker(c.DecayDuration / seriesNum) s.memoize = time.NewTicker(c.MemoizeScoreDuration) } if c.StatsdAddr != "" { s.stats, err = statsd.New(c.StatsdAddr, "service."+name) if err != nil { return nil, err } } if s.stats == nil { s.stats, _ = statsd.NewNoop() } else { runtime.SetFinalizer(s.stats, func(s statsd.Statter) { s.Close() }) s.stats.Gauge("conns.count", 0, sampleRate) s.stats.Gauge("hosts.count", 0, sampleRate) go s.monitor() } go s.serve() return s, nil }
func InitStats(statsPrefix string) (stats Stats, err error) { // Set up statsd monitoring // - If the env is not set up we wil use a noop connection statsdHostport := os.Getenv("STATSD_HOSTPORT") if statsdHostport == "" { // Error is meaningless here. stats, _ = statsd.NewNoop(statsdHostport, statsPrefix) } else { if stats, err = statsd.New(statsdHostport, statsPrefix); err != nil { return } log.Printf("Connected to statsd at %s\n", statsdHostport) } return }
func TestHandle(t *testing.T) { c, _ := statsd.NewNoop() SpadeHandler := &SpadeHandler{ EdgeLogger: &testEdgeLogger{}, Assigner: &testUUIDAssigner{}, StatLogger: c, } for _, tt := range testRequests { testrecorder := httptest.NewRecorder() req, err := http.NewRequest( tt.Request.Verb, "http://spade.example.com/"+tt.Request.Endpoint, strings.NewReader(tt.Request.Body), ) if err != nil { t.Fatalf("Failed to build request: %s error: %s\n", tt.Request.Endpoint, err) } req.Header.Add("X-Forwarded-For", "222.222.222.222") req.Header.Add("X-Original-Msec", "1399059241.000") if tt.Request.ContentType != "" { req.Header.Add("Content-Type", tt.Request.ContentType) } context := &requestContext{ Now: epoch, Method: req.Method, Endpoint: req.URL.Path, IpHeader: ipForwardHeader, Timers: make(map[string]time.Duration, nTimers), } status := SpadeHandler.serve(testrecorder, req, context) if status != tt.Response.Code { t.Fatalf("%s expected code %d not %d\n", tt.Request.Endpoint, tt.Response.Code, testrecorder.Code) } } }
func main() { // command line flags var opts struct { HostPort string `long:"host" default:"127.0.0.1:8125" description:"host:port of statsd server"` Prefix string `long:"prefix" default:"test-client" description:"Statsd prefix"` StatType string `long:"type" default:"count" description:"stat type to send. Can be timing, count, guage"` StatValue int64 `long:"value" default:"1" description:"Value to send"` Name string `short:"n" long:"name" default:"counter" description:"stat name"` Rate float32 `short:"r" long:"rate" default:"1.0" description:"sample rate"` Volume int `short:"c" long:"count" default:"1000" description:"Number of stats to send. Volume."` Noop bool `long:"noop" default:"false" description:"Use noop client"` Duration time.Duration `short:"d" long:"duration" default:"10s" description:"How long to spread the volume across. Each second of duration volume/seconds events will be sent."` } // parse said flags _, err := flags.Parse(&opts) if err != nil { if e, ok := err.(*flags.Error); ok { if e.Type == flags.ErrHelp { os.Exit(0) } } fmt.Printf("Error: %+v\n", err) os.Exit(1) } var client statsd.Statter if !opts.Noop { client, err = statsd.New(opts.HostPort, opts.Prefix) if err != nil { log.Fatal(err) } defer client.Close() } else { client, err = statsd.NewNoop(opts.HostPort, opts.Prefix) } var stat func(stat string, value int64, rate float32) error switch opts.StatType { case "count": stat = func(stat string, value int64, rate float32) error { return client.Inc(stat, value, rate) } case "gauge": stat = func(stat string, value int64, rate float32) error { return client.Gauge(stat, value, rate) } case "timing": stat = func(stat string, value int64, rate float32) error { return client.Timing(stat, value, rate) } default: log.Fatal("Unsupported state type") } pertick := opts.Volume / int(opts.Duration.Seconds()) / 10 // add some extra tiem, because the first tick takes a while ender := time.After(opts.Duration + 100*time.Millisecond) c := time.Tick(time.Second / 10) count := 0 for { select { case <-c: for x := 0; x < pertick; x++ { err := stat(opts.Name, opts.StatValue, opts.Rate) if err != nil { log.Printf("Got Error: %+v", err) break } count += 1 } case <-ender: log.Printf("%d events called", count) os.Exit(0) return } } }
func init() { // err from NewNoop is always nil stats, _ = statsd.NewNoop() }