|
require 'sinatra' |
|
require 'haml' |
|
require 'sequel' |
|
|
|
DBUSER = 'user' |
|
DBPASS = 'password' |
|
DBHOST = 'localhost' |
|
DBBASE = 'syslog' |
|
|
|
DB = Sequel.connect("mysql://#{DBUSER}:#{DBPASS}@#{DBHOST}/#{DBBASE}") |
|
Sequel.extension :pagination |
|
|
|
DB.create_table? :events do |
|
primary_key :id |
|
String :host |
|
String :message |
|
String :tag |
|
String :facility |
|
String :priority |
|
Time :received_at |
|
end |
|
|
|
Event = DB[:events] |
|
|
|
set :public_folder, File.dirname(__FILE__) + '/assets' |
|
set :haml, ugly: true |
|
|
|
helpers do |
|
def plabel(pri) |
|
return "label-#{ |
|
case pri |
|
when *%w(notice info debug) |
|
'info' |
|
when *%w(err error crit alert emerg panic) |
|
'important' |
|
when *%w(warn warning) |
|
'warning' |
|
else |
|
pri |
|
end |
|
}" |
|
end |
|
|
|
def selected(event, field) |
|
key = field.to_sym |
|
return params[key] == event[key] ? {selected: 'selected'} : Hash.new |
|
end |
|
|
|
def query? |
|
params[:q] && !params[:q].empty? |
|
end |
|
|
|
def paginate? |
|
params[:disable_pagination].nil? || params[:disable_pagination].to_i != 1 |
|
end |
|
|
|
def query_url(options) |
|
options.dup.each { |k,v| options[k.to_s] = v; options.delete(k.to_sym) } |
|
url('/?' + params.merge(options).delete_if { |_, v| v.nil? }.map { |k,v| |
|
"#{k}=#{URI.escape(v.to_s, /[^#{URI::PATTERN::UNRESERVED}]/)}" |
|
}.join('&')) |
|
end |
|
end |
|
|
|
get '/' do |
|
query = params.inject({}) do |h, (key, value)| |
|
next h unless %w(host priority facility).member?(key) |
|
next h if value.empty? |
|
h.update(key.to_sym => value) |
|
end |
|
|
|
|
|
@events = Event.filter(query) |
|
@events = @events.grep([:tag, :message], "%#{params[:q]}%", case_insensitive: true) if query? |
|
|
|
page ||= (i = (params[:page] || 1).to_i) <= 0 ? 1 : i |
|
@events = @events.paginate(page, 50) if paginate? |
|
|
|
haml :app |
|
end |
|
|
|
__END__ |
|
@@ app |
|
!!! 5 |
|
%html{lang: 'fr'} |
|
%head |
|
%meta{charset: 'utf-8'} |
|
%title Syslog Viewer |
|
%link{href: '/css/bootstrap.css', rel: 'stylesheet'} |
|
:css |
|
body { padding-bottom: 40px; } |
|
.control-group { |
|
display: inline-block; |
|
margin-right: 1em; |
|
} |
|
.evt-date a { text-decoration: none !important; } |
|
tr:target { background-color: #d9edf7; } |
|
.tag { color: #888; } |
|
.page-count { text-align: center; } |
|
.page-left { text-align: left; } |
|
.page-right { text-align: right; } |
|
%body |
|
.navbar |
|
.navbar-inner |
|
.container |
|
%a.brand#go-root{href: '/'} Syslog Viewer |
|
.container |
|
|
|
%h2 Filter logs |
|
|
|
%form.form-inline.well{method: 'GET'} |
|
.control-group |
|
%label.control-label{for: "filter-host"} Host |
|
.controls |
|
%select#filter-host.span2{name: 'host'} |
|
%option{value: ''} Any |
|
- Event.group(:host).each do |ev| |
|
%option{selected(ev, :host)}= ev[:host] |
|
.control-group |
|
%label.control-label{for: "filter-priority"} Priority |
|
.controls |
|
%select#filter-priority.span2{name: 'priority'} |
|
%option{value: ''} Any |
|
- Event.group(:priority).each do |ev| |
|
%option{selected(ev, :priority)}= ev[:priority] |
|
.control-group |
|
%label.control-label{for: "filter-facility"} Facility |
|
.controls |
|
%select#filter-facility.span2{name: 'facility'} |
|
%option{value: ''} Any |
|
- Event.group(:facility).each do |ev| |
|
%option{selected(ev, :facility)}= ev[:facility] |
|
.control-group |
|
.controls |
|
%input#filter-text.input-large{type: 'text', placeholder: 'Text', name: 'q', value: params[:q]} |
|
.control-group |
|
.controls |
|
%button.btn.btn-primary{type: 'submit'} Apply |
|
.control-group |
|
.controls |
|
- if paginate? |
|
%a.btn.btn-danger{href: query_url(disable_pagination: 1)} Show all |
|
- else |
|
%a.btn.btn-success{href: query_url(disable_pagination: nil)} Paginate |
|
%input{type: 'hidden', name: 'page', value: '1'} |
|
|
|
= haml :paginate, layout: false |
|
|
|
%table.table.table-condensed |
|
%thead |
|
%tr |
|
%th ID |
|
%th Host |
|
%th Facility |
|
%th Priority |
|
%th Date |
|
%th Message |
|
%tbody |
|
- @events.order(:id.desc).each do |ev| |
|
%tr{id: "evt-#{ev[:id]}"} |
|
%td.evt-id |
|
%a{href: "#evt-#{ev[:id]}"}= ev[:id] |
|
%td.evt-host |
|
%a{href: query_url(host: ev[:host])}= ev[:host] |
|
%td.evt-facility |
|
%a{href: query_url(facility: ev[:facility])}= ev[:facility] |
|
%td.evt-priority |
|
%a.label{href: query_url(priority: ev[:priority]), class: plabel(ev[:priority])}= ev[:priority] |
|
%td.evt-date |
|
%a{title: ev[:received_at]} |
|
= ev[:received_at].strftime('%R') |
|
%td.evt-message |
|
%span.tag= ev[:tag] |
|
= ev[:message] |
|
= haml :paginate, layout: false |
|
|
|
|
|
%script{src: '/js/jquery.js'} |
|
%script{src: '/js/bootstrap.js'} |
|
:javascript |
|
$(function() { |
|
$('.evt-date a').tooltip({ |
|
title: function (e) { |
|
return $(e).attr('title'); |
|
} |
|
}); |
|
$('.evt-date').tooltip({ |
|
title: function (e) { |
|
return $(e).attr('title'); |
|
} |
|
}); |
|
}); |
|
|
|
@@ paginate |
|
- if paginate? |
|
- cp = @events.current_page |
|
- pc = @events.page_count |
|
.pagination.pagination-centered |
|
%ul |
|
%li{class: cp <= 1 ? 'disabled' : ''} |
|
%a{href: cp > 1 ? query_url(page: @events.current_page - 1) : ''} Newer |
|
%li.disabled |
|
%a== #{@events.current_page}/#{@events.page_count} |
|
%li{class: cp >= pc ? 'disabled' : ''} |
|
%a{href: cp < pc ? query_url(page: @events.current_page + 1) : ''} Older |
|
// - if @events.current_page < @events.page_count |
|
// - if @events.current_page > 1 |