├── static ├── .DS_Store └── newops.jpg ├── zabbix ├── static │ └── tcp.png ├── zabbix-mysql-monitor │ ├── ss_get_mysql_stats.php.cnf │ ├── README.md │ ├── get_mysql_stats_wrapper.sh │ ├── mysql_status.conf │ └── ss_get_mysql_stats.php ├── zabbix-tcp-monitor │ ├── tcp_status.conf │ ├── README.md │ ├── tcp_status.sh │ └── zbx_tcp_status_templates.xml ├── zabbix-redis-monitor │ ├── redis_status.conf │ ├── README.md │ ├── redis_status.sh │ └── zbx_export_redis_status_templates.xml └── API拨测.md ├── README.md └── LICENSE /static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixhot/newops-x/HEAD/static/.DS_Store -------------------------------------------------------------------------------- /static/newops.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixhot/newops-x/HEAD/static/newops.jpg -------------------------------------------------------------------------------- /zabbix/static/tcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixhot/newops-x/HEAD/zabbix/static/tcp.png -------------------------------------------------------------------------------- /zabbix/zabbix-mysql-monitor/ss_get_mysql_stats.php.cnf: -------------------------------------------------------------------------------- 1 | 配置-->模板-->导入-->选择zbx_export_templates-redis.xml,注意请讲聚合图形选择上。 10 | 11 | 4. 在对应的主机上添加该模板 12 | -------------------------------------------------------------------------------- /zabbix/zabbix-mysql-monitor/README.md: -------------------------------------------------------------------------------- 1 | # MySQL 状态监控模板 For Zabbix 3.x ~ 4.x 2 | 3 | ## 使用帮助 4 | 5 | 基于Percona监控插件,官方提供的模板在Zabbix版本大于2.0无法正常使用。 6 | 7 | 1. 请将get_mysql_stats_wrapper.sh ss_get_mysql_stats.php ss_get_mysql_stats.php.cnf放置在/etc/zabbix/plugins目录下,并设置执行权限 chmod +x /etc/zabbix/plugins/get_mysql_stats_wrapper.sh 8 | 9 | 2. 请将redis_status.conf放置在/etc/zabbix/zabbix.agentd.d/目录下 10 | 11 | 3. 打开Web界面-->配置-->模板-->导入-->选择zbx_export_templates-redis.xml,注意请讲聚合图形选择上。 12 | 13 | 4. 在对应的主机上添加该模板 14 | -------------------------------------------------------------------------------- /zabbix/zabbix-tcp-monitor/README.md: -------------------------------------------------------------------------------- 1 | # TCP 状态监控模板 2 | 3 | - 支持Zabbix版本:Zabbix 3.x ~ 4.x 4 | 5 | ## 插件介绍 6 | 7 | - 通过ss获取TCP的11种状态,进行监控 8 | 9 | ## 使用帮助 10 | 11 | 1. 请将tcp_status.sh放置在/etc/zabbix/plugins/目录下,并设置执行权限 chmod +x /etc/zabbix/plugins/tcp_status.sh 12 | 13 | 2. 请将tcp_status.conf放置在/etc/zabbix/zabbix.agentd.d/目录下 14 | 15 | 3. 打开Web界面-->配置-->模板-->导入-->选择zbx_export_templates-tcp.xml,注意请将聚合图形选择上。 16 | 17 | 4. 在对应的主机上添加该模板 18 | 19 | ## 截图展示 20 | 21 | ![TCP](https://github.com/unixhot/newops-x/blob/master/zabbix/static/tcp.png) 22 | 23 | 24 | -------------------------------------------------------------------------------- /zabbix/API拨测.md: -------------------------------------------------------------------------------- 1 | ## 基于pyresttest的restful接口测试 2 | 3 | * [官方网站](https://github.com/svanoort/pyresttest) 4 | 5 | ### 安装pyresttest 6 | 7 | ``` 8 | [root@linux-node1 ~]# yum install -y python-pip 9 | 10 | [root@linux-node1 ~]# pip install pyresttest 11 | ``` 12 | 13 | ### 编写一个最简单的接口测试配置 14 | 15 | pyresttest使用YAML格式描述接口测试的请求的URL,请求的方法、请求头和请求主体。 16 | ``` 17 | [root@linux-node1 ~]# vim github-api-test.yaml 18 | 19 | --- 20 | - config: 21 | - testset: "Basic tests" 22 | - timeout: 100 23 | - test: 24 | - name: "Basic get" 25 | - url: "/events" 26 | 27 | ``` 28 | 29 | ### 进行第一次测试 30 | 使用pyresttest指定URL和配置文件即可进行接口状态测试。 31 | ``` 32 | [root@linux-node1 ~]# pyresttest --url=https://api.github.com/ github-api-test.yaml 33 | Test Group Default SUCCEEDED: : 1/1 Tests Passed! 34 | ``` 35 | -------------------------------------------------------------------------------- /zabbix/zabbix-redis-monitor/redis_status.sh: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # $Name: zabbix_linux_plugins.sh 3 | # $Version: v1.0 4 | # $Function: zabbix plugins 5 | # $Author: Jason Zhao 6 | # $organization: www.unixhot.com 7 | # $Create Date: 2014-08-10 8 | # $Description: Monitor Linux Service Status 9 | ############################################################ 10 | redis_status_fun(){ 11 | R_HOST=$1 12 | R_PORT=$2 13 | R_STAT_KEY=$3 14 | (echo -en "INFO \r\n";sleep 1;) | nc "$R_HOST" "$R_PORT" > /tmp/redis_"$R_PORT".tmp 15 | REDIS_STAT_VALUE=$(grep ""$R_STAT_KEY":" /tmp/redis_"$R_PORT".tmp | cut -d ':' -f2) 16 | echo $REDIS_STAT_VALUE 17 | } 18 | 19 | main(){ 20 | redis_status_fun $1 $2 $3 21 | } 22 | 23 | main $1 $2 $3 24 | -------------------------------------------------------------------------------- /zabbix/zabbix-tcp-monitor/tcp_status.sh: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # $Name: zabbix_linux_plugins.sh 3 | # $Version: v1.0 4 | # $Function: zabbix plugins 5 | # $Author: Jason Zhao 6 | # $organization: www.unixhot.com 7 | # $Create Date: 2014-08-10 8 | # $Description: Monitor Linux Service Status 9 | ############################################################ 10 | tcp_status_fun(){ 11 | TCP_STAT=$1 12 | #netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,state[key]}' > /tmp/netstat.tmp 13 | ss -ant | awk 'NR>1 {++s[$1]} END {for(k in s) print k,s[k]}' > /tmp/netstat.tmp 14 | TCP_STAT_VALUE=$(grep "$TCP_STAT" /tmp/netstat.tmp | cut -d ' ' -f2) 15 | if [ -z $TCP_STAT_VALUE ];then 16 | TCP_STAT_VALUE=0 17 | fi 18 | echo $TCP_STAT_VALUE 19 | } 20 | 21 | main(){ 22 | tcp_status_fun $1 23 | } 24 | 25 | main $1 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 新运维社区 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /zabbix/zabbix-mysql-monitor/get_mysql_stats_wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # The wrapper for Cacti PHP script. 3 | # It runs the script every 5 min. and parses the cache file on each following run. 4 | # Version: 1.1.8 5 | # 6 | # This program is part of Percona Monitoring Plugins 7 | # License: GPL License (see COPYING) 8 | # Copyright: 2018 Percona 9 | # Authors: Roman Vynar 10 | 11 | ITEM=$1 12 | HOST=localhost 13 | DIR=`dirname $0` 14 | CMD="/usr/bin/php -q $DIR/ss_get_mysql_stats.php --host $HOST --items gg" 15 | CACHEFILE="/tmp/$HOST-mysql_cacti_stats.txt" 16 | 17 | if [ "$ITEM" = "running-slave" ]; then 18 | # Check for running slave 19 | RES=`HOME=~zabbix mysql -e 'SHOW SLAVE STATUS\G' | egrep '(Slave_IO_Running|Slave_SQL_Running):' | awk -F: '{print $2}' | tr '\n' ','` 20 | if [ "$RES" = " Yes, Yes," ]; then 21 | echo 1 22 | else 23 | echo 0 24 | fi 25 | exit 26 | elif [ -e $CACHEFILE ]; then 27 | # Check and run the script 28 | TIMEFLM=`stat -c %Y /tmp/$HOST-mysql_cacti_stats.txt` 29 | TIMENOW=`date +%s` 30 | if [ `expr $TIMENOW - $TIMEFLM` -gt 300 ]; then 31 | rm -f $CACHEFILE 32 | $CMD 2>&1 > /dev/null 33 | fi 34 | else 35 | $CMD 2>&1 > /dev/null 36 | fi 37 | 38 | # Parse cache file 39 | if [ -e $CACHEFILE ]; then 40 | cat $CACHEFILE | sed 's/ /\n/g; s/-1/0/g'| grep $ITEM | awk -F: '{print $2}' 41 | else 42 | echo "ERROR: run the command manually to investigate the problem: $CMD" 43 | fi 44 | -------------------------------------------------------------------------------- /zabbix/zabbix-redis-monitor/zbx_export_redis_status_templates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0 4 | 2019-07-25T05:43:30Z 5 | 6 | 7 | Templates 8 | 9 | 10 | 11 | 203 | 204 | 205 | 206 | {Template Redis Status:redis-status[{HOST.IP},{$REDIS.PORT},used_memory].last(#1)}>800000 207 | 0 208 | 209 | Redis Memory 超过最大值 210 | 0 211 | 212 | 213 | 0 214 | 3 215 | 216 | 0 217 | 1 218 | 219 | 220 | 221 | 222 | 223 | 224 | Redis Status Client 225 | 900 226 | 200 227 | 0.0000 228 | 100.0000 229 | 1 230 | 1 231 | 0 232 | 1 233 | 0 234 | 0.0000 235 | 0.0000 236 | 0 237 | 0 238 | 0 239 | 0 240 | 241 | 242 | 0 243 | 0 244 | 1A7C11 245 | 0 246 | 2 247 | 0 248 | 249 | Template Redis Status 250 | redis-status[{HOST.IP},{$REDIS.PORT},connected_clients] 251 | 252 | 253 | 254 | 255 | 256 | Redis Status Memory 257 | 900 258 | 200 259 | 0.0000 260 | 100.0000 261 | 1 262 | 1 263 | 0 264 | 1 265 | 0 266 | 0.0000 267 | 0.0000 268 | 0 269 | 0 270 | 0 271 | 0 272 | 273 | 274 | 0 275 | 0 276 | 1A7C11 277 | 0 278 | 2 279 | 0 280 | 281 | Template Redis Status 282 | redis-status[{HOST.IP},{$REDIS.PORT},used_memory] 283 | 284 | 285 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /zabbix/zabbix-mysql-monitor/mysql_status.conf: -------------------------------------------------------------------------------- 1 | UserParameter=MySQL.Sort-scan,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kt 2 | UserParameter=MySQL.slave-stopped,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jh 3 | UserParameter=MySQL.Com-replace,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jz 4 | UserParameter=MySQL.innodb-lock-structs,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lp 5 | UserParameter=MySQL.Com-load,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kg 6 | UserParameter=MySQL.State-updating,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mi 7 | UserParameter=MySQL.Aborted-clients,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ip 8 | UserParameter=MySQL.innodb-lock-wait-secs,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ni 9 | UserParameter=MySQL.Handler-read-key,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mr 10 | UserParameter=MySQL.file-reads,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gy 11 | UserParameter=MySQL.Query-time-count-12,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ox 12 | UserParameter=MySQL.relay-log-space,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lj 13 | UserParameter=MySQL.Threads-connected,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iu 14 | UserParameter=MySQL.Qcache-lowmem-prunes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jp 15 | UserParameter=MySQL.Binlog-cache-use,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lm 16 | UserParameter=MySQL.State-freeing-items,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lt 17 | UserParameter=MySQL.Query-time-count-10,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ov 18 | UserParameter=MySQL.read-views,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gm 19 | UserParameter=MySQL.Bytes-received,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ky 20 | UserParameter=MySQL.os-waits,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hv 21 | UserParameter=MySQL.Handler-commit,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mm 22 | UserParameter=MySQL.Com-select,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jx 23 | UserParameter=MySQL.Qcache-total-blocks,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh js 24 | UserParameter=MySQL.Handler-read-prev,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mt 25 | UserParameter=MySQL.Sort-rows,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ks 26 | UserParameter=MySQL.Qcache-free-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jm 27 | UserParameter=MySQL.pages-read,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gu 28 | UserParameter=MySQL.Key-read-requests,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gg 29 | UserParameter=MySQL.State-other,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ml 30 | UserParameter=MySQL.Qcache-inserts,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jo 31 | UserParameter=MySQL.State-none,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mk 32 | UserParameter=MySQL.pending-normal-aio-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hp 33 | UserParameter=MySQL.hash-index-cells-total,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nj 34 | UserParameter=MySQL.pool-size,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gq 35 | UserParameter=MySQL.pending-ibuf-aio-reads,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hl 36 | UserParameter=MySQL.Handler-write,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ng 37 | UserParameter=MySQL.innodb-sem-waits,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ny 38 | UserParameter=MySQL.Handler-savepoint-rollback,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh my 39 | UserParameter=MySQL.Query-time-total-01,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pg 40 | UserParameter=MySQL.Query-time-total-00,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oz 41 | UserParameter=MySQL.Table-locks-waited,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ig 42 | UserParameter=MySQL.Handler-rollback,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mw 43 | UserParameter=MySQL.unflushed-log,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lg 44 | UserParameter=MySQL.Query-time-total-04,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pj 45 | UserParameter=MySQL.Query-time-total-07,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pm 46 | UserParameter=MySQL.Handler-savepoint,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mx 47 | UserParameter=MySQL.Query-time-total-09,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh po 48 | UserParameter=MySQL.Query-time-total-08,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pn 49 | UserParameter=MySQL.Select-range-check,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ko 50 | UserParameter=MySQL.Threads-running,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iw 51 | UserParameter=MySQL.State-init,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lu 52 | UserParameter=MySQL.Aborted-connects,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iq 53 | UserParameter=MySQL.Handler-read-first,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mq 54 | UserParameter=MySQL.Created-tmp-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ku 55 | UserParameter=MySQL.Created-tmp-disk-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kv 56 | UserParameter=MySQL.Select-full-range-join,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh km 57 | UserParameter=MySQL.Connections,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iz 58 | UserParameter=MySQL.Com-insert,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jw 59 | UserParameter=MySQL.Query-time-total-11,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pq 60 | UserParameter=MySQL.innodb-transactions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gl 61 | UserParameter=MySQL.State-sorting-result,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mg 62 | UserParameter=MySQL.State-statistics,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mh 63 | UserParameter=MySQL.innodb-locked-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lo 64 | UserParameter=MySQL.log-bytes-written,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh li 65 | UserParameter=MySQL.innodb-log-buffer-size,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kz 66 | UserParameter=MySQL.Select-full-join,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kl 67 | UserParameter=MySQL.locked-transactions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh go 68 | UserParameter=MySQL.Handler-read-rnd,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mu 69 | UserParameter=MySQL.Handler-delete,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mn 70 | UserParameter=MySQL.Query-time-total-13,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ps 71 | UserParameter=MySQL.Query-time-total-10,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pp 72 | UserParameter=MySQL.Key-buf-bytes-used,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oh 73 | UserParameter=MySQL.Com-delete-multi,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kj 74 | UserParameter=MySQL.Select-range,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kn 75 | UserParameter=MySQL.pending-aio-log-ios,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hh 76 | UserParameter=MySQL.ibuf-inserts,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hq 77 | UserParameter=MySQL.State-copying-to-tmp-table,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lr 78 | UserParameter=MySQL.Com-replace-select,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kk 79 | UserParameter=MySQL.modified-pages,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gt 80 | UserParameter=MySQL.Com-delete,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jy 81 | UserParameter=MySQL.Threads-cached,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh it 82 | UserParameter=MySQL.hash-index-cells-used,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nk 83 | UserParameter=MySQL.uncheckpointed-bytes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nn 84 | UserParameter=MySQL.Query-time-total-12,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pr 85 | UserParameter=MySQL.Qcache-hits,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jn 86 | UserParameter=MySQL.Questions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ju 87 | UserParameter=MySQL.Qcache-queries-in-cache,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jr 88 | UserParameter=MySQL.key-buffer-size,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oi 89 | UserParameter=MySQL.total-mem-alloc,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nl 90 | UserParameter=MySQL.spin-rounds,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hu 91 | UserParameter=MySQL.ibuf-merged,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hr 92 | UserParameter=MySQL.rows-inserted,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hw 93 | UserParameter=MySQL.file-fsyncs,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gx 94 | UserParameter=MySQL.Bytes-sent,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kx 95 | UserParameter=MySQL.Query-time-total-03,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pi 96 | UserParameter=MySQL.ibuf-merges,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hs 97 | UserParameter=MySQL.Query-time-total-02,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ph 98 | UserParameter=MySQL.pool-reads,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh qo 99 | UserParameter=MySQL.history-list,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gk 100 | UserParameter=MySQL.Query-time-total-05,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pk 101 | UserParameter=MySQL.rows-updated,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hx 102 | UserParameter=MySQL.max-connections,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ix 103 | UserParameter=MySQL.free-pages,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gr 104 | UserParameter=MySQL.Select-scan,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kp 105 | UserParameter=MySQL.pending-aio-sync-ios,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hi 106 | UserParameter=MySQL.recovery-system-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nw 107 | UserParameter=MySQL.Query-time-total-06,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh pl 108 | UserParameter=MySQL.innodb-sem-wait-time-ms,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nz 109 | UserParameter=MySQL.thread-hash-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nx 110 | UserParameter=MySQL.dictionary-cache-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nt 111 | UserParameter=MySQL.ibuf-used-cells,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh no 112 | UserParameter=MySQL.State-end,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ls 113 | UserParameter=MySQL.slave-running,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jg 114 | UserParameter=MySQL.pending-normal-aio-reads,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ho 115 | UserParameter=MySQL.Innodb-row-lock-waits,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ok 116 | UserParameter=MySQL.active-transactions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gp 117 | UserParameter=MySQL.Sort-range,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kr 118 | UserParameter=MySQL.spin-waits,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ht 119 | UserParameter=MySQL.Slow-queries,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ii 120 | UserParameter=MySQL.ibuf-cell-count,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nq 121 | UserParameter=MySQL.Qcache-free-blocks,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jl 122 | UserParameter=MySQL.Sort-merge-passes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kq 123 | UserParameter=MySQL.thread-cache-size,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iy 124 | UserParameter=MySQL.Key-write-requests,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gi 125 | UserParameter=MySQL.pending-buf-pool-flushes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hj 126 | UserParameter=MySQL.pending-log-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hn 127 | UserParameter=MySQL.Com-update-multi,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kh 128 | UserParameter=MySQL.State-login,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lw 129 | UserParameter=MySQL.State-reading-from-net,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ly 130 | UserParameter=MySQL.State-locked,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lv 131 | UserParameter=MySQL.log-bytes-flushed,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lh 132 | UserParameter=MySQL.ibuf-free-cells,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh np 133 | UserParameter=MySQL.Qcache-not-cached,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jq 134 | UserParameter=MySQL.pending-log-flushes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hm 135 | UserParameter=MySQL.Max-used-connections,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ir 136 | UserParameter=MySQL.State-sending-data,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lz 137 | UserParameter=MySQL.rows-read,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hz 138 | UserParameter=MySQL.lock-system-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nv 139 | UserParameter=MySQL.Handler-read-rnd-next,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mv 140 | UserParameter=MySQL.table-cache,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh io 141 | UserParameter=MySQL.rows-deleted,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hy 142 | UserParameter=MySQL.file-system-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nu 143 | UserParameter=MySQL.file-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gz 144 | UserParameter=MySQL.pending-chkp-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hk 145 | UserParameter=MySQL.additional-pool-alloc,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nm 146 | UserParameter=MySQL.current-transactions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gn 147 | UserParameter=MySQL.Key-reads,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gh 148 | UserParameter=MySQL.Handler-read-next,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ms 149 | UserParameter=MySQL.Key-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gj 150 | UserParameter=MySQL.Query-time-count-01,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh om 151 | UserParameter=MySQL.pool-read-requests,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh qp 152 | UserParameter=MySQL.Open-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ik 153 | UserParameter=MySQL.Query-time-count-13,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oy 154 | UserParameter=MySQL.Com-insert-select,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ki 155 | UserParameter=MySQL.Query-time-count-11,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ow 156 | UserParameter=MySQL.Query-time-count-03,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oo 157 | UserParameter=MySQL.slave-lag,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jj 158 | UserParameter=MySQL.Handler-update,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mz 159 | UserParameter=MySQL.Created-tmp-files,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh kw 160 | UserParameter=MySQL.Key-buf-bytes-unflushed,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh og 161 | UserParameter=MySQL.State-preparing,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lx 162 | UserParameter=MySQL.Binlog-cache-disk-use,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ll 163 | UserParameter=MySQL.Slave-open-temp-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jk 164 | UserParameter=MySQL.innodb-tables-in-use,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nh 165 | UserParameter=MySQL.Threads-created,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh iv 166 | UserParameter=MySQL.Slave-retried-transactions,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ji 167 | UserParameter=MySQL.State-writing-to-net,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh mj 168 | UserParameter=MySQL.pages-created,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gv 169 | UserParameter=MySQL.Opened-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh il 170 | UserParameter=MySQL.pages-written,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gw 171 | UserParameter=MySQL.database-pages,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh gs 172 | UserParameter=MySQL.query-cache-size,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jt 173 | UserParameter=MySQL.page-hash-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ns 174 | UserParameter=MySQL.Innodb-row-lock-time,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oj 175 | UserParameter=MySQL.Table-locks-immediate,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ih 176 | UserParameter=MySQL.binary-log-space,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ln 177 | UserParameter=MySQL.Com-update,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh jv 178 | UserParameter=MySQL.Query-time-count-00,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ol 179 | UserParameter=MySQL.adaptive-hash-memory,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh nr 180 | UserParameter=MySQL.Query-time-count-02,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh on 181 | UserParameter=MySQL.log-writes,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh hg 182 | UserParameter=MySQL.Query-time-count-04,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh op 183 | UserParameter=MySQL.Query-time-count-05,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh oq 184 | UserParameter=MySQL.Query-time-count-06,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh or 185 | UserParameter=MySQL.Query-time-count-07,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh os 186 | UserParameter=MySQL.Query-time-count-08,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ot 187 | UserParameter=MySQL.Query-time-count-09,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ou 188 | UserParameter=MySQL.Open-files,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh ij 189 | UserParameter=MySQL.State-closing-tables,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh lq 190 | UserParameter=MySQL.running-slave,/etc/zabbix/plugins/get_mysql_stats_wrapper.sh running-slave 191 | -------------------------------------------------------------------------------- /zabbix/zabbix-tcp-monitor/zbx_tcp_status_templates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0 4 | 2019-07-25T02:56:31Z 5 | 6 | 7 | Templates 8 | 9 | 10 | 11 | 734 | 735 | 736 | 737 | {Template TCP Status:tcp-status[TIME-WAIT].avg(5m)}>2000 738 | 0 739 | 740 | Too Many TIME_WAIT on {HOST.NAME} 741 | 0 742 | 743 | 744 | 0 745 | 2 746 | 747 | 0 748 | 0 749 | 750 | 751 | 752 | 753 | 754 | 755 | TCP Status LISTEN 756 | 900 757 | 200 758 | 0.0000 759 | 100.0000 760 | 1 761 | 1 762 | 0 763 | 1 764 | 0 765 | 0.0000 766 | 0.0000 767 | 0 768 | 0 769 | 0 770 | 0 771 | 772 | 773 | 0 774 | 0 775 | 1A7C11 776 | 0 777 | 2 778 | 0 779 | 780 | Template TCP Status 781 | tcp-status[CLOSED] 782 | 783 | 784 | 785 | 1 786 | 0 787 | F63100 788 | 0 789 | 2 790 | 0 791 | 792 | Template TCP Status 793 | tcp-status[CLOSE-WAIT] 794 | 795 | 796 | 797 | 2 798 | 0 799 | 2774A4 800 | 0 801 | 2 802 | 0 803 | 804 | Template TCP Status 805 | tcp-status[CLOSING] 806 | 807 | 808 | 809 | 3 810 | 0 811 | AC8C14 812 | 0 813 | 2 814 | 0 815 | 816 | Template TCP Status 817 | tcp-status[LAST-ACK] 818 | 819 | 820 | 821 | 4 822 | 0 823 | 611F27 824 | 0 825 | 2 826 | 0 827 | 828 | Template TCP Status 829 | tcp-status[LISTEN] 830 | 831 | 832 | 833 | 5 834 | 0 835 | F230E0 836 | 0 837 | 2 838 | 0 839 | 840 | Template TCP Status 841 | tcp-status[SYN-RECV] 842 | 843 | 844 | 845 | 6 846 | 0 847 | 5CCD18 848 | 0 849 | 2 850 | 0 851 | 852 | Template TCP Status 853 | tcp-status[SYN-SENT] 854 | 855 | 856 | 857 | 858 | 859 | TCP Status TIME-WAIT 860 | 900 861 | 200 862 | 0.0000 863 | 100.0000 864 | 1 865 | 1 866 | 0 867 | 1 868 | 0 869 | 0.0000 870 | 0.0000 871 | 0 872 | 0 873 | 0 874 | 0 875 | 876 | 877 | 0 878 | 0 879 | 1A7C11 880 | 0 881 | 2 882 | 0 883 | 884 | Template TCP Status 885 | tcp-status[ESTAB] 886 | 887 | 888 | 889 | 1 890 | 0 891 | F63100 892 | 0 893 | 2 894 | 0 895 | 896 | Template TCP Status 897 | tcp-status[FIN-WAIT-1] 898 | 899 | 900 | 901 | 2 902 | 0 903 | 2774A4 904 | 0 905 | 2 906 | 0 907 | 908 | Template TCP Status 909 | tcp-status[FIN-WAIT-2] 910 | 911 | 912 | 913 | 3 914 | 0 915 | A54F10 916 | 0 917 | 2 918 | 0 919 | 920 | Template TCP Status 921 | tcp-status[TIME-WAIT] 922 | 923 | 924 | 925 | 926 | 927 | 928 | -------------------------------------------------------------------------------- /zabbix/zabbix-mysql-monitor/ss_get_mysql_stats.php: -------------------------------------------------------------------------------- 1 | true, # Do you want to check InnoDB statistics? 51 | 'master' => true, # Do you want to check binary logging? 52 | 'slave' => true, # Do you want to check slave status? 53 | 'procs' => true, # Do you want to check SHOW PROCESSLIST? 54 | 'get_qrt' => true, # Get query response times from Percona Server or MariaDB? 55 | ); 56 | 57 | $use_ss = FALSE; # Whether to use the script server or not 58 | $debug = FALSE; # Define whether you want debugging behavior. 59 | $debug_log = FALSE; # If $debug_log is a filename, it'll be used. 60 | 61 | # ============================================================================ 62 | # You should not need to change anything below this line. 63 | # ============================================================================ 64 | $version = '1.1.8'; 65 | 66 | # ============================================================================ 67 | # Include settings from an external config file. 68 | # ============================================================================ 69 | if ( file_exists('/etc/cacti/' . basename(__FILE__) . '.cnf' ) ) { 70 | require('/etc/cacti/' . basename(__FILE__) . '.cnf'); 71 | debug('Found configuration file /etc/cacti/' . basename(__FILE__) . '.cnf'); 72 | } 73 | elseif ( file_exists(__FILE__ . '.cnf' ) ) { 74 | require(__FILE__ . '.cnf'); 75 | debug('Found configuration file ' . __FILE__ . '.cnf'); 76 | } 77 | 78 | # Make this a happy little script even when there are errors. 79 | $no_http_headers = true; 80 | ini_set('implicit_flush', false); # No output, ever. 81 | if ( $debug ) { 82 | ini_set('display_errors', true); 83 | ini_set('display_startup_errors', true); 84 | ini_set('error_reporting', 2147483647); 85 | } 86 | else { 87 | ini_set('error_reporting', E_ERROR); 88 | } 89 | ob_start(); # Catch all output such as notices of undefined array indexes. 90 | function error_handler($errno, $errstr, $errfile, $errline) { 91 | print("$errstr at $errfile line $errline\n"); 92 | debug("$errstr at $errfile line $errline"); 93 | } 94 | # ============================================================================ 95 | # Set up the stuff we need to be called by the script server. 96 | # ============================================================================ 97 | if ( $use_ss ) { 98 | if ( file_exists( dirname(__FILE__) . "/../include/global.php") ) { 99 | # See issue 5 for the reasoning behind this. 100 | debug("including " . dirname(__FILE__) . "/../include/global.php"); 101 | include_once(dirname(__FILE__) . "/../include/global.php"); 102 | } 103 | elseif ( file_exists( dirname(__FILE__) . "/../include/config.php" ) ) { 104 | # Some Cacti installations don't have global.php. 105 | debug("including " . dirname(__FILE__) . "/../include/config.php"); 106 | include_once(dirname(__FILE__) . "/../include/config.php"); 107 | } 108 | } 109 | 110 | # ============================================================================ 111 | # Set the default timezone either to the configured, system timezone, or the 112 | # default set above in the script. 113 | # ============================================================================ 114 | if ( function_exists("date_default_timezone_set") 115 | && function_exists("date_default_timezone_get") ) { 116 | $tz = ($timezone ? $timezone : @date_default_timezone_get()); 117 | if ( $tz ) { 118 | @date_default_timezone_set($tz); 119 | } 120 | } 121 | 122 | # ============================================================================ 123 | # Make sure we can also be called as a script. 124 | # ============================================================================ 125 | if (!isset($called_by_script_server)) { 126 | debug($_SERVER["argv"]); 127 | array_shift($_SERVER["argv"]); # Strip off this script's filename 128 | $options = parse_cmdline($_SERVER["argv"]); 129 | validate_options($options); 130 | $result = ss_get_mysql_stats($options); 131 | debug($result); 132 | if ( !$debug ) { 133 | # Throw away the buffer, which ought to contain only errors. 134 | ob_end_clean(); 135 | } 136 | else { 137 | ob_end_flush(); # In debugging mode, print out the errors. 138 | } 139 | 140 | # Split the result up and extract only the desired parts of it. 141 | $wanted = explode(',', $options['items']); 142 | $output = array(); 143 | foreach ( explode(' ', $result) as $item ) { 144 | if ( in_array(substr($item, 0, 2), $wanted) ) { 145 | $output[] = $item; 146 | } 147 | } 148 | debug(array("Final result", $output)); 149 | print(implode(' ', $output)); 150 | } 151 | 152 | # ============================================================================ 153 | # End "if file was not included" section. 154 | # ============================================================================ 155 | } 156 | 157 | # ============================================================================ 158 | # Work around the lack of array_change_key_case in older PHP. 159 | # ============================================================================ 160 | if ( !function_exists('array_change_key_case') ) { 161 | function array_change_key_case($arr) { 162 | $res = array(); 163 | foreach ( $arr as $key => $val ) { 164 | $res[strtolower($key)] = $val; 165 | } 166 | return $res; 167 | } 168 | } 169 | 170 | # ============================================================================ 171 | # Validate that the command-line options are here and correct 172 | # ============================================================================ 173 | function validate_options($options) { 174 | $opts = array('host', 'items', 'user', 'pass', 'nocache', 'port', 'server-id'); 175 | # Show help 176 | if ( array_key_exists('help', $options) ) { 177 | usage(''); 178 | } 179 | 180 | # Required command-line options 181 | foreach ( array('host', 'items') as $option ) { 182 | if ( !isset($options[$option]) || !$options[$option] ) { 183 | usage("Required option --$option is missing"); 184 | } 185 | } 186 | foreach ( $options as $key => $val ) { 187 | if ( !in_array($key, $opts) ) { 188 | usage("Unknown option --$key"); 189 | } 190 | } 191 | } 192 | 193 | # ============================================================================ 194 | # Print out a brief usage summary 195 | # ============================================================================ 196 | function usage($message) { 197 | global $mysql_user, $mysql_pass, $mysql_port; 198 | 199 | $usage = << --items [OPTION] 202 | 203 | --host MySQL host 204 | --items Comma-separated list of the items whose data you want 205 | --user MySQL username 206 | --pass MySQL password 207 | --port MySQL port 208 | --socket MySQL socket 209 | --flags MySQL flags 210 | --connection-timeout MySQL connection timeout 211 | --server-id Server id to associate with a heartbeat if heartbeat usage is enabled 212 | --nocache Do not cache results in a file 213 | --help Show usage 214 | 215 | EOF; 216 | die($usage); 217 | } 218 | 219 | # ============================================================================ 220 | # Parse command-line arguments, in the format --arg value --arg value, and 221 | # return them as an array ( arg => value ) 222 | # ============================================================================ 223 | function parse_cmdline( $args ) { 224 | $options = array(); 225 | while (list($tmp, $p) = each($args)) { 226 | if (strpos($p, '--') === 0) { 227 | $param = substr($p, 2); 228 | $value = null; 229 | $nextparam = current($args); 230 | if ($nextparam !== false && strpos($nextparam, '--') !==0) { 231 | list($tmp, $value) = each($args); 232 | } 233 | $options[$param] = $value; 234 | } 235 | } 236 | if ( array_key_exists('host', $options) ) { 237 | $options['host'] = substr($options['host'], 0, 4) == 'tcp:' ? substr($options['host'], 4) : $options['host']; 238 | } 239 | debug($options); 240 | return $options; 241 | } 242 | 243 | # ============================================================================ 244 | # This is the main function. Some parameters are filled in from defaults at the 245 | # top of this file. 246 | # ============================================================================ 247 | function ss_get_mysql_stats( $options ) { 248 | # Process connection options. 249 | global $debug, $mysql_user, $mysql_pass, $cache_dir, $poll_time, $chk_options, 250 | $mysql_port, $mysql_socket, $mysql_flags, 251 | $mysql_ssl, $mysql_ssl_key, $mysql_ssl_cert, $mysql_ssl_ca, 252 | $mysql_connection_timeout, 253 | $heartbeat, $heartbeat_table, $heartbeat_server_id, $heartbeat_utc; 254 | 255 | $user = isset($options['user']) ? $options['user'] : $mysql_user; 256 | $pass = isset($options['pass']) ? $options['pass'] : $mysql_pass; 257 | $host = $options['host']; 258 | $port = isset($options['port']) ? $options['port'] : $mysql_port; 259 | $socket = isset($options['socket']) ? $options['socket'] : $mysql_socket; 260 | $flags = isset($options['flags']) ? $options['flags'] : $mysql_flags; 261 | $connection_timeout = isset($options['connection-timeout']) ? $options['connection-timeout'] : $mysql_connection_timeout; 262 | $heartbeat_server_id = isset($options['server-id']) ? $options['server-id'] : $heartbeat_server_id; 263 | 264 | $sanitized_host = str_replace(array(":", "/"), array("", "_"), $host); 265 | $cache_file = "$cache_dir/$sanitized_host-mysql_cacti_stats.txt" . ($port != 3306 ? ":$port" : ''); 266 | debug("Cache file is $cache_file"); 267 | 268 | # First, check the cache. 269 | $fp = null; 270 | if ( $cache_dir && !array_key_exists('nocache', $options) ) { 271 | if ( $fp = fopen($cache_file, 'a+') ) { 272 | $locked = flock($fp, 1); # LOCK_SH 273 | if ( $locked ) { 274 | if ( filesize($cache_file) > 0 275 | && filectime($cache_file) + ($poll_time/2) > time() 276 | && ($arr = file($cache_file)) 277 | ) {# The cache file is good to use. 278 | debug("Using the cache file"); 279 | fclose($fp); 280 | return $arr[0]; 281 | } 282 | else { 283 | debug("The cache file seems too small or stale"); 284 | # Escalate the lock to exclusive, so we can write to it. 285 | if ( flock($fp, 2) ) { # LOCK_EX 286 | # We might have blocked while waiting for that LOCK_EX, and 287 | # another process ran and updated it. Let's see if we can just 288 | # return the data now: 289 | if ( filesize($cache_file) > 0 290 | && filectime($cache_file) + ($poll_time/2) > time() 291 | && ($arr = file($cache_file)) 292 | ) {# The cache file is good to use. 293 | debug("Using the cache file"); 294 | fclose($fp); 295 | return $arr[0]; 296 | } 297 | ftruncate($fp, 0); # Now it's ready for writing later. 298 | } 299 | } 300 | } 301 | else { 302 | $fp = null; 303 | debug("Couldn't lock the cache file, ignoring it"); 304 | } 305 | } 306 | else { 307 | $fp = null; 308 | debug("Couldn't open the cache file"); 309 | } 310 | } 311 | else { 312 | debug("Caching is disabled."); 313 | } 314 | 315 | # Connect to MySQL. 316 | debug(array('Connecting to', $host, $port, $user, $pass)); 317 | if ( !extension_loaded('mysqli') ) { 318 | debug("PHP MySQLi extension is not loaded"); 319 | die("PHP MySQLi extension is not loaded"); 320 | } 321 | if ( $mysql_ssl ) { 322 | $conn = mysqli_init(); 323 | $conn->options(MYSQLI_OPT_CONNECT_TIMEOUT, $connection_timeout); 324 | mysqli_ssl_set($conn, $mysql_ssl_key, $mysql_ssl_cert, $mysql_ssl_ca, NULL, NULL); 325 | mysqli_real_connect($conn, $host, $user, $pass, NULL, $port, $socket, $flags); 326 | } 327 | else { 328 | $conn = mysqli_init(); 329 | $conn->options(MYSQLI_OPT_CONNECT_TIMEOUT, $connection_timeout); 330 | mysqli_real_connect($conn, $host, $user, $pass, NULL, $port, $socket, $flags); 331 | } 332 | if ( mysqli_connect_errno() ) { 333 | debug("MySQL connection failed: " . mysqli_connect_error()); 334 | die("ERROR: " . mysqli_connect_error()); 335 | } 336 | 337 | # MySQL server version. 338 | # The form of this version number is main_version * 10000 + minor_version * 100 + sub_version 339 | # i.e. version 5.5.44 is 50544. 340 | $mysql_version = mysqli_get_server_version($conn); 341 | debug("MySQL server version is " . $mysql_version); 342 | 343 | # Set up variables. 344 | $status = array( # Holds the result of SHOW STATUS, SHOW INNODB STATUS, etc 345 | # Define some indexes so they don't cause errors with += operations. 346 | 'relay_log_space' => null, 347 | 'binary_log_space' => null, 348 | 'current_transactions' => 0, 349 | 'locked_transactions' => 0, 350 | 'active_transactions' => 0, 351 | 'innodb_locked_tables' => 0, 352 | 'innodb_tables_in_use' => 0, 353 | 'innodb_lock_structs' => 0, 354 | 'innodb_lock_wait_secs' => 0, 355 | 'innodb_sem_waits' => 0, 356 | 'innodb_sem_wait_time_ms' => 0, 357 | # Values for the 'state' column from SHOW PROCESSLIST (converted to 358 | # lowercase, with spaces replaced by underscores) 359 | 'State_closing_tables' => 0, 360 | 'State_copying_to_tmp_table' => 0, 361 | 'State_end' => 0, 362 | 'State_freeing_items' => 0, 363 | 'State_init' => 0, 364 | 'State_locked' => 0, 365 | 'State_login' => 0, 366 | 'State_preparing' => 0, 367 | 'State_reading_from_net' => 0, 368 | 'State_sending_data' => 0, 369 | 'State_sorting_result' => 0, 370 | 'State_statistics' => 0, 371 | 'State_updating' => 0, 372 | 'State_writing_to_net' => 0, 373 | 'State_none' => 0, 374 | 'State_other' => 0, # Everything not listed above 375 | ); 376 | 377 | # Get SHOW STATUS and convert the name-value array into a simple 378 | # associative array. 379 | $result = run_query("SHOW /*!50002 GLOBAL */ STATUS", $conn); 380 | foreach ( $result as $row ) { 381 | $status[$row[0]] = $row[1]; 382 | } 383 | 384 | # Get SHOW VARIABLES and do the same thing, adding it to the $status array. 385 | $result = run_query("SHOW VARIABLES", $conn); 386 | foreach ( $result as $row ) { 387 | $status[$row[0]] = $row[1]; 388 | } 389 | 390 | # Get SHOW SLAVE STATUS, and add it to the $status array. 391 | if ( $chk_options['slave'] ) { 392 | # Leverage lock-free SHOW SLAVE STATUS if available 393 | $result = run_query("SHOW SLAVE STATUS NONBLOCKING", $conn); 394 | if ( !$result ) { 395 | $result = run_query("SHOW SLAVE STATUS NOLOCK", $conn); 396 | if ( !$result ) { 397 | $result = run_query("SHOW SLAVE STATUS", $conn); 398 | } 399 | } 400 | $slave_status_rows_gotten = 0; 401 | foreach ( $result as $row ) { 402 | $slave_status_rows_gotten++; 403 | # Must lowercase keys because different MySQL versions have different 404 | # lettercase. 405 | $row = array_change_key_case($row, CASE_LOWER); 406 | $status['relay_log_space'] = $row['relay_log_space']; 407 | $status['slave_lag'] = $row['seconds_behind_master']; 408 | 409 | # Check replication heartbeat, if present. 410 | if ( $heartbeat ) { 411 | if ( $heartbeat_utc ) { 412 | $now_func = 'UNIX_TIMESTAMP(UTC_TIMESTAMP)'; 413 | } 414 | else { 415 | $now_func = 'UNIX_TIMESTAMP()'; 416 | } 417 | $result2 = run_query( 418 | "SELECT MAX($now_func - ROUND(UNIX_TIMESTAMP(ts)))" 419 | . " AS delay FROM $heartbeat_table" 420 | . " WHERE $heartbeat_server_id = 0 OR server_id = $heartbeat_server_id", $conn); 421 | $slave_delay_rows_gotten = 0; 422 | foreach ( $result2 as $row2 ) { 423 | $slave_delay_rows_gotten++; 424 | if ( $row2 && is_array($row2) 425 | && array_key_exists('delay', $row2) ) 426 | { 427 | $status['slave_lag'] = $row2['delay']; 428 | } 429 | else { 430 | debug("Couldn't get slave lag from $heartbeat_table"); 431 | } 432 | } 433 | if ( $slave_delay_rows_gotten == 0 ) { 434 | debug("Got nothing from heartbeat query"); 435 | } 436 | } 437 | 438 | # Scale slave_running and slave_stopped relative to the slave lag. 439 | $status['slave_running'] = ($row['slave_sql_running'] == 'Yes') 440 | ? $status['slave_lag'] : 0; 441 | $status['slave_stopped'] = ($row['slave_sql_running'] == 'Yes') 442 | ? 0 : $status['slave_lag']; 443 | } 444 | if ( $slave_status_rows_gotten == 0 ) { 445 | debug("Got nothing from SHOW SLAVE STATUS"); 446 | } 447 | } 448 | 449 | # Get SHOW MASTER STATUS, and add it to the $status array. 450 | if ( $chk_options['master'] 451 | && array_key_exists('log_bin', $status) 452 | && $status['log_bin'] == 'ON' 453 | ) { # See issue #8 454 | $binlogs = array(0); 455 | $result = run_query("SHOW MASTER LOGS", $conn); 456 | foreach ( $result as $row ) { 457 | $row = array_change_key_case($row, CASE_LOWER); 458 | # Older versions of MySQL may not have the File_size column in the 459 | # results of the command. Zero-size files indicate the user is 460 | # deleting binlogs manually from disk (bad user! bad!). 461 | if ( array_key_exists('file_size', $row) && $row['file_size'] > 0 ) { 462 | $binlogs[] = $row['file_size']; 463 | } 464 | } 465 | if (count($binlogs)) { 466 | $status['binary_log_space'] = to_int(array_sum($binlogs)); 467 | } 468 | } 469 | 470 | # Get SHOW PROCESSLIST and aggregate it by state, then add it to the array 471 | # too. 472 | if ( $chk_options['procs'] ) { 473 | $result = run_query('SHOW PROCESSLIST', $conn); 474 | foreach ( $result as $row ) { 475 | $state = $row['State']; 476 | if ( is_null($state) ) { 477 | $state = 'NULL'; 478 | } 479 | if ( $state == '' ) { 480 | $state = 'none'; 481 | } 482 | # MySQL 5.5 replaces the 'Locked' state with a variety of "Waiting for 483 | # X lock" types of statuses. Wrap these all back into "Locked" because 484 | # we don't really care about the type of locking it is. 485 | $state = preg_replace('/^(Table lock|Waiting for .*lock)$/', 'Locked', $state); 486 | $state = str_replace(' ', '_', strtolower($state)); 487 | if ( array_key_exists("State_$state", $status) ) { 488 | increment($status, "State_$state", 1); 489 | } 490 | else { 491 | increment($status, "State_other", 1); 492 | } 493 | } 494 | } 495 | 496 | # Get SHOW ENGINES to be able to determine whether InnoDB is present. 497 | $engines = array(); 498 | $result = run_query("SHOW ENGINES", $conn); 499 | foreach ( $result as $row ) { 500 | $engines[$row[0]] = $row[1]; 501 | } 502 | 503 | # Get SHOW INNODB STATUS and extract the desired metrics from it, then add 504 | # those to the array too. 505 | if ( $chk_options['innodb'] 506 | && array_key_exists('InnoDB', $engines) 507 | && $engines['InnoDB'] == 'YES' 508 | || $engines['InnoDB'] == 'DEFAULT' 509 | ) { 510 | $result = run_query("SHOW /*!50000 ENGINE*/ INNODB STATUS", $conn); 511 | $istatus_text = $result[0]['Status']; 512 | $istatus_vals = get_innodb_array($istatus_text, $mysql_version); 513 | 514 | # Get response time histogram from Percona Server or MariaDB if enabled. 515 | if ( $chk_options['get_qrt'] 516 | && (( isset($status['have_response_time_distribution']) 517 | && $status['have_response_time_distribution'] == 'YES') 518 | || (isset($status['query_response_time_stats']) 519 | && $status['query_response_time_stats'] == 'ON')) ) 520 | { 521 | debug('Getting query time histogram'); 522 | $i = 0; 523 | $result = run_query( 524 | "SELECT `count`, ROUND(total * 1000000) AS total " 525 | . "FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME " 526 | . "WHERE `time` <> 'TOO LONG'", 527 | $conn); 528 | foreach ( $result as $row ) { 529 | if ( $i > 13 ) { 530 | # It's possible that the number of rows returned isn't 14. 531 | # Don't add extra status counters. 532 | break; 533 | } 534 | $count_key = sprintf("Query_time_count_%02d", $i); 535 | $total_key = sprintf("Query_time_total_%02d", $i); 536 | $status[$count_key] = $row['count']; 537 | $status[$total_key] = $row['total']; 538 | $i++; 539 | } 540 | # It's also possible that the number of rows returned is too few. 541 | # Don't leave any status counters unassigned; it will break graphs. 542 | while ( $i <= 13 ) { 543 | $count_key = sprintf("Query_time_count_%02d", $i); 544 | $total_key = sprintf("Query_time_total_%02d", $i); 545 | $status[$count_key] = 0; 546 | $status[$total_key] = 0; 547 | $i++; 548 | } 549 | } 550 | else { 551 | debug('Not getting time histogram because it is not enabled'); 552 | } 553 | 554 | # Override values from InnoDB parsing with values from SHOW STATUS, 555 | # because InnoDB status might not have everything and the SHOW STATUS is 556 | # to be preferred where possible. 557 | $overrides = array( 558 | 'Innodb_buffer_pool_pages_data' => 'database_pages', 559 | 'Innodb_buffer_pool_pages_dirty' => 'modified_pages', 560 | 'Innodb_buffer_pool_pages_free' => 'free_pages', 561 | 'Innodb_buffer_pool_pages_total' => 'pool_size', 562 | 'Innodb_data_fsyncs' => 'file_fsyncs', 563 | 'Innodb_data_pending_reads' => 'pending_normal_aio_reads', 564 | 'Innodb_data_pending_writes' => 'pending_normal_aio_writes', 565 | 'Innodb_os_log_pending_fsyncs' => 'pending_log_flushes', 566 | 'Innodb_pages_created' => 'pages_created', 567 | 'Innodb_pages_read' => 'pages_read', 568 | 'Innodb_pages_written' => 'pages_written', 569 | 'Innodb_rows_deleted' => 'rows_deleted', 570 | 'Innodb_rows_inserted' => 'rows_inserted', 571 | 'Innodb_rows_read' => 'rows_read', 572 | 'Innodb_rows_updated' => 'rows_updated', 573 | 'Innodb_buffer_pool_reads' => 'pool_reads', 574 | 'Innodb_buffer_pool_read_requests' => 'pool_read_requests', 575 | ); 576 | 577 | # If the SHOW STATUS value exists, override... 578 | foreach ( $overrides as $key => $val ) { 579 | if ( array_key_exists($key, $status) ) { 580 | debug("Override $key"); 581 | $istatus_vals[$val] = $status[$key]; 582 | } 583 | } 584 | 585 | # Now copy the values into $status. 586 | foreach ( $istatus_vals as $key => $val ) { 587 | $status[$key] = $istatus_vals[$key]; 588 | } 589 | } 590 | 591 | # Make table_open_cache backwards-compatible (issue 63). 592 | if ( array_key_exists('table_open_cache', $status) ) { 593 | $status['table_cache'] = $status['table_open_cache']; 594 | } 595 | 596 | # Compute how much of the key buffer is used and unflushed (issue 127). 597 | $status['Key_buf_bytes_used'] 598 | = big_sub($status['key_buffer_size'], 599 | big_multiply($status['Key_blocks_unused'], 600 | $status['key_cache_block_size'])); 601 | $status['Key_buf_bytes_unflushed'] 602 | = big_multiply($status['Key_blocks_not_flushed'], 603 | $status['key_cache_block_size']); 604 | 605 | if ( array_key_exists('unflushed_log', $status) 606 | && $status['unflushed_log'] 607 | ) { 608 | # TODO: I'm not sure what the deal is here; need to debug this. But the 609 | # unflushed log bytes spikes a lot sometimes and it's impossible for it to 610 | # be more than the log buffer. 611 | debug("Unflushed log: $status[unflushed_log]"); 612 | $status['unflushed_log'] 613 | = max($status['unflushed_log'], $status['innodb_log_buffer_size']); 614 | } 615 | 616 | # Define the variables to output. I use shortened variable names so maybe 617 | # it'll all fit in 1024 bytes for Cactid and Spine's benefit. Strings must 618 | # have some non-hex characters (non a-f0-9) to avoid a Cacti bug. This list 619 | # must come right after the word MAGIC_VARS_DEFINITIONS. The Perl script 620 | # parses it and uses it as a Perl variable. 621 | $keys = array( 622 | 'Key_read_requests' => 'gg', 623 | 'Key_reads' => 'gh', 624 | 'Key_write_requests' => 'gi', 625 | 'Key_writes' => 'gj', 626 | 'history_list' => 'gk', 627 | 'innodb_transactions' => 'gl', 628 | 'read_views' => 'gm', 629 | 'current_transactions' => 'gn', 630 | 'locked_transactions' => 'go', 631 | 'active_transactions' => 'gp', 632 | 'pool_size' => 'gq', 633 | 'free_pages' => 'gr', 634 | 'database_pages' => 'gs', 635 | 'modified_pages' => 'gt', 636 | 'pages_read' => 'gu', 637 | 'pages_created' => 'gv', 638 | 'pages_written' => 'gw', 639 | 'file_fsyncs' => 'gx', 640 | 'file_reads' => 'gy', 641 | 'file_writes' => 'gz', 642 | 'log_writes' => 'hg', 643 | 'pending_aio_log_ios' => 'hh', 644 | 'pending_aio_sync_ios' => 'hi', 645 | 'pending_buf_pool_flushes' => 'hj', 646 | 'pending_chkp_writes' => 'hk', 647 | 'pending_ibuf_aio_reads' => 'hl', 648 | 'pending_log_flushes' => 'hm', 649 | 'pending_log_writes' => 'hn', 650 | 'pending_normal_aio_reads' => 'ho', 651 | 'pending_normal_aio_writes' => 'hp', 652 | 'ibuf_inserts' => 'hq', 653 | 'ibuf_merged' => 'hr', 654 | 'ibuf_merges' => 'hs', 655 | 'spin_waits' => 'ht', 656 | 'spin_rounds' => 'hu', 657 | 'os_waits' => 'hv', 658 | 'rows_inserted' => 'hw', 659 | 'rows_updated' => 'hx', 660 | 'rows_deleted' => 'hy', 661 | 'rows_read' => 'hz', 662 | 'Table_locks_waited' => 'ig', 663 | 'Table_locks_immediate' => 'ih', 664 | 'Slow_queries' => 'ii', 665 | 'Open_files' => 'ij', 666 | 'Open_tables' => 'ik', 667 | 'Opened_tables' => 'il', 668 | 'innodb_open_files' => 'im', 669 | 'open_files_limit' => 'in', 670 | 'table_cache' => 'io', 671 | 'Aborted_clients' => 'ip', 672 | 'Aborted_connects' => 'iq', 673 | 'Max_used_connections' => 'ir', 674 | 'Slow_launch_threads' => 'is', 675 | 'Threads_cached' => 'it', 676 | 'Threads_connected' => 'iu', 677 | 'Threads_created' => 'iv', 678 | 'Threads_running' => 'iw', 679 | 'max_connections' => 'ix', 680 | 'thread_cache_size' => 'iy', 681 | 'Connections' => 'iz', 682 | 'slave_running' => 'jg', 683 | 'slave_stopped' => 'jh', 684 | 'Slave_retried_transactions' => 'ji', 685 | 'slave_lag' => 'jj', 686 | 'Slave_open_temp_tables' => 'jk', 687 | 'Qcache_free_blocks' => 'jl', 688 | 'Qcache_free_memory' => 'jm', 689 | 'Qcache_hits' => 'jn', 690 | 'Qcache_inserts' => 'jo', 691 | 'Qcache_lowmem_prunes' => 'jp', 692 | 'Qcache_not_cached' => 'jq', 693 | 'Qcache_queries_in_cache' => 'jr', 694 | 'Qcache_total_blocks' => 'js', 695 | 'query_cache_size' => 'jt', 696 | 'Questions' => 'ju', 697 | 'Com_update' => 'jv', 698 | 'Com_insert' => 'jw', 699 | 'Com_select' => 'jx', 700 | 'Com_delete' => 'jy', 701 | 'Com_replace' => 'jz', 702 | 'Com_load' => 'kg', 703 | 'Com_update_multi' => 'kh', 704 | 'Com_insert_select' => 'ki', 705 | 'Com_delete_multi' => 'kj', 706 | 'Com_replace_select' => 'kk', 707 | 'Select_full_join' => 'kl', 708 | 'Select_full_range_join' => 'km', 709 | 'Select_range' => 'kn', 710 | 'Select_range_check' => 'ko', 711 | 'Select_scan' => 'kp', 712 | 'Sort_merge_passes' => 'kq', 713 | 'Sort_range' => 'kr', 714 | 'Sort_rows' => 'ks', 715 | 'Sort_scan' => 'kt', 716 | 'Created_tmp_tables' => 'ku', 717 | 'Created_tmp_disk_tables' => 'kv', 718 | 'Created_tmp_files' => 'kw', 719 | 'Bytes_sent' => 'kx', 720 | 'Bytes_received' => 'ky', 721 | 'innodb_log_buffer_size' => 'kz', 722 | 'unflushed_log' => 'lg', 723 | 'log_bytes_flushed' => 'lh', 724 | 'log_bytes_written' => 'li', 725 | 'relay_log_space' => 'lj', 726 | 'binlog_cache_size' => 'lk', 727 | 'Binlog_cache_disk_use' => 'll', 728 | 'Binlog_cache_use' => 'lm', 729 | 'binary_log_space' => 'ln', 730 | 'innodb_locked_tables' => 'lo', 731 | 'innodb_lock_structs' => 'lp', 732 | 'State_closing_tables' => 'lq', 733 | 'State_copying_to_tmp_table' => 'lr', 734 | 'State_end' => 'ls', 735 | 'State_freeing_items' => 'lt', 736 | 'State_init' => 'lu', 737 | 'State_locked' => 'lv', 738 | 'State_login' => 'lw', 739 | 'State_preparing' => 'lx', 740 | 'State_reading_from_net' => 'ly', 741 | 'State_sending_data' => 'lz', 742 | 'State_sorting_result' => 'mg', 743 | 'State_statistics' => 'mh', 744 | 'State_updating' => 'mi', 745 | 'State_writing_to_net' => 'mj', 746 | 'State_none' => 'mk', 747 | 'State_other' => 'ml', 748 | 'Handler_commit' => 'mm', 749 | 'Handler_delete' => 'mn', 750 | 'Handler_discover' => 'mo', 751 | 'Handler_prepare' => 'mp', 752 | 'Handler_read_first' => 'mq', 753 | 'Handler_read_key' => 'mr', 754 | 'Handler_read_next' => 'ms', 755 | 'Handler_read_prev' => 'mt', 756 | 'Handler_read_rnd' => 'mu', 757 | 'Handler_read_rnd_next' => 'mv', 758 | 'Handler_rollback' => 'mw', 759 | 'Handler_savepoint' => 'mx', 760 | 'Handler_savepoint_rollback' => 'my', 761 | 'Handler_update' => 'mz', 762 | 'Handler_write' => 'ng', 763 | 'innodb_tables_in_use' => 'nh', 764 | 'innodb_lock_wait_secs' => 'ni', 765 | 'hash_index_cells_total' => 'nj', 766 | 'hash_index_cells_used' => 'nk', 767 | 'total_mem_alloc' => 'nl', 768 | 'additional_pool_alloc' => 'nm', 769 | 'uncheckpointed_bytes' => 'nn', 770 | 'ibuf_used_cells' => 'no', 771 | 'ibuf_free_cells' => 'np', 772 | 'ibuf_cell_count' => 'nq', 773 | 'adaptive_hash_memory' => 'nr', 774 | 'page_hash_memory' => 'ns', 775 | 'dictionary_cache_memory' => 'nt', 776 | 'file_system_memory' => 'nu', 777 | 'lock_system_memory' => 'nv', 778 | 'recovery_system_memory' => 'nw', 779 | 'thread_hash_memory' => 'nx', 780 | 'innodb_sem_waits' => 'ny', 781 | 'innodb_sem_wait_time_ms' => 'nz', 782 | 'Key_buf_bytes_unflushed' => 'og', 783 | 'Key_buf_bytes_used' => 'oh', 784 | 'key_buffer_size' => 'oi', 785 | 'Innodb_row_lock_time' => 'oj', 786 | 'Innodb_row_lock_waits' => 'ok', 787 | 'Query_time_count_00' => 'ol', 788 | 'Query_time_count_01' => 'om', 789 | 'Query_time_count_02' => 'on', 790 | 'Query_time_count_03' => 'oo', 791 | 'Query_time_count_04' => 'op', 792 | 'Query_time_count_05' => 'oq', 793 | 'Query_time_count_06' => 'or', 794 | 'Query_time_count_07' => 'os', 795 | 'Query_time_count_08' => 'ot', 796 | 'Query_time_count_09' => 'ou', 797 | 'Query_time_count_10' => 'ov', 798 | 'Query_time_count_11' => 'ow', 799 | 'Query_time_count_12' => 'ox', 800 | 'Query_time_count_13' => 'oy', 801 | 'Query_time_total_00' => 'oz', 802 | 'Query_time_total_01' => 'pg', 803 | 'Query_time_total_02' => 'ph', 804 | 'Query_time_total_03' => 'pi', 805 | 'Query_time_total_04' => 'pj', 806 | 'Query_time_total_05' => 'pk', 807 | 'Query_time_total_06' => 'pl', 808 | 'Query_time_total_07' => 'pm', 809 | 'Query_time_total_08' => 'pn', 810 | 'Query_time_total_09' => 'po', 811 | 'Query_time_total_10' => 'pp', 812 | 'Query_time_total_11' => 'pq', 813 | 'Query_time_total_12' => 'pr', 814 | 'Query_time_total_13' => 'ps', 815 | 'wsrep_replicated_bytes' => 'pt', 816 | 'wsrep_received_bytes' => 'pu', 817 | 'wsrep_replicated' => 'pv', 818 | 'wsrep_received' => 'pw', 819 | 'wsrep_local_cert_failures' => 'px', 820 | 'wsrep_local_bf_aborts' => 'py', 821 | 'wsrep_local_send_queue' => 'pz', 822 | 'wsrep_local_recv_queue' => 'qg', 823 | 'wsrep_cluster_size' => 'qh', 824 | 'wsrep_cert_deps_distance' => 'qi', 825 | 'wsrep_apply_window' => 'qj', 826 | 'wsrep_commit_window' => 'qk', 827 | 'wsrep_flow_control_paused' => 'ql', 828 | 'wsrep_flow_control_sent' => 'qm', 829 | 'wsrep_flow_control_recv' => 'qn', 830 | 'pool_reads' => 'qo', 831 | 'pool_read_requests' => 'qp', 832 | ); 833 | 834 | # Return the output. 835 | $output = array(); 836 | foreach ($keys as $key => $short ) { 837 | # If the value isn't defined, return -1 which is lower than (most graphs') 838 | # minimum value of 0, so it'll be regarded as a missing value. 839 | $val = isset($status[$key]) ? $status[$key] : -1; 840 | $output[] = "$short:$val"; 841 | } 842 | $result = implode(' ', $output); 843 | if ( $fp ) { 844 | if ( fwrite($fp, $result) === FALSE ) { 845 | die("Can't write '$cache_file'"); 846 | } 847 | fclose($fp); 848 | } 849 | return $result; 850 | } 851 | 852 | # ============================================================================ 853 | # Given INNODB STATUS text, returns a key-value array of the parsed text. Each 854 | # line shows a sample of the input for both standard InnoDB as you would find in 855 | # MySQL 5.0, and XtraDB or enhanced InnoDB from Percona if applicable. Note 856 | # that extra leading spaces are ignored due to trim(). 857 | # ============================================================================ 858 | function get_innodb_array($text, $mysql_version) { 859 | $results = array( 860 | 'spin_waits' => array(), 861 | 'spin_rounds' => array(), 862 | 'os_waits' => array(), 863 | 'pending_normal_aio_reads' => null, 864 | 'pending_normal_aio_writes' => null, 865 | 'pending_ibuf_aio_reads' => null, 866 | 'pending_aio_log_ios' => null, 867 | 'pending_aio_sync_ios' => null, 868 | 'pending_log_flushes' => null, 869 | 'pending_buf_pool_flushes' => null, 870 | 'file_reads' => null, 871 | 'file_writes' => null, 872 | 'file_fsyncs' => null, 873 | 'ibuf_inserts' => null, 874 | 'ibuf_merged' => null, 875 | 'ibuf_merges' => null, 876 | 'log_bytes_written' => null, 877 | 'unflushed_log' => null, 878 | 'log_bytes_flushed' => null, 879 | 'pending_log_writes' => null, 880 | 'pending_chkp_writes' => null, 881 | 'log_writes' => null, 882 | 'pool_size' => null, 883 | 'free_pages' => null, 884 | 'database_pages' => null, 885 | 'modified_pages' => null, 886 | 'pages_read' => null, 887 | 'pages_created' => null, 888 | 'pages_written' => null, 889 | 'queries_inside' => null, 890 | 'queries_queued' => null, 891 | 'read_views' => null, 892 | 'rows_inserted' => null, 893 | 'rows_updated' => null, 894 | 'rows_deleted' => null, 895 | 'rows_read' => null, 896 | 'innodb_transactions' => null, 897 | 'unpurged_txns' => null, 898 | 'history_list' => null, 899 | 'current_transactions' => null, 900 | 'hash_index_cells_total' => null, 901 | 'hash_index_cells_used' => null, 902 | 'total_mem_alloc' => null, 903 | 'additional_pool_alloc' => null, 904 | 'last_checkpoint' => null, 905 | 'uncheckpointed_bytes' => null, 906 | 'ibuf_used_cells' => null, 907 | 'ibuf_free_cells' => null, 908 | 'ibuf_cell_count' => null, 909 | 'adaptive_hash_memory' => null, 910 | 'page_hash_memory' => null, 911 | 'dictionary_cache_memory' => null, 912 | 'file_system_memory' => null, 913 | 'lock_system_memory' => null, 914 | 'recovery_system_memory' => null, 915 | 'thread_hash_memory' => null, 916 | 'innodb_sem_waits' => null, 917 | 'innodb_sem_wait_time_ms' => null, 918 | ); 919 | $txn_seen = FALSE; 920 | foreach ( explode("\n", $text) as $line ) { 921 | $line = trim($line); 922 | $row = preg_split('/ +/', $line); 923 | 924 | # SEMAPHORES 925 | if (strpos($line, 'Mutex spin waits') === 0 ) { 926 | # Mutex spin waits 79626940, rounds 157459864, OS waits 698719 927 | # Mutex spin waits 0, rounds 247280272495, OS waits 316513438 928 | $results['spin_waits'][] = to_int($row[3]); 929 | $results['spin_rounds'][] = to_int($row[5]); 930 | $results['os_waits'][] = to_int($row[8]); 931 | } 932 | elseif (strpos($line, 'RW-shared spins') === 0 933 | && strpos($line, ';') > 0 ) { 934 | # RW-shared spins 3859028, OS waits 2100750; RW-excl spins 4641946, OS waits 1530310 935 | $results['spin_waits'][] = to_int($row[2]); 936 | $results['spin_waits'][] = to_int($row[8]); 937 | $results['os_waits'][] = to_int($row[5]); 938 | $results['os_waits'][] = to_int($row[11]); 939 | } 940 | elseif (strpos($line, 'RW-shared spins') === 0 && strpos($line, '; RW-excl spins') === FALSE) { 941 | # Post 5.5.17 SHOW ENGINE INNODB STATUS syntax 942 | # RW-shared spins 604733, rounds 8107431, OS waits 241268 943 | $results['spin_waits'][] = to_int($row[2]); 944 | $results['os_waits'][] = to_int($row[7]); 945 | } 946 | elseif (strpos($line, 'RW-excl spins') === 0) { 947 | # Post 5.5.17 SHOW ENGINE INNODB STATUS syntax 948 | # RW-excl spins 604733, rounds 8107431, OS waits 241268 949 | $results['spin_waits'][] = to_int($row[2]); 950 | $results['os_waits'][] = to_int($row[7]); 951 | } 952 | elseif (strpos($line, 'seconds the semaphore:') > 0) { 953 | # --Thread 907205 has waited at handler/ha_innodb.cc line 7156 for 1.00 seconds the semaphore: 954 | increment($results, 'innodb_sem_waits', 1); 955 | increment($results, 956 | 'innodb_sem_wait_time_ms', to_int($row[9]) * 1000); 957 | } 958 | 959 | # TRANSACTIONS 960 | elseif ( strpos($line, 'Trx id counter') === 0 ) { 961 | # The beginning of the TRANSACTIONS section: start counting 962 | # transactions 963 | if ( $mysql_version < 50600 ) { 964 | # For versions prior 5.6: two decimals or one hex 965 | # Trx id counter 0 1170664159 966 | # Trx id counter 861B144C 967 | $results['innodb_transactions'] = isset($row[4]) ? make_bigint( 968 | $row[3], $row[4]) : base_convert($row[3], 16, 10); 969 | } 970 | else { 971 | # For versions 5.6+ and MariaDB 10.x: one decimal 972 | # Trx id counter 2903813 973 | $results['innodb_transactions'] = $row[3]; 974 | } 975 | $txn_seen = TRUE; 976 | } 977 | elseif ( strpos($line, 'Purge done for trx') === 0 ) { 978 | if ( $mysql_version < 50600 ) { 979 | # For versions prior 5.6: two decimals or one hex 980 | # Purge done for trx's n:o < 0 1170663853 undo n:o < 0 0 981 | # Purge done for trx's n:o < 861B135D undo n:o < 0 982 | $purged_to = $row[7] == 'undo' ? base_convert($row[6], 16, 10) : make_bigint($row[6], $row[7]); 983 | } 984 | else { 985 | # For versions 5.6+ and MariaDB 10.x: one decimal 986 | # Purge done for trx's n:o < 2903354 undo n:o < 0 state: running but idle 987 | $purged_to = $row[6]; 988 | } 989 | $results['unpurged_txns'] 990 | = big_sub($results['innodb_transactions'], $purged_to); 991 | } 992 | elseif (strpos($line, 'History list length') === 0 ) { 993 | # History list length 132 994 | $results['history_list'] = to_int($row[3]); 995 | } 996 | elseif ( $txn_seen && strpos($line, '---TRANSACTION') === 0 ) { 997 | # ---TRANSACTION 0, not started, process no 13510, OS thread id 1170446656 998 | increment($results, 'current_transactions', 1); 999 | if ( strpos($line, 'ACTIVE') > 0 ) { 1000 | increment($results, 'active_transactions', 1); 1001 | } 1002 | } 1003 | elseif ( $txn_seen && strpos($line, '------- TRX HAS BEEN') === 0 ) { 1004 | # ------- TRX HAS BEEN WAITING 32 SEC FOR THIS LOCK TO BE GRANTED: 1005 | increment($results, 'innodb_lock_wait_secs', to_int($row[5])); 1006 | } 1007 | elseif ( strpos($line, 'read views open inside InnoDB') > 0 ) { 1008 | # 1 read views open inside InnoDB 1009 | $results['read_views'] = to_int($row[0]); 1010 | } 1011 | elseif ( strpos($line, 'mysql tables in use') === 0 ) { 1012 | # mysql tables in use 2, locked 2 1013 | increment($results, 'innodb_tables_in_use', to_int($row[4])); 1014 | increment($results, 'innodb_locked_tables', to_int($row[6])); 1015 | } 1016 | elseif ( $txn_seen && strpos($line, 'lock struct(s)') > 0 ) { 1017 | # 23 lock struct(s), heap size 3024, undo log entries 27 1018 | # LOCK WAIT 12 lock struct(s), heap size 3024, undo log entries 5 1019 | # LOCK WAIT 2 lock struct(s), heap size 368 1020 | if ( strpos($line, 'LOCK WAIT') === 0 ) { 1021 | increment($results, 'innodb_lock_structs', to_int($row[2])); 1022 | increment($results, 'locked_transactions', 1); 1023 | } 1024 | else { 1025 | increment($results, 'innodb_lock_structs', to_int($row[0])); 1026 | } 1027 | } 1028 | 1029 | # FILE I/O 1030 | elseif (strpos($line, ' OS file reads, ') > 0 ) { 1031 | # 8782182 OS file reads, 15635445 OS file writes, 947800 OS fsyncs 1032 | $results['file_reads'] = to_int($row[0]); 1033 | $results['file_writes'] = to_int($row[4]); 1034 | $results['file_fsyncs'] = to_int($row[8]); 1035 | } 1036 | elseif (strpos($line, 'Pending normal aio reads:') === 0 ) { 1037 | # Pending normal aio reads: 0, aio writes: 0, 1038 | $results['pending_normal_aio_reads'] = to_int($row[4]); 1039 | $results['pending_normal_aio_writes'] = to_int($row[7]); 1040 | } 1041 | elseif (strpos($line, 'ibuf aio reads') === 0 ) { 1042 | # ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0 1043 | $results['pending_ibuf_aio_reads'] = to_int($row[3]); 1044 | $results['pending_aio_log_ios'] = to_int($row[6]); 1045 | $results['pending_aio_sync_ios'] = to_int($row[9]); 1046 | } 1047 | elseif ( strpos($line, 'Pending flushes (fsync)') === 0 ) { 1048 | # Pending flushes (fsync) log: 0; buffer pool: 0 1049 | $results['pending_log_flushes'] = to_int($row[4]); 1050 | $results['pending_buf_pool_flushes'] = to_int($row[7]); 1051 | } 1052 | 1053 | # INSERT BUFFER AND ADAPTIVE HASH INDEX 1054 | elseif (strpos($line, 'Ibuf for space 0: size ') === 0 ) { 1055 | # Older InnoDB code seemed to be ready for an ibuf per tablespace. It 1056 | # had two lines in the output. Newer has just one line, see below. 1057 | # Ibuf for space 0: size 1, free list len 887, seg size 889, is not empty 1058 | # Ibuf for space 0: size 1, free list len 887, seg size 889, 1059 | $results['ibuf_used_cells'] = to_int($row[5]); 1060 | $results['ibuf_free_cells'] = to_int($row[9]); 1061 | $results['ibuf_cell_count'] = to_int($row[12]); 1062 | } 1063 | elseif (strpos($line, 'Ibuf: size ') === 0 ) { 1064 | # Ibuf: size 1, free list len 4634, seg size 4636, 1065 | $results['ibuf_used_cells'] = to_int($row[2]); 1066 | $results['ibuf_free_cells'] = to_int($row[6]); 1067 | $results['ibuf_cell_count'] = to_int($row[9]); 1068 | if (strpos($line, 'merges')) { 1069 | $results['ibuf_merges'] = to_int($row[10]); 1070 | } 1071 | } 1072 | elseif (strpos($line, ', delete mark ') > 0 && strpos($prev_line, 'merged operations:') === 0 ) { 1073 | # Output of show engine innodb status has changed in 5.5 1074 | # merged operations: 1075 | # insert 593983, delete mark 387006, delete 73092 1076 | $results['ibuf_inserts'] = to_int($row[1]); 1077 | $results['ibuf_merged'] = to_int($row[1]) + to_int($row[4]) + to_int($row[6]); 1078 | } 1079 | elseif (strpos($line, ' merged recs, ') > 0 ) { 1080 | # 19817685 inserts, 19817684 merged recs, 3552620 merges 1081 | $results['ibuf_inserts'] = to_int($row[0]); 1082 | $results['ibuf_merged'] = to_int($row[2]); 1083 | $results['ibuf_merges'] = to_int($row[5]); 1084 | } 1085 | elseif (strpos($line, 'Hash table size ') === 0 ) { 1086 | # In some versions of InnoDB, the used cells is omitted. 1087 | # Hash table size 4425293, used cells 4229064, .... 1088 | # Hash table size 57374437, node heap has 72964 buffer(s) <-- no used cells 1089 | $results['hash_index_cells_total'] = to_int($row[3]); 1090 | $results['hash_index_cells_used'] 1091 | = strpos($line, 'used cells') > 0 ? to_int($row[6]) : '0'; 1092 | } 1093 | 1094 | # LOG 1095 | elseif (strpos($line, " log i/o's done, ") > 0 ) { 1096 | # 3430041 log i/o's done, 17.44 log i/o's/second 1097 | # 520835887 log i/o's done, 17.28 log i/o's/second, 518724686 syncs, 2980893 checkpoints 1098 | # TODO: graph syncs and checkpoints 1099 | $results['log_writes'] = to_int($row[0]); 1100 | } 1101 | elseif ($mysql_version < 50700 && strpos($line, " pending log writes, ") > 0 ) { 1102 | # 0 pending log writes, 0 pending chkp writes 1103 | $results['pending_log_writes'] = to_int($row[0]); 1104 | $results['pending_chkp_writes'] = to_int($row[4]); 1105 | } 1106 | elseif ($mysql_version >= 50700 && strpos($line, " pending log flushes, ") > 0 ) { 1107 | # Post 5.7.x SHOW ENGINE INNODB STATUS syntax 1108 | # 0 pending log flushes, 0 pending chkp writes 1109 | $results['pending_log_writes'] = to_int($row[0]); 1110 | $results['pending_chkp_writes'] = to_int($row[4]); 1111 | } 1112 | elseif (strpos($line, "Log sequence number") === 0 ) { 1113 | # This number is NOT printed in hex in InnoDB plugin. 1114 | # Log sequence number 13093949495856 //plugin 1115 | # Log sequence number 125 3934414864 //normal 1116 | $results['log_bytes_written'] 1117 | = isset($row[4]) 1118 | ? make_bigint($row[3], $row[4]) 1119 | : to_int($row[3]); 1120 | } 1121 | elseif (strpos($line, "Log flushed up to") === 0 ) { 1122 | # This number is NOT printed in hex in InnoDB plugin. 1123 | # Log flushed up to 13093948219327 1124 | # Log flushed up to 125 3934414864 1125 | $results['log_bytes_flushed'] 1126 | = isset($row[5]) 1127 | ? make_bigint($row[4], $row[5]) 1128 | : to_int($row[4]); 1129 | } 1130 | elseif (strpos($line, "Last checkpoint at") === 0 ) { 1131 | # Last checkpoint at 125 3934293461 1132 | $results['last_checkpoint'] 1133 | = isset($row[4]) 1134 | ? make_bigint($row[3], $row[4]) 1135 | : to_int($row[3]); 1136 | } 1137 | 1138 | # BUFFER POOL AND MEMORY 1139 | elseif ( $mysql_version < 50700 && strpos($line, "Total memory allocated") === 0 && strpos($line, "in additional pool allocated") > 0 ) { 1140 | # Total memory allocated 29642194944; in additional pool allocated 0 1141 | # Total memory allocated by read views 96 1142 | $results['total_mem_alloc'] = to_int($row[3]); 1143 | $results['additional_pool_alloc'] = to_int($row[8]); 1144 | } 1145 | elseif ( $mysql_version >= 50700 && strpos($line, "Total large memory allocated") === 0 ) { 1146 | # Post 5.7.x SHOW ENGINE INNODB STATUS syntax 1147 | # Total large memory allocated 2198863872 1148 | $results['total_mem_alloc'] = to_int($row[4]); 1149 | $results['additional_pool_alloc'] = 0; 1150 | } 1151 | elseif(strpos($line, 'Adaptive hash index ') === 0 ) { 1152 | # Adaptive hash index 1538240664 (186998824 + 1351241840) 1153 | $results['adaptive_hash_memory'] = to_int($row[3]); 1154 | } 1155 | elseif(strpos($line, 'Page hash ') === 0 ) { 1156 | # Page hash 11688584 1157 | $results['page_hash_memory'] = to_int($row[2]); 1158 | } 1159 | elseif(strpos($line, 'Dictionary cache ') === 0 ) { 1160 | # Dictionary cache 145525560 (140250984 + 5274576) 1161 | $results['dictionary_cache_memory'] = to_int($row[2]); 1162 | } 1163 | elseif(strpos($line, 'File system ') === 0 ) { 1164 | # File system 313848 (82672 + 231176) 1165 | $results['file_system_memory'] = to_int($row[2]); 1166 | } 1167 | elseif(strpos($line, 'Lock system ') === 0 ) { 1168 | # Lock system 29232616 (29219368 + 13248) 1169 | $results['lock_system_memory'] = to_int($row[2]); 1170 | } 1171 | elseif(strpos($line, 'Recovery system ') === 0 ) { 1172 | # Recovery system 0 (0 + 0) 1173 | $results['recovery_system_memory'] = to_int($row[2]); 1174 | } 1175 | elseif(strpos($line, 'Threads ') === 0 ) { 1176 | # Threads 409336 (406936 + 2400) 1177 | $results['thread_hash_memory'] = to_int($row[1]); 1178 | } 1179 | elseif(strpos($line, 'innodb_io_pattern ') === 0 ) { 1180 | # innodb_io_pattern 0 (0 + 0) 1181 | $results['innodb_io_pattern_memory'] = to_int($row[1]); 1182 | } 1183 | elseif (strpos($line, "Buffer pool size ") === 0 ) { 1184 | # The " " after size is necessary to avoid matching the wrong line: 1185 | # Buffer pool size 1769471 1186 | # Buffer pool size, bytes 28991012864 1187 | $results['pool_size'] = to_int($row[3]); 1188 | } 1189 | elseif (strpos($line, "Free buffers") === 0 ) { 1190 | # Free buffers 0 1191 | $results['free_pages'] = to_int($row[2]); 1192 | } 1193 | elseif (strpos($line, "Database pages") === 0 ) { 1194 | # Database pages 1696503 1195 | $results['database_pages'] = to_int($row[2]); 1196 | } 1197 | elseif (strpos($line, "Modified db pages") === 0 ) { 1198 | # Modified db pages 160602 1199 | $results['modified_pages'] = to_int($row[3]); 1200 | } 1201 | elseif (strpos($line, "Pages read ahead") === 0 ) { 1202 | # Must do this BEFORE the next test, otherwise it'll get fooled by this 1203 | # line from the new plugin (see samples/innodb-015.txt): 1204 | # Pages read ahead 0.00/s, evicted without access 0.06/s 1205 | # TODO: No-op for now, see issue 134. 1206 | } 1207 | elseif (strpos($line, "Pages read") === 0 ) { 1208 | # Pages read 15240822, created 1770238, written 21705836 1209 | $results['pages_read'] = to_int($row[2]); 1210 | $results['pages_created'] = to_int($row[4]); 1211 | $results['pages_written'] = to_int($row[6]); 1212 | } 1213 | 1214 | # ROW OPERATIONS 1215 | elseif (strpos($line, 'Number of rows inserted') === 0 ) { 1216 | # Number of rows inserted 50678311, updated 66425915, deleted 20605903, read 454561562 1217 | $results['rows_inserted'] = to_int($row[4]); 1218 | $results['rows_updated'] = to_int($row[6]); 1219 | $results['rows_deleted'] = to_int($row[8]); 1220 | $results['rows_read'] = to_int($row[10]); 1221 | } 1222 | elseif (strpos($line, " queries inside InnoDB, ") > 0 ) { 1223 | # 0 queries inside InnoDB, 0 queries in queue 1224 | $results['queries_inside'] = to_int($row[0]); 1225 | $results['queries_queued'] = to_int($row[4]); 1226 | } 1227 | $prev_line = $line; 1228 | } 1229 | 1230 | foreach ( array('spin_waits', 'spin_rounds', 'os_waits') as $key ) { 1231 | $results[$key] = to_int(array_sum($results[$key])); 1232 | } 1233 | $results['unflushed_log'] 1234 | = big_sub($results['log_bytes_written'], $results['log_bytes_flushed']); 1235 | $results['uncheckpointed_bytes'] 1236 | = big_sub($results['log_bytes_written'], $results['last_checkpoint']); 1237 | 1238 | return $results; 1239 | } 1240 | 1241 | 1242 | # ============================================================================ 1243 | # Returns a bigint from two ulint. This is tested in 1244 | # t/mysql_stats.php and copied, without tests, to ss_get_by_ssh.php. 1245 | # ============================================================================ 1246 | function make_bigint ($hi, $lo) { 1247 | debug(array($hi, $lo)); 1248 | $hi = $hi ? $hi : '0'; # Handle empty-string or whatnot 1249 | $lo = $lo ? $lo : '0'; 1250 | return big_add(big_multiply($hi, 4294967296), $lo); 1251 | } 1252 | 1253 | # ============================================================================ 1254 | # Extracts the numbers from a string. You can't reliably do this by casting to 1255 | # an int, because numbers that are bigger than PHP's int (varies by platform) 1256 | # will be truncated. And you can't use sprintf(%u) either, because the maximum 1257 | # value that will return on some platforms is 4022289582. So this just handles 1258 | # them as a string instead. It extracts digits until it finds a non-digit and 1259 | # quits. This is tested in t/mysql_stats.php and copied, without tests, to 1260 | # ss_get_by_ssh.php. 1261 | # ============================================================================ 1262 | function to_int ( $str ) { 1263 | debug($str); 1264 | global $debug; 1265 | preg_match('{(\d+)}', $str, $m); 1266 | if ( isset($m[1]) ) { 1267 | return $m[1]; 1268 | } 1269 | elseif ( $debug ) { 1270 | print_r(debug_backtrace()); 1271 | } 1272 | else { 1273 | return 0; 1274 | } 1275 | } 1276 | 1277 | # ============================================================================ 1278 | # Wrap mysqli_query in error-handling, and instead of returning the result, 1279 | # return an array of arrays in the result. 1280 | # ============================================================================ 1281 | function run_query($sql, $conn) { 1282 | global $debug; 1283 | debug($sql); 1284 | $result = @mysqli_query($conn, $sql); 1285 | if ( $debug && strpos($sql, 'SHOW SLAVE STATUS ') === false ) { 1286 | $error = @mysqli_error($conn); 1287 | if ( $error ) { 1288 | debug(array($sql, $error)); 1289 | die("SQLERR $error in $sql"); 1290 | } 1291 | } 1292 | $array = array(); 1293 | $count = @mysqli_num_rows($result); 1294 | if ( $count > 10000 ) { 1295 | debug('Abnormal number of rows returned: ' . $count); 1296 | } 1297 | else { 1298 | while ( $row = @mysqli_fetch_array($result) ) { 1299 | $array[] = $row; 1300 | } 1301 | } 1302 | debug(array($sql, $array)); 1303 | return $array; 1304 | } 1305 | 1306 | # ============================================================================ 1307 | # Safely increments a value that might be null. 1308 | # ============================================================================ 1309 | function increment(&$arr, $key, $howmuch) { 1310 | debug(array($key, $howmuch)); 1311 | if ( array_key_exists($key, $arr) && isset($arr[$key]) ) { 1312 | $arr[$key] = big_add($arr[$key], $howmuch); 1313 | } 1314 | else { 1315 | $arr[$key] = $howmuch; 1316 | } 1317 | } 1318 | 1319 | # ============================================================================ 1320 | # Multiply two big integers together as accurately as possible with reasonable 1321 | # effort. This is tested in t/mysql_stats.php and copied, without tests, to 1322 | # ss_get_by_ssh.php. $force is for testability. 1323 | # ============================================================================ 1324 | function big_multiply ($left, $right, $force = null) { 1325 | if ( function_exists("gmp_mul") && (is_null($force) || $force == 'gmp') ) { 1326 | debug(array('gmp_mul', $left, $right)); 1327 | return gmp_strval( gmp_mul( $left, $right )); 1328 | } 1329 | elseif ( function_exists("bcmul") && (is_null($force) || $force == 'bc') ) { 1330 | debug(array('bcmul', $left, $right)); 1331 | return bcmul( $left, $right ); 1332 | } 1333 | else { # Or $force == 'something else' 1334 | debug(array('sprintf', $left, $right)); 1335 | return sprintf("%.0f", $left * $right); 1336 | } 1337 | } 1338 | 1339 | # ============================================================================ 1340 | # Subtract two big integers as accurately as possible with reasonable effort. 1341 | # This is tested in t/mysql_stats.php and copied, without tests, to 1342 | # ss_get_by_ssh.php. $force is for testability. 1343 | # ============================================================================ 1344 | function big_sub ($left, $right, $force = null) { 1345 | debug(array($left, $right)); 1346 | if ( is_null($left) ) { $left = 0; } 1347 | if ( is_null($right) ) { $right = 0; } 1348 | if ( function_exists("gmp_sub") && (is_null($force) || $force == 'gmp')) { 1349 | debug(array('gmp_sub', $left, $right)); 1350 | return gmp_strval( gmp_sub( $left, $right )); 1351 | } 1352 | elseif ( function_exists("bcsub") && (is_null($force) || $force == 'bc')) { 1353 | debug(array('bcsub', $left, $right)); 1354 | return bcsub( $left, $right ); 1355 | } 1356 | else { # Or $force == 'something else' 1357 | debug(array('to_int', $left, $right)); 1358 | return to_int($left - $right); 1359 | } 1360 | } 1361 | 1362 | # ============================================================================ 1363 | # Add two big integers together as accurately as possible with reasonable 1364 | # effort. This is tested in t/mysql_stats.php and copied, without tests, to 1365 | # ss_get_by_ssh.php. $force is for testability. 1366 | # ============================================================================ 1367 | function big_add ($left, $right, $force = null) { 1368 | if ( is_null($left) ) { $left = 0; } 1369 | if ( is_null($right) ) { $right = 0; } 1370 | if ( function_exists("gmp_add") && (is_null($force) || $force == 'gmp')) { 1371 | debug(array('gmp_add', $left, $right)); 1372 | return gmp_strval( gmp_add( $left, $right )); 1373 | } 1374 | elseif ( function_exists("bcadd") && (is_null($force) || $force == 'bc')) { 1375 | debug(array('bcadd', $left, $right)); 1376 | return bcadd( $left, $right ); 1377 | } 1378 | else { # Or $force == 'something else' 1379 | debug(array('to_int', $left, $right)); 1380 | return to_int($left + $right); 1381 | } 1382 | } 1383 | 1384 | # ============================================================================ 1385 | # Writes to a debugging log. 1386 | # ============================================================================ 1387 | function debug($val) { 1388 | global $debug_log; 1389 | if ( !$debug_log ) { 1390 | return; 1391 | } 1392 | if ( $fp = fopen($debug_log, 'a+') ) { 1393 | $trace = debug_backtrace(); 1394 | $calls = array(); 1395 | $i = 0; 1396 | $line = 0; 1397 | $file = ''; 1398 | foreach ( debug_backtrace() as $arr ) { 1399 | if ( $i++ ) { 1400 | $calls[] = "$arr[function]() at $file:$line"; 1401 | } 1402 | $line = array_key_exists('line', $arr) ? $arr['line'] : '?'; 1403 | $file = array_key_exists('file', $arr) ? $arr['file'] : '?'; 1404 | } 1405 | if ( !count($calls) ) { 1406 | $calls[] = "at $file:$line"; 1407 | } 1408 | fwrite($fp, date('Y-m-d H:i:s') . ' ' . implode(' <- ', $calls)); 1409 | fwrite($fp, "\n" . var_export($val, TRUE) . "\n"); 1410 | fclose($fp); 1411 | } 1412 | else { # Disable logging 1413 | print("Warning: disabling debug logging to $debug_log\n"); 1414 | $debug_log = FALSE; 1415 | } 1416 | } 1417 | 1418 | --------------------------------------------------------------------------------