diff --git a/.chloggen/drosiek-mysql-perf-metrics.yaml b/.chloggen/drosiek-mysql-perf-metrics.yaml
new file mode 100755
index 000000000000..1a1acb62dbcd
--- /dev/null
+++ b/.chloggen/drosiek-mysql-perf-metrics.yaml
@@ -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:
diff --git a/receiver/mysqlreceiver/README.md b/receiver/mysqlreceiver/README.md
index 8cba9ae6a6c6..4c91e3ca7caa 100644
--- a/receiver/mysqlreceiver/README.md
+++ b/receiver/mysqlreceiver/README.md
@@ -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
@@ -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).
diff --git a/receiver/mysqlreceiver/client.go b/receiver/mysqlreceiver/client.go
index fd3b47d2deb3..9b65b79983cd 100644
--- a/receiver/mysqlreceiver/client.go
+++ b/receiver/mysqlreceiver/client.go
@@ -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"
@@ -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 {
@@ -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 {
@@ -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,
}
}
@@ -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 {
diff --git a/receiver/mysqlreceiver/config.go b/receiver/mysqlreceiver/config.go
index 650f10f802dc..e3d8ed02a6a4 100644
--- a/receiver/mysqlreceiver/config.go
+++ b/receiver/mysqlreceiver/config.go
@@ -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"`
@@ -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"`
}
diff --git a/receiver/mysqlreceiver/documentation.md b/receiver/mysqlreceiver/documentation.md
index 6d31029765ef..cae126923559 100644
--- a/receiver/mysqlreceiver/documentation.md
+++ b/receiver/mysqlreceiver/documentation.md
@@ -29,6 +29,8 @@ These are the metrics available for this scraper.
| **mysql.row_locks** | The number of InnoDB row locks. | 1 | Sum(Int) |
|
| **mysql.row_operations** | The number of InnoDB row operations. | 1 | Sum(Int) | |
| **mysql.sorts** | The number of MySQL sorts. | 1 | Sum(Int) | |
+| mysql.statement_event.count | Summary of current and recent statement events. | 1 | Sum(Int) | - schema
- digest
- digest_text
- event_state
|
+| mysql.statement_event.wait.time | The total wait time of the summarized timed events. | ns | Sum(Int) | - schema
- digest
- digest_text
|
| **mysql.table.io.wait.count** | The total count of I/O wait events for a table. | 1 | Sum(Int) | - io_waits_operations
- table_name
- schema
|
| **mysql.table.io.wait.time** | The total time of I/O wait events for a table. | ns | Sum(Int) | - io_waits_operations
- table_name
- schema
|
| **mysql.threads** | The state of MySQL threads. | 1 | Sum(Int) | |
@@ -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 |
diff --git a/receiver/mysqlreceiver/factory.go b/receiver/mysqlreceiver/factory.go
index d9fc054e8d67..a5ac04bbc2f5 100644
--- a/receiver/mysqlreceiver/factory.go
+++ b/receiver/mysqlreceiver/factory.go
@@ -52,6 +52,11 @@ func createDefaultConfig() config.Receiver {
Transport: "tcp",
},
Metrics: metadata.DefaultMetricsSettings(),
+ StatementEvents: StatementEventsConfig{
+ DigestTextLimit: defaultStatementEventsDigestTextLimit,
+ Limit: defaultStatementEventsLimit,
+ TimeLimit: defaultStatementEventsTimeLimit,
+ },
}
}
diff --git a/receiver/mysqlreceiver/internal/metadata/generated_metrics.go b/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
index c22f3d185711..eeb49e256695 100644
--- a/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
+++ b/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
@@ -19,31 +19,33 @@ type MetricSettings struct {
// MetricsSettings provides settings for mysqlreceiver metrics.
type MetricsSettings struct {
- MysqlBufferPoolDataPages MetricSettings `mapstructure:"mysql.buffer_pool.data_pages"`
- MysqlBufferPoolLimit MetricSettings `mapstructure:"mysql.buffer_pool.limit"`
- MysqlBufferPoolOperations MetricSettings `mapstructure:"mysql.buffer_pool.operations"`
- MysqlBufferPoolPageFlushes MetricSettings `mapstructure:"mysql.buffer_pool.page_flushes"`
- MysqlBufferPoolPages MetricSettings `mapstructure:"mysql.buffer_pool.pages"`
- MysqlBufferPoolUsage MetricSettings `mapstructure:"mysql.buffer_pool.usage"`
- MysqlCommands MetricSettings `mapstructure:"mysql.commands"`
- MysqlDoubleWrites MetricSettings `mapstructure:"mysql.double_writes"`
- MysqlHandlers MetricSettings `mapstructure:"mysql.handlers"`
- MysqlIndexIoWaitCount MetricSettings `mapstructure:"mysql.index.io.wait.count"`
- MysqlIndexIoWaitTime MetricSettings `mapstructure:"mysql.index.io.wait.time"`
- MysqlLockedConnects MetricSettings `mapstructure:"mysql.locked_connects"`
- MysqlLocks MetricSettings `mapstructure:"mysql.locks"`
- MysqlLogOperations MetricSettings `mapstructure:"mysql.log_operations"`
- MysqlMysqlxWorkerThreads MetricSettings `mapstructure:"mysql.mysqlx_worker_threads"`
- MysqlOpenedResources MetricSettings `mapstructure:"mysql.opened_resources"`
- MysqlOperations MetricSettings `mapstructure:"mysql.operations"`
- MysqlPageOperations MetricSettings `mapstructure:"mysql.page_operations"`
- MysqlRowLocks MetricSettings `mapstructure:"mysql.row_locks"`
- MysqlRowOperations MetricSettings `mapstructure:"mysql.row_operations"`
- MysqlSorts MetricSettings `mapstructure:"mysql.sorts"`
- MysqlTableIoWaitCount MetricSettings `mapstructure:"mysql.table.io.wait.count"`
- MysqlTableIoWaitTime MetricSettings `mapstructure:"mysql.table.io.wait.time"`
- MysqlThreads MetricSettings `mapstructure:"mysql.threads"`
- MysqlTmpResources MetricSettings `mapstructure:"mysql.tmp_resources"`
+ MysqlBufferPoolDataPages MetricSettings `mapstructure:"mysql.buffer_pool.data_pages"`
+ MysqlBufferPoolLimit MetricSettings `mapstructure:"mysql.buffer_pool.limit"`
+ MysqlBufferPoolOperations MetricSettings `mapstructure:"mysql.buffer_pool.operations"`
+ MysqlBufferPoolPageFlushes MetricSettings `mapstructure:"mysql.buffer_pool.page_flushes"`
+ MysqlBufferPoolPages MetricSettings `mapstructure:"mysql.buffer_pool.pages"`
+ MysqlBufferPoolUsage MetricSettings `mapstructure:"mysql.buffer_pool.usage"`
+ MysqlCommands MetricSettings `mapstructure:"mysql.commands"`
+ MysqlDoubleWrites MetricSettings `mapstructure:"mysql.double_writes"`
+ MysqlHandlers MetricSettings `mapstructure:"mysql.handlers"`
+ MysqlIndexIoWaitCount MetricSettings `mapstructure:"mysql.index.io.wait.count"`
+ MysqlIndexIoWaitTime MetricSettings `mapstructure:"mysql.index.io.wait.time"`
+ MysqlLockedConnects MetricSettings `mapstructure:"mysql.locked_connects"`
+ MysqlLocks MetricSettings `mapstructure:"mysql.locks"`
+ MysqlLogOperations MetricSettings `mapstructure:"mysql.log_operations"`
+ MysqlMysqlxWorkerThreads MetricSettings `mapstructure:"mysql.mysqlx_worker_threads"`
+ MysqlOpenedResources MetricSettings `mapstructure:"mysql.opened_resources"`
+ MysqlOperations MetricSettings `mapstructure:"mysql.operations"`
+ MysqlPageOperations MetricSettings `mapstructure:"mysql.page_operations"`
+ MysqlRowLocks MetricSettings `mapstructure:"mysql.row_locks"`
+ MysqlRowOperations MetricSettings `mapstructure:"mysql.row_operations"`
+ MysqlSorts MetricSettings `mapstructure:"mysql.sorts"`
+ MysqlStatementEventCount MetricSettings `mapstructure:"mysql.statement_event.count"`
+ MysqlStatementEventWaitTime MetricSettings `mapstructure:"mysql.statement_event.wait.time"`
+ MysqlTableIoWaitCount MetricSettings `mapstructure:"mysql.table.io.wait.count"`
+ MysqlTableIoWaitTime MetricSettings `mapstructure:"mysql.table.io.wait.time"`
+ MysqlThreads MetricSettings `mapstructure:"mysql.threads"`
+ MysqlTmpResources MetricSettings `mapstructure:"mysql.tmp_resources"`
}
func DefaultMetricsSettings() MetricsSettings {
@@ -111,6 +113,12 @@ func DefaultMetricsSettings() MetricsSettings {
MysqlSorts: MetricSettings{
Enabled: true,
},
+ MysqlStatementEventCount: MetricSettings{
+ Enabled: false,
+ },
+ MysqlStatementEventWaitTime: MetricSettings{
+ Enabled: false,
+ },
MysqlTableIoWaitCount: MetricSettings{
Enabled: true,
},
@@ -296,6 +304,64 @@ var MapAttributeDoubleWrites = map[string]AttributeDoubleWrites{
"writes": AttributeDoubleWritesWrites,
}
+// AttributeEventState specifies the a value event_state attribute.
+type AttributeEventState int
+
+const (
+ _ AttributeEventState = iota
+ AttributeEventStateErrors
+ AttributeEventStateWarnings
+ AttributeEventStateRowsAffected
+ AttributeEventStateRowsSent
+ AttributeEventStateRowsExamined
+ AttributeEventStateCreatedTmpDiskTables
+ AttributeEventStateCreatedTmpTables
+ AttributeEventStateSortMergePasses
+ AttributeEventStateSortRows
+ AttributeEventStateNoIndexUsed
+)
+
+// String returns the string representation of the AttributeEventState.
+func (av AttributeEventState) String() string {
+ switch av {
+ case AttributeEventStateErrors:
+ return "errors"
+ case AttributeEventStateWarnings:
+ return "warnings"
+ case AttributeEventStateRowsAffected:
+ return "rows_affected"
+ case AttributeEventStateRowsSent:
+ return "rows_sent"
+ case AttributeEventStateRowsExamined:
+ return "rows_examined"
+ case AttributeEventStateCreatedTmpDiskTables:
+ return "created_tmp_disk_tables"
+ case AttributeEventStateCreatedTmpTables:
+ return "created_tmp_tables"
+ case AttributeEventStateSortMergePasses:
+ return "sort_merge_passes"
+ case AttributeEventStateSortRows:
+ return "sort_rows"
+ case AttributeEventStateNoIndexUsed:
+ return "no_index_used"
+ }
+ return ""
+}
+
+// MapAttributeEventState is a helper map of string to AttributeEventState attribute value.
+var MapAttributeEventState = map[string]AttributeEventState{
+ "errors": AttributeEventStateErrors,
+ "warnings": AttributeEventStateWarnings,
+ "rows_affected": AttributeEventStateRowsAffected,
+ "rows_sent": AttributeEventStateRowsSent,
+ "rows_examined": AttributeEventStateRowsExamined,
+ "created_tmp_disk_tables": AttributeEventStateCreatedTmpDiskTables,
+ "created_tmp_tables": AttributeEventStateCreatedTmpTables,
+ "sort_merge_passes": AttributeEventStateSortMergePasses,
+ "sort_rows": AttributeEventStateSortRows,
+ "no_index_used": AttributeEventStateNoIndexUsed,
+}
+
// AttributeHandler specifies the a value handler attribute.
type AttributeHandler int
@@ -1863,6 +1929,117 @@ func newMetricMysqlSorts(settings MetricSettings) metricMysqlSorts {
return m
}
+type metricMysqlStatementEventCount struct {
+ data pmetric.Metric // data buffer for generated metric.
+ settings MetricSettings // metric settings provided by user.
+ capacity int // max observed number of data points added to the metric.
+}
+
+// init fills mysql.statement_event.count metric with initial data.
+func (m *metricMysqlStatementEventCount) init() {
+ m.data.SetName("mysql.statement_event.count")
+ m.data.SetDescription("Summary of current and recent statement events.")
+ m.data.SetUnit("1")
+ m.data.SetEmptySum()
+ m.data.Sum().SetIsMonotonic(false)
+ m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
+ m.data.Sum().DataPoints().EnsureCapacity(m.capacity)
+}
+
+func (m *metricMysqlStatementEventCount) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, schemaAttributeValue string, digestAttributeValue string, digestTextAttributeValue string, eventStateAttributeValue string) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntValue(val)
+ dp.Attributes().PutStr("schema", schemaAttributeValue)
+ dp.Attributes().PutStr("digest", digestAttributeValue)
+ dp.Attributes().PutStr("digest_text", digestTextAttributeValue)
+ dp.Attributes().PutStr("kind", eventStateAttributeValue)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricMysqlStatementEventCount) updateCapacity() {
+ if m.data.Sum().DataPoints().Len() > m.capacity {
+ m.capacity = m.data.Sum().DataPoints().Len()
+ }
+}
+
+// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points.
+func (m *metricMysqlStatementEventCount) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricMysqlStatementEventCount(settings MetricSettings) metricMysqlStatementEventCount {
+ m := metricMysqlStatementEventCount{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
+type metricMysqlStatementEventWaitTime struct {
+ data pmetric.Metric // data buffer for generated metric.
+ settings MetricSettings // metric settings provided by user.
+ capacity int // max observed number of data points added to the metric.
+}
+
+// init fills mysql.statement_event.wait.time metric with initial data.
+func (m *metricMysqlStatementEventWaitTime) init() {
+ m.data.SetName("mysql.statement_event.wait.time")
+ m.data.SetDescription("The total wait time of the summarized timed events.")
+ m.data.SetUnit("ns")
+ m.data.SetEmptySum()
+ m.data.Sum().SetIsMonotonic(false)
+ m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
+ m.data.Sum().DataPoints().EnsureCapacity(m.capacity)
+}
+
+func (m *metricMysqlStatementEventWaitTime) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, schemaAttributeValue string, digestAttributeValue string, digestTextAttributeValue string) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntValue(val)
+ dp.Attributes().PutStr("schema", schemaAttributeValue)
+ dp.Attributes().PutStr("digest", digestAttributeValue)
+ dp.Attributes().PutStr("digest_text", digestTextAttributeValue)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricMysqlStatementEventWaitTime) updateCapacity() {
+ if m.data.Sum().DataPoints().Len() > m.capacity {
+ m.capacity = m.data.Sum().DataPoints().Len()
+ }
+}
+
+// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points.
+func (m *metricMysqlStatementEventWaitTime) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricMysqlStatementEventWaitTime(settings MetricSettings) metricMysqlStatementEventWaitTime {
+ m := metricMysqlStatementEventWaitTime{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
type metricMysqlTableIoWaitCount struct {
data pmetric.Metric // data buffer for generated metric.
settings MetricSettings // metric settings provided by user.
@@ -2082,36 +2259,38 @@ func newMetricMysqlTmpResources(settings MetricSettings) metricMysqlTmpResources
// MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations
// required to produce metric representation defined in metadata and user settings.
type MetricsBuilder struct {
- startTime pcommon.Timestamp // start time that will be applied to all recorded data points.
- metricsCapacity int // maximum observed number of metrics per resource.
- resourceCapacity int // maximum observed number of resource attributes.
- metricsBuffer pmetric.Metrics // accumulates metrics data before emitting.
- buildInfo component.BuildInfo // contains version information
- metricMysqlBufferPoolDataPages metricMysqlBufferPoolDataPages
- metricMysqlBufferPoolLimit metricMysqlBufferPoolLimit
- metricMysqlBufferPoolOperations metricMysqlBufferPoolOperations
- metricMysqlBufferPoolPageFlushes metricMysqlBufferPoolPageFlushes
- metricMysqlBufferPoolPages metricMysqlBufferPoolPages
- metricMysqlBufferPoolUsage metricMysqlBufferPoolUsage
- metricMysqlCommands metricMysqlCommands
- metricMysqlDoubleWrites metricMysqlDoubleWrites
- metricMysqlHandlers metricMysqlHandlers
- metricMysqlIndexIoWaitCount metricMysqlIndexIoWaitCount
- metricMysqlIndexIoWaitTime metricMysqlIndexIoWaitTime
- metricMysqlLockedConnects metricMysqlLockedConnects
- metricMysqlLocks metricMysqlLocks
- metricMysqlLogOperations metricMysqlLogOperations
- metricMysqlMysqlxWorkerThreads metricMysqlMysqlxWorkerThreads
- metricMysqlOpenedResources metricMysqlOpenedResources
- metricMysqlOperations metricMysqlOperations
- metricMysqlPageOperations metricMysqlPageOperations
- metricMysqlRowLocks metricMysqlRowLocks
- metricMysqlRowOperations metricMysqlRowOperations
- metricMysqlSorts metricMysqlSorts
- metricMysqlTableIoWaitCount metricMysqlTableIoWaitCount
- metricMysqlTableIoWaitTime metricMysqlTableIoWaitTime
- metricMysqlThreads metricMysqlThreads
- metricMysqlTmpResources metricMysqlTmpResources
+ startTime pcommon.Timestamp // start time that will be applied to all recorded data points.
+ metricsCapacity int // maximum observed number of metrics per resource.
+ resourceCapacity int // maximum observed number of resource attributes.
+ metricsBuffer pmetric.Metrics // accumulates metrics data before emitting.
+ buildInfo component.BuildInfo // contains version information
+ metricMysqlBufferPoolDataPages metricMysqlBufferPoolDataPages
+ metricMysqlBufferPoolLimit metricMysqlBufferPoolLimit
+ metricMysqlBufferPoolOperations metricMysqlBufferPoolOperations
+ metricMysqlBufferPoolPageFlushes metricMysqlBufferPoolPageFlushes
+ metricMysqlBufferPoolPages metricMysqlBufferPoolPages
+ metricMysqlBufferPoolUsage metricMysqlBufferPoolUsage
+ metricMysqlCommands metricMysqlCommands
+ metricMysqlDoubleWrites metricMysqlDoubleWrites
+ metricMysqlHandlers metricMysqlHandlers
+ metricMysqlIndexIoWaitCount metricMysqlIndexIoWaitCount
+ metricMysqlIndexIoWaitTime metricMysqlIndexIoWaitTime
+ metricMysqlLockedConnects metricMysqlLockedConnects
+ metricMysqlLocks metricMysqlLocks
+ metricMysqlLogOperations metricMysqlLogOperations
+ metricMysqlMysqlxWorkerThreads metricMysqlMysqlxWorkerThreads
+ metricMysqlOpenedResources metricMysqlOpenedResources
+ metricMysqlOperations metricMysqlOperations
+ metricMysqlPageOperations metricMysqlPageOperations
+ metricMysqlRowLocks metricMysqlRowLocks
+ metricMysqlRowOperations metricMysqlRowOperations
+ metricMysqlSorts metricMysqlSorts
+ metricMysqlStatementEventCount metricMysqlStatementEventCount
+ metricMysqlStatementEventWaitTime metricMysqlStatementEventWaitTime
+ metricMysqlTableIoWaitCount metricMysqlTableIoWaitCount
+ metricMysqlTableIoWaitTime metricMysqlTableIoWaitTime
+ metricMysqlThreads metricMysqlThreads
+ metricMysqlTmpResources metricMysqlTmpResources
}
// metricBuilderOption applies changes to default metrics builder.
@@ -2126,34 +2305,36 @@ func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption {
func NewMetricsBuilder(settings MetricsSettings, buildInfo component.BuildInfo, options ...metricBuilderOption) *MetricsBuilder {
mb := &MetricsBuilder{
- startTime: pcommon.NewTimestampFromTime(time.Now()),
- metricsBuffer: pmetric.NewMetrics(),
- buildInfo: buildInfo,
- metricMysqlBufferPoolDataPages: newMetricMysqlBufferPoolDataPages(settings.MysqlBufferPoolDataPages),
- metricMysqlBufferPoolLimit: newMetricMysqlBufferPoolLimit(settings.MysqlBufferPoolLimit),
- metricMysqlBufferPoolOperations: newMetricMysqlBufferPoolOperations(settings.MysqlBufferPoolOperations),
- metricMysqlBufferPoolPageFlushes: newMetricMysqlBufferPoolPageFlushes(settings.MysqlBufferPoolPageFlushes),
- metricMysqlBufferPoolPages: newMetricMysqlBufferPoolPages(settings.MysqlBufferPoolPages),
- metricMysqlBufferPoolUsage: newMetricMysqlBufferPoolUsage(settings.MysqlBufferPoolUsage),
- metricMysqlCommands: newMetricMysqlCommands(settings.MysqlCommands),
- metricMysqlDoubleWrites: newMetricMysqlDoubleWrites(settings.MysqlDoubleWrites),
- metricMysqlHandlers: newMetricMysqlHandlers(settings.MysqlHandlers),
- metricMysqlIndexIoWaitCount: newMetricMysqlIndexIoWaitCount(settings.MysqlIndexIoWaitCount),
- metricMysqlIndexIoWaitTime: newMetricMysqlIndexIoWaitTime(settings.MysqlIndexIoWaitTime),
- metricMysqlLockedConnects: newMetricMysqlLockedConnects(settings.MysqlLockedConnects),
- metricMysqlLocks: newMetricMysqlLocks(settings.MysqlLocks),
- metricMysqlLogOperations: newMetricMysqlLogOperations(settings.MysqlLogOperations),
- metricMysqlMysqlxWorkerThreads: newMetricMysqlMysqlxWorkerThreads(settings.MysqlMysqlxWorkerThreads),
- metricMysqlOpenedResources: newMetricMysqlOpenedResources(settings.MysqlOpenedResources),
- metricMysqlOperations: newMetricMysqlOperations(settings.MysqlOperations),
- metricMysqlPageOperations: newMetricMysqlPageOperations(settings.MysqlPageOperations),
- metricMysqlRowLocks: newMetricMysqlRowLocks(settings.MysqlRowLocks),
- metricMysqlRowOperations: newMetricMysqlRowOperations(settings.MysqlRowOperations),
- metricMysqlSorts: newMetricMysqlSorts(settings.MysqlSorts),
- metricMysqlTableIoWaitCount: newMetricMysqlTableIoWaitCount(settings.MysqlTableIoWaitCount),
- metricMysqlTableIoWaitTime: newMetricMysqlTableIoWaitTime(settings.MysqlTableIoWaitTime),
- metricMysqlThreads: newMetricMysqlThreads(settings.MysqlThreads),
- metricMysqlTmpResources: newMetricMysqlTmpResources(settings.MysqlTmpResources),
+ startTime: pcommon.NewTimestampFromTime(time.Now()),
+ metricsBuffer: pmetric.NewMetrics(),
+ buildInfo: buildInfo,
+ metricMysqlBufferPoolDataPages: newMetricMysqlBufferPoolDataPages(settings.MysqlBufferPoolDataPages),
+ metricMysqlBufferPoolLimit: newMetricMysqlBufferPoolLimit(settings.MysqlBufferPoolLimit),
+ metricMysqlBufferPoolOperations: newMetricMysqlBufferPoolOperations(settings.MysqlBufferPoolOperations),
+ metricMysqlBufferPoolPageFlushes: newMetricMysqlBufferPoolPageFlushes(settings.MysqlBufferPoolPageFlushes),
+ metricMysqlBufferPoolPages: newMetricMysqlBufferPoolPages(settings.MysqlBufferPoolPages),
+ metricMysqlBufferPoolUsage: newMetricMysqlBufferPoolUsage(settings.MysqlBufferPoolUsage),
+ metricMysqlCommands: newMetricMysqlCommands(settings.MysqlCommands),
+ metricMysqlDoubleWrites: newMetricMysqlDoubleWrites(settings.MysqlDoubleWrites),
+ metricMysqlHandlers: newMetricMysqlHandlers(settings.MysqlHandlers),
+ metricMysqlIndexIoWaitCount: newMetricMysqlIndexIoWaitCount(settings.MysqlIndexIoWaitCount),
+ metricMysqlIndexIoWaitTime: newMetricMysqlIndexIoWaitTime(settings.MysqlIndexIoWaitTime),
+ metricMysqlLockedConnects: newMetricMysqlLockedConnects(settings.MysqlLockedConnects),
+ metricMysqlLocks: newMetricMysqlLocks(settings.MysqlLocks),
+ metricMysqlLogOperations: newMetricMysqlLogOperations(settings.MysqlLogOperations),
+ metricMysqlMysqlxWorkerThreads: newMetricMysqlMysqlxWorkerThreads(settings.MysqlMysqlxWorkerThreads),
+ metricMysqlOpenedResources: newMetricMysqlOpenedResources(settings.MysqlOpenedResources),
+ metricMysqlOperations: newMetricMysqlOperations(settings.MysqlOperations),
+ metricMysqlPageOperations: newMetricMysqlPageOperations(settings.MysqlPageOperations),
+ metricMysqlRowLocks: newMetricMysqlRowLocks(settings.MysqlRowLocks),
+ metricMysqlRowOperations: newMetricMysqlRowOperations(settings.MysqlRowOperations),
+ metricMysqlSorts: newMetricMysqlSorts(settings.MysqlSorts),
+ metricMysqlStatementEventCount: newMetricMysqlStatementEventCount(settings.MysqlStatementEventCount),
+ metricMysqlStatementEventWaitTime: newMetricMysqlStatementEventWaitTime(settings.MysqlStatementEventWaitTime),
+ metricMysqlTableIoWaitCount: newMetricMysqlTableIoWaitCount(settings.MysqlTableIoWaitCount),
+ metricMysqlTableIoWaitTime: newMetricMysqlTableIoWaitTime(settings.MysqlTableIoWaitTime),
+ metricMysqlThreads: newMetricMysqlThreads(settings.MysqlThreads),
+ metricMysqlTmpResources: newMetricMysqlTmpResources(settings.MysqlTmpResources),
}
for _, op := range options {
op(mb)
@@ -2234,6 +2415,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) {
mb.metricMysqlRowLocks.emit(ils.Metrics())
mb.metricMysqlRowOperations.emit(ils.Metrics())
mb.metricMysqlSorts.emit(ils.Metrics())
+ mb.metricMysqlStatementEventCount.emit(ils.Metrics())
+ mb.metricMysqlStatementEventWaitTime.emit(ils.Metrics())
mb.metricMysqlTableIoWaitCount.emit(ils.Metrics())
mb.metricMysqlTableIoWaitTime.emit(ils.Metrics())
mb.metricMysqlThreads.emit(ils.Metrics())
@@ -2447,6 +2630,16 @@ func (mb *MetricsBuilder) RecordMysqlSortsDataPoint(ts pcommon.Timestamp, inputV
return nil
}
+// RecordMysqlStatementEventCountDataPoint adds a data point to mysql.statement_event.count metric.
+func (mb *MetricsBuilder) RecordMysqlStatementEventCountDataPoint(ts pcommon.Timestamp, val int64, schemaAttributeValue string, digestAttributeValue string, digestTextAttributeValue string, eventStateAttributeValue AttributeEventState) {
+ mb.metricMysqlStatementEventCount.recordDataPoint(mb.startTime, ts, val, schemaAttributeValue, digestAttributeValue, digestTextAttributeValue, eventStateAttributeValue.String())
+}
+
+// RecordMysqlStatementEventWaitTimeDataPoint adds a data point to mysql.statement_event.wait.time metric.
+func (mb *MetricsBuilder) RecordMysqlStatementEventWaitTimeDataPoint(ts pcommon.Timestamp, val int64, schemaAttributeValue string, digestAttributeValue string, digestTextAttributeValue string) {
+ mb.metricMysqlStatementEventWaitTime.recordDataPoint(mb.startTime, ts, val, schemaAttributeValue, digestAttributeValue, digestTextAttributeValue)
+}
+
// RecordMysqlTableIoWaitCountDataPoint adds a data point to mysql.table.io.wait.count metric.
func (mb *MetricsBuilder) RecordMysqlTableIoWaitCountDataPoint(ts pcommon.Timestamp, val int64, ioWaitsOperationsAttributeValue AttributeIoWaitsOperations, tableNameAttributeValue string, schemaAttributeValue string) {
mb.metricMysqlTableIoWaitCount.recordDataPoint(mb.startTime, ts, val, ioWaitsOperationsAttributeValue.String(), tableNameAttributeValue, schemaAttributeValue)
diff --git a/receiver/mysqlreceiver/metadata.yaml b/receiver/mysqlreceiver/metadata.yaml
index 9e39d7d0f1b8..c3727fe92c37 100644
--- a/receiver/mysqlreceiver/metadata.yaml
+++ b/receiver/mysqlreceiver/metadata.yaml
@@ -75,6 +75,16 @@ attributes:
index_name:
value: index
description: The name of the index.
+ digest:
+ value: digest
+ description: Digest.
+ digest_text:
+ value: digest_text
+ description: Text before digestion.
+ event_state:
+ value: kind
+ description: Possible event states.
+ enum: [errors, warnings, rows_affected, rows_sent, rows_examined, created_tmp_disk_tables, created_tmp_tables, sort_merge_passes, sort_rows, no_index_used]
opened_resources:
value: kind
description: The kind of the resource.
@@ -320,6 +330,24 @@ metrics:
monotonic: true
aggregation: cumulative
attributes: [tmp_resource]
+ mysql.statement_event.count:
+ enabled: false
+ description: Summary of current and recent statement events.
+ unit: 1
+ sum:
+ value_type: int
+ monotonic: false
+ aggregation: cumulative
+ attributes: [schema, digest, digest_text, event_state]
+ mysql.statement_event.wait.time:
+ enabled: false
+ description: The total wait time of the summarized timed events.
+ unit: ns
+ sum:
+ value_type: int
+ monotonic: false
+ aggregation: cumulative
+ attributes: [schema, digest, digest_text]
mysql.mysqlx_worker_threads:
enabled: true
description: The number of worker threads available.
diff --git a/receiver/mysqlreceiver/scraper.go b/receiver/mysqlreceiver/scraper.go
index 9336d1a8f666..c69296cbca74 100644
--- a/receiver/mysqlreceiver/scraper.go
+++ b/receiver/mysqlreceiver/scraper.go
@@ -98,6 +98,9 @@ func (m *mySQLScraper) scrape(context.Context) (pmetric.Metrics, error) {
m.scrapeTableIoWaitsStats(now, errs)
m.scrapeIndexIoWaitsStats(now, errs)
+ // collect performance event statements metrics.
+ m.scrapeStatementEventsStats(now, errs)
+
// collect global status metrics.
m.scrapeGlobalStats(now, errs)
@@ -379,6 +382,31 @@ func (m *mySQLScraper) scrapeIndexIoWaitsStats(now pcommon.Timestamp, errs *scra
}
}
+func (m *mySQLScraper) scrapeStatementEventsStats(now pcommon.Timestamp, errs *scrapererror.ScrapeErrors) {
+ statementEventsStats, err := m.sqlclient.getStatementEventsStats()
+ if err != nil {
+ m.logger.Error("Failed to fetch index io_waits stats", zap.Error(err))
+ errs.AddPartial(8, err)
+ return
+ }
+
+ for i := 0; i < len(statementEventsStats); i++ {
+ s := statementEventsStats[i]
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countCreatedTmpDiskTables, s.schema, s.digest, s.digestText, metadata.AttributeEventStateCreatedTmpDiskTables)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countCreatedTmpTables, s.schema, s.digest, s.digestText, metadata.AttributeEventStateCreatedTmpTables)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countErrors, s.schema, s.digest, s.digestText, metadata.AttributeEventStateErrors)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countNoIndexUsed, s.schema, s.digest, s.digestText, metadata.AttributeEventStateNoIndexUsed)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countRowsAffected, s.schema, s.digest, s.digestText, metadata.AttributeEventStateRowsAffected)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countRowsExamined, s.schema, s.digest, s.digestText, metadata.AttributeEventStateRowsExamined)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countRowsSent, s.schema, s.digest, s.digestText, metadata.AttributeEventStateRowsSent)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countSortMergePasses, s.schema, s.digest, s.digestText, metadata.AttributeEventStateSortMergePasses)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countSortRows, s.schema, s.digest, s.digestText, metadata.AttributeEventStateSortRows)
+ m.mb.RecordMysqlStatementEventCountDataPoint(now, s.countWarnings, s.schema, s.digest, s.digestText, metadata.AttributeEventStateWarnings)
+
+ m.mb.RecordMysqlStatementEventWaitTimeDataPoint(now, s.sumTimerWait/picosecondsInNanoseconds, s.schema, s.digest, s.digestText)
+ }
+}
+
func addPartialIfError(errors *scrapererror.ScrapeErrors, err error) {
if err != nil {
errors.AddPartial(1, err)
diff --git a/receiver/mysqlreceiver/scraper_test.go b/receiver/mysqlreceiver/scraper_test.go
index b6a940d7436b..0ca70bfe22be 100644
--- a/receiver/mysqlreceiver/scraper_test.go
+++ b/receiver/mysqlreceiver/scraper_test.go
@@ -39,13 +39,16 @@ func TestScrape(t *testing.T) {
cfg.Username = "otel"
cfg.Password = "otel"
cfg.NetAddr = confignet.NetAddr{Endpoint: "localhost:3306"}
+ cfg.Metrics.MysqlStatementEventCount.Enabled = true
+ cfg.Metrics.MysqlStatementEventWaitTime.Enabled = true
scraper := newMySQLScraper(componenttest.NewNopReceiverCreateSettings(), cfg)
scraper.sqlclient = &mockClient{
- globalStatsFile: "global_stats",
- innodbStatsFile: "innodb_stats",
- tableIoWaitsFile: "table_io_waits_stats",
- indexIoWaitsFile: "index_io_waits_stats",
+ globalStatsFile: "global_stats",
+ innodbStatsFile: "innodb_stats",
+ tableIoWaitsFile: "table_io_waits_stats",
+ indexIoWaitsFile: "index_io_waits_stats",
+ statementEventsFile: "statement_events",
}
actualMetrics, err := scraper.scrape(context.Background())
@@ -66,10 +69,11 @@ func TestScrape(t *testing.T) {
scraper := newMySQLScraper(componenttest.NewNopReceiverCreateSettings(), cfg)
scraper.sqlclient = &mockClient{
- globalStatsFile: "global_stats_partial",
- innodbStatsFile: "innodb_stats_empty",
- tableIoWaitsFile: "table_io_waits_stats_empty",
- indexIoWaitsFile: "index_io_waits_stats_empty",
+ globalStatsFile: "global_stats_partial",
+ innodbStatsFile: "innodb_stats_empty",
+ tableIoWaitsFile: "table_io_waits_stats_empty",
+ indexIoWaitsFile: "index_io_waits_stats_empty",
+ statementEventsFile: "statement_events_empty",
}
actualMetrics, scrapeErr := scraper.scrape(context.Background())
@@ -92,10 +96,11 @@ func TestScrape(t *testing.T) {
var _ client = (*mockClient)(nil)
type mockClient struct {
- globalStatsFile string
- innodbStatsFile string
- tableIoWaitsFile string
- indexIoWaitsFile string
+ globalStatsFile string
+ innodbStatsFile string
+ tableIoWaitsFile string
+ indexIoWaitsFile string
+ statementEventsFile string
}
func readFile(fname string) (map[string]string, error) {
@@ -185,6 +190,39 @@ func (c *mockClient) getIndexIoWaitsStats() ([]IndexIoWaitsStats, error) {
return stats, nil
}
+func (c *mockClient) getStatementEventsStats() ([]StatementEventStats, error) {
+ var stats []StatementEventStats
+ file, err := os.Open(filepath.Join("testdata", "scraper", c.statementEventsFile+".txt"))
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ var s StatementEventStats
+ text := strings.Split(scanner.Text(), "\t")
+
+ s.schema = text[0]
+ s.digest = text[1]
+ s.digestText = text[2]
+ s.sumTimerWait, _ = parseInt(text[3])
+ s.countErrors, _ = parseInt(text[4])
+ s.countWarnings, _ = parseInt(text[5])
+ s.countRowsAffected, _ = parseInt(text[6])
+ s.countRowsSent, _ = parseInt(text[7])
+ s.countRowsExamined, _ = parseInt(text[8])
+ s.countCreatedTmpDiskTables, _ = parseInt(text[9])
+ s.countCreatedTmpTables, _ = parseInt(text[10])
+ s.countSortMergePasses, _ = parseInt(text[11])
+ s.countSortRows, _ = parseInt(text[12])
+ s.countNoIndexUsed, _ = parseInt(text[13])
+
+ stats = append(stats, s)
+ }
+ return stats, nil
+}
+
func (c *mockClient) Close() error {
return nil
}
diff --git a/receiver/mysqlreceiver/testdata/scraper/expected.json b/receiver/mysqlreceiver/testdata/scraper/expected.json
index 2653251f0a4f..cc7b093b32b7 100644
--- a/receiver/mysqlreceiver/testdata/scraper/expected.json
+++ b/receiver/mysqlreceiver/testdata/scraper/expected.json
@@ -1537,6 +1537,361 @@
},
"unit": "ns"
},
+ {
+ "description": "Summary of current and recent statement events.",
+ "name": "mysql.statement_event.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "8",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "created_tmp_disk_tables"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "9",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "created_tmp_tables"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "3",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "errors"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "12",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "no_index_used"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "5",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "rows_affected"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "7",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "rows_examined"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "6",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "rows_sent"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "10",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "sort_merge_passes"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "11",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "sort_rows"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "4",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "warnings"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ }
+ ]
+ },
+ "unit": "1"
+ },
+ {
+ "description": "The total wait time of the summarized timed events.",
+ "name": "mysql.statement_event.wait.time",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "2",
+ "attributes": [
+ {
+ "key": "digest",
+ "value": {
+ "stringValue": "070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317"
+ }
+ },
+ {
+ "key": "digest_text",
+ "value": {
+ "stringValue": "SHOW GLOBAL STATUS"
+ }
+ },
+ {
+ "key": "schema",
+ "value": {
+ "stringValue": "otel"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ }
+ ]
+ },
+ "unit": "ns"
+ },
{
"description": "The number of worker threads available.",
"name": "mysql.mysqlx_worker_threads",
diff --git a/receiver/mysqlreceiver/testdata/scraper/statement_events.txt b/receiver/mysqlreceiver/testdata/scraper/statement_events.txt
new file mode 100644
index 000000000000..fd49b0d4058e
--- /dev/null
+++ b/receiver/mysqlreceiver/testdata/scraper/statement_events.txt
@@ -0,0 +1 @@
+otel 070e38632eb4444e50cdcbf0b17474ba801e203add89783a24584951442a2317 SHOW GLOBAL STATUS 2000 3 4 5 6 7 8 9 10 11 12
diff --git a/receiver/mysqlreceiver/testdata/scraper/statement_events_empty.txt b/receiver/mysqlreceiver/testdata/scraper/statement_events_empty.txt
new file mode 100644
index 000000000000..e69de29bb2d1