コード例 #1
0
ファイル: statsdaemon.go プロジェクト: rugby110/statsdaemon
// submit basically invokes the processing function (instrumented) and tries to buffer to graphite
func (s *StatsDaemon) submit(c *counters.Counters, g *gauges.Gauges, t *timers.Timers, deadline time.Time) error {
	var buffer bytes.Buffer

	now := time.Now().Unix()

	// TODO: in future, buffer up data (with a TTL/max size) and submit later
	client, err := net.Dial("tcp", s.graphite_addr)
	if err != nil {
		c.Process(&buffer, now, s.flushInterval)
		g.Process(&buffer, now, s.flushInterval)
		t.Process(&buffer, now, s.flushInterval)
		errmsg := fmt.Sprintf("dialing %s failed - %s", s.graphite_addr, err.Error())
		return errors.New(errmsg)
	}
	defer client.Close()

	err = client.SetDeadline(deadline)
	if err != nil {
		errmsg := fmt.Sprintf("could not set deadline - %s", err.Error())
		return errors.New(errmsg)
	}
	s.instrument(c, &buffer, now, "counter")
	s.instrument(g, &buffer, now, "gauge")
	s.instrument(t, &buffer, now, "timer")

	if s.debug {
		for _, line := range bytes.Split(buffer.Bytes(), []byte("\n")) {
			if len(line) == 0 {
				continue
			}
			log.Printf("DEBUG: WRITING %s", line)
		}
	}

	time_start := time.Now()
	_, err = client.Write(buffer.Bytes())
	if err != nil {
		errmsg := fmt.Sprintf("failed to write stats - %s", err)
		return errors.New(errmsg)
	}
	time_end := time.Now()
	duration_ms := float64(time_end.Sub(time_start).Nanoseconds()) / float64(1000000)
	if s.debug {
		log.Println("submit() successfully finished")
	}

	buffer.Reset()
	fmt.Fprintf(&buffer, "%starget_type_is_gauge.type_is_send.unit_is_ms %f %d\n", s.prefix, duration_ms, now)
	_, err = client.Write(buffer.Bytes())
	if err != nil {
		errmsg := fmt.Sprintf("failed to write target_type_is_gauge.type_is_send.unit_is_ms - %s", err)
		return errors.New(errmsg)
	}

	return nil
}
コード例 #2
0
ファイル: statsdaemon.go プロジェクト: rugby110/statsdaemon
// metricsMonitor basically guards the metrics datastructures.
// it typically receives metrics on the Metrics channel but also responds to
// external signals and every flushInterval, computes and flushes the data
func (s *StatsDaemon) metricsMonitor() {
	period := time.Duration(s.flushInterval) * time.Second
	tick := ticker.GetAlignedTicker(period)

	var c *counters.Counters
	var g *gauges.Gauges
	var t *timers.Timers

	initializeCounters := func() {
		c = counters.New(s.prefix_rates)
		g = gauges.New(s.prefix_gauges)
		t = timers.New(s.prefix_timers, s.pct)
		for _, name := range []string{"timer", "gauge", "counter"} {
			c.Add(&common.Metric{
				Bucket:   fmt.Sprintf("%sdirection_is_in.statsd_type_is_%s.target_type_is_count.unit_is_Metric", s.prefix, name),
				Sampling: 1,
			})
		}
	}
	initializeCounters()
	for {
		select {
		case sig := <-s.signalchan:
			switch sig {
			case syscall.SIGTERM, syscall.SIGINT:
				fmt.Printf("!! Caught signal %s... shutting down\n", sig)
				if err := s.submit(c, g, t, time.Now().Add(period)); err != nil {
					log.Printf("ERROR: %s", err)
				}
				return
			default:
				fmt.Printf("unknown signal %s, ignoring\n", sig)
			}
		case <-tick.C:
			go func(c *counters.Counters, g *gauges.Gauges, t *timers.Timers) {
				if err := s.submit(c, g, t, time.Now().Add(period)); err != nil {
					log.Printf("ERROR: %s", err)
				}
				s.events.Broadcast <- "flush"
			}(c, g, t)
			initializeCounters()
			tick = ticker.GetAlignedTicker(period)
		case m := <-s.Metrics:
			var name string
			if m.Modifier == "ms" {
				t.Add(m)
				name = "timer"
			} else if m.Modifier == "g" {
				g.Add(m)
				name = "gauge"
			} else {
				c.Add(m)
				name = "counter"
			}
			c.Add(&common.Metric{
				Bucket:   fmt.Sprintf("%sdirection_is_in.statsd_type_is_%s.target_type_is_count.unit_is_Metric", s.prefix, name),
				Value:    1,
				Sampling: 1,
			})
		}
	}
}