func testLogfQuiet(t *testing.T, vlogf bool) string { var buf bytes.Buffer log.SetOutput(&buf) start := time.Now() squelchTime := 100 * time.Millisecond vlog.SetSuppressDuration(squelchTime) for i := 0; i < 5; i++ { if vlogf { vlog.VLogfQuiet("", "Line 1 message %d", i) vlog.VLogfQuiet("", "Line 2 message %d", i) } else { vlog.LogfQuiet("", "Line 3 message %d", i) vlog.LogfQuiet("", "Line 4 message %d", i) } time.Sleep(10 * time.Millisecond) } time.Sleep(start.Add(110 * time.Millisecond).Sub(time.Now())) log.SetOutput(os.Stdout) return string(buf.Bytes()) }
// NewGangliaReporterWithOptions is NewGangliaReporter with the groupName. func NewGangliaReporterWithOptions(interval time.Duration, groupName string) *Reporter { gm, err := NewGmetric() if err != nil { vlog.VLogfQuiet("ganglia", "Couldn't start Ganglia reporter: %s", err) return nil } else if gm == nil { return nil } stopper := stopper.NewChanStopper() gr := &Reporter{ ChanStopper: stopper, prefix: "", callbacks: []ReporterCallback{}, previous: make(map[string]gmetricSample), groupName: groupName, dmax: 0, } go func() { defer stopper.Done() for { select { case <-stopper.Chan: return case <-time.After(interval): go func() { // SendMetric "opens" and "closes" UDP connections each // time, but since we expect the callback to send several // metrics at once, avoid that here. conns := gm.OpenConnections() n := 0 sender := func(name string, value string, metricType uint32, units string, rate bool) { v := value if rate { prev, exists := gr.previous[name] units += "/sec" now := time.Now() switch metricType { case Ushort, Short, Uint, Int: i, err := strconv.Atoi(value) if err != nil { vlog.VLogfQuiet(name, "Value %q doesn't look like an int: %s", value, err) return } gr.previous[name] = gmetricSample{i, now} if !exists { return } delta := i - prev.value.(int) elapsed := time.Now().Sub(prev.when).Seconds() v = fmt.Sprint(float64(delta) / elapsed) // upgrade to a float to avoid loss of precision metricType = Float case Float, Double: f, err := strconv.ParseFloat(value, 64) if err != nil { vlog.VLogfQuiet(name, "Value %q doesn't look like a float: %s", value, err) return } gr.previous[name] = gmetricSample{f, now} if !exists { return } delta := f - prev.value.(float64) elapsed := time.Now().Sub(prev.when).Seconds() v = fmt.Sprint(delta / elapsed) case String: vlog.VLogfQuiet(name, "Can't compute deltas for string metric %q", value) return } } // gmetad fails to escape quotes, eventually generating // invalid xml. do it here as a workaround. v = html.EscapeString(v) name = html.EscapeString(name) units = html.EscapeString(units) n++ gm.SendMetricPackets( gr.prefix+name, v, metricType, units, gmetric.SLOPE_BOTH, uint32(interval.Seconds()), // tmax is the expected reporting interval gr.dmax, gr.groupName, gmetric.PACKET_BOTH, conns, ) if debug.On() { if rate { log.Printf("gmetric: name=%q, rate=%q, value=%q, type=%d, units=%q, slope=%d, tmax=%d, dmax=%v, group=%q, packet=%d", gr.prefix+name, v, value, metricType, units, gmetric.SLOPE_BOTH, uint32(interval.Seconds()), gr.dmax, gr.groupName, gmetric.PACKET_BOTH, ) } else { log.Printf("gmetric: name=%q, value=%q, type=%d, units=%q, slope=%d, tmax=%d, dmax=%v, group=%q, packet=%d", gr.prefix+name, v, metricType, units, gmetric.SLOPE_BOTH, uint32(interval.Seconds()), gr.dmax, gr.groupName, gmetric.PACKET_BOTH, ) } } } defer gm.CloseConnections(conns) for _, callback := range gr.callbacks { callback(sender) } if debug.On() { log.Printf("Published %d metrics to Ganglia", n) } }() } } }() return gr }