blob: 4018f9098308ab831a9b9179ff77dadeb97d369a [file] [log] [blame]
#
# Copyright (c) 2013 Big Switch Networks, Inc.
#
# Licensed under the Eclipse Public License, Version 1.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.eclipse.org/legal/epl-v10.html
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# Views for the application
#
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.utils import simplejson
from sdncon.rest.jsonview import JsonResponse
from sdncon.apploader import AppLoader, AppLister
from sdncon.stats.views import init_db_connection
from sdncon.stats.data import get_log_event_data
import os
import time
import sdncon
ComponentXlation = {
'cassandra': 'database',
'sdncon': 'sdncon',
'sdnplatform': 'controller'
}
def log_collection_enabled(config_file="%s/statd/statd.conf" % sdncon.SDN_ROOT):
import json
enabled = False
try:
with open(config_file, 'r') as fp:
conf = json.load(fp)
if conf.get('input'):
for i in conf['input']:
if i.get('name') == 'LogCollector' and i.get('modules'):
enabled = True
break;
except:
pass
return enabled
def bsc_app_init():
# Check if logging is enabled, else do not start the app
if not log_collection_enabled():
return
# By default, App Name is the same as directory name. Change if needed.
APP_NAME = os.path.dirname(__file__).split("/")[-1]
# Create the App. Parameters are
# - Name: the id, lowercase letters only
# - Label: Human readable discription for the menu to the left
# - Priority: determines ranking the menu to the left), One-line description
# - Description: One line description of the app
app = AppLister(APP_NAME, "Logs", 5, "Controller Logs")
# Add Tabs. Parameters are:
# - Name: the id, lowercase letters only
# - Label: Human readable discription for the menu to the left
# - View: name of the python function that contains the django view (see below)
app.addTab("controllerlogs", "Controller Logs", controller)
app.addTab("dblogs", "Database Logs", db)
app.addTab("sdnconlogs", "SDNCon Logs", sdncon)
app.addTab("alllogs", "All Logs", all)
AppLoader.addApp(app)
# Views - functions that serve the HTML that goes into each tab
def controller(request):
return render_to_response('apps/logs/templates/logs.html', { 'source' : 'controller' } )
def db(request):
return render_to_response('apps/logs/templates/logs.html', { 'source' : 'db' } )
def sdncon(request):
return render_to_response('apps/logs/templates/logs.html', { 'source' : 'sdncon' } )
def all(request):
return render_to_response('apps/logs/templates/logs.html', { 'source' : 'all' } )
# Views defined in urls.py
def controller_log_data_all(request, cluster, controller):
init_db_connection()
time_now = time.time()*1000 #conver to ms
# we only get one day for now, this will be fixed when we move to an actually scalable solution
data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
arr = get_array_from_dict(data_dict, True)
return generic_server_side_datatable(request, arr)
def controller_log_data_controller(request, cluster, controller):
init_db_connection()
time_now = time.time()*1000 #conver to ms
# we only get one day for now, this will be fixed when we move to an actually scalable solution
data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
filtered_dict = []
for e in data_dict:
if e['component'] == 'sdnplatform' or e['component'] == 'sdnplatform.request':
filtered_dict.append(e)
arr = get_array_from_dict(filtered_dict, False)
return generic_server_side_datatable(request, arr)
def controller_log_data_db(request, cluster, controller):
init_db_connection()
time_now = time.time()*1000 #conver to ms
# we only get one day for now, this will be fixed when we move to an actually scalable solution
data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
filtered_dict = []
for e in data_dict:
if e['component'] == 'cassandra':
filtered_dict.append(e)
arr = get_array_from_dict(filtered_dict, False)
return generic_server_side_datatable(request, arr)
def controller_log_data_sdncon(request, cluster, controller):
init_db_connection()
time_now = time.time()*1000 #conver to ms
# we only get one day for now, this will be fixed when we move to an actually scalable solution
data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
filtered_dict = []
for e in data_dict:
if e['component'] == 'sdncon':
filtered_dict.append(e)
arr = get_array_from_dict(filtered_dict, False)
return generic_server_side_datatable(request, arr)
# Helper functions
def generic_server_side_datatable(request, data_array):
start = request.GET.get("iDisplayStart",0)
length = request.GET.get("iDisplayLength",10)
search_str = request.GET.get("sSearch",None)
if search_str:
data_array_f = []
for d in data_array:
for e in d:
try:
if e.find(search_str) > -1:
data_array_f.append(d)
break
except Exception:
pass
else:
data_array_f = data_array
data_subset = data_array_f[int(start):int(start)+int(length)]
response_data = '{ "aaData":'+simplejson.dumps(data_subset) + ', "iTotalDisplayRecords": ' + str(len(data_array_f)) + ', "iTotalRecords": ' + str(len(data_array_f)) +'}'
return HttpResponse(response_data, 'application/json')
# Takes a dictionary that includes
# { "timestamp": unix_ts, "level" : "string", "message": "msg" }
# and turns it into a 2D array that includes
# [ [unix_ts, level, message], [etc], [etc] ]
def get_array_from_dict(dict, includeComp):
array = []
for element in reversed(dict):
if 'component' in element and element['component'] == 'sdnplatform.request':
entry = parse_sdnplatform_request_log_entry(element)
else:
entry = []
if 'timestamp' in element:
entry.append(element['timestamp'])
else:
entry.append('-')
if 'log-level' in element:
entry.append(element['log-level'])
else:
entry.append('-')
if 'message' in element:
entry.append(element['message'])
else:
entry.append('-')
if includeComp:
if 'component' in element:
entry.insert(1, ComponentXlation[element['component']])
else:
entry.append(1, '-')
array.append(entry)
return array
# Parses a SDNPlatform request log entry into an array
# Format is similar to
# {
# 'package': 'Python-urllib/2.7',
# 'timestamp': 1306967011000L,
# 'component': 'sdnplatform.request',
# 'request': 'GET /wm/core/counter/00:00:00:00:00:73:28:02_OFPacketIn_L3_IPv4/json HTTP/1.1',
# 'responseLen': '37',
# 'client': '127.0.0.1',
# 'responseCode': '200'
# }
# Output array is [unix_ts, level, message]
def parse_sdnplatform_request_log_entry(element):
entry = []
if 'timestamp' in element:
entry.append(element['timestamp'])
else:
entry.append('-')
if 'responseCode' in element:
rc = element['responseCode']
if rc == '404' or rc == '500':
entry.append('ERROR')
elif rc == '200':
entry.append('INFO')
else:
entry.append('-')
else:
entry.append('-')
msg = ''
if 'request' in element:
msg += element['request']
if 'client' in element:
msg += ' CLIENT ' + element['client']
if 'responseCode' in element:
msg += ' ' + element['responseCode']
if 'package' in element:
msg += ' ' + element['package']
entry.append(msg)
return entry