// Emit errors as `error.$event-name` func EmitError(stats statsd.Statter, eventName string) (err error) { eventName = CleanStatsdComponent(eventName) if stats != nil { err = stats.Inc(StatsdEventName("error", eventName), 1, StatsSampleRate) } return }
func timedHandler(fn func(w http.ResponseWriter, r *http.Request), stats statsd.Statter) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() fn(w, r) stats.TimingDuration("request", time.Since(start), 1) } }
// Emit stop signals as `stop.$signal` func EmitStopSignal(stats statsd.Statter, signal string) (err error) { signal = CleanStatsdComponent(signal) if stats != nil { err = stats.Inc(StatsdEventName("stop", signal), 1, StatsSampleRate) } return }
// Emit successful actions as `$action.success.$event-name` func EmitActionSuccessTiming(stats statsd.Statter, action, eventName string, took time.Duration) (err error) { action = CleanStatsdComponent(action) eventName = CleanStatsdComponent(eventName) if stats != nil { err = stats.TimingDuration(StatsdEventName(action, eventName), took, StatsSampleRate) } return }
// Emit successful actions as `$action.success.$event-name` func EmitActionSuccess(stats statsd.Statter, action, eventName string) (err error) { action = CleanStatsdComponent(action) eventName = CleanStatsdComponent(eventName) if stats != nil { err = stats.Inc(StatsdEventName("success", action, eventName), 1, StatsSampleRate) } return }
func send_gauge(client statsd.Statter, v []string, name string, position int64) { stat := fmt.Sprint(v[0], ".", name) value, _ := strconv.ParseInt(v[position], 10, 64) fmt.Println(fmt.Sprint(stat, ":", value, "|g")) err := client.Gauge(stat, value, 1.0) if err != nil { log.Printf("Error sending metric: %+v", err) } }
func send_counter(previous int64, client statsd.Statter, v []string, name string, position int64) { stat := fmt.Sprint(v[0], ".", name) value_at_interval, _ := strconv.ParseInt(v[position], 10, 64) value := value_at_interval - previous fmt.Println(fmt.Sprint(stat, ":", value, "|c")) err := client.Inc(stat, value, 1) if err != nil { log.Printf("Error sending metric: %+v", err) } }
func pushMem(client statsd.Statter, mem Mem) error { var err error err = client.Gauge("mem.resident", mem.Resident, 1.0) if err != nil { return err } err = client.Gauge("mem.virtual", mem.Virtual, 1.0) if err != nil { return err } err = client.Gauge("mem.mapped", mem.Mapped, 1.0) if err != nil { return err } err = client.Gauge("mem.mapped_with_journal", mem.MappedWithJournal, 1.0) if err != nil { return err } return nil }
func (r *requestContext) recordStats(statter statsd.Statter) { prefix := strings.Join([]string{ r.Method, strings.Replace(r.Endpoint, ".", "_", -1), strconv.Itoa(r.Status), }, ".") for stat, duration := range r.Timers { statter.Timing(prefix+"."+stat, duration.Nanoseconds(), 0.1) } if r.BadClient { // We expect these to be infrequent. We may want to decreate this // if it turns out not to be the case statter.Inc("bad_client", 1, 1.0) } }
func pushExtraInfo(client statsd.Statter, info ExtraInfo) error { var err error err = client.Gauge("extra.page_faults", info.PageFaults, 1.0) if err != nil { return err } err = client.Gauge("extra.heap_usage", info.HeapUsageInBytes, 1.0) if err != nil { return err } return nil }
func test(target string, s statsd.Statter, debug bool) { tuple := strings.Split(target, ":") host := tuple[0] port := tuple[1] subhost := strings.Replace(host, ".", "_", -1) pre := time.Now() conn, err := net.Dial("tcp", target) if err != nil { if debug { fmt.Println("connect error:", subhost, port) } s.Inc(fmt.Sprintf("%s.%s.dial_failed", subhost, port), 1, 1) return } conn.Close() duration := time.Since(pre) ms := int64(duration / time.Millisecond) if debug { fmt.Printf("%s.%s.duration %d\n", subhost, port, ms) } s.Timing(fmt.Sprintf("%s.%s", subhost, port), ms, 1) }
func pushConnections(client statsd.Statter, connections Connections) error { var err error // Connections err = client.Gauge("connections.current", int64(connections.Current), 1.0) if err != nil { return err } err = client.Gauge("connections.available", int64(connections.Available), 1.0) if err != nil { return err } err = client.Gauge("connections.created", int64(connections.TotalCreated), 1.0) if err != nil { return err } return nil }
// Emit reloads as `reload` func EmitReload(stats statsd.Statter) (err error) { if stats != nil { err = stats.Inc(StatsdEventName("reload"), 1, StatsSampleRate) } return }
// NewAmqpRPCClient constructs an RPC client using AMQP func NewAmqpRPCClient( clientQueuePrefix string, amqpConf *cmd.AMQPConfig, rpcConf *cmd.RPCServerConfig, stats statsd.Statter, ) (rpc *AmqpRPCCLient, err error) { hostname, err := os.Hostname() if err != nil { return nil, err } randID := make([]byte, 3) _, err = rand.Read(randID) if err != nil { return nil, err } clientQueue := fmt.Sprintf("%s.%s.%x", clientQueuePrefix, hostname, randID) reconnectBase := amqpConf.ReconnectTimeouts.Base.Duration if reconnectBase == 0 { reconnectBase = 20 * time.Millisecond } reconnectMax := amqpConf.ReconnectTimeouts.Max.Duration if reconnectMax == 0 { reconnectMax = time.Minute } timeout := rpcConf.RPCTimeout.Duration if timeout == 0 { timeout = 10 * time.Second } rpc = &AmqpRPCCLient{ serverQueue: rpcConf.Server, clientQueue: clientQueue, connection: newAMQPConnector(clientQueue, reconnectBase, reconnectMax), pending: make(map[string]chan []byte), timeout: timeout, log: blog.Get(), stats: stats, } err = rpc.connection.connect(amqpConf) if err != nil { return nil, err } go func() { for { select { case msg, ok := <-rpc.connection.messages(): if ok { corrID := msg.CorrelationId rpc.mu.RLock() responseChan, present := rpc.pending[corrID] rpc.mu.RUnlock() if !present { // occurs when a request is timed out and the arrives // afterwards stats.Inc("RPC.AfterTimeoutResponseArrivals."+clientQueuePrefix, 1, 1.0) continue } responseChan <- msg.Body rpc.mu.Lock() delete(rpc.pending, corrID) rpc.mu.Unlock() } else { // chan has been closed by rpc.connection.Cancel rpc.log.Info(fmt.Sprintf(" [!] Client reply channel closed: %s", rpc.clientQueue)) continue } case err = <-rpc.connection.closeChannel(): rpc.log.Info(fmt.Sprintf(" [!] Client reply channel closed : %s", rpc.clientQueue)) rpc.connection.reconnect(amqpConf, rpc.log) } } }() return rpc, err }
func sendGauges(client statsd.Statter, gauges map[string]int64) { for gauge, value := range gauges { client.Gauge(gauge, value, 1.0) } }
func pushOpcounters(client statsd.Statter, opscounters Opcounters) error { var err error // Ops Counters (non-RS) err = client.Gauge("ops.inserts", opscounters.Insert, 1.0) if err != nil { return err } err = client.Gauge("ops.queries", opscounters.Query, 1.0) if err != nil { return err } err = client.Gauge("ops.updates", opscounters.Update, 1.0) if err != nil { return err } err = client.Gauge("ops.deletes", opscounters.Delete, 1.0) if err != nil { return err } err = client.Gauge("ops.getmores", opscounters.GetMore, 1.0) if err != nil { return err } err = client.Gauge("ops.commands", opscounters.Command, 1.0) if err != nil { return err } return nil }
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 pushGlobalLocks(client statsd.Statter, glob GlobalLock) error { var err error err = client.Gauge("global_lock.total_time", glob.TotalTime, 1.0) if err != nil { return err } err = client.Gauge("global_lock.lock_time", glob.LockTime, 1.0) if err != nil { return err } err = client.Gauge("global_lock.active_readers", glob.ActiveClients.Readers, 1.0) if err != nil { return err } err = client.Gauge("global_lock.active_writers", glob.ActiveClients.Writers, 1.0) if err != nil { return err } err = client.Gauge("global_lock.active_total", glob.ActiveClients.Total, 1.0) if err != nil { return err } err = client.Gauge("global_lock.queued_readers", glob.CurrentQueue.Readers, 1.0) if err != nil { return err } err = client.Gauge("global_lock.queued_writers", glob.CurrentQueue.Writers, 1.0) if err != nil { return err } err = client.Gauge("global_lock.queued_total", glob.CurrentQueue.Total, 1.0) if err != nil { return err } return nil }
func sendCounters(client statsd.Statter, counters map[string]int64) { for counter, value := range counters { client.Inc(counter, value, 1.0) } }
// ProfileCmd runs forever, sending Go runtime statistics to StatsD. func ProfileCmd(stats statsd.Statter) { c := time.Tick(1 * time.Second) for range c { var memoryStats runtime.MemStats runtime.ReadMemStats(&memoryStats) stats.Gauge("Gostats.Goroutines", int64(runtime.NumGoroutine()), 1.0) stats.Gauge("Gostats.Heap.Alloc", int64(memoryStats.HeapAlloc), 1.0) stats.Gauge("Gostats.Heap.Objects", int64(memoryStats.HeapObjects), 1.0) stats.Gauge("Gostats.Heap.Idle", int64(memoryStats.HeapIdle), 1.0) stats.Gauge("Gostats.Heap.InUse", int64(memoryStats.HeapInuse), 1.0) stats.Gauge("Gostats.Heap.Released", int64(memoryStats.HeapReleased), 1.0) // Calculate average and last and convert from nanoseconds to milliseconds gcPauseAvg := (int64(memoryStats.PauseTotalNs) / int64(len(memoryStats.PauseNs))) / 1000000 lastGC := int64(memoryStats.PauseNs[(memoryStats.NumGC+255)%256]) / 1000000 stats.Timing("Gostats.Gc.PauseAvg", gcPauseAvg, 1.0) stats.Gauge("Gostats.Gc.LastPauseTook", lastGC, 1.0) stats.Gauge("Gostats.Gc.NextAt", int64(memoryStats.NextGC), 1.0) } }