initial commit.
This commit is contained in:
commit
7941a8eb60
4 changed files with 176 additions and 0 deletions
11
Dockerfile
Normal file
11
Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
FROM alpine:3.4
|
||||
|
||||
RUN apk add --no-cache python3 &&\
|
||||
pip3 install apscheduler &&\
|
||||
pip3 install requests
|
||||
|
||||
COPY pagespeed.py pagespeed.conf /
|
||||
|
||||
EXPOSE 9113
|
||||
|
||||
CMD python3 /pagespeed.py
|
22
README.md
Normal file
22
README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# pagespeed_exporter for providing Google PageSpeed Insights as metrics
|
||||
|
||||
## Requirements
|
||||
|
||||
Software:
|
||||
|
||||
* Python3
|
||||
* APScheduler
|
||||
* requests
|
||||
|
||||
Google PageSpeed API key. See here on how to [get a server API key for googles platform](https://developers.google.com/console/help/generating-dev-keys).
|
||||
|
||||
## Configuration
|
||||
|
||||
The exporter is currently able to check one URI, buffer the results
|
||||
and serve them as metrics.
|
||||
|
||||
Configuration is done via pagespeed.conf, see example file for documentation and defaults.
|
||||
All config values can be overriden with environment variables given the same names.
|
||||
|
||||
N.B.: Google caches it's results itself for 30 seconds, so a shorter fetch interval would
|
||||
be useless.
|
25
pagespeed.conf
Normal file
25
pagespeed.conf
Normal file
|
@ -0,0 +1,25 @@
|
|||
[EXPORTER]
|
||||
# URI to run tests against. Make sure it is reachable from the public internet.
|
||||
# ENV override: PAGESPEED_TEST_URI
|
||||
test_uri = https://www.test.de/
|
||||
|
||||
# Your PageSpeed Insights API key from Google. See README.md for documentation link.
|
||||
# ENV override: PAGESPEED_API_KEY
|
||||
api_key =
|
||||
|
||||
# IP to bind the metrics server to.
|
||||
# Default: empty, binds to all available interfaces.
|
||||
# ENV override: PAGESPEED_BIND_IP
|
||||
bind_ip =
|
||||
|
||||
# TCP port to bind the metrics server to.
|
||||
# Default: 9113
|
||||
# ENV override: PAGESPEED_BIND_PORT
|
||||
bind_port = 9113
|
||||
|
||||
# Interval for instanciating pagespeed tests at google in seconds.
|
||||
# Do not go below 30 seconds.
|
||||
# Default: 300
|
||||
# ENV override: PAGESPEED_FETCH_INTERVAL
|
||||
fetch_interval = 300
|
||||
|
118
pagespeed.py
Normal file
118
pagespeed.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
import configparser
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from time import sleep, time
|
||||
|
||||
import requests
|
||||
from pytz import utc
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
|
||||
# try to read configfile
|
||||
config = configparser.ConfigParser()
|
||||
try:
|
||||
config.read('pagespeed.conf')
|
||||
exporter_config = config['EXPORTER']
|
||||
except:
|
||||
exporter_config = {'EXPORTER': {}}
|
||||
|
||||
|
||||
# try to get config from ENV
|
||||
TEST_URI = os.environ.get('PAGESPEED_URI', exporter_config.get('TEST_URI'))
|
||||
API_KEY = os.environ.get('PAGESPEED_API_KEY', exporter_config.get('API_KEY'))
|
||||
BIND_IP = os.environ.get('PAGESPEED_HOST', exporter_config.get('BIND_IP', ''))
|
||||
BIND_PORT = os.environ.get('PAGESPEED_PORT', exporter_config.get('BIND_PORT', 9113))
|
||||
FETCH_INTERVAL = os.environ.get('PAGESPEED_FETCH_INTERVAL', exporter_config.get('FETCH_INTERVAL', 300))
|
||||
|
||||
|
||||
# input validation :)
|
||||
if not TEST_URI:
|
||||
logger.error('TEST_URI needs to be defined either in config file or in ENV.')
|
||||
sys.exit(1)
|
||||
if not API_KEY:
|
||||
logger.error('API_KEY needs to be definer either in config file or in ENV.')
|
||||
sys.exit(1)
|
||||
try:
|
||||
FETCH_INTERVAL = int(FETCH_INTERVAL)
|
||||
BIND_PORT = int(BIND_PORT)
|
||||
except:
|
||||
logger.exception('Value error in FETCH_INTERVAL or BIND_PORT.')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
metric_data = ""
|
||||
error_instances = 0
|
||||
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def fetch_pagespeed():
|
||||
global metric_data
|
||||
global error_instances
|
||||
|
||||
logger.debug('fetching pagespeed')
|
||||
|
||||
try:
|
||||
req = requests.get('https://www.googleapis.com/pagespeedonline/v2/'
|
||||
'runPagespeed?url={url}&key={key}&'
|
||||
'prettyprint=false'.format(
|
||||
url=TEST_URI,
|
||||
key=API_KEY
|
||||
))
|
||||
result = req.json()
|
||||
except:
|
||||
logger.exception('error while doing request')
|
||||
error_instances += 1
|
||||
|
||||
translation_table = {
|
||||
'speed_score': result['ruleGroups']['SPEED']['score'],
|
||||
'stats_resources_total': result['pageStats']['numberResources'],
|
||||
'stats_hosts_total': result['pageStats']['numberHosts'],
|
||||
'stats_request_bytes': result['pageStats']['totalRequestBytes'],
|
||||
'stats_static_resources_total': result['pageStats']['numberStaticResources'],
|
||||
'stats_html_resources_bytes': result['pageStats']['htmlResponseBytes'],
|
||||
'stats_image_resources_bytes': result['pageStats']['imageResponseBytes'],
|
||||
'stats_javascript_resources_bytes': result['pageStats']['javascriptResponseBytes'],
|
||||
'stats_javascript_resources_total': result['pageStats']['numberJsResources'],
|
||||
'stats_css_resources_bytes': result['pageStats']['cssResponseBytes'],
|
||||
'stats_css_resources_total': result['pageStats']['numberCssResources'],
|
||||
'stats_other_resources_bytes': result['pageStats']['otherResponseBytes'],
|
||||
}
|
||||
metric_data = ""
|
||||
for metric, value in translation_table.items():
|
||||
metric_data += 'pagespeed_{metric}{{site="{job}"}}' \
|
||||
' {metric_value}\n'.format(
|
||||
metric=metric,
|
||||
job=result['id'],
|
||||
metric_value=value,
|
||||
)
|
||||
metric_data += 'pagespeed_last_update {}\n'.format(time())
|
||||
metric_data += 'pagespeed_metric_errors_total {}\n'.format(error_instances)
|
||||
metric_data += 'up 1\n'
|
||||
logger.debug('fetched pagespeed')
|
||||
|
||||
|
||||
class AllGetHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
def do_GET(s):
|
||||
s.send_response(200)
|
||||
s.send_header("Content-Type", "text/plain")
|
||||
s.end_headers()
|
||||
s.wfile.write(metric_data.encode('utf-8'))
|
||||
|
||||
scheduler = BackgroundScheduler(timezone=utc)
|
||||
scheduler.add_job(fetch_pagespeed, 'interval', seconds=FETCH_INTERVAL, max_instances=1)
|
||||
scheduler.start()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
logger.info('starting pagespeed_exporter')
|
||||
if metric_data == '':
|
||||
fetch_pagespeed()
|
||||
server_address = (BIND_IP, BIND_PORT)
|
||||
httpd = HTTPServer(server_address, AllGetHTTPRequestHandler)
|
||||
logger.info('binding to {}'.format(server_address))
|
||||
httpd.serve_forever()
|
Loading…
Reference in a new issue