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)
		}
	}
}
Exemple #3
0
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
}
Exemple #4
0
// 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
}
Exemple #5
0
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)
		}
	}
}
Exemple #7
0
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
		}
	}
}
Exemple #8
0
func init() {
	// err from NewNoop is always nil
	stats, _ = statsd.NewNoop()
}