2015-05-18 18:54:11 +00:00
|
|
|
package mysql
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
2015-05-22 23:45:14 +00:00
|
|
|
"github.com/influxdb/telegraf/plugins"
|
2015-05-18 18:54:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Mysql struct {
|
2015-05-18 22:22:04 +00:00
|
|
|
Servers []string
|
2015-05-18 22:10:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var sampleConfig = `
|
2015-10-15 21:53:29 +00:00
|
|
|
# specify servers via a url matching:
|
|
|
|
# [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]]
|
|
|
|
# e.g.
|
|
|
|
# root:root@http://10.0.0.18/?tls=false
|
|
|
|
# root:passwd@tcp(127.0.0.1:3036)/
|
|
|
|
#
|
|
|
|
# If no servers are specified, then localhost is used as the host.
|
|
|
|
servers = ["localhost"]
|
2015-08-26 15:21:39 +00:00
|
|
|
`
|
2015-05-18 22:10:11 +00:00
|
|
|
|
|
|
|
func (m *Mysql) SampleConfig() string {
|
|
|
|
return sampleConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mysql) Description() string {
|
|
|
|
return "Read metrics from one or many mysql servers"
|
2015-05-18 18:54:11 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 22:22:04 +00:00
|
|
|
var localhost = ""
|
2015-05-18 18:54:11 +00:00
|
|
|
|
|
|
|
func (m *Mysql) Gather(acc plugins.Accumulator) error {
|
|
|
|
if len(m.Servers) == 0 {
|
|
|
|
// if we can't get stats in this case, thats fine, don't report
|
|
|
|
// an error.
|
|
|
|
m.gatherServer(localhost, acc)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, serv := range m.Servers {
|
|
|
|
err := m.gatherServer(serv, acc)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type mapping struct {
|
|
|
|
onServer string
|
|
|
|
inExport string
|
|
|
|
}
|
|
|
|
|
|
|
|
var mappings = []*mapping{
|
2015-09-01 17:30:56 +00:00
|
|
|
{
|
|
|
|
onServer: "Aborted_",
|
|
|
|
inExport: "aborted_",
|
|
|
|
},
|
2015-05-18 18:54:11 +00:00
|
|
|
{
|
|
|
|
onServer: "Bytes_",
|
2015-05-18 19:15:15 +00:00
|
|
|
inExport: "bytes_",
|
2015-05-18 18:54:11 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Com_",
|
2015-05-18 19:15:15 +00:00
|
|
|
inExport: "commands_",
|
2015-05-18 18:54:11 +00:00
|
|
|
},
|
2015-09-01 17:30:56 +00:00
|
|
|
{
|
|
|
|
onServer: "Created_",
|
|
|
|
inExport: "created_",
|
|
|
|
},
|
2015-05-18 18:54:11 +00:00
|
|
|
{
|
|
|
|
onServer: "Handler_",
|
2015-05-18 19:15:15 +00:00
|
|
|
inExport: "handler_",
|
2015-05-18 18:54:11 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Innodb_",
|
2015-05-18 19:15:15 +00:00
|
|
|
inExport: "innodb_",
|
2015-05-18 18:54:11 +00:00
|
|
|
},
|
2015-09-01 17:30:56 +00:00
|
|
|
{
|
|
|
|
onServer: "Key_",
|
|
|
|
inExport: "key_",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Open_",
|
|
|
|
inExport: "open_",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Opened_",
|
|
|
|
inExport: "opened_",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Qcache_",
|
|
|
|
inExport: "qcache_",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
onServer: "Table_",
|
|
|
|
inExport: "table_",
|
|
|
|
},
|
2015-07-19 20:01:45 +00:00
|
|
|
{
|
2015-08-04 22:09:59 +00:00
|
|
|
onServer: "Tokudb_",
|
|
|
|
inExport: "tokudb_",
|
|
|
|
},
|
2015-05-18 18:54:11 +00:00
|
|
|
{
|
|
|
|
onServer: "Threads_",
|
2015-05-18 19:15:15 +00:00
|
|
|
inExport: "threads_",
|
2015-05-18 18:54:11 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-05-18 22:22:04 +00:00
|
|
|
func (m *Mysql) gatherServer(serv string, acc plugins.Accumulator) error {
|
2015-05-18 23:08:22 +00:00
|
|
|
if serv == "localhost" {
|
|
|
|
serv = ""
|
|
|
|
}
|
|
|
|
|
2015-05-18 22:22:04 +00:00
|
|
|
db, err := sql.Open("mysql", serv)
|
2015-05-18 18:54:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer db.Close()
|
|
|
|
|
|
|
|
rows, err := db.Query(`SHOW /*!50002 GLOBAL */ STATUS`)
|
|
|
|
if err != nil {
|
2015-07-03 12:25:18 +00:00
|
|
|
return err
|
2015-05-18 18:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
var name string
|
|
|
|
var val interface{}
|
|
|
|
|
|
|
|
err = rows.Scan(&name, &val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var found bool
|
|
|
|
|
2015-08-25 19:18:33 +00:00
|
|
|
// Parse out user/password from server address tag if given
|
|
|
|
var servtag string
|
|
|
|
if strings.Contains(serv, "@") {
|
|
|
|
servtag = strings.Split(serv, "@")[1]
|
2015-09-16 21:04:14 +00:00
|
|
|
} else if serv == "" {
|
|
|
|
servtag = "localhost"
|
2015-08-25 19:18:33 +00:00
|
|
|
} else {
|
|
|
|
servtag = serv
|
|
|
|
}
|
|
|
|
tags := map[string]string{"server": servtag}
|
|
|
|
|
2015-05-18 18:54:11 +00:00
|
|
|
for _, mapped := range mappings {
|
|
|
|
if strings.HasPrefix(name, mapped.onServer) {
|
|
|
|
i, _ := strconv.Atoi(string(val.([]byte)))
|
2015-08-25 19:18:33 +00:00
|
|
|
acc.Add(mapped.inExport+name[len(mapped.onServer):], i, tags)
|
2015-05-18 18:54:11 +00:00
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if found {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch name {
|
|
|
|
case "Queries":
|
|
|
|
i, err := strconv.ParseInt(string(val.([]byte)), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-08-25 19:18:33 +00:00
|
|
|
acc.Add("queries", i, tags)
|
2015-05-18 18:54:11 +00:00
|
|
|
case "Slow_queries":
|
|
|
|
i, err := strconv.ParseInt(string(val.([]byte)), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-08-25 19:18:33 +00:00
|
|
|
acc.Add("slow_queries", i, tags)
|
2015-05-18 18:54:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
plugins.Add("mysql", func() plugins.Plugin {
|
|
|
|
return &Mysql{}
|
|
|
|
})
|
|
|
|
}
|