• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python
2
3# Copyright 2016 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Queries a MySQL database and emits status metrics to Monarch.
8
9Note: confusingly, 'Innodb_buffer_pool_reads' is actually the cache-misses, not
10the number of reads to the buffer pool.  'Innodb_buffer_pool_read_requests'
11corresponds to the number of reads the the buffer pool.
12"""
13import logging
14import sys
15
16import MySQLdb
17import time
18
19import common
20
21from autotest_lib.client.common_lib import global_config
22from autotest_lib.client.common_lib import utils
23
24try:
25    from chromite.lib import metrics
26    from chromite.lib import ts_mon_config
27except ImportError:
28    metrics = utils.metrics_mock
29    ts_mon_config = utils.metrics_mock
30
31
32AT_DIR='/usr/local/autotest'
33DEFAULT_USER = global_config.global_config.get_config_value(
34        'CROS', 'db_backup_user', type=str, default='')
35DEFAULT_PASSWD = global_config.global_config.get_config_value(
36        'CROS', 'db_backup_password', type=str, default='')
37LOOP_INTERVAL = 60
38EMITTED_STATUSES_COUNTERS = [
39    'bytes_received',
40    'bytes_sent',
41    'connections',
42    'Innodb_buffer_pool_read_requests',
43    'Innodb_buffer_pool_reads',
44    'questions',
45    'slow_queries',
46    'threads_created',
47]
48
49EMITTED_STATUS_GAUGES = ['threads_running', 'threads_connected']
50
51
52def main():
53    """Sets up ts_mon and repeatedly queries MySQL stats"""
54    logging.basicConfig(stream=sys.stdout, level=logging.INFO)
55    db = MySQLdb.connect('localhost', DEFAULT_USER, DEFAULT_PASSWD)
56    cursor = db.cursor()
57
58    with ts_mon_config.SetupTsMonGlobalState('mysql_stats', indirect=True):
59      QueryLoop(cursor)
60
61
62def QueryLoop(cursor):
63    """Queries and emits metrics every LOOP_INTERVAL seconds.
64
65    @param cursor: The mysql command line.
66    """
67    # Get the baselines for cumulative metrics. Otherwise the windowed rate at
68    # the very beginning will be extremely high as it shoots up from 0 to its
69    # current value.
70    baselines = dict((s, GetStatus(cursor, s))
71                     for s in EMITTED_STATUSES_COUNTERS)
72
73    while True:
74        now = time.time()
75        QueryAndEmit(baselines, cursor)
76        time_spent = time.time() - now
77        sleep_duration = LOOP_INTERVAL - time_spent
78        time.sleep(max(0, sleep_duration))
79
80
81def GetStatus(cursor, s):
82    """Get the status variable from database.
83
84    @param cursor: MySQLdb cursor to query with.
85    @param s: Name of the status variable.
86    @returns The mysql query result.
87    """
88    cursor.execute('SHOW GLOBAL STATUS LIKE "%s";' % s)
89    output = cursor.fetchone()[1]
90    if not output:
91        logging.error('Cannot find any global status like %s', s)
92    return int(output)
93
94
95def QueryAndEmit(baselines, cursor):
96    """Queries MySQL for important stats and emits Monarch metrics
97
98    @param baselines: A dict containing the initial values for the cumulative
99                      metrics.
100    @param cursor: The mysql command line.
101    """
102
103    for status in EMITTED_STATUSES_COUNTERS:
104        delta = GetStatus(cursor, status) - baselines[status]
105        metric_name = 'chromeos/autotest/afe_db/%s' % status.lower()
106        metrics.Counter(metric_name).set(delta)
107
108    for status in EMITTED_STATUS_GAUGES:
109        metric_name = 'chromeos/autotest/afe_db/%s' % status.lower()
110        metrics.Gauge(metric_name).set(GetStatus(cursor, status))
111
112    pages_free = GetStatus(cursor, 'Innodb_buffer_pool_pages_free')
113    pages_total = GetStatus(cursor, 'Innodb_buffer_pool_pages_total')
114
115    metrics.Gauge('chromeos/autotest/afe_db/buffer_pool_pages').set(
116        pages_free, fields={'used': False})
117
118    metrics.Gauge('chromeos/autotest/afe_db/buffer_pool_pages').set(
119        pages_total - pages_free, fields={'used': True})
120
121
122if __name__ == '__main__':
123  main()
124