mongodb_logger 0.2.6-jruby
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|