Monitoring MySQL with the HTTP collector
Subscribe

From OpenNMS

Jump to: navigation, search

Contents

HOWTO: Monitoring MySQL with the HTTP collector

There are sometimes situations where SNMP monitoring isn“t possible. If you have a hosted website and would like monitor your MySQL statistics you can use the HTTP-Collector and little PHP-page to collect some statistics.

First you have to create a little PHP file (e.g. mystats.php) like this:

 <?php
   ##
   ## sqlstats()
   ## -> Get mysql stats and display them
   ##
   sqlstats();
 
   function sqlstats() {
     $db_host = "<your-mysql-server>";
     $db_user = "<your-db-user>";
     $db_pass = "<your-db-password>";
     $db_name = "<your-db>";
   
     ## Connect to mysql and gather data
     $link = mysql_connect($db_host,$db_user,$db_pass) or die("Unable to connect to MySQL");
 
     $stats = explode(' ', mysql_stat($link));
     $myLink = mysql_stat($link);
     echo $myLink;
 
     ## Data gather complete, close MySQL connection
     mysql_close();
   }
 ?>

If you deployed this file to your server correctly the output looks like this:

 Uptime: 2132074 Threads: 2 Questions: 5917908 Slow queries: 3 Opens: 118392 Flush tables: 1 Open tables: 768 Queries per second avg: 2.776

Next we can start to use OpenNMS to graph this stuff.

Identify data collection

To identify the node to do the HTTP datacollection. I created a service HTTP-MySQL-Stats in the configuration file capsd-configuration.xml. I prefer the manual provisioning method so I turned scan=off. You can also create detection with Capsd to make HTTP call to /mystats.php.

 <protocol-plugin protocol="HTTP-MySQL-Stats" class-name="org.opennms.netmgt.capsd.plugins.HttpPlugin" scan="off">
     <property key="port" value="80" />
     <property key="timeout" value="3000" />
     <property key="retry" value="1" />
 </protocol-plugin>

Create a collection package

Tell the collectd to use a http-collection package. For this we have to add this service in collectd-configuration.xml. The package we will collect is named mysql-stats.

 <package name="default">
     <filter>IPADDR != '0.0.0.0'</filter>	 
     <include-range begin="1.1.1.1" end="254.254.254.254"/>
 	
     <service name="SNMP" interval="300000" user-defined="false" status="on">
         <parameter key="collection" value="default"/>
     </service>
     <service name="HTTP-MySQL-Stats" interval="300000" user-defined="false" status="on">
         <parameter key="collection" value="mysql-stats"/>
     </service>
 </package>
 ...
 <collector service="HTTP-MySQL-Stats"  class-name="org.opennms.netmgt.collectd.HttpCollector"/>

Define a HTTP collection package

Now we have to define the specific values to collect in the http-datacollection-config.xml.

 <http-collection name="mysql-stats">
     <rrd step="300">
         <rra>RRA:AVERAGE:0.5:1:8928</rra>
         <rra>RRA:AVERAGE:0.5:12:8784</rra>
         <rra>RRA:MIN:0.5:12:8784</rra>
         <rra>RRA:MAX:0.5:12:8784</rra>
     </rrd>
     <uris>
         <uri name="mysql-stats">
             <url path="/mystats.php"
                 virtual-host="<your-host>"
                 user-agent="OpenNMS HTTP Datacollection" 
                 matches="(?s).*Uptime:\s([0-9]+).*Threads:\s([0-9]+).*Questions:\s([0-9]+).*Slow queries:\s([0-9]+).* \
                   Opens:\s([0-9]+).*Flush tables:\s([0-9]+).*Open tables:\s([0-9]+).*Queries per second avg:\s([0-9]+). \
                   ([0-9]+).*" response-range="100-399">
             </url>
             <attributes>
                 <attrib alias="uptime" match-group="1" type="integer"/>
                 <attrib alias="threads" match-group="2" type="gauge32"/>
                 <attrib alias="questions" match-group="3" type="counter32"/>
                 <attrib alias="slowQueries" match-group="4" type="gauge32"/>
                 <attrib alias="opens" match-group="5" type="counter32"/>
                 <attrib alias="flushTables" match-group="6" type="gauge32"/>
                 <attrib alias="openTables" match-group="7" type="gauge32"/>
                 <attrib alias="queriesPerSec" match-group="8" type="integer"/>
                 <attrib alias="queriesPerSecMilli" match-group="9" type="integer"/>
             </attributes>
         </uri>
     </uris>
 </http-collection>

The line matches should be a one liner but for better reading the line break is marked with \.

Define graphs

To display the collected values in the WebUI we have to define a graph definition in snmp-graph.properties. First define the new reports in the PREFAB section:

 reports= ... mysql.stats.uptime, mysql.stats.threads, mysql.stats.questions, mysql.stats.slowqueries, \
              mysql.stats.opens, mysql.stats.flushtables, mysql.stats.opentables, mysql.stats.queries

Now the graphs itself

 #########
 ## MySQL stats http data collection
 ########
 
 report.mysql.stats.uptime.name=MySQL Uptime
 report.mysql.stats.uptime.columns=uptime
 report.mysql.stats.uptime.type=nodeSnmp
 report.mysql.stats.uptime.command=--title="MySQL Uptime" \
  --vertical-label Days \
  DEF:time={rrd1}:uptime:AVERAGE \
  DEF:minTime={rrd1}:uptime:MIN \
  DEF:maxTime={rrd1}:uptime:MAX \
  CDEF:days=time,86400,/ \
  CDEF:minDays=minTime,86400,/ \
  CDEF:maxDays=maxTime,86400,/ \
  LINE2:days#0000ff:"Uptime (Days)" \
  GPRINT:days:AVERAGE:"Avg  \\: %8.1lf %s" \
  GPRINT:days:MIN:"Min  \\: %8.1lf %s" \
  GPRINT:days:MAX:"Max  \\: %8.1lf %s\\n"
 
 report.mysql.stats.threads.name=MySQL Threads
 report.mysql.stats.threads.columns=threads
 report.mysql.stats.threads.type=nodeSnmp
 report.mysql.stats.threads.command=--title="MySQL Threads" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgThreads={rrd1}:threads:AVERAGE \
  DEF:minThreads={rrd1}:threads:MIN \
  DEF:maxThreads={rrd1}:threads:MAX \
  LINE2:avgThreads#000000:"Threads" \
  GPRINT:avgThreads:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minThreads:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxThreads:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.questions.name=MySQL Questions
 report.mysql.stats.questions.columns=questions
 report.mysql.stats.questions.type=nodeSnmp
 report.mysql.stats.questions.command=--title="MySQL Questions" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgQuest={rrd1}:questions:AVERAGE \
  DEF:minQuest={rrd1}:questions:MIN \
  DEF:maxQuest={rrd1}:questions:MAX \
  AREA:avgQuest#0000ff:"Questions" \
  GPRINT:avgQuest:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minQuest:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxQuest:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.slowqueries.name=MySQL Slow Queries
 report.mysql.stats.slowqueries.columns=slowQueries
 report.mysql.stats.slowqueries.type=nodeSnmp
 report.mysql.stats.slowqueries.command=--title="MySQL Slow Queries" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgSlowQueries={rrd1}:slowQueries:AVERAGE \
  DEF:minSlowQueries={rrd1}:slowQueries:MIN \
  DEF:maxSlowQueries={rrd1}:slowQueries:MAX \
  LINE2:avgSlowQueries#0000ff:"Slow Queries" \
  GPRINT:avgSlowQueries:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minSlowQueries:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxSlowQueries:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.opens.name=MySQL Opens
 report.mysql.stats.opens.columns=opens
 report.mysql.stats.opens.type=nodeSnmp
 report.mysql.stats.opens.command=--title="MySQL Opens" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgopens={rrd1}:opens:AVERAGE \
  DEF:minopens={rrd1}:opens:MIN \
  DEF:maxopens={rrd1}:opens:MAX \
  LINE2:avgopens#bc5500:"Opens" \
  GPRINT:avgopens:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minopens:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxopens:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.flushtables.name=MySQL Flush Tables
 report.mysql.stats.flushtables.columns=flushTables
 report.mysql.stats.flushtables.type=nodeSnmp
 report.mysql.stats.flushtables.command=--title="MySQL Flush tables" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgflshTbles={rrd1}:flushTables:AVERAGE \
  DEF:minflshTbles={rrd1}:flushTables:MIN \
  DEF:maxflshTbles={rrd1}:flushTables:MAX \
  LINE2:avgflshTbles#00ff00:"Flush Tables" \
  GPRINT:avgflshTbles:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minflshTbles:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxflshTbles:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.opentables.name=MySQL Open Tables
 report.mysql.stats.opentables.columns=openTables
 report.mysql.stats.opentables.type=nodeSnmp
 report.mysql.stats.opentables.command=--title="MySQL Open Tables" \
  --vertical-label="count" \
  --lower-limit 0 \
  DEF:avgOpenTbles={rrd1}:openTables:AVERAGE \
  DEF:minOpenTbles={rrd1}:openTables:MIN \
  DEF:maxOpenTbles={rrd1}:openTables:MAX \
  LINE2:avgOpenTbles#ff0000:"Flush Tables" \
  GPRINT:avgOpenTbles:AVERAGE:"Avg \\: %10.2lf %s" \
  GPRINT:minOpenTbles:MIN:"Min \\: %10.2lf %s" \
  GPRINT:maxOpenTbles:MAX:"Max \\: %10.2lf %s\\n"
 
 report.mysql.stats.queries.name=MySQL Queries per second (avg)
 report.mysql.stats.queries.columns=queriesPerSec, queriesPerSecMilli
 report.mysql.stats.queries.type=nodeSnmp
 report.mysql.stats.queries.command=--title="MySQL Queries per second (avg)" \
  --vertical-label="second" \
  DEF:avgQryPerSec={rrd1}:queriesPerSec:AVERAGE \
  DEF:minQryPerSec={rrd1}:queriesPerSec:MIN \
  DEF:maxQryPerSec={rrd1}:queriesPerSec:MAX \
  DEF:rawAvgQryPerSecMilli={rrd2}:queriesPerSecMilli:AVERAGE \
  DEF:rawMinQryPerSecMilli={rrd2}:queriesPerSecMilli:MIN \
  DEF:rawMaxQryPerSecMilli={rrd2}:queriesPerSecMilli:MAX \
  CDEF:avgQryPerSecMilli=rawAvgQryPerSecMilli,1000,/ \
  CDEF:minQryPerSecMilli=rawMinQryPerSecMilli,1000,/ \
  CDEF:maxQryPerSecMilli=rawMaxQryPerSecMilli,1000,/ \
  CDEF:avgDrQryPerSec=avgQryPerSec,avgQryPerSecMilli,+ \
  CDEF:minDrQryPerSec=minQryPerSec,minQryPerSecMilli,+ \
  CDEF:maxDrQryPerSec=maxQryPerSec,maxQryPerSecMilli,+ \
  LINE2:avgDrQryPerSec#0000FF:"Queries per second " \
  GPRINT:avgDrQryPerSec:AVERAGE:"Avg \\: %8.2lf %s" \
  GPRINT:minDrQryPerSec:MIN:"Min \\: %8.2lf %s" \
  GPRINT:maxDrQryPerSec:MAX:"Max \\: %8.2lf %s\\n"

It is a good idea to add all your self defined graphs at the end of a section, to make it easier to keep your OpenNMS up to date. Feel free to use and extend this little How-To.