blob: 4018f9098308ab831a9b9179ff77dadeb97d369a [file] [log] [blame]
srikanth116e6e82014-08-19 07:22:37 -07001#
2# Copyright (c) 2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17# Views for the application
18#
19
20from django.http import HttpResponse
21from django.shortcuts import render_to_response
22from django.utils import simplejson
23from sdncon.rest.jsonview import JsonResponse
24from sdncon.apploader import AppLoader, AppLister
25from sdncon.stats.views import init_db_connection
26from sdncon.stats.data import get_log_event_data
27import os
28import time
29import sdncon
30
31ComponentXlation = {
32 'cassandra': 'database',
33 'sdncon': 'sdncon',
34 'sdnplatform': 'controller'
35}
36
37def log_collection_enabled(config_file="%s/statd/statd.conf" % sdncon.SDN_ROOT):
38 import json
39 enabled = False
40 try:
41 with open(config_file, 'r') as fp:
42 conf = json.load(fp)
43 if conf.get('input'):
44 for i in conf['input']:
45 if i.get('name') == 'LogCollector' and i.get('modules'):
46 enabled = True
47 break;
48 except:
49 pass
50 return enabled
51
52def bsc_app_init():
53 # Check if logging is enabled, else do not start the app
54 if not log_collection_enabled():
55 return
56
57 # By default, App Name is the same as directory name. Change if needed.
58 APP_NAME = os.path.dirname(__file__).split("/")[-1]
59
60 # Create the App. Parameters are
61 # - Name: the id, lowercase letters only
62 # - Label: Human readable discription for the menu to the left
63 # - Priority: determines ranking the menu to the left), One-line description
64 # - Description: One line description of the app
65 app = AppLister(APP_NAME, "Logs", 5, "Controller Logs")
66
67 # Add Tabs. Parameters are:
68 # - Name: the id, lowercase letters only
69 # - Label: Human readable discription for the menu to the left
70 # - View: name of the python function that contains the django view (see below)
71 app.addTab("controllerlogs", "Controller Logs", controller)
72 app.addTab("dblogs", "Database Logs", db)
73 app.addTab("sdnconlogs", "SDNCon Logs", sdncon)
74 app.addTab("alllogs", "All Logs", all)
75 AppLoader.addApp(app)
76
77# Views - functions that serve the HTML that goes into each tab
78def controller(request):
79 return render_to_response('apps/logs/templates/logs.html', { 'source' : 'controller' } )
80
81def db(request):
82 return render_to_response('apps/logs/templates/logs.html', { 'source' : 'db' } )
83
84def sdncon(request):
85 return render_to_response('apps/logs/templates/logs.html', { 'source' : 'sdncon' } )
86
87def all(request):
88 return render_to_response('apps/logs/templates/logs.html', { 'source' : 'all' } )
89
90# Views defined in urls.py
91def controller_log_data_all(request, cluster, controller):
92 init_db_connection()
93 time_now = time.time()*1000 #conver to ms
94 # we only get one day for now, this will be fixed when we move to an actually scalable solution
95 data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
96 arr = get_array_from_dict(data_dict, True)
97 return generic_server_side_datatable(request, arr)
98
99def controller_log_data_controller(request, cluster, controller):
100 init_db_connection()
101 time_now = time.time()*1000 #conver to ms
102 # we only get one day for now, this will be fixed when we move to an actually scalable solution
103 data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
104 filtered_dict = []
105 for e in data_dict:
106 if e['component'] == 'sdnplatform' or e['component'] == 'sdnplatform.request':
107 filtered_dict.append(e)
108 arr = get_array_from_dict(filtered_dict, False)
109 return generic_server_side_datatable(request, arr)
110
111def controller_log_data_db(request, cluster, controller):
112 init_db_connection()
113 time_now = time.time()*1000 #conver to ms
114 # we only get one day for now, this will be fixed when we move to an actually scalable solution
115 data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
116 filtered_dict = []
117 for e in data_dict:
118 if e['component'] == 'cassandra':
119 filtered_dict.append(e)
120 arr = get_array_from_dict(filtered_dict, False)
121 return generic_server_side_datatable(request, arr)
122
123def controller_log_data_sdncon(request, cluster, controller):
124 init_db_connection()
125 time_now = time.time()*1000 #conver to ms
126 # we only get one day for now, this will be fixed when we move to an actually scalable solution
127 data_dict = get_log_event_data(cluster, controller, time_now - 86400000, time_now)
128 filtered_dict = []
129 for e in data_dict:
130 if e['component'] == 'sdncon':
131 filtered_dict.append(e)
132 arr = get_array_from_dict(filtered_dict, False)
133 return generic_server_side_datatable(request, arr)
134
135
136# Helper functions
137def generic_server_side_datatable(request, data_array):
138 start = request.GET.get("iDisplayStart",0)
139 length = request.GET.get("iDisplayLength",10)
140 search_str = request.GET.get("sSearch",None)
141
142 if search_str:
143 data_array_f = []
144 for d in data_array:
145 for e in d:
146 try:
147 if e.find(search_str) > -1:
148 data_array_f.append(d)
149 break
150 except Exception:
151 pass
152 else:
153 data_array_f = data_array
154
155 data_subset = data_array_f[int(start):int(start)+int(length)]
156 response_data = '{ "aaData":'+simplejson.dumps(data_subset) + ', "iTotalDisplayRecords": ' + str(len(data_array_f)) + ', "iTotalRecords": ' + str(len(data_array_f)) +'}'
157 return HttpResponse(response_data, 'application/json')
158
159# Takes a dictionary that includes
160# { "timestamp": unix_ts, "level" : "string", "message": "msg" }
161# and turns it into a 2D array that includes
162# [ [unix_ts, level, message], [etc], [etc] ]
163def get_array_from_dict(dict, includeComp):
164 array = []
165 for element in reversed(dict):
166 if 'component' in element and element['component'] == 'sdnplatform.request':
167 entry = parse_sdnplatform_request_log_entry(element)
168 else:
169 entry = []
170 if 'timestamp' in element:
171 entry.append(element['timestamp'])
172 else:
173 entry.append('-')
174 if 'log-level' in element:
175 entry.append(element['log-level'])
176 else:
177 entry.append('-')
178 if 'message' in element:
179 entry.append(element['message'])
180 else:
181 entry.append('-')
182
183 if includeComp:
184 if 'component' in element:
185 entry.insert(1, ComponentXlation[element['component']])
186 else:
187 entry.append(1, '-')
188
189 array.append(entry)
190 return array
191
192# Parses a SDNPlatform request log entry into an array
193# Format is similar to
194# {
195# 'package': 'Python-urllib/2.7',
196# 'timestamp': 1306967011000L,
197# 'component': 'sdnplatform.request',
198# 'request': 'GET /wm/core/counter/00:00:00:00:00:73:28:02_OFPacketIn_L3_IPv4/json HTTP/1.1',
199# 'responseLen': '37',
200# 'client': '127.0.0.1',
201# 'responseCode': '200'
202# }
203# Output array is [unix_ts, level, message]
204def parse_sdnplatform_request_log_entry(element):
205 entry = []
206 if 'timestamp' in element:
207 entry.append(element['timestamp'])
208 else:
209 entry.append('-')
210 if 'responseCode' in element:
211 rc = element['responseCode']
212 if rc == '404' or rc == '500':
213 entry.append('ERROR')
214 elif rc == '200':
215 entry.append('INFO')
216 else:
217 entry.append('-')
218 else:
219 entry.append('-')
220 msg = ''
221 if 'request' in element:
222 msg += element['request']
223 if 'client' in element:
224 msg += ' CLIENT ' + element['client']
225 if 'responseCode' in element:
226 msg += ' ' + element['responseCode']
227 if 'package' in element:
228 msg += ' ' + element['package']
229 entry.append(msg)
230 return entry
231