Skip to content

Conversation

sklochkov
Copy link

What & why

This PR adds two opt-in collectors that expose per-user statement activity from MySQL’s sys schema, and fixes a failure mode in the existing --collect.sys.user_summary on MySQL 8.x. It also includes unit tests, docs, and a Docker Compose harness to exercise collectors locally.

New collectors (opt-in)

  • --collect.sys.user_summary_by_statement_latency
    Scrapes sys.x$user_summary_by_statement_latency to expose per-user totals and latency aggregates.

  • --collect.sys.user_summary_by_statement_type
    Scrapes sys.x$user_summary_by_statement_type to expose per-user by statement type aggregates.

Requirements: MySQL ≥ 5.7 with performance_schema enabled and the sys schema available.

Harden existing collector

  • --collect.sys.user_summary
    Some MySQL 8.x installations occasionally surface negative values for current_memory / total_memory_allocated in the sys view, which previously caused a scan into uint64 to fail and the scrape to error. We now clamp these to ≥ 0 (via SQL), avoiding exporter errors while preserving metric semantics.

Flags & metrics

--collect.sys.user_summary_by_statement_latency

Labels: user
Emits:

  • mysql_sys_user_summary_by_statement_latency_total
  • mysql_sys_user_summary_by_statement_latency (seconds total)
  • mysql_sys_user_summary_by_statement_max_latency (seconds)
  • mysql_sys_user_summary_by_statement_lock_latency (seconds total)
  • mysql_sys_user_summary_by_statement_cpu_latency (seconds total)
  • mysql_sys_user_summary_by_statement_rows_sent_total
  • mysql_sys_user_summary_by_statement_rows_examined_total
  • mysql_sys_user_summary_by_statement_rows_affected_total
  • mysql_sys_user_summary_by_statement_full_scans_total

--collect.sys.user_summary_by_statement_type

Labels: user, statement
Emits:

  • mysql_sys_user_summary_by_statement_type_total
  • mysql_sys_user_summary_by_statement_type_latency (seconds total)
  • mysql_sys_user_summary_by_statement_type_max_latency (seconds)
  • mysql_sys_user_summary_by_statement_type_lock_latency (seconds total)
  • mysql_sys_user_summary_by_statement_type_cpu_latency (seconds total)
  • mysql_sys_user_summary_by_statement_type_rows_sent_total
  • mysql_sys_user_summary_by_statement_type_rows_examined_total
  • mysql_sys_user_summary_by_statement_type_rows_affected_total
  • mysql_sys_user_summary_by_statement_type_full_scans_total

Implementation notes

  • Metric names follow the existing sys_user_summary.go style (namespace mysql, subsystem sys, metric stem user_summary_by_*).
  • Latencies are converted from picoseconds → seconds using the shared picoSeconds constant.
  • Exported as gauges, in line with other sys collectors.

Behavior change in --collect.sys.user_summary

  • Query uses GREATEST(current_memory, 0) and GREATEST(total_memory_allocated, 0) to avoid negative values in 8.x. No metric name/type changes.

Testing

Unit tests

  • New: sys_user_summary_by_statement_latency_test.go
  • New: sys_user_summary_by_statement_type_test.go
  • Updated: sys_user_summary_test.go (robust SQL matcher, guard channel reads, fix column name, align with clamping)

Each test uses sqlmock and the repo’s MetricResult/readMetric helpers to verify:

  • SQL is issued against the correct sys.x$… view,
  • label sets and value order,
  • latency ps→seconds conversion,
  • metric types (gauges).

Run:

go test ./collector -run UserSummary
go test ./...

Docker Compose integration harness (developer convenience)

A self-contained script to validate collectors against a local MySQL:

  • docker-compose.yml (fixed network mysql-test)

  • mysql/conf.d/perf-schema.cnf (ensures Performance Schema/consumers on)

  • mysql/initdb/01-users.sql (creates/grants exporter and app; caching_sha2_password)

  • seed/seed.sh (simple INSERT/SELECT/UPDATE/SLEEP to populate sys views)

  • test_compose_collectors.sh

    • builds local exporter image
    • ensures users/grants if the data dir is reused
    • starts exporter per --collect.* flag (inside the Docker network; no host port binding)
    • fetches /metrics from inside the network
    • writes per-flag logs to _testlogs/
    • includes a broad TESTS set (plus optional auto-discovery of flags from --help)

Run:

./test_compose_collectors.sh

Backwards compatibility & perf

  • New collectors are disabled by default; no changes for existing users unless flags are set.
  • The user_summary clamp only affects rare negative values; otherwise behavior and types are unchanged.
  • Queries are single simple SELECTs over sys.x$… views; expected to be inexpensive with Performance Schema enabled.

How to review

Key files:

  • collector/sys_user_summary_by_statement_latency.go
  • collector/sys_user_summary_by_statement_type.go
  • collector/sys_user_summary.go (clamp)
  • collector/*_test.go (new + updated tests)
  • README.md (docs for new flags + integration test)
  • docker-compose.yml, mysql/, seed/, test_compose_collectors.sh (integration harness)

Happy to split the test harness/docs into a separate PR if you prefer, but they’re isolated from runtime code.

@sklochkov sklochkov force-pushed the main branch 2 times, most recently from 4141e24 to c889bec Compare September 11, 2025 15:46
…p negative memory; unit tests

Add two new collectors:
- --collect.sys.user_summary_by_statement_latency
- --collect.sys.user_summary_by_statement_type

Both follow the existing sys collector patterns:
- metric names: mysql_sys_user_summary_by_statement_{latency|type}_*
- label sets: {user} and {user,statement}
- latencies converted from picoseconds to seconds (picoSeconds)
- exported as gauges

Also harden --collect.sys.user_summary against negative memory values
observed on MySQL 8.x by clamping:
  GREATEST(current_memory, 0) AS current_memory
  GREATEST(total_memory_allocated, 0) AS total_memory_allocated

Tests:
- Update sys_user_summary_test.go:
  * robust SQL regex match
  * channel-read guard (no nil deref)
  * column name typo fixed ("statements")
  * expected values aligned with SQL-side clamping
- Add sys_user_summary_by_statement_latency_test.go
- Add sys_user_summary_by_statement_type_test.go

Notes:
- No changes to default enablement; flags must be passed explicitly.
- Metric help strings note seconds for latency metrics.

Verification:
- go test ./collector -run UserSummary
- go test ./... (full)

Signed-off-by: Sergei Klochkov <[email protected]>
… runner; docs

Add a self-contained integration test that spins up MySQL 8.4 with
performance_schema, seeds a small workload, and validates collectors
via a locally-built exporter image.

What's included:
- docker-compose.yml (fixed network name: mysql-test)
- mysql/conf.d/perf-schema.cnf
- mysql/initdb/01-users.sql (exporter/app users, grants)
- seed/seed.sh (INSERT/SELECT/UPDATE/SLEEP loop)
- test_compose_collectors.sh:
  * builds mysqld-exporter:local
  * ensures users (caching_sha2_password)
  * runs exporter per --collect.* flag (no host port binding)
  * curls /metrics from inside the network
  * per-flag log files under ./_testlogs/
  * robust readiness + failure diagnostics
  * optional auto-discovery of collector flags from --help

Docs (README.md):
- Document new flags:
  --collect.sys.user_summary_by_statement_latency
  --collect.sys.user_summary_by_statement_type
  * list emitted metric families and units
- Note clamping behavior in --collect.sys.user_summary
- Add "Docker Compose integration test" section with usage

Usage:
  ./test_compose_collectors.sh
Artifacts:
  _testlogs/exporter_<flag>.log

License:
  Added the mandatory license comments to the newly-committed source files.

This commit touches only test infra and docs; no exporter runtime code changes.

Signed-off-by: Sergei Klochkov <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant