Source Code
- Go to your cloned repository:
cd /path/to/watchlog-agent vim integration.json - Locate the MySQL config:
{ "service": "mysql", "monitor": false, "host": "localhost", "port": "3306", "username": "root", "password": "", "database": [] }
3. Set `"monitor"` to `true` and fill in the credentials:
```diff
- "monitor": false
+ "monitor": true
database is only read by the legacy collector. The advanced collector discovers every schema itself, so leaving it [] is correct for new setups. 4. Restart the agent:
pm2 restart watchlog-agent
Run the collector directly
Useful for checking what a given server actually exposes without waiting for the 60s tick:
node -e "
const list = require('./integration.json');
const cfg = list.find(i => i.service === 'mysql');
require('./app/integrations/mysql/index').collect(cfg, (err, res) => {
if (err) return console.error('failed:', err.message);
const a = res.advanced;
console.log('version :', a.server.version, '(' + a.server.flavour + ')');
console.log('capabilities :', JSON.stringify(a.capabilities));
console.log('notes :', JSON.stringify(a.capabilityNotes || []));
console.log('digests :', (a.queries || []).length);
console.log('tables :', (a.tables || []).length);
});
"
The capabilityNotes array is the useful part when a tab is missing — it names the exact reason, e.g. performance_schema is disabled; query, index and lock detail are unavailable.
Running the tests
The MySQL parsers, query normalizer and collector derivations are covered by the agent's test suite, which needs no live server:
npm test
Fixtures deliberately cover what a live server cannot show you on demand: a MariaDB row shape, a 5.7 lock table, a counter reset after restart, and a permission-denied path.
Development notes
- The advanced collector is
app/integrations/mysql/index.js; the legacy one isapp/integrations/mysql.jsbeside it. Require the advanced one by full path. performance_schematimings are picoseconds. Divide by 1e9 for milliseconds. This is the opposite of PostgreSQL, whosepg_stat_statementstimings are already milliseconds.- Queries are ranked by impact — executions in the interval × interval mean latency — not by average latency. Sorting by average hides the 2 ms query running 50 000 times.
- An unused index is
reads === 0, notreads === 0 && writes === 0. The second form excludes every index on a write-heavy table.UNIQUEandPRIMARYare protected viainformation_schema.statisticsand are never removal candidates. CARDINALITYis an InfluxQL reserved word and appears naturally in index queries — every alias inmysqlAdvanced.jsmust stay quoted, or the endpoint returns a runtime-only 500.- Version gates live in
parsers.js:supportsDataLocks(MySQL 8+, never MariaDB) andsupportsReplicaTerminology(MySQL 8.0.22+). Nothing downstream branches on version — the queries alias everything to one stable shape. - Never log query text from a driver error. Driver errors echo the failing statement, and statements carry literals.
