mongodb_logger 0.2.6-jruby
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/.rvmrc +1 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +207 -0
- data/Rakefile +169 -0
- data/SUPPORTED_RAILS_VERSIONS +17 -0
- data/TESTING.md +24 -0
- data/bin/mongodb_logger_web +24 -0
- data/config.ru +17 -0
- data/examples/server_config.yml +5 -0
- data/features/mongodb_logger_web.feature +14 -0
- data/features/rails.feature +12 -0
- data/features/step_definitions/mongodb_logger_web_steps.rb +45 -0
- data/features/step_definitions/rails_application_steps.rb +65 -0
- data/features/support/env.rb +15 -0
- data/features/support/rails.rb +98 -0
- data/features/support/terminal.rb +95 -0
- data/lib/mongodb_logger/initializer_mixin.rb +26 -0
- data/lib/mongodb_logger/logger.rb +239 -0
- data/lib/mongodb_logger/railtie.rb +12 -0
- data/lib/mongodb_logger/replica_set_helper.rb +19 -0
- data/lib/mongodb_logger/server/coffee/logs.coffee +250 -0
- data/lib/mongodb_logger/server/content_for.rb +58 -0
- data/lib/mongodb_logger/server/model/additional_filter.rb +104 -0
- data/lib/mongodb_logger/server/model/analytic.rb +82 -0
- data/lib/mongodb_logger/server/model/filter.rb +84 -0
- data/lib/mongodb_logger/server/partials.rb +24 -0
- data/lib/mongodb_logger/server/public/images/arrow-down.png +0 -0
- data/lib/mongodb_logger/server/public/images/arrow-up.png +0 -0
- data/lib/mongodb_logger/server/public/images/date.png +0 -0
- data/lib/mongodb_logger/server/public/images/external.png +0 -0
- data/lib/mongodb_logger/server/public/images/failure.png +0 -0
- data/lib/mongodb_logger/server/public/images/logo.png +0 -0
- data/lib/mongodb_logger/server/public/images/mongodb.png +0 -0
- data/lib/mongodb_logger/server/public/images/newlog.png +0 -0
- data/lib/mongodb_logger/server/public/images/play-icon.png +0 -0
- data/lib/mongodb_logger/server/public/images/spinner.gif +0 -0
- data/lib/mongodb_logger/server/public/images/spinner2.gif +0 -0
- data/lib/mongodb_logger/server/public/images/stop-icon.png +0 -0
- data/lib/mongodb_logger/server/public/images/success.png +0 -0
- data/lib/mongodb_logger/server/public/javascripts/logs.js +1 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/highlight.pack.js +1 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-1.7.1.min.js +4 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-ui-1.8.16.min.js +791 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery.pjax.min.js +6 -0
- data/lib/mongodb_logger/server/public/stylesheets/all.css +12 -0
- data/lib/mongodb_logger/server/public/stylesheets/grids.css +18 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-buttons.css +81 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-forms.css +59 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-headers.css +8 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-tables.css +87 -0
- data/lib/mongodb_logger/server/public/stylesheets/highlight/zenburn.css +115 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_100_f5f0e5_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_25_cb842e_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_70_ede4d4_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_100_f4f0ec_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_65_fee4bd_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_75_f5f5b5_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_inset-soft_100_f4f0ec_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_c47a23_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_cb672b_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f08000_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f35f07_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ff7519_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/jquery-ui-1.8.16.custom.css +568 -0
- data/lib/mongodb_logger/server/public/stylesheets/layout.css +205 -0
- data/lib/mongodb_logger/server/public/stylesheets/library.css +330 -0
- data/lib/mongodb_logger/server/public/stylesheets/reset.css +43 -0
- data/lib/mongodb_logger/server/public/stylesheets/spaces.css +42 -0
- data/lib/mongodb_logger/server/view_helpers.rb +113 -0
- data/lib/mongodb_logger/server/views/analytics.erb +61 -0
- data/lib/mongodb_logger/server/views/error.erb +2 -0
- data/lib/mongodb_logger/server/views/layout.erb +47 -0
- data/lib/mongodb_logger/server/views/overview.erb +119 -0
- data/lib/mongodb_logger/server/views/shared/_collection_stats.erb +14 -0
- data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +34 -0
- data/lib/mongodb_logger/server/views/shared/_log.erb +8 -0
- data/lib/mongodb_logger/server/views/shared/_log_info.erb +27 -0
- data/lib/mongodb_logger/server/views/shared/_message_tabs.erb +15 -0
- data/lib/mongodb_logger/server/views/shared/_tabs.erb +4 -0
- data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +13 -0
- data/lib/mongodb_logger/server/views/shared/_top_panel.erb +7 -0
- data/lib/mongodb_logger/server/views/show_log.erb +105 -0
- data/lib/mongodb_logger/server.rb +174 -0
- data/lib/mongodb_logger/server_config.rb +77 -0
- data/lib/mongodb_logger/version.rb +3 -0
- data/lib/mongodb_logger.rb +31 -0
- data/mongodb_logger.gemspec +44 -0
- data/mongodb_logger.java.gemspec +42 -0
- data/spec/javascripts/MongodbLoggerMainSpec.js +13 -0
- data/spec/javascripts/helpers/SpecHelper.js +3 -0
- data/spec/javascripts/support/jasmine.yml +77 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/test/active_record.rb +13 -0
- data/test/config/samples/database.yml +9 -0
- data/test/config/samples/database_no_file_logging.yml +10 -0
- data/test/config/samples/database_replica_set.yml +12 -0
- data/test/config/samples/database_with_auth.yml +9 -0
- data/test/config/samples/database_with_collection.yml +8 -0
- data/test/config/samples/mongodb_logger.yml +2 -0
- data/test/config/samples/mongoid.yml +30 -0
- data/test/config/samples/server_config.yml +3 -0
- data/test/rails/app/controllers/order_controller.rb +23 -0
- data/test/rails/test/functional/order_controller_test.rb +116 -0
- data/test/rails/test/test_helper.rb +10 -0
- data/test/rails.rb +22 -0
- data/test/shoulda_macros/log_macros.rb +13 -0
- data/test/test.sh +6 -0
- data/test/test_helper.rb +89 -0
- data/test/unit/mongodb_logger_replica_test.rb +56 -0
- data/test/unit/mongodb_logger_test.rb +270 -0
- metadata +383 -0
@@ -0,0 +1,250 @@
|
|
1
|
+
root = global ? window
|
2
|
+
|
3
|
+
root.MongodbLoggerMain =
|
4
|
+
tail_logs_url: null
|
5
|
+
tail_log_started: false
|
6
|
+
log_info_offset: null
|
7
|
+
log_info_padding: 15
|
8
|
+
is_charts_ready: false
|
9
|
+
|
10
|
+
init: ->
|
11
|
+
# spinner
|
12
|
+
$(document).ajaxStart =>
|
13
|
+
$('#ajax_loader').show()
|
14
|
+
$(document).ajaxStop =>
|
15
|
+
$('#ajax_loader').hide()
|
16
|
+
# tail logs buttons
|
17
|
+
$(document).on 'click', '#tail_logs_link', (event) =>
|
18
|
+
MongodbLoggerMain.tail_logs_url = $(event.target).attr('data-url')
|
19
|
+
$('#tail_logs_block').addClass('started')
|
20
|
+
MongodbLoggerMain.tail_logs(null)
|
21
|
+
return false
|
22
|
+
$(document).on 'click', '#tail_logs_stop_link', (event) =>
|
23
|
+
MongodbLoggerMain.tail_log_started = false
|
24
|
+
$('#tail_logs_block').removeClass('started')
|
25
|
+
return false
|
26
|
+
# log info click
|
27
|
+
$(document).on 'click', '.log_info', (event) =>
|
28
|
+
elm_obj = $(event.target)
|
29
|
+
url = elm_obj.data('url')
|
30
|
+
url = elm_obj.parent('tr').data('url') if !url?
|
31
|
+
if url?
|
32
|
+
elm_obj.parents('table').find('tr').removeClass('current')
|
33
|
+
elm_obj.parent('tr').addClass('current')
|
34
|
+
$('#log_info').load(url)
|
35
|
+
return false
|
36
|
+
# filter tougle
|
37
|
+
$(document).on 'click', 'div.filter-toggle', (event) =>
|
38
|
+
$('div.filter').slideToggle()
|
39
|
+
$('div.filter-toggle span.arrow-down').toggleClass('rotate')
|
40
|
+
# additional filters
|
41
|
+
$(document).on 'click', '#add_more_filter', (event) =>
|
42
|
+
url = $(event.target).attr('href')
|
43
|
+
$.ajax
|
44
|
+
url: url
|
45
|
+
success: (data) ->
|
46
|
+
content = $('<li></li>').html(data)
|
47
|
+
$('#more_filter_list').append(content)
|
48
|
+
return false
|
49
|
+
# select filter types (integer, string, date)
|
50
|
+
$(document).on 'change', 'select.filter_type', (event) =>
|
51
|
+
elm_object = $(event.target)
|
52
|
+
url = elm_object.attr('rel') + "/" + elm_object.val()
|
53
|
+
$.ajax
|
54
|
+
url: url
|
55
|
+
dataType: "json"
|
56
|
+
success: (data) ->
|
57
|
+
cond_options = ""
|
58
|
+
value_input = ""
|
59
|
+
$.each data.conditions, (key, val) =>
|
60
|
+
cond_options += '<option value="' + val + '">' + val + '</option>'
|
61
|
+
elm_object.parents('div.filter_block').find('select.filter_conditions').empty().append(cond_options)
|
62
|
+
if data.values.length > 0
|
63
|
+
value_input = '<select id="filter[more][]_value" name="filter[more][][value]">'
|
64
|
+
$.each data.values, (key, val) =>
|
65
|
+
value_input += '<option value="' + val + '">' + val + '</option>'
|
66
|
+
value_input += '</select>'
|
67
|
+
else
|
68
|
+
value_input = '<input type="text" name="filter[more][][value]" value="" placeholder="value">'
|
69
|
+
elm_object.parents('div.filter_block').find('div.filter_values').html(value_input)
|
70
|
+
if "date" == elm_object.val()
|
71
|
+
elm_object.parents('div.filter_block').find('div.filter_values input').datepicker
|
72
|
+
dateFormat: "yy-mm-dd"
|
73
|
+
changeMonth: true
|
74
|
+
changeYear: true
|
75
|
+
yearRange: 'c-50:c+10'
|
76
|
+
return false
|
77
|
+
# delete one filter
|
78
|
+
$(document).on 'click', '.close_more_filter', (event) =>
|
79
|
+
$(event.target).parents('li').remove()
|
80
|
+
return false
|
81
|
+
# message tabs
|
82
|
+
$(document).on 'click', 'li.message_tab', (event) =>
|
83
|
+
elm_obj = $(event.target)
|
84
|
+
tab = elm_obj.attr('data-tab')
|
85
|
+
if tab?
|
86
|
+
$('li.message_tab').removeClass('active')
|
87
|
+
$('pre.tab_content').addClass('hidden')
|
88
|
+
elm_obj.addClass('active')
|
89
|
+
$('.' + tab).removeClass('hidden')
|
90
|
+
# analytic form
|
91
|
+
$(document).on 'submit', '#analyticForm', (event) =>
|
92
|
+
element = $('#analyticForm')
|
93
|
+
url = element.attr('action')
|
94
|
+
data = element.serializeArray()
|
95
|
+
$.ajax
|
96
|
+
url: url
|
97
|
+
dataType: 'json'
|
98
|
+
data: data
|
99
|
+
type: "POST"
|
100
|
+
success: (data, textStatus, jqXHR) =>
|
101
|
+
MongodbLoggerMain.build_analytic_charts(data)
|
102
|
+
return false
|
103
|
+
# keydown by logs
|
104
|
+
$(document).on 'keydown', '*', (event) =>
|
105
|
+
console.log event.keyCode
|
106
|
+
switch event.keyCode
|
107
|
+
when 37 # left
|
108
|
+
MongodbLoggerMain.move_by_logs('begin')
|
109
|
+
when 38 # up
|
110
|
+
MongodbLoggerMain.move_by_logs('up')
|
111
|
+
when 39 # right
|
112
|
+
MongodbLoggerMain.move_by_logs('end')
|
113
|
+
when 40 # down
|
114
|
+
MongodbLoggerMain.move_by_logs('down')
|
115
|
+
|
116
|
+
# init pjax
|
117
|
+
this.init_pjax()
|
118
|
+
this.init_on_pages()
|
119
|
+
|
120
|
+
init_pjax: ->
|
121
|
+
# pjax
|
122
|
+
$('a[data-pjax]').pjax()
|
123
|
+
$('body').bind 'pjax:start', () =>
|
124
|
+
$('#ajax_loader').show()
|
125
|
+
$('body').bind 'pjax:end', () =>
|
126
|
+
$('#ajax_loader').hide()
|
127
|
+
# stop tailing
|
128
|
+
MongodbLoggerMain.tail_log_started = false
|
129
|
+
# scroll on top
|
130
|
+
if ($(window).scrollTop() > 100)
|
131
|
+
$('html, body').stop().animate({ scrollTop: 0 }, 'slow')
|
132
|
+
# init pages
|
133
|
+
MongodbLoggerMain.init_on_pages()
|
134
|
+
# init this on pjax
|
135
|
+
init_on_pages: ->
|
136
|
+
# code highlight
|
137
|
+
$('pre code').each (i, e) ->
|
138
|
+
hljs.highlightBlock(e, ' ')
|
139
|
+
# callendars
|
140
|
+
$( ".datepicker, .filter_values input.date" ).datepicker
|
141
|
+
dateFormat: "yy-mm-dd"
|
142
|
+
changeMonth: true
|
143
|
+
changeYear: true
|
144
|
+
yearRange: 'c-50:c+10'
|
145
|
+
# log info window
|
146
|
+
if $("#log_info").length > 0
|
147
|
+
MongodbLoggerMain.log_info_offset = $("#log_info").offset()
|
148
|
+
$(window).scroll =>
|
149
|
+
if $(window).scrollTop() > MongodbLoggerMain.log_info_offset.top
|
150
|
+
$("#log_info").stop().animate
|
151
|
+
marginTop: $(window).scrollTop() - MongodbLoggerMain.log_info_offset.top + MongodbLoggerMain.log_info_padding
|
152
|
+
else
|
153
|
+
$("#log_info").stop().animate
|
154
|
+
marginTop: 0
|
155
|
+
# tail logs function
|
156
|
+
tail_logs: (log_last_id) ->
|
157
|
+
url = MongodbLoggerMain.tail_logs_url
|
158
|
+
if log_last_id? && log_last_id.length > 0
|
159
|
+
url = MongodbLoggerMain.tail_logs_url + "/" + log_last_id
|
160
|
+
else
|
161
|
+
MongodbLoggerMain.tail_log_started = true
|
162
|
+
log_last_id = ""
|
163
|
+
if MongodbLoggerMain.tail_log_started
|
164
|
+
$.ajax
|
165
|
+
url: url
|
166
|
+
dataType: "json"
|
167
|
+
success: (data) ->
|
168
|
+
if data.time
|
169
|
+
$('#tail_logs_time').text(data.time)
|
170
|
+
if data.log_last_id?
|
171
|
+
log_last_id = data.log_last_id
|
172
|
+
if data.content? && data.content.length > 0
|
173
|
+
elements = $(data.content)
|
174
|
+
elements.addClass('newlog')
|
175
|
+
$('#logs_list tr:first').after(elements).effect("highlight", {}, 1000)
|
176
|
+
if data.collection_stats && $("#collection_stats").length > 0
|
177
|
+
$("#collection_stats").html(data.collection_stats)
|
178
|
+
if MongodbLoggerMain.tail_log_started
|
179
|
+
fcallback = -> MongodbLoggerMain.tail_logs(log_last_id)
|
180
|
+
setTimeout fcallback, 2000
|
181
|
+
# move using keys by logs
|
182
|
+
move_by_logs: (direction) ->
|
183
|
+
if $('#logs_list').length > 0 && $('#logs_list').find('tr.current').length > 0
|
184
|
+
current_element = $('#logs_list').find('tr.current')
|
185
|
+
switch direction
|
186
|
+
when 'begin'
|
187
|
+
element = $('#logs_list tr:first').next("tr")
|
188
|
+
if element.length > 0
|
189
|
+
element.find('td:first').trigger('click')
|
190
|
+
$(window).scrollTop(element.height() + element.offset().top - 100)
|
191
|
+
return false
|
192
|
+
when 'end'
|
193
|
+
element = $('#logs_list tr:last')
|
194
|
+
if element.length > 0
|
195
|
+
element.find('td:first').trigger('click')
|
196
|
+
$(window).scrollTop(element.height() + element.offset().top - 100)
|
197
|
+
return false
|
198
|
+
when 'down'
|
199
|
+
element = current_element.next("tr")
|
200
|
+
if element.length > 0
|
201
|
+
element.find('td:first').trigger('click')
|
202
|
+
if MongodbLoggerMain.is_scrolled_into_view(element)
|
203
|
+
$(window).scrollTop($(window).scrollTop() + element.height())
|
204
|
+
else
|
205
|
+
$(window).scrollTop(element.height() + element.offset().top - 100)
|
206
|
+
return false
|
207
|
+
when 'up'
|
208
|
+
element = current_element.prev("tr")
|
209
|
+
if element.length > 0
|
210
|
+
element.find('td:first').trigger('click')
|
211
|
+
if MongodbLoggerMain.is_scrolled_into_view(element)
|
212
|
+
$(window).scrollTop($(window).scrollTop() - element.height())
|
213
|
+
else
|
214
|
+
$(window).scrollTop(element.height() + element.offset().top - 100)
|
215
|
+
return false
|
216
|
+
# check in selected element is visible for user
|
217
|
+
is_scrolled_into_view: (elem) ->
|
218
|
+
docViewTop = $(window).scrollTop()
|
219
|
+
docViewBottom = docViewTop + $(window).height()
|
220
|
+
elemTop = $(elem).offset().top
|
221
|
+
elemBottom = elemTop + $(elem).height()
|
222
|
+
return ((docViewTop < elemTop) && (docViewBottom > elemBottom))
|
223
|
+
# charts ready for usage
|
224
|
+
init_analytic_charts: ->
|
225
|
+
MongodbLoggerMain.is_charts_ready = true
|
226
|
+
# build charts
|
227
|
+
build_analytic_charts: (data) ->
|
228
|
+
if MongodbLoggerMain.is_charts_ready is true
|
229
|
+
if data.data?
|
230
|
+
data_table = new google.visualization.DataTable()
|
231
|
+
data_table.addColumn('date', 'Date')
|
232
|
+
data_table.addColumn('number', 'Requests')
|
233
|
+
temp_data = []
|
234
|
+
for row in data.data
|
235
|
+
temp_data.push([new Date(row['_id'].year, row['_id'].month - 1, row['_id'].day), row.value.count])
|
236
|
+
|
237
|
+
data_table.addRows(temp_data)
|
238
|
+
chart = new google.visualization.LineChart(document.getElementById('analyticData'))
|
239
|
+
options =
|
240
|
+
title: $('#analytic_type option:selected').text()
|
241
|
+
width: '100%'
|
242
|
+
height: 600
|
243
|
+
vAxis:
|
244
|
+
title: $('#analytic_type option:selected').text()
|
245
|
+
chart.draw(data_table, options)
|
246
|
+
else
|
247
|
+
alert "Error of loading Google Charts. Sorry :("
|
248
|
+
|
249
|
+
$ ->
|
250
|
+
MongodbLoggerMain.init()
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module ContentFor
|
3
|
+
# Capture a block of content to be rendered later. For example:
|
4
|
+
#
|
5
|
+
# <% content_for :head do %>
|
6
|
+
# <script type="text/javascript" src="/foo.js"></script>
|
7
|
+
# <% end %>
|
8
|
+
#
|
9
|
+
# You can call +content_for+ multiple times with the same key
|
10
|
+
# (in the example +:head+), and when you render the blocks for
|
11
|
+
# that key all of them will be rendered, in the same order you
|
12
|
+
# captured them.
|
13
|
+
#
|
14
|
+
# Your blocks can also receive values, which are passed to them
|
15
|
+
# by <tt>yield_content</tt>
|
16
|
+
def content_for(key, &block)
|
17
|
+
content_blocks[key.to_sym] << block
|
18
|
+
end
|
19
|
+
|
20
|
+
# Render the captured blocks for a given key. For example:
|
21
|
+
#
|
22
|
+
# <head>
|
23
|
+
# <title>Example</title>
|
24
|
+
# <% yield_content :head %>
|
25
|
+
# </head>
|
26
|
+
#
|
27
|
+
# Would render everything you declared with <tt>content_for
|
28
|
+
# :head</tt> before closing the <tt><head></tt> tag.
|
29
|
+
#
|
30
|
+
# You can also pass values to the content blocks by passing them
|
31
|
+
# as arguments after the key:
|
32
|
+
#
|
33
|
+
# <% yield_content :head, 1, 2 %>
|
34
|
+
#
|
35
|
+
# Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered
|
36
|
+
# for <tt>:head</tt>.
|
37
|
+
#
|
38
|
+
# *NOTICE* that you call this without an <tt>=</tt> sign. IE,
|
39
|
+
# in a <tt><% %></tt> block, and not in a <tt><%= %></tt> block.
|
40
|
+
def yield_content(key, *args)
|
41
|
+
content_blocks[key.to_sym].map do |content|
|
42
|
+
if respond_to?(:block_is_haml?) && block_is_haml?(content)
|
43
|
+
capture_haml(*args, &content)
|
44
|
+
else
|
45
|
+
content.call(*args)
|
46
|
+
end
|
47
|
+
end.join
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def content_blocks
|
53
|
+
@content_blocks ||= Hash.new {|h,k| h[k] = [] }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
helpers ContentFor
|
58
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module MongodbLogger
|
4
|
+
module ServerModel
|
5
|
+
class AdditionalFilter
|
6
|
+
|
7
|
+
FORM_NAME = "more"
|
8
|
+
FIXED_PARAMS_ON_FORM = ['type', 'key', 'condition', 'value']
|
9
|
+
|
10
|
+
VAR_TYPES = ["integer", "string", "boolean", "date"]
|
11
|
+
|
12
|
+
VAR_TYPE_CONDITIONS = [
|
13
|
+
["equals", "not equals", "regexes", "<", "<=", ">=", ">"],
|
14
|
+
["equals", "not equals", "regexes", "<", "<=", ">=", ">"],
|
15
|
+
["equals", "exists"],
|
16
|
+
["<", "<=", ">=", ">"]
|
17
|
+
]
|
18
|
+
|
19
|
+
VAR_TYPE_VALUES = [
|
20
|
+
[],
|
21
|
+
[],
|
22
|
+
["true", "false"],
|
23
|
+
[]
|
24
|
+
]
|
25
|
+
|
26
|
+
attr_reader :form_data, :filter_model
|
27
|
+
|
28
|
+
def initialize(params, filter_model)
|
29
|
+
@filter_model = filter_model
|
30
|
+
@params = params
|
31
|
+
FIXED_PARAMS_ON_FORM.each do |key|
|
32
|
+
create_variable(key, nil)
|
33
|
+
end
|
34
|
+
@params.each do |k,v|
|
35
|
+
self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
|
36
|
+
end unless @params.blank?
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_variable(k, v)
|
40
|
+
self.instance_variable_set("@#{k}", v) ## create instance variable
|
41
|
+
self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
|
42
|
+
self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.get_type_index(type)
|
46
|
+
type.nil? ? 0 : VAR_TYPES.index(type)
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_type_index
|
50
|
+
@type.nil? ? 0 : VAR_TYPES.index(@type)
|
51
|
+
end
|
52
|
+
|
53
|
+
def selected_values
|
54
|
+
VAR_TYPE_VALUES[get_type_index]
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_selected_values?
|
58
|
+
!VAR_TYPE_VALUES[get_type_index].blank?
|
59
|
+
end
|
60
|
+
|
61
|
+
def form_name
|
62
|
+
"#{filter_model.form_name}[#{FORM_NAME}][]"
|
63
|
+
end
|
64
|
+
|
65
|
+
def mongo_conditions
|
66
|
+
data = Hash.new
|
67
|
+
return data if self.key.blank?
|
68
|
+
m_value = case self.type
|
69
|
+
when "integer"
|
70
|
+
self.value.to_i
|
71
|
+
when "boolean"
|
72
|
+
("true" == self.value || "1" == self.value) ? true : false
|
73
|
+
when "date"
|
74
|
+
val_date = Date.parse(self.value) rescue nil
|
75
|
+
Time.utc(val_date.year, val_date.month, val_date.day) unless val_date.nil?
|
76
|
+
else
|
77
|
+
self.value
|
78
|
+
end
|
79
|
+
data = case self.condition
|
80
|
+
when "equals"
|
81
|
+
{"#{self.key}" => m_value }
|
82
|
+
when "not equals"
|
83
|
+
{"#{self.key}" => { "$ne" => m_value }}
|
84
|
+
when "exists"
|
85
|
+
{"#{self.key}" => { "$exists" => m_value }}
|
86
|
+
when "regexes"
|
87
|
+
{"#{self.key}" => { "$regex" => m_value, "$options" => 'i' }}
|
88
|
+
when "<"
|
89
|
+
{"#{self.key}" => { "$lt" => m_value }}
|
90
|
+
when "<="
|
91
|
+
{"#{self.key}" => { "$lte" => m_value }}
|
92
|
+
when ">"
|
93
|
+
{"#{self.key}" => { "$gt" => m_value }}
|
94
|
+
when ">="
|
95
|
+
{"#{self.key}" => { "$gte" => m_value }}
|
96
|
+
else
|
97
|
+
Hash.new
|
98
|
+
end
|
99
|
+
data
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module MongodbLogger
|
2
|
+
module ServerModel
|
3
|
+
class Analytic
|
4
|
+
|
5
|
+
FIXED_PARAMS_ON_FORM = ['type', 'start_date', 'end_date']
|
6
|
+
ANALYTIC_TYPES = [[0, "Count of requests"], [1, "Count of errors"]]
|
7
|
+
ANALYTIC_HEADERS = [
|
8
|
+
{
|
9
|
+
:key => ["year", "month", "day"],
|
10
|
+
:value => ["count"]
|
11
|
+
},
|
12
|
+
{
|
13
|
+
:key => ["year", "month", "day"],
|
14
|
+
:value => ["count"]
|
15
|
+
}
|
16
|
+
]
|
17
|
+
attr_reader :params, :collection
|
18
|
+
FORM_NAME = "analytic"
|
19
|
+
|
20
|
+
|
21
|
+
def initialize(collection, params)
|
22
|
+
FIXED_PARAMS_ON_FORM.each do |key|
|
23
|
+
create_variable(key, nil)
|
24
|
+
end
|
25
|
+
@collection = collection
|
26
|
+
@params = params
|
27
|
+
@params.each do |k,v|
|
28
|
+
self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
|
29
|
+
end unless @params.blank?
|
30
|
+
|
31
|
+
# def values
|
32
|
+
self.start_date ||= Time.now.strftime('%Y-%m-%d')
|
33
|
+
self.end_date ||= Time.now.strftime('%Y-%m-%d')
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_variable(k, v)
|
37
|
+
self.instance_variable_set("@#{k}", v) ## create instance variable
|
38
|
+
self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
|
39
|
+
self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
|
40
|
+
end
|
41
|
+
|
42
|
+
def form_name
|
43
|
+
FORM_NAME
|
44
|
+
end
|
45
|
+
|
46
|
+
def count_of_requests(conditions, is_errors = false)
|
47
|
+
collection_name = "mongodb_logger_count_of_requests"
|
48
|
+
map = "function() { var key = {year: this.request_time.getFullYear(), month: this.request_time.getMonth() + 1, day: this.request_time.getDate()}; emit(key, {count: 1});}"
|
49
|
+
reduce_count = "function(key, values) { var sum = 0; values.forEach(function(f) { sum += f.count; }); return {count: sum};}"
|
50
|
+
if is_errors
|
51
|
+
collection_name = "mongodb_logger_count_of_errors"
|
52
|
+
conditions.merge!({:is_exception => true})
|
53
|
+
end
|
54
|
+
@collection.map_reduce(map, reduce_count, {:out => collection_name, :query => conditions, :sort => ['$natural', -1]})
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_data
|
58
|
+
m_start= Date.parse(self.start_date) rescue nil
|
59
|
+
m_start = Date.today if m_start.nil?
|
60
|
+
m_end = Date.parse(self.end_date) rescue nil
|
61
|
+
m_end = Date.today if m_end.nil?
|
62
|
+
|
63
|
+
conditions = { :request_time => {
|
64
|
+
'$gte' => Time.utc(m_start.year, m_start.month, m_start.day, 0, 0, 0),
|
65
|
+
'$lte' => Time.utc(m_end.year, m_end.month, m_end.day, 23, 59, 59)
|
66
|
+
}}
|
67
|
+
|
68
|
+
mapreduce_collection = case self.type.to_i
|
69
|
+
when 0
|
70
|
+
count_of_requests(conditions)
|
71
|
+
when 1
|
72
|
+
count_of_requests(conditions, true)
|
73
|
+
else
|
74
|
+
count_of_requests(conditions)
|
75
|
+
end
|
76
|
+
|
77
|
+
{:data => mapreduce_collection.find(), :headers => ANALYTIC_HEADERS[self.type.to_i]}
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'mongodb_logger/server/model/additional_filter'
|
2
|
+
|
3
|
+
module MongodbLogger
|
4
|
+
module ServerModel
|
5
|
+
class Filter
|
6
|
+
|
7
|
+
DEFAULT_LIMIT = 100
|
8
|
+
FIXED_PARAMS_ON_FORM = ['action', 'controller', 'ip', 'application_name', 'is_exception', 'limit']
|
9
|
+
attr_reader :params, :mongo_conditions
|
10
|
+
# dynamic filters
|
11
|
+
FORM_NAME = "filter"
|
12
|
+
attr_accessor :more_filters
|
13
|
+
|
14
|
+
def initialize(params)
|
15
|
+
FIXED_PARAMS_ON_FORM.each do |key|
|
16
|
+
create_variable(key, nil)
|
17
|
+
end
|
18
|
+
@params = params
|
19
|
+
@params.each do |k,v|
|
20
|
+
self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
|
21
|
+
end unless @params.blank?
|
22
|
+
# limits
|
23
|
+
self.limit = DEFAULT_LIMIT.to_s if self.limit.nil?
|
24
|
+
# dynamic filters
|
25
|
+
create_dynamic_filters
|
26
|
+
# build mongo conditions
|
27
|
+
build_mongo_conditions
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_variable(k, v)
|
31
|
+
self.instance_variable_set("@#{k}", v) ## create instance variable
|
32
|
+
self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
|
33
|
+
self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_dynamic_filters
|
37
|
+
self.more_filters = []
|
38
|
+
@params[AdditionalFilter::FORM_NAME].each do |filter|
|
39
|
+
self.more_filters << AdditionalFilter.new(filter, self)
|
40
|
+
end if !@params.blank? && @params[AdditionalFilter::FORM_NAME] && !@params[AdditionalFilter::FORM_NAME].blank?
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_mongo_conditions
|
44
|
+
@mongo_conditions = Hash.new
|
45
|
+
FIXED_PARAMS_ON_FORM.each do |param_key|
|
46
|
+
value = self.send param_key
|
47
|
+
mkey_val = case param_key
|
48
|
+
when 'is_exception'
|
49
|
+
(value ? true : nil)
|
50
|
+
when 'limit'
|
51
|
+
nil # skip
|
52
|
+
else
|
53
|
+
value
|
54
|
+
end
|
55
|
+
@mongo_conditions[param_key.to_s] = mkey_val if !mkey_val.nil? && !mkey_val.blank?
|
56
|
+
end
|
57
|
+
|
58
|
+
self.more_filters.each do |m_filter|
|
59
|
+
unless m_filter.mongo_conditions.blank?
|
60
|
+
cond = m_filter.mongo_conditions
|
61
|
+
if @mongo_conditions[m_filter.key] && @mongo_conditions[m_filter.key].is_a?(Hash)
|
62
|
+
@mongo_conditions[m_filter.key].merge!(cond[m_filter.key])
|
63
|
+
else
|
64
|
+
@mongo_conditions.merge!(m_filter.mongo_conditions)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end unless self.more_filters.blank?
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_mongo_conditions
|
71
|
+
@mongo_conditions
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_mongo_limit
|
75
|
+
self.limit.to_i
|
76
|
+
end
|
77
|
+
|
78
|
+
def form_name
|
79
|
+
FORM_NAME
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# stolen from http://github.com/cschneid/irclogger/blob/master/lib/partials.rb
|
2
|
+
# and made a lot more robust by me
|
3
|
+
# this implementation uses erb by default. if you want to use any other template mechanism
|
4
|
+
# then replace `erb` on line 13 and line 17 with `haml` or whatever
|
5
|
+
module Sinatra::Partials
|
6
|
+
def partial(template, *args)
|
7
|
+
template_array = template.to_s.split('/')
|
8
|
+
template = template_array[0..-2].join('/') + "/_#{template_array[-1]}"
|
9
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
10
|
+
options.merge!(:layout => false)
|
11
|
+
locals = options[:locals] || {}
|
12
|
+
if collection = options.delete(:collection)
|
13
|
+
collection.inject([]) do |buffer, member|
|
14
|
+
buffer << erb(:"#{template}", options.merge(:layout =>
|
15
|
+
false, :locals => {template_array[-1].to_sym => member}.merge(locals)))
|
16
|
+
end.join("\n")
|
17
|
+
elsif partial_object = options.delete(:object)
|
18
|
+
erb(:"#{template}", options.merge(:layout =>
|
19
|
+
false, :locals => {template_array[-1].to_sym => partial_object}).merge(locals))
|
20
|
+
else
|
21
|
+
erb(:"#{template}", options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
((function(){var a;a=typeof global!="undefined"&&global!==null?global:window,a.MongodbLoggerMain={tail_logs_url:null,tail_log_started:!1,log_info_offset:null,log_info_padding:15,is_charts_ready:!1,init:function(){var a=this;return $(document).ajaxStart(function(){return $("#ajax_loader").show()}),$(document).ajaxStop(function(){return $("#ajax_loader").hide()}),$(document).on("click","#tail_logs_link",function(a){return MongodbLoggerMain.tail_logs_url=$(a.target).attr("data-url"),$("#tail_logs_block").addClass("started"),MongodbLoggerMain.tail_logs(null),!1}),$(document).on("click","#tail_logs_stop_link",function(a){return MongodbLoggerMain.tail_log_started=!1,$("#tail_logs_block").removeClass("started"),!1}),$(document).on("click",".log_info",function(a){var b,c;return b=$(a.target),c=b.data("url"),c==null&&(c=b.parent("tr").data("url")),c!=null&&(b.parents("table").find("tr").removeClass("current"),b.parent("tr").addClass("current"),$("#log_info").load(c)),!1}),$(document).on("click","div.filter-toggle",function(a){return $("div.filter").slideToggle(),$("div.filter-toggle span.arrow-down").toggleClass("rotate")}),$(document).on("click","#add_more_filter",function(a){var b;return b=$(a.target).attr("href"),$.ajax({url:b,success:function(a){var b;return b=$("<li></li>").html(a),$("#more_filter_list").append(b)}}),!1}),$(document).on("change","select.filter_type",function(a){var b,c;return b=$(a.target),c=b.attr("rel")+"/"+b.val(),$.ajax({url:c,dataType:"json",success:function(a){var c,d,e=this;c="",d="",$.each(a.conditions,function(a,b){return c+='<option value="'+b+'">'+b+"</option>"}),b.parents("div.filter_block").find("select.filter_conditions").empty().append(c),a.values.length>0?(d='<select id="filter[more][]_value" name="filter[more][][value]">',$.each(a.values,function(a,b){return d+='<option value="'+b+'">'+b+"</option>"}),d+="</select>"):d='<input type="text" name="filter[more][][value]" value="" placeholder="value">',b.parents("div.filter_block").find("div.filter_values").html(d);if("date"===b.val())return b.parents("div.filter_block").find("div.filter_values input").datepicker({dateFormat:"yy-mm-dd",changeMonth:!0,changeYear:!0,yearRange:"c-50:c+10"})}}),!1}),$(document).on("click",".close_more_filter",function(a){return $(a.target).parents("li").remove(),!1}),$(document).on("click","li.message_tab",function(a){var b,c;b=$(a.target),c=b.attr("data-tab");if(c!=null)return $("li.message_tab").removeClass("active"),$("pre.tab_content").addClass("hidden"),b.addClass("active"),$("."+c).removeClass("hidden")}),$(document).on("submit","#analyticForm",function(a){var b,c,d;return c=$("#analyticForm"),d=c.attr("action"),b=c.serializeArray(),$.ajax({url:d,dataType:"json",data:b,type:"POST",success:function(a,b,c){return MongodbLoggerMain.build_analytic_charts(a)}}),!1}),$(document).on("keydown","*",function(a){console.log(a.keyCode);switch(a.keyCode){case 37:return MongodbLoggerMain.move_by_logs("begin");case 38:return MongodbLoggerMain.move_by_logs("up");case 39:return MongodbLoggerMain.move_by_logs("end");case 40:return MongodbLoggerMain.move_by_logs("down")}}),this.init_pjax(),this.init_on_pages()},init_pjax:function(){var a=this;return $("a[data-pjax]").pjax(),$("body").bind("pjax:start",function(){return $("#ajax_loader").show()}),$("body").bind("pjax:end",function(){return $("#ajax_loader").hide(),MongodbLoggerMain.tail_log_started=!1,$(window).scrollTop()>100&&$("html, body").stop().animate({scrollTop:0},"slow"),MongodbLoggerMain.init_on_pages()})},init_on_pages:function(){var a=this;$("pre code").each(function(a,b){return hljs.highlightBlock(b," ")}),$(".datepicker, .filter_values input.date").datepicker({dateFormat:"yy-mm-dd",changeMonth:!0,changeYear:!0,yearRange:"c-50:c+10"});if($("#log_info").length>0)return MongodbLoggerMain.log_info_offset=$("#log_info").offset(),$(window).scroll(function(){return $(window).scrollTop()>MongodbLoggerMain.log_info_offset.top?$("#log_info").stop().animate({marginTop:$(window).scrollTop()-MongodbLoggerMain.log_info_offset.top+MongodbLoggerMain.log_info_padding}):$("#log_info").stop().animate({marginTop:0})})},tail_logs:function(a){var b;b=MongodbLoggerMain.tail_logs_url,a!=null&&a.length>0?b=MongodbLoggerMain.tail_logs_url+"/"+a:(MongodbLoggerMain.tail_log_started=!0,a="");if(MongodbLoggerMain.tail_log_started)return $.ajax({url:b,dataType:"json",success:function(b){var c,d;b.time&&($("#tail_logs_time").text(b.time),b.log_last_id!=null&&(a=b.log_last_id),b.content!=null&&b.content.length>0&&(c=$(b.content),c.addClass("newlog"),$("#logs_list tr:first").after(c).effect("highlight",{},1e3)),b.collection_stats&&$("#collection_stats").length>0&&$("#collection_stats").html(b.collection_stats));if(MongodbLoggerMain.tail_log_started)return d=function(){return MongodbLoggerMain.tail_logs(a)},setTimeout(d,2e3)}})},move_by_logs:function(a){var b,c;if($("#logs_list").length>0&&$("#logs_list").find("tr.current").length>0){b=$("#logs_list").find("tr.current");switch(a){case"begin":c=$("#logs_list tr:first").next("tr");if(c.length>0)return c.find("td:first").trigger("click"),$(window).scrollTop(c.height()+c.offset().top-100),!1;break;case"end":c=$("#logs_list tr:last");if(c.length>0)return c.find("td:first").trigger("click"),$(window).scrollTop(c.height()+c.offset().top-100),!1;break;case"down":c=b.next("tr");if(c.length>0)return c.find("td:first").trigger("click"),MongodbLoggerMain.is_scrolled_into_view(c)?$(window).scrollTop($(window).scrollTop()+c.height()):$(window).scrollTop(c.height()+c.offset().top-100),!1;break;case"up":c=b.prev("tr");if(c.length>0)return c.find("td:first").trigger("click"),MongodbLoggerMain.is_scrolled_into_view(c)?$(window).scrollTop($(window).scrollTop()-c.height()):$(window).scrollTop(c.height()+c.offset().top-100),!1}}},is_scrolled_into_view:function(a){var b,c,d,e;return c=$(window).scrollTop(),b=c+$(window).height(),e=$(a).offset().top,d=e+$(a).height(),c<e&&b>d},init_analytic_charts:function(){return MongodbLoggerMain.is_charts_ready=!0},build_analytic_charts:function(a){var b,c,d,e,f,g,h,i;if(MongodbLoggerMain.is_charts_ready!==!0)return alert("Error of loading Google Charts. Sorry :(");if(a.data!=null){c=new google.visualization.DataTable,c.addColumn("date","Date"),c.addColumn("number","Requests"),f=[],i=a.data;for(g=0,h=i.length;g<h;g++)e=i[g],f.push([new Date(e._id.year,e._id.month-1,e._id.day),e.value.count]);return c.addRows(f),b=new google.visualization.LineChart(document.getElementById("analyticData")),d={title:$("#analytic_type option:selected").text(),width:"100%",height:600,vAxis:{title:$("#analytic_type option:selected").text()}},b.draw(c,d)}}},$(function(){return MongodbLoggerMain.init()})})).call(this)
|