Last active
May 15, 2019 22:00
-
-
Save codeinthehole/7f60b011f969787a7fff to your computer and use it in GitHub Desktop.
Zabbix plugin script for extracting uWSGI metrics from a log file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Extract metrics from a uWSGI log file | |
This should be saved as /etc/zabbix/pluginx/uwsgi_stats and called from | |
/etc/zabbix/zabbix_agentd.conf.d/uwsgi.conf, which should have contents: | |
UserParameter=uwsgi.stats[*],/etc/zabbix/plugins/uwsgi_stats $1 $2 | |
To gather these metrics in Zabbix, create a new item which calls this plugin and | |
passes the filepath and metric key. Eg: | |
uwsgi.stats[/var/log/client/project/logs/prod/uwsgi.log,req_count] | |
The available metric keys are: | |
- req_count -> requests per minute | |
- get_req_count -> GET requests per minute | |
- post_req_count -> POST requests per minute | |
- avg_req_time -> average request time in ms | |
- avg_req_size -> average request size in bytes | |
Author: David Winterbottom | |
""" | |
import datetime | |
import subprocess | |
import re | |
import sys | |
import os | |
def extract_metric(filepath, metric): | |
# Determine time pattern to grep for | |
now = datetime.datetime.now() | |
# Fiddle with date format as uWSGI does not zero pad the day | |
last_minute = now - datetime.timedelta(minutes=1) | |
day = last_minute.strftime("%d").lstrip("0") | |
month = last_minute.strftime("%b") | |
time = last_minute.strftime("%H:%M") | |
pattern = "%s %s %s" % (month, day, time) | |
# Extract data from access log | |
try: | |
output = subprocess.Popen( | |
["grep", pattern, filepath], stdout=subprocess.PIPE).communicate()[0] | |
except subprocess.CalledProcessError: | |
# Happens when no matches | |
lines = [] | |
else: | |
lines = output.split("\n") | |
data = [] | |
regex = re.compile(r'.* (?P<method>[A-Z]+) (?P<path>\S+) => generated (?P<bytes>\d+) bytes in (?P<msecs>\d+) msecs \(HTTP/1.\d (?P<status>\d+).*') | |
for line in lines: | |
match = regex.match(line) | |
if match: | |
data.append(match.groupdict()) | |
if not data: | |
return | |
# Calculate and print appropriate metric | |
if metric == 'avg_req_time': | |
times = [int(x['msecs']) for x in data] | |
return float(sum(times)) / len(times) | |
elif metric == 'avg_req_size': | |
sizes = [int(x['bytes']) for x in data] | |
return float(sum(sizes)) / len(sizes) | |
elif metric == 'req_count': | |
return len(data) | |
elif metric == 'get_req_count': | |
return len([1 for x in data if x['method'] == 'GET']) | |
elif metric == 'post_req_count': | |
return len([1 for x in data if x['method'] == 'POST']) | |
elif metric == '2xx_req_count': | |
return len([1 for x in data if x['status'].startswith('2')]) | |
elif metric == '3xx_req_count': | |
return len([1 for x in data if x['status'].startswith('3')]) | |
elif metric == '4xx_req_count': | |
return len([1 for x in data if x['status'].startswith('4')]) | |
elif metric == '5xx_req_count': | |
return len([1 for x in data if x['status'].startswith('5')]) | |
if __name__ == '__main__': | |
filepath = sys.argv[1] | |
metric_key = sys.argv[2] | |
metric = extract_metric(filepath, metric_key) | |
if metric is not None: | |
print metric |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment