Skip to content

Commit 524e5ab

Browse files
committed
Add metrics from information_schema.tables
Collect metrics from information_schema.tables * Allow filtered list of databases to avoid performance problems on MySQL < 5.6 * Default to all databases * Include extra labels in `table_version`, useful for detecting crashed tables `{engine="NONE"}`
1 parent 53a159b commit 524e5ab

File tree

2 files changed

+141
-1
lines changed

2 files changed

+141
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Name | Description
1717
collect.auto_increment.columns | Collect auto_increment columns and max values from information_schema.
1818
collect.binlog_size | Compute the size of all binlog files combined (as specified by "SHOW MASTER LOGS")
1919
collect.info_schema.userstats | If running with userstat=1, set to true to collect user statistics.
20+
collect.info_schema.tables | Collect metrics from information_schema.tables.
21+
collect.info_schema.tables.databases | The list of databases to collect table stats for, or '`*`' for all.
2022
collect.perf_schema.eventsstatements | Collect metrics from performance_schema.events_statements_summary_by_digest.
2123
collect.perf_schema.eventsstatements.limit | Limit the number of events statements digests by response time. (default: 250)
2224
collect.perf_schema.eventsstatements.digest_text_limit | Maximum length of the normalized statement text. (default: 120)

mysqld_exporter.go

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ var (
3030
"collect.info_schema.processlist", false,
3131
"Collect current thread state counts from the information_schema.processlist",
3232
)
33+
collectTableSchema = flag.Bool(
34+
"collect.info_schema.tables", true,
35+
"Collect metrics from information_schema.tables",
36+
)
37+
tableSchemaDatabases = flag.String(
38+
"collect.info_schema.tables.databases", "*",
39+
"The list of databases to collect table stats for, or '*' for all",
40+
)
3341
collectGlobalStatus = flag.Bool(
3442
"collect.global_status", true,
3543
"Collect from SHOW GLOBAL STATUS",
@@ -204,7 +212,29 @@ const (
204212
COUNT_MISC, SUM_TIMER_MISC
205213
FROM performance_schema.file_summary_by_event_name
206214
`
207-
userStatQuery = `SELECT * FROM information_schema.USER_STATISTICS`
215+
userStatQuery = `SELECT * FROM information_schema.USER_STATISTICS`
216+
tableSchemaQuery = `
217+
SELECT
218+
TABLE_SCHEMA,
219+
TABLE_NAME,
220+
TABLE_TYPE,
221+
ifnull(ENGINE, 'NONE') as ENGINE,
222+
ifnull(VERSION, '0') as VERSION,
223+
ifnull(ROW_FORMAT, 'NONE') as ROW_FORMAT,
224+
ifnull(TABLE_ROWS, '0') as TABLE_ROWS,
225+
ifnull(DATA_LENGTH, '0') as DATA_LENGTH,
226+
ifnull(INDEX_LENGTH, '0') as INDEX_LENGTH,
227+
ifnull(DATA_FREE, '0') as DATA_FREE,
228+
ifnull(CREATE_OPTIONS, 'NONE') as CREATE_OPTIONS
229+
FROM information_schema.tables
230+
WHERE TABLE_SCHEMA = '%s'
231+
`
232+
dbListQuery = `
233+
SELECT
234+
SCHEMA_NAME
235+
FROM information_schema.schemata
236+
WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'information_schema')
237+
`
208238
)
209239

210240
// landingPage contains the HTML served at '/'.
@@ -255,6 +285,21 @@ var (
255285
"The max value of an auto_increment column from information_schema.",
256286
[]string{"schema", "table", "column"}, nil,
257287
)
288+
infoSchemaTablesVersionDesc = prometheus.NewDesc(
289+
prometheus.BuildFQName(namespace, informationSchema, "table_version"),
290+
"The version number of the table's .frm file",
291+
[]string{"schema", "table", "type", "engine", "row_format", "create_options"}, nil,
292+
)
293+
infoSchemaTablesRowsDesc = prometheus.NewDesc(
294+
prometheus.BuildFQName(namespace, informationSchema, "table_rows"),
295+
"The estimated number of rows in the table from information_schema.tables",
296+
[]string{"schema", "table"}, nil,
297+
)
298+
infoSchemaTablesSizeDesc = prometheus.NewDesc(
299+
prometheus.BuildFQName(namespace, informationSchema, "table_size"),
300+
"The size of the table components from information_schema.tables",
301+
[]string{"schema", "table", "component"}, nil,
302+
)
258303
globalPerformanceSchemaLostDesc = prometheus.NewDesc(
259304
prometheus.BuildFQName(namespace, globalStatus, "performance_schema_lost_total"),
260305
"Total number of MySQL instrumentations that could not be loaded or created due to memory constraints.",
@@ -676,6 +721,12 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
676721
return
677722
}
678723
}
724+
if *collectTableSchema {
725+
if err = scrapeTableSchema(db, ch); err != nil {
726+
log.Println("Error scraping table schema:", err)
727+
return
728+
}
729+
}
679730
if *collectAutoIncrementColumns {
680731
if err = scrapeInformationSchema(db, ch); err != nil {
681732
log.Println("Error scraping information schema:", err)
@@ -1457,6 +1508,93 @@ func scrapeProcesslist(db *sql.DB, ch chan<- prometheus.Metric) error {
14571508
return nil
14581509
}
14591510

1511+
func scrapeTableSchema(db *sql.DB, ch chan<- prometheus.Metric) error {
1512+
var dbList []string
1513+
if *tableSchemaDatabases == "*" {
1514+
dbListRows, err := db.Query(dbListQuery)
1515+
if err != nil {
1516+
return err
1517+
}
1518+
defer dbListRows.Close()
1519+
1520+
var database string
1521+
1522+
for dbListRows.Next() {
1523+
if err := dbListRows.Scan(
1524+
&database,
1525+
); err != nil {
1526+
return err
1527+
}
1528+
dbList = append(dbList, database)
1529+
}
1530+
} else {
1531+
dbList = strings.Split(*tableSchemaDatabases, ",")
1532+
}
1533+
1534+
for _, database := range dbList {
1535+
tableSchemaRows, err := db.Query(fmt.Sprintf(tableSchemaQuery, database))
1536+
if err != nil {
1537+
return err
1538+
}
1539+
defer tableSchemaRows.Close()
1540+
1541+
var (
1542+
tableSchema string
1543+
tableName string
1544+
tableType string
1545+
engine string
1546+
version uint64
1547+
rowFormat string
1548+
tableRows uint64
1549+
dataLength uint64
1550+
indexLength uint64
1551+
dataFree uint64
1552+
createOptions string
1553+
)
1554+
1555+
for tableSchemaRows.Next() {
1556+
err = tableSchemaRows.Scan(
1557+
&tableSchema,
1558+
&tableName,
1559+
&tableType,
1560+
&engine,
1561+
&version,
1562+
&rowFormat,
1563+
&tableRows,
1564+
&dataLength,
1565+
&indexLength,
1566+
&dataFree,
1567+
&createOptions,
1568+
)
1569+
if err != nil {
1570+
return err
1571+
}
1572+
ch <- prometheus.MustNewConstMetric(
1573+
infoSchemaTablesVersionDesc, prometheus.GaugeValue, float64(version),
1574+
tableSchema, tableName, tableType, engine, rowFormat, createOptions,
1575+
)
1576+
ch <- prometheus.MustNewConstMetric(
1577+
infoSchemaTablesRowsDesc, prometheus.GaugeValue, float64(tableRows),
1578+
tableSchema, tableName,
1579+
)
1580+
ch <- prometheus.MustNewConstMetric(
1581+
infoSchemaTablesSizeDesc, prometheus.GaugeValue, float64(dataLength),
1582+
tableSchema, tableName, "data_length",
1583+
)
1584+
ch <- prometheus.MustNewConstMetric(
1585+
infoSchemaTablesSizeDesc, prometheus.GaugeValue, float64(indexLength),
1586+
tableSchema, tableName, "index_length",
1587+
)
1588+
ch <- prometheus.MustNewConstMetric(
1589+
infoSchemaTablesSizeDesc, prometheus.GaugeValue, float64(dataFree),
1590+
tableSchema, tableName, "data_free",
1591+
)
1592+
}
1593+
}
1594+
1595+
return nil
1596+
}
1597+
14601598
func newDesc(subsystem, name, help string) *prometheus.Desc {
14611599
return prometheus.NewDesc(
14621600
prometheus.BuildFQName(namespace, subsystem, name),

0 commit comments

Comments
 (0)