Ales Komarek | 2675e84 | 2016-10-05 00:10:44 +0200 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # Copyright 2016 Mirantis, Inc. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | import collectd |
| 17 | import requests |
| 18 | |
| 19 | import collectd_base as base |
| 20 | |
| 21 | NAME = 'influxdb' |
| 22 | METRICS_BY_NAME = { |
| 23 | 'cluster': { |
| 24 | 'writeShardPointsReq': ('cluster_write_shard_points_requests', |
| 25 | 'gauge'), |
| 26 | 'writeShardReq': ('cluster_write_shard_requests', 'gauge')}, |
| 27 | |
| 28 | 'httpd': { |
| 29 | 'authFail': ('httpd_failed_auths', 'gauge'), |
| 30 | 'pingReq': ('httpd_ping_requests', 'gauge'), |
| 31 | 'pointsWrittenOK': ('httpd_write_points_ok', 'gauge'), |
| 32 | 'queryReq': ('httpd_query_requests', 'gauge'), |
| 33 | 'queryRespBytes': ('httpd_query_response_bytes', 'gauge'), |
| 34 | 'req': ('httpd_requests', 'gauge'), |
| 35 | 'writeReq': ('httpd_write_requests', 'gauge'), |
| 36 | 'writeReqBytes': ('httpd_write_request_bytes', 'gauge')}, |
| 37 | |
| 38 | 'write': { |
| 39 | 'pointReq': ('write_point_requests', 'gauge'), |
| 40 | 'pointReqLocal': ('write_point_local_requests', 'gauge'), |
| 41 | 'pointReqRemote': ('write_point_remote_requests', 'gauge'), |
| 42 | 'req': ('write_requests', 'gauge'), |
| 43 | 'subWriteOk': ('write_sub_ok', 'gauge'), |
| 44 | 'writeOk': ('write_ok', 'gauge')}, |
| 45 | |
| 46 | 'runtime': { |
| 47 | 'Alloc': ('memory_alloc', 'gauge'), |
| 48 | 'TotalAlloc': ('memory_total_alloc', 'gauge'), |
| 49 | 'Sys': ('memory_system', 'gauge'), |
| 50 | 'Lookups': ('memory_lookups', 'gauge'), |
| 51 | 'Mallocs': ('memory_mallocs', 'gauge'), |
| 52 | 'Frees': ('memory_frees', 'gauge'), |
| 53 | 'HeapIdle': ('heap_idle', 'gauge'), |
| 54 | 'HeapInUse': ('heap_in_use', 'gauge'), |
| 55 | 'HeapObjects': ('heap_objects', 'gauge'), |
| 56 | 'HeapReleased': ('heap_released', 'gauge'), |
| 57 | 'HeapSys': ('heap_system', 'gauge'), |
| 58 | 'NumGC': ('garbage_collections', 'gauge'), |
| 59 | 'NumGoroutine': ('go_routines', 'gauge')} |
| 60 | } |
| 61 | |
| 62 | |
| 63 | class InfluxDBClusterPlugin(base.Base): |
| 64 | def __init__(self, *args, **kwargs): |
| 65 | super(InfluxDBClusterPlugin, self).__init__(*args, **kwargs) |
| 66 | self.plugin = NAME |
| 67 | self.session = requests.Session() |
| 68 | self.address = "localhost" |
| 69 | self.port = "8086" |
| 70 | self.session.mount( |
| 71 | 'http://', |
| 72 | requests.adapters.HTTPAdapter(max_retries=3) |
| 73 | ) |
| 74 | |
| 75 | def config_callback(self, conf): |
| 76 | super(InfluxDBClusterPlugin, self).config_callback(conf) |
| 77 | |
| 78 | for node in conf.children: |
| 79 | if node.key == 'Username': |
| 80 | username = node.values[0] |
| 81 | elif node.key == 'Password': |
| 82 | password = node.values[0] |
| 83 | elif node.key == 'Address': |
| 84 | self.address = node.values[0] |
| 85 | elif node.key == 'Port': |
| 86 | self.port = node.values[0] |
| 87 | |
| 88 | if username is None or password is None: |
| 89 | self.logger.error("Username and Password parameters are required") |
| 90 | else: |
| 91 | self.session.auth = (username, password) |
| 92 | |
| 93 | def itermetrics(self): |
| 94 | |
| 95 | payload = {'q': 'show stats'} |
| 96 | url = "http://{}:{}/query".format(self.address, self.port) |
| 97 | |
| 98 | try: |
| 99 | r = self.session.get(url, params=payload) |
| 100 | except Exception as e: |
| 101 | msg = "Got {0} when getting stats from {1}".format(e, url) |
| 102 | raise base.CheckException(msg) |
| 103 | |
| 104 | if r.status_code != 200: |
| 105 | msg = "Got response {0} from {0}".format(r.status_code, url) |
| 106 | raise base.CheckException(msg) |
| 107 | |
| 108 | data = r.json() |
| 109 | try: |
| 110 | series_list = data['results'][0]['series'] |
| 111 | except: |
| 112 | self.logger.error("Failed to retrieve series for InfluxDB cluster") |
| 113 | return |
| 114 | |
| 115 | for serie in series_list: |
| 116 | metrics_list = METRICS_BY_NAME.get(serie['name'], None) |
| 117 | if not metrics_list: |
| 118 | continue |
| 119 | for i in range(len(serie['columns'])): |
| 120 | metric_name = serie['columns'][i] |
| 121 | if metric_name in metrics_list: |
| 122 | yield { |
| 123 | 'type_instance': metrics_list[metric_name][0], |
| 124 | 'type': metrics_list[metric_name][1], |
| 125 | 'values': [serie['values'][0][i]], |
| 126 | } |
| 127 | |
| 128 | |
| 129 | plugin = InfluxDBClusterPlugin(collectd) |
| 130 | |
| 131 | |
Ales Komarek | 2675e84 | 2016-10-05 00:10:44 +0200 | [diff] [blame] | 132 | def config_callback(conf): |
| 133 | plugin.config_callback(conf) |
| 134 | |
| 135 | |
| 136 | def read_callback(): |
| 137 | plugin.read_callback() |
| 138 | |
Ales Komarek | 2675e84 | 2016-10-05 00:10:44 +0200 | [diff] [blame] | 139 | collectd.register_config(config_callback) |
| 140 | collectd.register_read(read_callback) |