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.
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)