mongodb_logger 0.2.6-jruby

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.gitignore +20 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +19 -0
  4. data/CHANGELOG.md +30 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE +22 -0
  7. data/README.md +207 -0
  8. data/Rakefile +169 -0
  9. data/SUPPORTED_RAILS_VERSIONS +17 -0
  10. data/TESTING.md +24 -0
  11. data/bin/mongodb_logger_web +24 -0
  12. data/config.ru +17 -0
  13. data/examples/server_config.yml +5 -0
  14. data/features/mongodb_logger_web.feature +14 -0
  15. data/features/rails.feature +12 -0
  16. data/features/step_definitions/mongodb_logger_web_steps.rb +45 -0
  17. data/features/step_definitions/rails_application_steps.rb +65 -0
  18. data/features/support/env.rb +15 -0
  19. data/features/support/rails.rb +98 -0
  20. data/features/support/terminal.rb +95 -0
  21. data/lib/mongodb_logger/initializer_mixin.rb +26 -0
  22. data/lib/mongodb_logger/logger.rb +239 -0
  23. data/lib/mongodb_logger/railtie.rb +12 -0
  24. data/lib/mongodb_logger/replica_set_helper.rb +19 -0
  25. data/lib/mongodb_logger/server/coffee/logs.coffee +250 -0
  26. data/lib/mongodb_logger/server/content_for.rb +58 -0
  27. data/lib/mongodb_logger/server/model/additional_filter.rb +104 -0
  28. data/lib/mongodb_logger/server/model/analytic.rb +82 -0
  29. data/lib/mongodb_logger/server/model/filter.rb +84 -0
  30. data/lib/mongodb_logger/server/partials.rb +24 -0
  31. data/lib/mongodb_logger/server/public/images/arrow-down.png +0 -0
  32. data/lib/mongodb_logger/server/public/images/arrow-up.png +0 -0
  33. data/lib/mongodb_logger/server/public/images/date.png +0 -0
  34. data/lib/mongodb_logger/server/public/images/external.png +0 -0
  35. data/lib/mongodb_logger/server/public/images/failure.png +0 -0
  36. data/lib/mongodb_logger/server/public/images/logo.png +0 -0
  37. data/lib/mongodb_logger/server/public/images/mongodb.png +0 -0
  38. data/lib/mongodb_logger/server/public/images/newlog.png +0 -0
  39. data/lib/mongodb_logger/server/public/images/play-icon.png +0 -0
  40. data/lib/mongodb_logger/server/public/images/spinner.gif +0 -0
  41. data/lib/mongodb_logger/server/public/images/spinner2.gif +0 -0
  42. data/lib/mongodb_logger/server/public/images/stop-icon.png +0 -0
  43. data/lib/mongodb_logger/server/public/images/success.png +0 -0
  44. data/lib/mongodb_logger/server/public/javascripts/logs.js +1 -0
  45. data/lib/mongodb_logger/server/public/javascripts/vendors/highlight.pack.js +1 -0
  46. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-1.7.1.min.js +4 -0
  47. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-ui-1.8.16.min.js +791 -0
  48. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery.pjax.min.js +6 -0
  49. data/lib/mongodb_logger/server/public/stylesheets/all.css +12 -0
  50. data/lib/mongodb_logger/server/public/stylesheets/grids.css +18 -0
  51. data/lib/mongodb_logger/server/public/stylesheets/group-buttons.css +81 -0
  52. data/lib/mongodb_logger/server/public/stylesheets/group-forms.css +59 -0
  53. data/lib/mongodb_logger/server/public/stylesheets/group-headers.css +8 -0
  54. data/lib/mongodb_logger/server/public/stylesheets/group-tables.css +87 -0
  55. data/lib/mongodb_logger/server/public/stylesheets/highlight/zenburn.css +115 -0
  56. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
  57. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_100_f5f0e5_1x400.png +0 -0
  58. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_25_cb842e_1x400.png +0 -0
  59. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_70_ede4d4_1x400.png +0 -0
  60. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_100_f4f0ec_1x100.png +0 -0
  61. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_65_fee4bd_1x100.png +0 -0
  62. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_75_f5f5b5_1x100.png +0 -0
  63. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_inset-soft_100_f4f0ec_1x100.png +0 -0
  64. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_c47a23_256x240.png +0 -0
  65. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_cb672b_256x240.png +0 -0
  66. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f08000_256x240.png +0 -0
  67. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f35f07_256x240.png +0 -0
  68. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ff7519_256x240.png +0 -0
  69. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ffffff_256x240.png +0 -0
  70. data/lib/mongodb_logger/server/public/stylesheets/humanity/jquery-ui-1.8.16.custom.css +568 -0
  71. data/lib/mongodb_logger/server/public/stylesheets/layout.css +205 -0
  72. data/lib/mongodb_logger/server/public/stylesheets/library.css +330 -0
  73. data/lib/mongodb_logger/server/public/stylesheets/reset.css +43 -0
  74. data/lib/mongodb_logger/server/public/stylesheets/spaces.css +42 -0
  75. data/lib/mongodb_logger/server/view_helpers.rb +113 -0
  76. data/lib/mongodb_logger/server/views/analytics.erb +61 -0
  77. data/lib/mongodb_logger/server/views/error.erb +2 -0
  78. data/lib/mongodb_logger/server/views/layout.erb +47 -0
  79. data/lib/mongodb_logger/server/views/overview.erb +119 -0
  80. data/lib/mongodb_logger/server/views/shared/_collection_stats.erb +14 -0
  81. data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +34 -0
  82. data/lib/mongodb_logger/server/views/shared/_log.erb +8 -0
  83. data/lib/mongodb_logger/server/views/shared/_log_info.erb +27 -0
  84. data/lib/mongodb_logger/server/views/shared/_message_tabs.erb +15 -0
  85. data/lib/mongodb_logger/server/views/shared/_tabs.erb +4 -0
  86. data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +13 -0
  87. data/lib/mongodb_logger/server/views/shared/_top_panel.erb +7 -0
  88. data/lib/mongodb_logger/server/views/show_log.erb +105 -0
  89. data/lib/mongodb_logger/server.rb +174 -0
  90. data/lib/mongodb_logger/server_config.rb +77 -0
  91. data/lib/mongodb_logger/version.rb +3 -0
  92. data/lib/mongodb_logger.rb +31 -0
  93. data/mongodb_logger.gemspec +44 -0
  94. data/mongodb_logger.java.gemspec +42 -0
  95. data/spec/javascripts/MongodbLoggerMainSpec.js +13 -0
  96. data/spec/javascripts/helpers/SpecHelper.js +3 -0
  97. data/spec/javascripts/support/jasmine.yml +77 -0
  98. data/spec/javascripts/support/jasmine_config.rb +23 -0
  99. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  100. data/test/active_record.rb +13 -0
  101. data/test/config/samples/database.yml +9 -0
  102. data/test/config/samples/database_no_file_logging.yml +10 -0
  103. data/test/config/samples/database_replica_set.yml +12 -0
  104. data/test/config/samples/database_with_auth.yml +9 -0
  105. data/test/config/samples/database_with_collection.yml +8 -0
  106. data/test/config/samples/mongodb_logger.yml +2 -0
  107. data/test/config/samples/mongoid.yml +30 -0
  108. data/test/config/samples/server_config.yml +3 -0
  109. data/test/rails/app/controllers/order_controller.rb +23 -0
  110. data/test/rails/test/functional/order_controller_test.rb +116 -0
  111. data/test/rails/test/test_helper.rb +10 -0
  112. data/test/rails.rb +22 -0
  113. data/test/shoulda_macros/log_macros.rb +13 -0
  114. data/test/test.sh +6 -0
  115. data/test/test_helper.rb +89 -0
  116. data/test/unit/mongodb_logger_replica_test.rb +56 -0
  117. data/test/unit/mongodb_logger_test.rb +270 -0
  118. 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
@@ -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)