stacktach/stacktach/views.py
2012-06-20 10:27:43 +10:00

279 lines
8.3 KiB
Python

# Copyright 2012 - Dark Secret Software Inc.
from django.shortcuts import render_to_response
from django import http
from django import template
from django.utils.functional import wraps
from django.views.decorators.csrf import csrf_protect
from stacktach import models
import datetime
import json
import logging
import pprint
import random
import sys
logger = logging.getLogger(__name__)
VERSION = 4
class My401(BaseException):
pass
class HttpResponseUnauthorized(http.HttpResponse):
status_code = 401
def _monitor_message(routing_key, body):
event = body['event_type']
publisher = body['publisher_id']
parts = publisher.split('.')
service = parts[0]
host = parts[1]
payload = body['payload']
request_spec = payload.get('request_spec', None)
instance = payload.get('instance_id', None)
instance = payload.get('instance_uuid', instance)
nova_tenant = body.get('_context_project_id', None)
nova_tenant = payload.get('tenant_id', nova_tenant)
return dict(host=host, instance=instance, publisher=publisher,
service=service, event=event, nova_tenant=nova_tenant)
def _compute_update_message(routing_key, body):
publisher = None
instance = None
args = body['args']
host = args['host']
service = args['service_name']
event = body['method']
nova_tenant = args.get('_context_project_id', None)
return dict(host=host, instance=instance, publisher=publisher,
service=service, event=event, nova_tenant=nova_tenant)
def _tach_message(routing_key, body):
event = body['event_type']
value = body['value']
units = body['units']
transaction_id = body['transaction_id']
return dict(event=event, value=value, units=units, transaction_id=transaction_id)
# routing_key : handler
HANDLERS = {'monitor.info':_monitor_message,
'monitor.error':_monitor_message,
'tach':_tach_message,
'':_compute_update_message}
def _parse(tenant, args, json_args):
routing_key, body = args
handler = HANDLERS.get(routing_key, None)
if handler:
values = handler(routing_key, body)
if not values:
return {}
values['tenant'] = tenant
when = body['_context_timestamp']
try:
when = datetime.datetime.strptime(when, "%Y-%m-%dT%H:%M:%S.%f")
values['microseconds'] = when.microsecond
except Exception, e:
pass
values['when'] = when
values['routing_key'] = routing_key
values['json'] = json_args
record = models.RawData(**values)
record.save()
return values
return {}
def _post_process_raw_data(rows, state, highlight=None):
for row in rows:
if "error" in row.routing_key:
row.is_error = True
if highlight and row.id == int(highlight):
row.highlight = True
row.when += datetime.timedelta(microseconds=row.microseconds)
novastats = state.tenant.nova_stats_template
if novastats and row.instance:
novastats = novastats.replace("[instance]", row.instance)
row.novastats = novastats
loggly = state.tenant.loggly_template
if loggly and row.instance:
loggly = loggly.replace("[instance]", row.instance)
row.loggly = loggly
class State(object):
def __init__(self):
self.version = VERSION
self.tenant = None
def __str__(self):
tenant = "?"
if self.tenant:
tenant = "'%s' - %s (%d)" % (self.tenant.project_name,
self.tenant.email, self.tenant.id)
return "[Version %s, Tenant %s]" % (self.version, tenant)
return "[Version %s, Tenant %s]" % (self.version, tenant)
def _reset_state(request):
state = State()
request.session['state'] = state
return state
def _get_state(request, tenant_id=None):
tenant = None
if tenant_id:
try:
tenant = models.Tenant.objects.get(tenant_id=tenant_id)
except models.Tenant.DoesNotExist:
raise My401()
if 'state' in request.session:
state = request.session['state']
else:
state =_reset_state(request)
if hasattr(state, 'version') and state.version < VERSION:
state =_reset_state(request)
state.tenant = tenant
return state
def tenant_check(view):
@wraps(view)
def inner(*args, **kwargs):
try:
return view(*args, **kwargs)
# except HttpResponseUnauthorized, e:
except My401:
return HttpResponseUnauthorized()
return inner
def _default_context(state):
context = dict(utc=datetime.datetime.utcnow(), state=state)
return context
def welcome(request):
state = _reset_state(request)
return render_to_response('stacktach/welcome.html', _default_context(state))
@tenant_check
def home(request, tenant_id):
state = _get_state(request, tenant_id)
return render_to_response('stacktach/index.html', _default_context(state))
def logout(request):
del request.session['state']
return render_to_response('stacktach/welcome.html', _default_context(None))
@csrf_protect
def new_tenant(request):
state = _get_state(request)
context = _default_context(state)
if request.method == 'POST':
form = models.TenantForm(request.POST)
if form.is_valid():
rec = models.Tenant(**form.cleaned_data)
rec.save()
_reset_state(request)
return http.HttpResponseRedirect('/%d' % rec.tenant_id)
else:
form = models.TenantForm()
context['form'] = form
return render_to_response('stacktach/new_tenant.html', context,
context_instance=template.RequestContext(request))
@tenant_check
def data(request, tenant_id):
state = _get_state(request, tenant_id)
raw_args = request.POST.get('args', "{}")
args = json.loads(raw_args)
c = _default_context(state)
fields = _parse(state.tenant, args, raw_args)
c['cooked_args'] = fields
return render_to_response('stacktach/data.html', c)
@tenant_check
def details(request, tenant_id, column, row_id):
state = _get_state(request, tenant_id)
c = _default_context(state)
row = models.RawData.objects.get(pk=row_id)
value = getattr(row, column)
rows = models.RawData.objects.filter(tenant=tenant_id)
if column != 'when':
rows = rows.filter(**{column:value})
else:
value += datetime.timedelta(microseconds=row.microseconds)
from_time = value - datetime.timedelta(minutes=1)
to_time = value + datetime.timedelta(minutes=1)
rows = rows.filter(when__range=(from_time, to_time))
rows = rows.order_by('-when', '-microseconds')[:200]
_post_process_raw_data(rows, state, highlight=row_id)
c['rows'] = rows
c['allow_expansion'] = True
c['show_absolute_time'] = True
return render_to_response('stacktach/rows.html', c)
@tenant_check
def expand(request, tenant_id, row_id):
state = _get_state(request, tenant_id)
c = _default_context(state)
row = models.RawData.objects.get(pk=row_id)
payload = json.loads(row.json)
pp = pprint.PrettyPrinter()
c['payload'] = pp.pformat(payload)
return render_to_response('stacktach/expand.html', c)
@tenant_check
def host_status(request, tenant_id):
state = _get_state(request, tenant_id)
c = _default_context(state)
hosts = models.RawData.objects.filter(tenant=tenant_id).\
order_by('-when', '-microseconds')[:20]
_post_process_raw_data(hosts, state)
c['rows'] = hosts
return render_to_response('stacktach/host_status.html', c)
@tenant_check
def search(request, tenant_id):
state = _get_state(request, tenant_id)
c = _default_context(state)
column = request.POST.get('field', None)
value = request.POST.get('value', None)
rows = None
if column != None and value != None:
rows = models.RawData.objects.filter(tenant=tenant_id).\
filter(**{column:value}).\
order_by('-when', '-microseconds')
_post_process_raw_data(rows, state)
c['rows'] = rows
c['allow_expansion'] = True
c['show_absolute_time'] = True
return render_to_response('stacktach/rows.html', c)