]> arthur.barton.de Git - netdata.git/commitdiff
preserve configs across installaitons
authorpaulfantom <paulfantom@gmail.com>
Mon, 13 Jun 2016 21:37:18 +0000 (23:37 +0200)
committerpaulfantom <paulfantom@gmail.com>
Tue, 14 Jun 2016 19:27:15 +0000 (21:27 +0200)
python mysql plugin

Makefile with mysql.chart.py

minor fixes in mysql.chart.py installation

add connection timeout

no need to execute query when chceking for active servers

fix function failure message

handle interval

connection timeout

directories should end with "/"

timeout should be int type

fix normalizing config_dir

comment out mysql.conf

updated readme to include mysql plugin

remove pymysql

conf.d/Makefile.am
conf.d/python.d.conf
conf.d/python.d/mysql.conf [new file with mode: 0644]
netdata-installer.sh
plugins.d/python.d.plugin
python.d/Makefile.am
python.d/README.md
python.d/mysql.chart.py [new file with mode: 0644]

index c8c518fabd244c3edf95b5639afb5612a6e0d1a1..f60faaa570a65af29ec793592c5a10714f6f4319 100644 (file)
@@ -19,7 +19,8 @@ dist_nodeconfig_DATA = \
 
 pythonconfigdir=$(configdir)/python.d
 dist_pythonconfig_DATA = \
-       python.d/example.conf
+       python.d/example.conf \
+       python.d/mysql.conf \
        $(NULL)
 
 
index 4803e893c005484a4d0b0c9bd7755565b8957b89..020ba36cc02189feeff9c00f30d272ee725f0666 100644 (file)
@@ -9,3 +9,4 @@
 # By default python.d.plugin enables all modules stored in python.d
 # Modules can be disabled with setting "module_name = no"
 example=no
+mysql=no
diff --git a/conf.d/python.d/mysql.conf b/conf.d/python.d/mysql.conf
new file mode 100644 (file)
index 0000000..f3b5739
--- /dev/null
@@ -0,0 +1,18 @@
+# Example configuration of mysql.chart.py
+# Indentation is important
+
+#update_every=5
+
+#config=[
+#    {
+#        'name'     : 'local',
+#        'user'     : 'root',
+#        'password' : 'blablablabla',
+#        'socket'   : '/var/run/mysqld/mysqld.sock'
+#    },{
+#        'name'     : 'remote',
+#        'user'     : 'admin',
+#        'password' : 'bla',
+#        'host'     : 'example.org',
+#        'port'     : '3306'
+#    }]
index 4289840de0e2b189809841ef8e33c9ad6277c5df..da0ec82159338c46f0a027a5163b9eede22addfe 100755 (executable)
@@ -338,15 +338,15 @@ run make || exit 1
 
 # backup user configurations
 installer_backup_suffix="${PID}.${RANDOM}"
-for x in apps_groups.conf charts.d.conf
+for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
 do
-       if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}" ]
+       if [ -f "${x}" ]
                then
-               cp -p "${NETDATA_PREFIX}/etc/netdata/${x}" "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}"
+               cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
 
-       elif [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}" ]
+       elif [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
                then
-               rm -f "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}"
+               rm -f "${x}.installer_backup.${installer_backup_suffix}"
        fi
 done
 
@@ -354,12 +354,12 @@ echo >&2 "Installing netdata ..."
 run make install || exit 1
 
 # restore user configurations
-for x in apps_groups.conf charts.d.conf
+for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
 do
-       if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}" ]
+       if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
                then
-               cp -p "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}" "${NETDATA_PREFIX}/etc/netdata/${x}"
-               rm -f "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup.${installer_backup_suffix}"
+               cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
+               rm -f "${x}.installer_backup.${installer_backup_suffix}"
        fi
 done
 
index bb7468d8f6648fdd1fba6a643d038a76ace3a5d3..5dc4f0b0612e2f16edbae4e97c19c5dd32b93418 100755 (executable)
@@ -27,12 +27,10 @@ class PythonCharts(object):
         self.configs = modules_configs
 
         # load modules
-        self.modules = self._load_modules(modules_path,modules)
+        modules = self._load_modules(modules_path,modules)
         
         # check if loaded modules are on disabled modules list
-        for mod in self.modules:
-            if mod.__name__ in modules_disabled:
-                self.modules.remove(mod)
+        self.modules = [ m for m in modules if m.__name__ not in modules_disabled ]
         
         # load configuration files
         self._load_configs()
@@ -123,9 +121,9 @@ class PythonCharts(object):
                   "() function. Disabling it.")
         elif reason[:7] == "failed ":
             debug("chart '" +
-                  mod.__name__ +
-                  reason[3:] +
-                  "() function. reports failure.")
+                  mod.__name__ + "' " +
+                  reason[7:] +
+                  "() function reports failure.")
         elif reason[:13] == "configuration":
             debug(mod.__name__,
                   "configuration file '" +
@@ -272,6 +270,8 @@ def parse_cmdline(directory, *commands):
                 pass
 
     debug("started from", commands[0], "with options:", *commands[1:])
+    if len(mods) == 0 and DEBUG_FLAG is False:
+        interval = None
 
     return {'interval': interval,
             'modules': mods}
@@ -292,9 +292,8 @@ def run():
     # read configuration file
     disabled = []
     if config_dir[-1] != '/':
-        configfile = config_dir + '/' + "python.d.conf"
-    else:
-        configfile = config_dir + "python.d.conf"
+        config_dir += '/'
+    configfile = config_dir + "python.d.conf"
 
     try:
         conf = read_config(configfile)
index 8c84254b8f93af846b8367939938e9d56b782add..1a43fe07e2465695eacfa8cbd0e0d3e3ca2b374f 100644 (file)
@@ -2,6 +2,7 @@ MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
 
 dist_python_SCRIPTS = \
        example.chart.py \
+       mysql.chart.py \
        $(NULL)
 
 dist_python_DATA = \
@@ -10,4 +11,33 @@ dist_python_DATA = \
 
 pythonmodulesdir=$(pythondir)/python_modules
 dist_pythonmodules_DATA = \
+       python_modules/__init__.py
+       $(NULL)
+
+
+pythonmodulespymysqldir=$(pythondir)/python_modules/pymysql
+dist_pythonmodulespymysql_DATA = \
+       python_modules/pymysql/charset.py \
+       python_modules/pymysql/_compat.py \
+       python_modules/pymysql/connections.py \
+       python_modules/pymysql/converters.py \
+       python_modules/pymysql/cursors.py \
+       python_modules/pymysql/err.py \
+       python_modules/pymysql/__init__.py \
+       python_modules/pymysql/optionfile.py \
+       python_modules/pymysql/_socketio.py \
+       python_modules/pymysql/times.py \
+       python_modules/pymysql/util.py \
+       $(NULL)
+
+pythonmodulespymysqlconstantsdir=$(pythondir)/python_modules/pymysql/constants
+dist_pythonmodulespymysqlconstants_DATA = \
+       python_modules/pymysql/constants/CLIENT.py \
+       python_modules/pymysql/constants/COMMAND.py \
+       python_modules/pymysql/constants/CR.py \
+       python_modules/pymysql/constants/ER.py \
+       python_modules/pymysql/constants/FIELD_TYPE.py \
+       python_modules/pymysql/constants/FLAG.py \
+       python_modules/pymysql/constants/__init__.py \
+       python_modules/pymysql/constants/SERVER_STATUS.py \
        $(NULL)
index b4407977103da210cc6813b0fafda326d44c43a5..5a7dd89d492a02a87d762c9a0b2ac29ccaaafb3f 100644 (file)
@@ -1,6 +1,87 @@
+Every plugin supports changing its data collection frequency by setting `update_every` variable in its configuration file.
+
 The following python.d plugins are supported:
 
-# None
+# mysql
+
+The plugin will monitor one or more mysql servers
+
+It will produce the following charts (if data is available):
+
+1. **Bandwidth** in kbps
+ * in
+ * out
+
+2. **Queries** in queries/sec
+ * queries
+ * questions
+ * slow queries
+
+3. **Operations** in operations/sec
+ * opened tables
+ * flush
+ * commit
+ * delete
+ * prepare
+ * read first
+ * read key
+ * read next
+ * read prev
+ * read random
+ * read random next
+ * rollback
+ * save point
+ * update
+ * write
+
+4. **Table Locks** in locks/sec
+ * immediate
+ * waited
+
+5. **Select Issues** in issues/sec
+ * full join
+ * full range join
+ * range
+ * range check
+ * scan
+
+6. **Sort Issues** in issues/sec
+ * merge passes
+ * range
+ * scan
+
+### configuration
+
+You can provide, per server, the following:
+
+1. a name, anything you like, but keep it short
+2. username which have access to database (deafults to 'root')
+3. password (defaults to none)
+4. mysql socket (optional)
+5. mysql host (ip or hostname)
+3. mysql port (defaults to 3306)
+
+Here is an example for 2 servers updating data every 10 seconds
+
+```js
+update_every = 10
+
+config=[
+    {
+       'name'     : 'local',
+        'user'     : 'root',
+        'password' : 'blablablabla',
+        'socket'   : '/var/run/mysqld/mysqld.sock'
+    },{
+        'name'     : 'remote',
+        'user'     : 'admin',
+        'password' : 'bla',
+        'host'     : 'example.org',
+        'port'     : '9000'
+    }]
+```
+
+If no configuration is given, the plugin will attempt to connect to mysql server via unix socket at `/var/run/mysqld/mysqld.sock` without password and username `root`
 
-Currently we don't have any python plugins, but we are counting on you to add some new ones.
+---
 
diff --git a/python.d/mysql.chart.py b/python.d/mysql.chart.py
new file mode 100644 (file)
index 0000000..44b8452
--- /dev/null
@@ -0,0 +1,433 @@
+#!/usr/bin/python3 -u
+
+try:
+    import pymysql.cursors
+    # https://github.com/PyMySQL/PyMySQL
+except ImportError:
+    import sys
+    sys.write.stderr("You need to install PyMySQL module to use mysql.chart.py plugin")
+
+config = [
+    {
+        'name'     : 'local',
+        'user'     : 'root',
+        'password' : None,
+        'socket'   : '/var/run/mysqld/mysqld.sock'
+    }
+]
+
+update_every = 3
+priority = 90000
+
+#query = "SHOW GLOBAL STATUS WHERE value REGEX '^[0-9]'"
+QUERY = "SHOW GLOBAL STATUS"
+ORDER = ['net', 
+         'queries', 
+         'handlers', 
+         'table_locks', 
+         'join_issues', 
+         'sort_issues', 
+         'tmp', 
+         'connections', 
+         'binlog_cache', 
+         'threads', 
+         'thread_cache_misses', 
+         'innodb_io', 
+         'innodb_io_ops',
+         'innodb_io_pending_ops',
+         'innodb_log',
+         'innodb_os_log',
+         'innodb_os_log_io',
+         'innodb_cur_row_lock',
+         'innodb_rows',
+         'innodb_buffer_pool_pages',
+         'innodb_buffer_pool_bytes',
+         'innodb_buffer_pool_read_ahead',
+         'innodb_buffer_pool_reqs',
+         'innodb_buffer_pool_ops',
+         'qcache_ops',
+         'qcache',
+         'qcache_freemem',
+         'qcache_memblocks',
+         'key_blocks',
+         'key_requests',
+         'key_disk_ops',
+         'files',
+         'files_rate',
+         'binlog_stmt_cache',
+         'connection_errors']
+
+CHARTS = {
+    'net' : (
+        "'' 'mysql Bandwidth' 'kilobits/s' bandwidth mysql.net area",
+        (
+            ("Bytes_received", "in incremental 8 1024"),
+            ("Bytes_sent",     "out incremental -8 1024")
+        )),
+    'queries' : (
+        "'' 'mysql Queries' 'queries/s' queries mysql.queries line",
+        (
+            ("Queries",      "queries incremental 1 1"),
+            ("Questions",    "questions incremental 1 1"),
+            ("Slow_queries", "slow_queries incremental -1 1")
+        )),
+    'handlers' : (
+        "'' 'mysql Handlers' 'handlers/s' handlers mysql.handlers line",
+        (
+            ("Handler_commit", "commit incremental 1 1"),
+            ("Handler_delete", "delete incremental 1 1"),
+            ("Handler_prepare", "prepare incremental 1 1"),
+            ("Handler_read_first", "read_first incremental 1 1"),
+            ("Handler_read_key", "read_key incremental 1 1"),
+            ("Handler_read_next", "read_next incremental 1 1"),
+            ("Handler_read_prev", "read_prev incremental 1 1"),
+            ("Handler_read_rnd", "read_rnd incremental 1 1"),
+            ("Handler_read_rnd_next", "read_rnd_next incremental 1 1"),
+            ("Handler_rollback", "rollback incremental 1 1"),
+            ("Handler_savepoint", "savepoint incremental 1 1"),
+            ("Handler_savepoint_rollback", "savepoint_rollback incremental 1 1"),
+            ("Handler_update", "update incremental 1 1"),
+            ("Handler_write", "write incremental 1 1")
+        )),
+    'table_locks' : (
+        "'' 'mysql Tables Locks' 'locks/s' locks mysql.table_locks line",
+        (
+            ("Table_locks_immediate", "immediate incremental 1 1"),
+            ("Table_locks_waited", "waited incremental -1 1")
+        )),
+    'join_issues' : (
+        "'' 'mysql Select Join Issues' 'joins/s' issues mysql.join_issues line",
+        (
+            ("Select_full_join", "full_join incremental 1 1"),
+            ("Select_full_range_join", "full_range_join incremental 1 1"),
+            ("Select_range", "range incremental 1 1"),
+            ("Select_range_check", "range_check incremental 1 1"),
+            ("Select_scan", "scan incremental 1 1"),
+        )),
+    'sort_issues' : (
+        "'' 'mysql Sort Issues' 'issues/s' issues mysql.sort.issues line",
+        (
+            ("Sort_merge_passes", "merge_passes incremental 1 1"),
+            ("Sort_range", "range incremental 1 1"),
+            ("Sort_scan", "scan incremental 1 1"),
+        )),
+    'tmp' : (
+        "'' 'mysql Tmp Operations' 'counter' temporaries mysql.tmp line",
+        (
+            ("Created_tmp_disk_tables", "disk_tables incremental 1 1"),
+            ("Created_tmp_files", "files incremental 1 1"),
+            ("Created_tmp_tables", "tables incremental 1 1"),
+        )),
+    'connections' : (
+        "'' 'mysql Connections' 'connections/s' connections mysql.connections line",
+        (
+            ("Connections", "all incremental 1 1"),
+            ("Aborted_connects", "aborted incremental 1 1"),
+        )),
+    'binlog_cache' : (
+        "'' 'mysql Binlog Cache' 'transactions/s' binlog mysql.binlog_cache line",
+        (
+            ("Binlog_cache_disk_use", "disk incremental 1 1"),
+            ("Binlog_cache_use", "all incremental 1 1"),
+        )),
+    'threads' : (
+        "'' 'mysql Threads' 'threads' threads mysql.threads line",
+        (
+            ("Threads_connected", "connected absolute 1 1"),
+            ("Threads_created", "created incremental 1 1"),
+            ("Threads_cached", "cached absolute -1 1"),
+            ("Threads_running", "running absolute 1 1"),
+        )),
+    'thread_cache_misses' : (
+        "'' 'mysql Threads Cache Misses' 'misses' threads mysql.thread_cache_misses area",
+        (
+            ("Thread_cache_misses", "misses misses absolute 1 100"),
+        )),
+    'innodb_io' : (
+        "'' 'mysql InnoDB I/O Bandwidth' 'kilobytes/s' innodb mysql.innodb_io area",
+        (
+            ("Innodb_data_read", "read incremental 1 1024"),
+            ("Innodb_data_written", "write incremental -1 1024"),
+        )),
+    'innodb_io_ops' : (
+        "'' 'mysql InnoDB I/O Operations' 'operations/s' innodb mysql.innodb_io_ops line",
+        (
+            ("Innodb_data_reads", "reads incremental 1 1"),
+            ("Innodb_data_writes", "writes incremental -1 1"),
+            ("Innodb_data_fsyncs", "fsyncs incremental 1 1"),
+        )),
+    'innodb_io_pending_ops' : (
+        "'' 'mysql InnoDB Pending I/O Operations' 'operations' innodb mysql.innodb_io_pending_ops line",
+        (
+            ("Innodb_data_pending_reads", "reads absolute 1 1"),
+            ("Innodb_data_pending_writes", "writes absolute -1 1"),
+            ("Innodb_data_pending_fsyncs", "fsyncs absolute 1 1"),
+        )),
+    'innodb_log' : (
+        "'' 'mysql InnoDB Log Operations' 'operations/s' innodb mysql.innodb_log line",
+        (
+            ("Innodb_log_waits", "waits incremental 1 1"),
+            ("Innodb_log_write_requests", "write_requests incremental -1 1"),
+            ("Innodb_log_writes", "incremental -1 1"),
+        )),
+    'innodb_os_log' : (
+        "'' 'mysql InnoDB OS Log Operations' 'operations' innodb mysql.innodb_os_log line",
+        (
+            ("Innodb_os_log_fsyncs", "fsyncs incremental 1 1"),
+            ("Innodb_os_log_pending_fsyncs", "pending_fsyncs absolute 1 1"),
+            ("Innodb_os_log_pending_writes", "pending_writes absolute -1 1"),
+        )),
+    'innodb_os_log_io' : (
+        "'' 'mysql InnoDB OS Log Bandwidth' 'kilobytes/s' innodb mysql.innodb_os_log_io area",
+        (
+            ("Innodb_os_log_written", "write incremental -1 1024"),
+        )),
+    'innodb_cur_row_lock' : (
+        "'' 'mysql InnoDB Current Row Locks' 'operations' innodb mysql.innodb_cur_row_lock area",
+        (
+            ("Innodb_row_lock_current_waits", "current_waits absolute 1 1"),
+        )),
+    'innodb_rows' : (
+        "'' 'mysql InnoDB Row Operations' 'operations/s' innodb mysql.innodb_rows area",
+        (
+            ("Innodb_rows_inserted", "read incremental 1 1"),
+            ("Innodb_rows_read", "deleted incremental -1 1"),
+            ("Innodb_rows_updated", "inserted incremental 1 1"),
+            ("Innodb_rows_deleted", "updated incremental -1 1"),
+        )),
+    'innodb_buffer_pool_pages' : (
+        "'' 'mysql InnoDB Buffer Pool Pages' 'pages' innodb mysql.innodb_buffer_pool_pages line",
+        (
+            ("Innodb_buffer_pool_pages_data", "data absolute 1 1"),
+            ("Innodb_buffer_pool_pages_dirty", "dirty absolute -1 1"),
+            ("Innodb_buffer_pool_pages_free", "free absolute 1 1"),
+            ("Innodb_buffer_pool_pages_flushed", "flushed incremental -1 1"),
+            ("Innodb_buffer_pool_pages_misc", "misc absolute -1 1"),
+            ("Innodb_buffer_pool_pages_total", "total absolute 1 1"),
+        )),
+    'innodb_buffer_pool_bytes' : (
+        "'' 'mysql InnoDB Buffer Pool Bytes' 'MB' innodb mysql.innodb_buffer_pool_bytes area",
+        (
+            ("Innodb_buffer_pool_bytes_data", "data absolute 1"),
+            ("Innodb_buffer_pool_bytes_dirty", "dirty absolute -1"),
+        )),
+    'innodb_buffer_pool_read_ahead' : (
+        "'' 'mysql InnoDB Buffer Pool Read Ahead' 'operations/s' innodb mysql.innodb_buffer_pool_read_ahead area",
+        (
+            ("Innodb_buffer_pool_read_ahead", "all incremental 1 1"),
+            ("Innodb_buffer_pool_read_ahead_evicted", "evicted incremental -1 1"),
+            ("Innodb_buffer_pool_read_ahead_rnd", "random incremental 1 1"),
+        )),
+    'innodb_buffer_pool_reqs' : (
+        "'' 'mysql InnoDB Buffer Pool Requests' 'requests/s' innodb mysql.innodb_buffer_pool_reqs area",
+        (
+            ("Innodb_buffer_pool_read_requests", "reads incremental 1 1"),
+            ("Innodb_buffer_pool_write_requests", "writes incremental -1 1"),
+        )),
+    'innodb_buffer_pool_ops' : (
+        "'' 'mysql InnoDB Buffer Pool Operations' 'operations/s' innodb mysql.innodb_buffer_pool_ops area",
+        (
+            ("Innodb_buffer_pool_reads", "'disk reads' incremental 1 1"),
+            ("Innodb_buffer_pool_wait_free", "'wait free' incremental -1 1"),
+        )),
+    'qcache_ops' : (
+        "'' 'mysql QCache Operations' 'queries/s' qcache mysql.qcache_ops line",
+        (
+            ("Qcache_hits", "hits incremental 1 1"),
+            ("Qcache_lowmem_prunes", "'lowmem prunes' incremental -1 1"),
+            ("Qcache_inserts", "inserts incremental 1 1"),
+            ("Qcache_not_cached", "'not cached' incremental -1 1"),
+        )),
+    'qcache' : (
+        "'' 'mysql QCache Queries in Cache' 'queries' qcache mysql.qcache line",
+        (
+            ("Qcache_queries_in_cache", "queries absolute 1 1"),
+        )),
+    'qcache_freemem' : (
+        "'' 'mysql QCache Free Memory' 'MB' qcache mysql.qcache_freemem area",
+        (
+            ("Qcache_free_memory", "free absolute 1"),
+        )),
+    'qcache_memblocks' : (
+        "'' 'mysql QCache Memory Blocks' 'blocks' qcache mysql.qcache_memblocks line",
+        (
+            ("Qcache_free_blocks", "free absolute 1"),
+            ("Qcache_total_blocks", "total absolute 1 1"),
+        )),
+    'key_blocks' : (
+        "'' 'mysql MyISAM Key Cache Blocks' 'blocks' myisam mysql.key_blocks line",
+        (
+            ("Key_blocks_unused", "unused absolute 1 1"),
+            ("Key_blocks_used", "used absolute -1 1"),
+            ("Key_blocks_not_flushed", "'not flushed' absolute 1 1"),
+        )),
+    'key_requests' : (
+        "'' 'mysql MyISAM Key Cache Requests' 'requests/s' myisam mysql.key_requests area",
+        (
+            ("Key_read_requests", "reads incremental 1 1"),
+            ("Key_write_requests", "writes incremental -1 1"),
+        )),
+    'key_disk_ops' : (
+        "'' 'mysql MyISAM Key Cache Disk Operations' 'operations/s' myisam mysql.key_disk_ops area",
+        (
+            ("Key_reads", "reads incremental 1 1"),
+            ("Key_writes", "writes incremental -1 1"),
+        )),
+    'files' : (
+        "'' 'mysql Open Files' 'files' files mysql.files line",
+        (
+            ("Open_files", "files absolute 1 1"),
+        )),
+    'files_rate' : (
+        "'' 'mysql Opened Files Rate' 'files/s' files mysql.files_rate line",
+        (
+            ("Opened_files", "files incremental 1 1"),
+        )),
+    'binlog_stmt_cache' : (
+        "'' 'mysql Binlog Statement Cache' 'statements/s' binlog mysql.binlog_stmt_cache line",
+        (
+            ("Binlog_stmt_cache_disk_use", "disk incremental 1 1"),
+            ("Binlog_stmt_cache_use", "all incremental 1 1"),
+        )),
+    'connection_errors' : (
+        "'' 'mysql Connection Errors' 'connections/s' connections mysql.connection_errors line",
+        (
+            ("Connection_errors_accept", "accept incremental 1 1"),
+            ("Connection_errors_internal", "internal incremental 1 1"),
+            ("Connection_errors_max_connections", "max incremental 1 1"),
+            ("Connection_errors_peer_address", "peer_addr incremental 1 1"),
+            ("Connection_errors_select", "select incremental 1 1"),
+            ("Connection_errors_tcpwrap", "tcpwrap incremental 1 1")
+        ))
+}
+mysql_def = {}
+valid = []
+connections = {}
+
+def get_data(config):
+    global connections
+    try:
+        cnx = connections[config['name']]
+    except KeyError:
+        cnx = pymysql.connect(user=config['user'],
+                              password=config['password'],
+                              unix_socket=config['socket'],
+                              host=config['host'],
+                              port=config['port'],
+                              connect_timeout=int(update_every))
+        connections[config['name']] = cnx
+
+    try:
+        with cnx.cursor() as cursor:
+            cursor.execute(QUERY)
+            raw_data = cursor.fetchall()
+    except Exception:
+        cnx.close()
+        del connections[config['name']]
+        return None
+    
+    return dict(raw_data)
+
+
+def check():
+    # TODO what are the default credentials
+    global valid, config
+    if type(config) is str:
+        from json import loads
+        cfg = loads(config.replace("'",'"').replace('\n',' '))
+        config = cfg
+    for i in range(len(config)):
+        if 'name' not in config[i]:
+            config[i]['name'] = "mysql_srv_"+str(i)
+        if 'user' not in config[i]:
+            config[i]['user'] = 'root'
+        if 'password' not in config[i]:
+            config[i]['password'] = None
+        if 'socket' not in config[i]:
+            config[i]['socket'] = None
+        if 'host' not in config[i]:
+            config[i]['host'] = None
+        if 'port' in config[i]:
+            config[i]['port'] = int(config[i]['port'])
+        else:
+            config[i]['port'] = 3306
+        if config[i]['host'] is None:
+            config[i]['port'] = None
+        if config[i]['host'] is None and config[i]['socket'] is None:
+            remove.append(i)
+
+    for srv in config:
+        try:
+            cnx = pymysql.connect(user=srv['user'],
+                                  password=srv['password'],
+                                  unix_socket=srv['socket'],
+                                  host=srv['host'],
+                                  port=srv['port'],
+                                  connect_timeout=int(update_every))
+            cnx.close()
+        except:
+            config.remove(srv)
+
+    if len(config) == 0:
+        return False
+    return True
+
+
+def create():
+    global config, mysql_def
+    for name in ORDER:
+        mysql_def[name] = []
+        for line in CHARTS[name][1]:
+            mysql_def[name].append(line[0])
+
+    idx = 0
+    for srv in config:
+        data = get_data(srv)
+        for name in ORDER:
+            header = "CHART mysql_" + \
+                     str(srv['name']) + "." + \
+                     name + " " + \
+                     CHARTS[name][0] + " " + \
+                     str(priority + idx) + " " + \
+                     str(update_every)
+            content = ""
+            # check if server has this datapoint
+            for line in CHARTS[name][1]:
+                if line[0] in data:
+                     content += "DIMENSION " + line[0] + " " + line[1] + "\n"
+            if len(content) > 0:
+                print(header)
+                print(content)
+                idx += 1
+
+    if idx == 0:
+        return False
+    return True
+
+
+def update(interval):
+    global config
+    for srv in config:
+        data = get_data(srv)
+        if data is None:
+            config.remove(srv)
+            # TODO notify user about problems with server
+            continue
+        try:
+            data['Thread cache misses'] = int( int(data['Threads_created']) * 10000 / int(data['Connections']))
+        except Exception:
+            pass
+        for chart, dimensions in mysql_def.items():
+            header = "BEGIN mysql_" + str(srv['name']) + "." + chart + " " + str(interval) + '\n'
+            lines = ""
+            for d in dimensions:
+                try:
+                    lines += "SET " + d + " = " + data[d] + '\n'
+                except KeyError:
+                    pass
+            if len(lines) > 0:
+                print(header + lines + "END")
+            
+    if len(config) == 0:
+        return False 
+    return True