├── Dockerfile ├── Grafana └── elasticsearch2elastic.py ├── README.md └── bin └── entrypoint.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7-slim 2 | 3 | ADD . /app 4 | 5 | RUN useradd -u 10106 -r -s /bin/false monitor 6 | RUN chmod 755 /app/bin/entrypoint.sh 7 | 8 | USER monitor 9 | 10 | ENTRYPOINT [ "/app/bin/entrypoint.sh" ] 11 | -------------------------------------------------------------------------------- /Grafana/elasticsearch2elastic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import datetime 3 | import time 4 | import json 5 | import urllib2 6 | import os 7 | import sys 8 | 9 | # ElasticSearch Cluster to Monitor 10 | elasticServer = os.environ.get('ES_METRICS_CLUSTER_URL', 'http://server1:9200') 11 | interval = int(os.environ.get('ES_METRICS_INTERVAL', '60')) 12 | 13 | # ElasticSearch Cluster to Send Metrics 14 | elasticIndex = os.environ.get('ES_METRICS_INDEX_NAME', 'elasticsearch_metrics') 15 | elasticMonitoringCluster = os.environ.get('ES_METRICS_MONITORING_CLUSTER_URL', 'http://server2:9200') 16 | 17 | # Enable Elasticsearch Security 18 | # read_username and read_password for read ES cluster information 19 | # write_username and write_passowrd for write monitor metric to ES. 20 | read_es_security_enable = False 21 | read_username = "read_username" 22 | read_password = "read_password" 23 | 24 | write_es_security_enable = False 25 | write_username = "write_username" 26 | write_password = "write_password" 27 | 28 | def handle_urlopen(urlData, read_username, read_password): 29 | if read_es_security_enable: 30 | try: 31 | password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 32 | password_mgr.add_password(None, urlData, read_username, read_password) 33 | handler = urllib2.HTTPBasicAuthHandler(password_mgr) 34 | opener = urllib2.build_opener(handler) 35 | urllib2.install_opener(opener) 36 | response = urllib2.urlopen(urlData) 37 | return response 38 | except Exception as e: 39 | print "Error: {0}".format(str(e)) 40 | else: 41 | try: 42 | response = urllib2.urlopen(urlData) 43 | return response 44 | except Exception as e: 45 | print "Error: {0}".format(str(e)) 46 | 47 | def fetch_clusterhealth(): 48 | try: 49 | utc_datetime = datetime.datetime.utcnow() 50 | endpoint = "/_cluster/health" 51 | urlData = elasticServer + endpoint 52 | response = handle_urlopen(urlData,read_username,read_password) 53 | jsonData = json.loads(response.read()) 54 | clusterName = jsonData['cluster_name'] 55 | jsonData['@timestamp'] = str(utc_datetime.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]) 56 | if jsonData['status'] == 'green': 57 | jsonData['status_code'] = 0 58 | elif jsonData['status'] == 'yellow': 59 | jsonData['status_code'] = 1 60 | elif jsonData['status'] == 'red': 61 | jsonData['status_code'] = 2 62 | post_data(jsonData) 63 | return clusterName 64 | except IOError as err: 65 | print "IOError: Maybe can't connect to elasticsearch." 66 | clusterName = "unknown" 67 | return clusterName 68 | 69 | 70 | def fetch_clusterstats(): 71 | utc_datetime = datetime.datetime.utcnow() 72 | endpoint = "/_cluster/stats" 73 | urlData = elasticServer + endpoint 74 | response = handle_urlopen(urlData,read_username,read_password) 75 | jsonData = json.loads(response.read()) 76 | jsonData['@timestamp'] = str(utc_datetime.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]) 77 | post_data(jsonData) 78 | 79 | 80 | def fetch_nodestats(clusterName): 81 | utc_datetime = datetime.datetime.utcnow() 82 | endpoint = "/_cat/nodes?v&h=n" 83 | urlData = elasticServer + endpoint 84 | response = handle_urlopen(urlData,read_username,read_password) 85 | nodes = response.read()[1:-1].strip().split('\n') 86 | for node in nodes: 87 | endpoint = "/_nodes/%s/stats" % node.rstrip() 88 | urlData = elasticServer + endpoint 89 | response = handle_urlopen(urlData,read_username,read_password) 90 | jsonData = json.loads(response.read()) 91 | nodeID = jsonData['nodes'].keys() 92 | try: 93 | jsonData['nodes'][nodeID[0]]['@timestamp'] = str(utc_datetime.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]) 94 | jsonData['nodes'][nodeID[0]]['cluster_name'] = clusterName 95 | newJsonData = jsonData['nodes'][nodeID[0]] 96 | post_data(newJsonData) 97 | except: 98 | continue 99 | 100 | 101 | def fetch_indexstats(clusterName): 102 | utc_datetime = datetime.datetime.utcnow() 103 | endpoint = "/_stats" 104 | urlData = elasticServer + endpoint 105 | response = handle_urlopen(urlData,read_username,read_password) 106 | jsonData = json.loads(response.read()) 107 | jsonData['_all']['@timestamp'] = str(utc_datetime.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3]) 108 | jsonData['_all']['cluster_name'] = clusterName 109 | post_data(jsonData['_all']) 110 | 111 | 112 | def post_data(data): 113 | utc_datetime = datetime.datetime.utcnow() 114 | url_parameters = {'cluster': elasticMonitoringCluster, 'index': elasticIndex, 115 | 'index_period': utc_datetime.strftime("%Y.%m.%d"), } 116 | url = "%(cluster)s/%(index)s-%(index_period)s/message" % url_parameters 117 | headers = {'content-type': 'application/json'} 118 | try: 119 | req = urllib2.Request(url, headers=headers, data=json.dumps(data)) 120 | if write_es_security_enable: 121 | password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 122 | password_mgr.add_password(None, url, write_username, write_password) 123 | handler = urllib2.HTTPBasicAuthHandler(password_mgr) 124 | opener = urllib2.build_opener(handler) 125 | urllib2.install_opener(opener) 126 | response = urllib2.urlopen(req) 127 | else: 128 | response = urllib2.urlopen(req) 129 | except Exception as e: 130 | print "Error: {0}".format(str(e)) 131 | 132 | 133 | def main(): 134 | clusterName = fetch_clusterhealth() 135 | if clusterName != "unknown": 136 | fetch_clusterstats() 137 | fetch_nodestats(clusterName) 138 | fetch_indexstats(clusterName) 139 | 140 | 141 | if __name__ == '__main__': 142 | try: 143 | nextRun = 0 144 | while True: 145 | if time.time() >= nextRun: 146 | nextRun = time.time() + interval 147 | now = time.time() 148 | main() 149 | elapsed = time.time() - now 150 | print "Total Elapsed Time: %s" % elapsed 151 | timeDiff = nextRun - time.time() 152 | 153 | # Check timediff , if timediff >=0 sleep, if < 0 send metrics to es 154 | if timeDiff >= 0: 155 | time.sleep(timeDiff) 156 | 157 | except KeyboardInterrupt: 158 | print 'Interrupted' 159 | try: 160 | sys.exit(0) 161 | except SystemExit: 162 | os._exit(0) 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elasticsearch-metrics 2 | 3 | https://grafana.net/dashboards/878 4 | 5 | Run either as a standalone script or docker container. 6 | 7 | To build the container: 8 | 9 | ```bash 10 | git clone https://github.com/trevorndodds/elasticsearch-metrics.git es-monitor 11 | cd es-monitor 12 | docker build -t /es-monitor:latest . 13 | ``` 14 | 15 | To run it: 16 | 17 | ```bash 18 | docker run -d -e ES_METRICS_CLUSTER_URL=http://search1.example.net:9200 \ 19 | -e ES_METRICS_INDEX_NAME=elasticsearch_metrics-search1 \ 20 | -e ES_METRICS_MONITORING_CLUSTER_URL=http://es-monitor.example.net:9200 \ 21 | /es-monitor:latest 22 | ``` 23 | -------------------------------------------------------------------------------- /bin/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REPO_BASE=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd ) 4 | 5 | /usr/local/bin/python ${REPO_BASE}/Grafana/elasticsearch2elastic.py 6 | --------------------------------------------------------------------------------