Commit 855b6d70 authored by ale's avatar ale

new web app, part 1

parent 8435b6f2
......@@ -47,6 +47,11 @@ class LogStore(object):
""""Remove the entire index."""
self.conn.delete_index(self.INDEX)
def get_status(self):
"""Return the index status."""
status = self.conn.status(indexes=[self.INDEX])
return status['indices'][self.INDEX]
def _init(self):
"""Create the index and set up the schema."""
log.info('creating index "%s"', self.INDEX)
......
import logging
import optparse
import sys
from lens2 import daemonize
from lens2 import io
from lens2 import logstore
from lens2 import pattern
from lens2 import syslog_parser
from lens2 import utils
from lens2 import wsgiapp
from lens2 import daemonize
from lens2 import www_app
log = logging.getLogger(__name__)
......@@ -15,7 +15,7 @@ DEFAULT_ES_URL = 'localhost:9200'
def run_http_server(lens, opts, args):
server = wsgiapp.LensWSGIServer(lens)
server = www_app.make_app()
server.serve_forever(opts.http_port)
......
// lens2.js
lens = {};
lens.util = {};
lens.ERROR_TEMPLATE = 'Server reported an error: ${error}<br><span id=\"errorThrown\">${errorThrown}</span>';
// Date and timestamp helper functions.
lens.util.timestampToDate = function(ts) {
return new Date(ts / 1000);
};
lens.util.dateToTimestamp = function(d) {
return (d.getTime() * 1000);
};
lens.util.timestampNow = function() {
return lens.util.dateToTimestamp(new Date());
};
lens.util.timestampAdd = function(ts, seconds) {
return (ts + (1000000 * seconds));
};
lens.util.timestampToString = function(ts) {
return lens.util.timestampToDate(ts).strftime('%Y/%m/%d %H:%M:%S');
};
/**
* Lens object.
*
* Provides all the methods to interact with the LENS2 backend.
*
* @param {Object} config config object
*/
lens.Lens = function(config) {
// Reset internal state.
this.cur_query = undef;
this.cur_hash = '';
this.offset = 0;
this.page_size = 50;
this.total_results = 0;
this.time_range = {start:0, end: 0};
// Merge config with defaults and find the elements we need.
if (!config) {
config = {};
}
var log_template_id = (config.log_template_id ? config.log_template_id
: '#log_template');
var log_viewer_id = (config.log_viewer_id ? config.log_viewer_id
: '#log_viewer');
this.results_view_elem = $(log_viewer_id + ' #results');
var pagination_title_id = (config.pagination_title_id ? config.pagination_title_id
: '#log_pagination_title');
this.pagination_title_elem = $(pagination_title_id);
var pagination_next_id = (config.pagination_next_id ? config.pagination_next_id
: '#log_pagination_next');
this.pagination_next_elem = $(pagination_next_id);
this.pagination_next_elem.click(this.pageNext);
var pagination_prev_id = (config.pagination_prev_id ? config.pagination_prev_id
: '#log_pagination_prev');
this.pagination_prev_elem = $(pagination_prev_id);
this.pagination_prev_elem.click(this.pagePrev);
// Create the rendering templates.
this.log_template = $.template(null, $(log_template_id));
this.error_template = $.template(null, lens.ERROR_TEMPLATE);
};
/**
* Render some logs into an element.
*
* @param {Object} dest destination element (jQuery object)
* @param {Array[string]} logs list of logs
*/
lens.Lens.prototype.renderLogs = function(logs) {
var out = '';
var template = this.log_template;
$.each(logs, function(idx, elem) {
out += $.tmpl(template, elem);
});
this.results_view_elem.html(out);
};
lens.Lens.prototype.renderPagination = function(logs) {
// Find min and max of shown timestamps.
var ts_min = (2 << 32 * 1000000);
var ts_max = 0;
$.each(logs, function(idx, elem) {
if (elem.timestamp > ts_max) { ts_max = elem.timestamp; }
if (elem.timestamp < ts_min) { ts_min = elem.timestamp; }
});
// Update the pagination UI elements.
if (this.offset > 0) {
this.pagination_title_next.show();
} else {
this.pagination_title_next.hide();
}
this.pagination_title_prev.show();
if (ts_min > ts_max) {
this.pagination_title_elem.text('-');
} else {
this.pagination_title_elem.text(lens.util.timestampToString(ts_min) + ' - '
+ lens.util.timestampToString(ts_max));
}
};
lens.Lens.prototype.render = function(logs) {
// Render the logs.
this.renderLogs(logs);
// Render pagination elements.
this.renderPagination(logs);
};
/**
* Refresh the view with the current query and params.
*/
lens.Lens.prototype.refresh = function() {
this.clearError();
this.showLoading();
// Autodetect whether to extend the time range.
if ((this.total_results > 0) &&
(this.offset + this.page_size > this.total_results)) {
this.time_range.start = lens.util.timestampAdd(this.time_range.start, -86400);
}
// Perform the query.
var lensobj = this;
var time_range_str = ('' + this.time_range.start +
':' + (
(this.time_range.end > 0)
? this.time_range.end
: lens.util.timestampNow()));
$.ajax({
url: '/search',
data: {q: query_str,
start: this.offset,
page_size: this.page_size,
time_range: time_range_str,
},
dataType: 'json',
success: function(data, status, jqxhr) {
lensobj.total_results = data.total_results;
lensobj.render(data.results);
lensobj.clearLoading();
},
error: this.ajaxError
});
};
/**
* Search.
*/
lens.Lens.prototype.search = function(query_str) {
this.cur_query = query_str;
this.total_results = 0;
this.offset = 0;
this.time_range = {start:0, end: 0};
this.refresh();
}
/**
* General AJAX error callback.
*/
lens.Lens.prototype.ajaxError = function(jqxhr, textStatus, errorThrown) {
this.clearLoading();
$('#error').html($.tmpl(this.error_template,
{error: textStatus,
errorThrown: errorThrown})
).show();
};
/**
* Clear error message.
*/
lens.Lens.prototype.clearError = function() {
$('#error').hide();
};
/**
* Show 'loading' icon.
*/
lens.Lens.prototype.showLoading = function() {
$('#loading').show();
};
/**
* Hide 'loading' icon.
*/
lens.Lens.prototype.clearLoading = function() {
$('#loading').hide();
};
Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof (r)=="undefined"){r=10}for(;parseInt(x,10)<r&&r>1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(d){return Date.ext.locales[d.locale].a[d.getDay()]},A:function(d){return Date.ext.locales[d.locale].A[d.getDay()]},b:function(d){return Date.ext.locales[d.locale].b[d.getMonth()]},B:function(d){return Date.ext.locales[d.locale].B[d.getMonth()]},c:"toLocaleString",C:function(d){return Date.ext.util.xPad(parseInt(d.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(d){return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100,10),0)},G:function(d){var y=d.getFullYear();var V=parseInt(Date.ext.formats.V(d),10);var W=parseInt(Date.ext.formats.W(d),10);if(W>V){y++}else{if(W===0&&V>=52){y--}}return y},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return Date.ext.util.xPad(I===0?12:I,0)},j:function(d){var ms=d-new Date(""+d.getFullYear()+"/1/1 GMT");ms+=d.getTimezoneOffset()*60000;var doy=parseInt(ms/60000/60/24,10)+1;return Date.ext.util.xPad(doy,0,100)},m:function(d){return Date.ext.util.xPad(d.getMonth()+1,0)},M:["getMinutes","0"],p:function(d){return Date.ext.locales[d.locale].p[d.getHours()>=12?1:0]},P:function(d){return Date.ext.locales[d.locale].P[d.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow},U:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0)},V:function(d){var woy=parseInt(Date.ext.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow==53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4){idow=1}else{if(idow===0){idow=Date.ext.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(idow,0)},w:"getDay",W:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=7-Date.ext.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0,10)},y:function(d){return Date.ext.util.xPad(d.getFullYear()%100,0)},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=Date.ext.util.xPad(parseInt(Math.abs(o/60),10),0);var M=Date.ext.util.xPad(o%60,0);return(o>0?"-":"+")+H+M},Z:function(d){return d.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(d){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(fmt){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var d=this;while(fmt.match(/%[cDhnrRtTxXzZ]/)){fmt=fmt.replace(/%([cDhnrRtTxXzZ])/g,function(m0,m1){var f=Date.ext.aggregates[m1];return(f=="locale"?Date.ext.locales[d.locale][m1]:f)})}var str=fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(m0,m1){var f=Date.ext.formats[m1];if(typeof (f)=="string"){return d[f]()}else{if(typeof (f)=="function"){return f.call(d,d)}else{if(typeof (f)=="object"&&typeof (f[0])=="string"){return Date.ext.util.xPad(d[f[0]](),f[1])}else{return m1}}}});d=null;return str};
import logging
from flask import Blueprint, Flask, abort, redirect, request, \
g, current_app, jsonify
api_app = Blueprint('api', __name__)
log = logging.getLogger(__name__)
@api_app.route('/search', methods=['POST'])
def api_search():
try:
query = request.form['q']
start = int(request.form.get('start', 0))
page_size = int(request.form.get('page_size', 20))
time_range = utils.parse_time_range('time_range', '1d')
except (KeyError, ValueError):
abort(400)
results, total = current_app.logstore.search(
query, time_range, start=start, size=page_size)
return jsonify(results=results, total=total)
@api_app.route('/status')
def api_status():
index_stats = current_app.logstore.get_status()
return jsonify(docs=index_stats['docs'],
index=index_stats['index'],
merges=index_stats['merges'])
from flask import Flask
from lens2 import logstore
from lens2 import www_api
from lens2 import www_ui
def make_app(config={}):
app = Flask(__name__)
app.config.update(config)
app.config.from_envvar('APP_SETTINGS', silent=True)
app.register_blueprint(api_app)
app.register_blueprint(ui_app)
server_list = config.get('ES_SERVER', 'localhost:9200')
app.logstore = logstore.LogStore(server_list)
app.jinja_env.globals['version'] = '0.3'
return app
from flask import Blueprint, Flask, abort, redirect, request, \
g, current_app, render_template
ui_app = Blueprint('ui', __name__,
template_folder='templates')
@ui_app.route('/')
def ui_index():
return render_template('index.html')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment