271 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| package beanstalkd
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/textproto"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/influxdata/telegraf"
 | |
| 	"github.com/influxdata/telegraf/plugins/inputs"
 | |
| 	"gopkg.in/yaml.v2"
 | |
| )
 | |
| 
 | |
| const sampleConfig = `
 | |
|   ## Server to collect data from
 | |
|   server = "localhost:11300"
 | |
| 
 | |
|   ## List of tubes to gather stats about.
 | |
|   ## If no tubes specified then data gathered for each tube on server reported by list-tubes command
 | |
|   tubes = ["notifications"]
 | |
| `
 | |
| 
 | |
| type Beanstalkd struct {
 | |
| 	Server string   `toml:"server"`
 | |
| 	Tubes  []string `toml:"tubes"`
 | |
| }
 | |
| 
 | |
| func (b *Beanstalkd) Description() string {
 | |
| 	return "Collects Beanstalkd server and tubes stats"
 | |
| }
 | |
| 
 | |
| func (b *Beanstalkd) SampleConfig() string {
 | |
| 	return sampleConfig
 | |
| }
 | |
| 
 | |
| func (b *Beanstalkd) Gather(acc telegraf.Accumulator) error {
 | |
| 	connection, err := textproto.Dial("tcp", b.Server)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer connection.Close()
 | |
| 
 | |
| 	tubes := b.Tubes
 | |
| 	if len(tubes) == 0 {
 | |
| 		err = runQuery(connection, "list-tubes", &tubes)
 | |
| 		if err != nil {
 | |
| 			acc.AddError(err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	var wg sync.WaitGroup
 | |
| 
 | |
| 	wg.Add(1)
 | |
| 	go func() {
 | |
| 		err := b.gatherServerStats(connection, acc)
 | |
| 		if err != nil {
 | |
| 			acc.AddError(err)
 | |
| 		}
 | |
| 		wg.Done()
 | |
| 	}()
 | |
| 
 | |
| 	for _, tube := range tubes {
 | |
| 		wg.Add(1)
 | |
| 		go func(tube string) {
 | |
| 			b.gatherTubeStats(connection, tube, acc)
 | |
| 			wg.Done()
 | |
| 		}(tube)
 | |
| 	}
 | |
| 
 | |
| 	wg.Wait()
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (b *Beanstalkd) gatherServerStats(connection *textproto.Conn, acc telegraf.Accumulator) error {
 | |
| 	stats := new(statsResponse)
 | |
| 	if err := runQuery(connection, "stats", stats); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	acc.AddFields("beanstalkd_overview",
 | |
| 		map[string]interface{}{
 | |
| 			"binlog_current_index":     stats.BinlogCurrentIndex,
 | |
| 			"binlog_max_size":          stats.BinlogMaxSize,
 | |
| 			"binlog_oldest_index":      stats.BinlogOldestIndex,
 | |
| 			"binlog_records_migrated":  stats.BinlogRecordsMigrated,
 | |
| 			"binlog_records_written":   stats.BinlogRecordsWritten,
 | |
| 			"cmd_bury":                 stats.CmdBury,
 | |
| 			"cmd_delete":               stats.CmdDelete,
 | |
| 			"cmd_ignore":               stats.CmdIgnore,
 | |
| 			"cmd_kick":                 stats.CmdKick,
 | |
| 			"cmd_list_tube_used":       stats.CmdListTubeUsed,
 | |
| 			"cmd_list_tubes":           stats.CmdListTubes,
 | |
| 			"cmd_list_tubes_watched":   stats.CmdListTubesWatched,
 | |
| 			"cmd_pause_tube":           stats.CmdPauseTube,
 | |
| 			"cmd_peek":                 stats.CmdPeek,
 | |
| 			"cmd_peek_buried":          stats.CmdPeekBuried,
 | |
| 			"cmd_peek_delayed":         stats.CmdPeekDelayed,
 | |
| 			"cmd_peek_ready":           stats.CmdPeekReady,
 | |
| 			"cmd_put":                  stats.CmdPut,
 | |
| 			"cmd_release":              stats.CmdRelease,
 | |
| 			"cmd_reserve":              stats.CmdReserve,
 | |
| 			"cmd_reserve_with_timeout": stats.CmdReserveWithTimeout,
 | |
| 			"cmd_stats":                stats.CmdStats,
 | |
| 			"cmd_stats_job":            stats.CmdStatsJob,
 | |
| 			"cmd_stats_tube":           stats.CmdStatsTube,
 | |
| 			"cmd_touch":                stats.CmdTouch,
 | |
| 			"cmd_use":                  stats.CmdUse,
 | |
| 			"cmd_watch":                stats.CmdWatch,
 | |
| 			"current_connections":      stats.CurrentConnections,
 | |
| 			"current_jobs_buried":      stats.CurrentJobsBuried,
 | |
| 			"current_jobs_delayed":     stats.CurrentJobsDelayed,
 | |
| 			"current_jobs_ready":       stats.CurrentJobsReady,
 | |
| 			"current_jobs_reserved":    stats.CurrentJobsReserved,
 | |
| 			"current_jobs_urgent":      stats.CurrentJobsUrgent,
 | |
| 			"current_producers":        stats.CurrentProducers,
 | |
| 			"current_tubes":            stats.CurrentTubes,
 | |
| 			"current_waiting":          stats.CurrentWaiting,
 | |
| 			"current_workers":          stats.CurrentWorkers,
 | |
| 			"job_timeouts":             stats.JobTimeouts,
 | |
| 			"max_job_size":             stats.MaxJobSize,
 | |
| 			"pid":                      stats.Pid,
 | |
| 			"rusage_stime":             stats.RusageStime,
 | |
| 			"rusage_utime":             stats.RusageUtime,
 | |
| 			"total_connections":        stats.TotalConnections,
 | |
| 			"total_jobs":               stats.TotalJobs,
 | |
| 			"uptime":                   stats.Uptime,
 | |
| 		},
 | |
| 		map[string]string{
 | |
| 			"hostname": stats.Hostname,
 | |
| 			"id":       stats.Id,
 | |
| 			"server":   b.Server,
 | |
| 			"version":  stats.Version,
 | |
| 		},
 | |
| 	)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (b *Beanstalkd) gatherTubeStats(connection *textproto.Conn, tube string, acc telegraf.Accumulator) error {
 | |
| 	stats := new(statsTubeResponse)
 | |
| 	if err := runQuery(connection, "stats-tube "+tube, stats); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	acc.AddFields("beanstalkd_tube",
 | |
| 		map[string]interface{}{
 | |
| 			"cmd_delete":            stats.CmdDelete,
 | |
| 			"cmd_pause_tube":        stats.CmdPauseTube,
 | |
| 			"current_jobs_buried":   stats.CurrentJobsBuried,
 | |
| 			"current_jobs_delayed":  stats.CurrentJobsDelayed,
 | |
| 			"current_jobs_ready":    stats.CurrentJobsReady,
 | |
| 			"current_jobs_reserved": stats.CurrentJobsReserved,
 | |
| 			"current_jobs_urgent":   stats.CurrentJobsUrgent,
 | |
| 			"current_using":         stats.CurrentUsing,
 | |
| 			"current_waiting":       stats.CurrentWaiting,
 | |
| 			"current_watching":      stats.CurrentWatching,
 | |
| 			"pause":                 stats.Pause,
 | |
| 			"pause_time_left":       stats.PauseTimeLeft,
 | |
| 			"total_jobs":            stats.TotalJobs,
 | |
| 		},
 | |
| 		map[string]string{
 | |
| 			"name":   stats.Name,
 | |
| 			"server": b.Server,
 | |
| 		},
 | |
| 	)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func runQuery(connection *textproto.Conn, cmd string, result interface{}) error {
 | |
| 	requestId, err := connection.Cmd(cmd)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	connection.StartResponse(requestId)
 | |
| 	defer connection.EndResponse(requestId)
 | |
| 
 | |
| 	status, err := connection.ReadLine()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	size := 0
 | |
| 	if _, err = fmt.Sscanf(status, "OK %d", &size); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	body := make([]byte, size+2)
 | |
| 	if _, err = io.ReadFull(connection.R, body); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return yaml.Unmarshal(body, result)
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	inputs.Add("beanstalkd", func() telegraf.Input {
 | |
| 		return &Beanstalkd{}
 | |
| 	})
 | |
| }
 | |
| 
 | |
| type statsResponse struct {
 | |
| 	BinlogCurrentIndex    int     `yaml:"binlog-current-index"`
 | |
| 	BinlogMaxSize         int     `yaml:"binlog-max-size"`
 | |
| 	BinlogOldestIndex     int     `yaml:"binlog-oldest-index"`
 | |
| 	BinlogRecordsMigrated int     `yaml:"binlog-records-migrated"`
 | |
| 	BinlogRecordsWritten  int     `yaml:"binlog-records-written"`
 | |
| 	CmdBury               int     `yaml:"cmd-bury"`
 | |
| 	CmdDelete             int     `yaml:"cmd-delete"`
 | |
| 	CmdIgnore             int     `yaml:"cmd-ignore"`
 | |
| 	CmdKick               int     `yaml:"cmd-kick"`
 | |
| 	CmdListTubeUsed       int     `yaml:"cmd-list-tube-used"`
 | |
| 	CmdListTubes          int     `yaml:"cmd-list-tubes"`
 | |
| 	CmdListTubesWatched   int     `yaml:"cmd-list-tubes-watched"`
 | |
| 	CmdPauseTube          int     `yaml:"cmd-pause-tube"`
 | |
| 	CmdPeek               int     `yaml:"cmd-peek"`
 | |
| 	CmdPeekBuried         int     `yaml:"cmd-peek-buried"`
 | |
| 	CmdPeekDelayed        int     `yaml:"cmd-peek-delayed"`
 | |
| 	CmdPeekReady          int     `yaml:"cmd-peek-ready"`
 | |
| 	CmdPut                int     `yaml:"cmd-put"`
 | |
| 	CmdRelease            int     `yaml:"cmd-release"`
 | |
| 	CmdReserve            int     `yaml:"cmd-reserve"`
 | |
| 	CmdReserveWithTimeout int     `yaml:"cmd-reserve-with-timeout"`
 | |
| 	CmdStats              int     `yaml:"cmd-stats"`
 | |
| 	CmdStatsJob           int     `yaml:"cmd-stats-job"`
 | |
| 	CmdStatsTube          int     `yaml:"cmd-stats-tube"`
 | |
| 	CmdTouch              int     `yaml:"cmd-touch"`
 | |
| 	CmdUse                int     `yaml:"cmd-use"`
 | |
| 	CmdWatch              int     `yaml:"cmd-watch"`
 | |
| 	CurrentConnections    int     `yaml:"current-connections"`
 | |
| 	CurrentJobsBuried     int     `yaml:"current-jobs-buried"`
 | |
| 	CurrentJobsDelayed    int     `yaml:"current-jobs-delayed"`
 | |
| 	CurrentJobsReady      int     `yaml:"current-jobs-ready"`
 | |
| 	CurrentJobsReserved   int     `yaml:"current-jobs-reserved"`
 | |
| 	CurrentJobsUrgent     int     `yaml:"current-jobs-urgent"`
 | |
| 	CurrentProducers      int     `yaml:"current-producers"`
 | |
| 	CurrentTubes          int     `yaml:"current-tubes"`
 | |
| 	CurrentWaiting        int     `yaml:"current-waiting"`
 | |
| 	CurrentWorkers        int     `yaml:"current-workers"`
 | |
| 	Hostname              string  `yaml:"hostname"`
 | |
| 	Id                    string  `yaml:"id"`
 | |
| 	JobTimeouts           int     `yaml:"job-timeouts"`
 | |
| 	MaxJobSize            int     `yaml:"max-job-size"`
 | |
| 	Pid                   int     `yaml:"pid"`
 | |
| 	RusageStime           float64 `yaml:"rusage-stime"`
 | |
| 	RusageUtime           float64 `yaml:"rusage-utime"`
 | |
| 	TotalConnections      int     `yaml:"total-connections"`
 | |
| 	TotalJobs             int     `yaml:"total-jobs"`
 | |
| 	Uptime                int     `yaml:"uptime"`
 | |
| 	Version               string  `yaml:"version"`
 | |
| }
 | |
| 
 | |
| type statsTubeResponse struct {
 | |
| 	CmdDelete           int    `yaml:"cmd-delete"`
 | |
| 	CmdPauseTube        int    `yaml:"cmd-pause-tube"`
 | |
| 	CurrentJobsBuried   int    `yaml:"current-jobs-buried"`
 | |
| 	CurrentJobsDelayed  int    `yaml:"current-jobs-delayed"`
 | |
| 	CurrentJobsReady    int    `yaml:"current-jobs-ready"`
 | |
| 	CurrentJobsReserved int    `yaml:"current-jobs-reserved"`
 | |
| 	CurrentJobsUrgent   int    `yaml:"current-jobs-urgent"`
 | |
| 	CurrentUsing        int    `yaml:"current-using"`
 | |
| 	CurrentWaiting      int    `yaml:"current-waiting"`
 | |
| 	CurrentWatching     int    `yaml:"current-watching"`
 | |
| 	Name                string `yaml:"name"`
 | |
| 	Pause               int    `yaml:"pause"`
 | |
| 	PauseTimeLeft       int    `yaml:"pause-time-left"`
 | |
| 	TotalJobs           int    `yaml:"total-jobs"`
 | |
| }
 |