Skip to content

Commit

Permalink
receiver/mysql: add metrics based on events_statements_summary_by_dig…
Browse files Browse the repository at this point in the history
…est table (open-telemetry#14477)

Signed-off-by: Dominik Rosiek <drosiek@sumologic.com>
Co-authored-by: Daniel Jaglowski <jaglows3@gmail.com>
  • Loading branch information
sumo-drosiek and djaglowski committed Oct 20, 2022
1 parent 7f77b16 commit 7518b0b
Show file tree
Hide file tree
Showing 13 changed files with 852 additions and 98 deletions.
16 changes: 16 additions & 0 deletions .chloggen/drosiek-mysql-perf-metrics.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: receiver/mysql

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add metrics based on events_statements_summary_by_digest table

# One or more tracking issues related to the change
issues: [14138]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
8 changes: 8 additions & 0 deletions receiver/mysqlreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ The following settings are optional:
- `collection_interval` (default = `10s`): This receiver collects metrics on an interval. This value must be a string readable by Golang's [time.ParseDuration](https://pkg.go.dev/time#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`.

- `transport`: (default = `tcp`): Defines the network to use for connecting to the server.
- `statement_events`: Additional configuration for query to build `mysql.statement_events.count` and `mysql.statement_events.wait.time` metrics:
- `digest_text_limit` - maximum length of `digest_text`. Longer text will be truncated (default=`120`)
- `time_limit` - maximum time from since the statements have been observed last time (default=`24h`)
- `limit` - limit of records, which is maximum number of generated metrics (default=`250`)

### Example Configuration

Expand All @@ -38,6 +42,10 @@ receivers:
password: $MYSQL_PASSWORD
database: otel
collection_interval: 10s
perf_events_statements:
digest_text_limit: 120
time_limit: 24h
limit: 250
```
The full list of settings exposed for this receiver are documented [here](./config.go) with detailed sample configurations [here](./testdata/config.yaml).
Expand Down
68 changes: 65 additions & 3 deletions receiver/mysqlreceiver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package mysqlreceiver // import "github.com/open-telemetry/opentelemetry-collect
import (
"database/sql"
"fmt"
"time"

// registers the mysql driver
"github.com/go-sql-driver/mysql"
Expand All @@ -28,12 +29,16 @@ type client interface {
getInnodbStats() (map[string]string, error)
getTableIoWaitsStats() ([]TableIoWaitsStats, error)
getIndexIoWaitsStats() ([]IndexIoWaitsStats, error)
getStatementEventsStats() ([]StatementEventStats, error)
Close() error
}

type mySQLClient struct {
connStr string
client *sql.DB
connStr string
client *sql.DB
statementEventsDigestTextLimit int
statementEventsLimit int
statementEventsTimeLimit time.Duration
}

type IoWaitsStats struct {
Expand All @@ -58,6 +63,23 @@ type IndexIoWaitsStats struct {
index string
}

type StatementEventStats struct {
schema string
digest string
digestText string
sumTimerWait int64
countErrors int64
countWarnings int64
countRowsAffected int64
countRowsSent int64
countRowsExamined int64
countCreatedTmpDiskTables int64
countCreatedTmpTables int64
countSortMergePasses int64
countSortRows int64
countNoIndexUsed int64
}

var _ client = (*mySQLClient)(nil)

func newMySQLClient(conf *Config) client {
Expand All @@ -72,7 +94,10 @@ func newMySQLClient(conf *Config) client {
connStr := driverConf.FormatDSN()

return &mySQLClient{
connStr: connStr,
connStr: connStr,
statementEventsDigestTextLimit: conf.StatementEvents.DigestTextLimit,
statementEventsLimit: conf.StatementEvents.Limit,
statementEventsTimeLimit: conf.StatementEvents.TimeLimit,
}
}

Expand Down Expand Up @@ -152,6 +177,43 @@ func (c *mySQLClient) getIndexIoWaitsStats() ([]IndexIoWaitsStats, error) {
return stats, nil
}

func (c *mySQLClient) getStatementEventsStats() ([]StatementEventStats, error) {
query := fmt.Sprintf("SELECT ifnull(SCHEMA_NAME, 'NONE') as SCHEMA_NAME, DIGEST,"+
"LEFT(DIGEST_TEXT, %d) as DIGEST_TEXT, SUM_TIMER_WAIT, SUM_ERRORS,"+
"SUM_WARNINGS, SUM_ROWS_AFFECTED, SUM_ROWS_SENT, SUM_ROWS_EXAMINED,"+
"SUM_CREATED_TMP_DISK_TABLES, SUM_CREATED_TMP_TABLES, SUM_SORT_MERGE_PASSES,"+
"SUM_SORT_ROWS, SUM_NO_INDEX_USED "+
"FROM performance_schema.events_statements_summary_by_digest "+
"WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'information_schema') "+
"AND last_seen > DATE_SUB(NOW(), INTERVAL %d SECOND) "+
"ORDER BY SUM_TIMER_WAIT DESC "+
"LIMIT %d",
c.statementEventsDigestTextLimit,
int64(c.statementEventsTimeLimit.Seconds()),
c.statementEventsLimit)

rows, err := c.client.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()

var stats []StatementEventStats
for rows.Next() {
var s StatementEventStats
err := rows.Scan(&s.schema, &s.digest, &s.digestText,
&s.sumTimerWait, &s.countErrors, &s.countWarnings,
&s.countRowsAffected, &s.countRowsSent, &s.countRowsExamined, &s.countCreatedTmpDiskTables,
&s.countCreatedTmpTables, &s.countSortMergePasses, &s.countSortRows, &s.countNoIndexUsed)
if err != nil {
return nil, err
}
stats = append(stats, s)
}

return stats, nil
}

func Query(c mySQLClient, query string) (map[string]string, error) {
rows, err := c.client.Query(query)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions receiver/mysqlreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,20 @@
package mysqlreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver"

import (
"time"

"go.opentelemetry.io/collector/config/confignet"
"go.opentelemetry.io/collector/receiver/scraperhelper"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver/internal/metadata"
)

const (
defaultStatementEventsDigestTextLimit = 120
defaultStatementEventsLimit = 250
defaultStatementEventsTimeLimit = 24 * time.Hour
)

type Config struct {
scraperhelper.ScraperControllerSettings `mapstructure:",squash"`
Username string `mapstructure:"username,omitempty"`
Expand All @@ -29,4 +37,11 @@ type Config struct {
AllowNativePasswords bool `mapstructure:"allow_native_passwords,omitempty"`
confignet.NetAddr `mapstructure:",squash"`
Metrics metadata.MetricsSettings `mapstructure:"metrics"`
StatementEvents StatementEventsConfig `mapstructure:"statement_events"`
}

type StatementEventsConfig struct {
DigestTextLimit int `mapstructure:"digest_text_limit"`
Limit int `mapstructure:"limit"`
TimeLimit time.Duration `mapstructure:"time_limit"`
}
5 changes: 5 additions & 0 deletions receiver/mysqlreceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ These are the metrics available for this scraper.
| **mysql.row_locks** | The number of InnoDB row locks. | 1 | Sum(Int) | <ul> <li>row_locks</li> </ul> |
| **mysql.row_operations** | The number of InnoDB row operations. | 1 | Sum(Int) | <ul> <li>row_operations</li> </ul> |
| **mysql.sorts** | The number of MySQL sorts. | 1 | Sum(Int) | <ul> <li>sorts</li> </ul> |
| mysql.statement_event.count | Summary of current and recent statement events. | 1 | Sum(Int) | <ul> <li>schema</li> <li>digest</li> <li>digest_text</li> <li>event_state</li> </ul> |
| mysql.statement_event.wait.time | The total wait time of the summarized timed events. | ns | Sum(Int) | <ul> <li>schema</li> <li>digest</li> <li>digest_text</li> </ul> |
| **mysql.table.io.wait.count** | The total count of I/O wait events for a table. | 1 | Sum(Int) | <ul> <li>io_waits_operations</li> <li>table_name</li> <li>schema</li> </ul> |
| **mysql.table.io.wait.time** | The total time of I/O wait events for a table. | ns | Sum(Int) | <ul> <li>io_waits_operations</li> <li>table_name</li> <li>schema</li> </ul> |
| **mysql.threads** | The state of MySQL threads. | 1 | Sum(Int) | <ul> <li>threads</li> </ul> |
Expand Down Expand Up @@ -57,7 +59,10 @@ metrics:
| buffer_pool_operations (operation) | The buffer pool operations types. | read_ahead_rnd, read_ahead, read_ahead_evicted, read_requests, reads, wait_free, write_requests |
| buffer_pool_pages (kind) | The buffer pool pages types. | data, free, misc |
| command (command) | The command types. | execute, close, fetch, prepare, reset, send_long_data |
| digest (digest) | Digest. | |
| digest_text (digest_text) | Text before digestion. | |
| double_writes (kind) | The doublewrite types. | pages_written, writes |
| event_state (kind) | Possible event states. | errors, warnings, rows_affected, rows_sent, rows_examined, created_tmp_disk_tables, created_tmp_tables, sort_merge_passes, sort_rows, no_index_used |
| handler (kind) | The handler types. | commit, delete, discover, external_lock, mrr_init, prepare, read_first, read_key, read_last, read_next, read_prev, read_rnd, read_rnd_next, rollback, savepoint, savepoint_rollback, update, write |
| index_name (index) | The name of the index. | |
| io_waits_operations (operation) | The io_waits operation type. | delete, fetch, insert, update |
Expand Down
5 changes: 5 additions & 0 deletions receiver/mysqlreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ func createDefaultConfig() config.Receiver {
Transport: "tcp",
},
Metrics: metadata.DefaultMetricsSettings(),
StatementEvents: StatementEventsConfig{
DigestTextLimit: defaultStatementEventsDigestTextLimit,
Limit: defaultStatementEventsLimit,
TimeLimit: defaultStatementEventsTimeLimit,
},
}
}

Expand Down
Loading

0 comments on commit 7518b0b

Please sign in to comment.