Add Minecraft input plugin (#2960)
This commit is contained in:
142
plugins/inputs/minecraft/minecraft.go
Normal file
142
plugins/inputs/minecraft/minecraft.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package minecraft
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
const sampleConfig = `
|
||||
## server address for minecraft
|
||||
# server = "localhost"
|
||||
## port for RCON
|
||||
# port = "25575"
|
||||
## password RCON for mincraft server
|
||||
# password = ""
|
||||
`
|
||||
|
||||
var (
|
||||
playerNameRegex = regexp.MustCompile(`for\s([^:]+):-`)
|
||||
scoreboardRegex = regexp.MustCompile(`(?U):\s(\d+)\s\((.*)\)`)
|
||||
)
|
||||
|
||||
// Client is an interface for a client which gathers data from a minecraft server
|
||||
type Client interface {
|
||||
Gather() ([]string, error)
|
||||
}
|
||||
|
||||
// Minecraft represents a connection to a minecraft server
|
||||
type Minecraft struct {
|
||||
Server string
|
||||
Port string
|
||||
Password string
|
||||
client Client
|
||||
}
|
||||
|
||||
// Description gives a brief description.
|
||||
func (s *Minecraft) Description() string {
|
||||
return "Collects scores from a minecraft server's scoreboard using the RCON protocol"
|
||||
}
|
||||
|
||||
// SampleConfig returns our sampleConfig.
|
||||
func (s *Minecraft) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Gather uses the RCON protocal to collect player and
|
||||
// scoreboard stats from a minecraft server.
|
||||
func (s *Minecraft) Gather(acc telegraf.Accumulator) error {
|
||||
if s.client == nil {
|
||||
var err error
|
||||
s.client, err = NewRCON(s.Server, s.Port, s.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
scores, err := s.client.Gather()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, score := range scores {
|
||||
player, err := ParsePlayerName(score)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tags := map[string]string{
|
||||
"player": player,
|
||||
"server": s.Server + ":" + s.Port,
|
||||
}
|
||||
|
||||
stats, err := ParseScoreboard(score)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var fields = make(map[string]interface{}, len(stats))
|
||||
for _, stat := range stats {
|
||||
fields[stat.Name] = stat.Value
|
||||
}
|
||||
|
||||
acc.AddFields("minecraft", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParsePlayerName takes an input string from rcon, to parse
|
||||
// the player.
|
||||
func ParsePlayerName(input string) (string, error) {
|
||||
playerMatches := playerNameRegex.FindAllStringSubmatch(input, -1)
|
||||
if playerMatches == nil {
|
||||
return "", fmt.Errorf("no player was matched")
|
||||
}
|
||||
return playerMatches[0][1], nil
|
||||
}
|
||||
|
||||
// Score is an individual tracked scoreboard stat.
|
||||
type Score struct {
|
||||
Name string
|
||||
Value int
|
||||
}
|
||||
|
||||
// ParseScoreboard takes an input string from rcon, to parse
|
||||
// scoreboard stats.
|
||||
func ParseScoreboard(input string) ([]Score, error) {
|
||||
scoreMatches := scoreboardRegex.FindAllStringSubmatch(input, -1)
|
||||
if scoreMatches == nil {
|
||||
return nil, fmt.Errorf("No scores found")
|
||||
}
|
||||
|
||||
var scores []Score
|
||||
|
||||
for _, match := range scoreMatches {
|
||||
number := match[1]
|
||||
name := match[2]
|
||||
n, err := strconv.Atoi(number)
|
||||
// Not necessary in current state, because regex can only match integers,
|
||||
// maybe become necessary if regex is modified to match more types of
|
||||
// numbers
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse score")
|
||||
}
|
||||
s := Score{
|
||||
Name: name,
|
||||
Value: n,
|
||||
}
|
||||
scores = append(scores, s)
|
||||
}
|
||||
return scores, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("minecraft", func() telegraf.Input {
|
||||
return &Minecraft{
|
||||
Server: "localhost",
|
||||
Port: "25575",
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user