mongodb_logger 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.rvmrc +1 -1
  2. data/.travis.yml +13 -7
  3. data/Gemfile +1 -7
  4. data/README.md +128 -117
  5. data/Rakefile +11 -40
  6. data/SUPPORTED_RAILS_VERSIONS +3 -1
  7. data/app/assets/javascripts/analytics.js.coffee +66 -0
  8. data/app/assets/javascripts/logs.js.coffee +107 -164
  9. data/app/assets/javascripts/mongodb_logger.js +11 -2
  10. data/app/assets/javascripts/vendors/jquery-1.8.3.min.js +2 -0
  11. data/app/assets/javascripts/vendors/jquery-ui-1.9.2.min.js +6 -0
  12. data/app/assets/javascripts/vendors/jquery.pjax.min.js +13 -6
  13. data/app/assets/javascripts/vendors/rickshaw/d3.layout.min.js +1 -0
  14. data/app/assets/javascripts/vendors/rickshaw/d3.min.js +2 -0
  15. data/app/assets/javascripts/vendors/rickshaw/rickshaw.js +2637 -0
  16. data/app/assets/stylesheets/humanity/{jquery-ui-1.8.16.custom.css → jquery-ui-1.9.2.custom.css} +0 -0
  17. data/app/assets/stylesheets/layout.css +1 -1
  18. data/app/assets/stylesheets/library.css.erb +2 -2
  19. data/app/assets/stylesheets/mongodb_logger.css +2 -1
  20. data/app/assets/stylesheets/rickshaw/rickshaw.css +307 -0
  21. data/bin/mongodb_logger_web +1 -2
  22. data/config.ru +8 -1
  23. data/examples/server_config.yml +1 -2
  24. data/features/mongodb_logger_web.feature +1 -1
  25. data/features/step_definitions/mongodb_logger_web_steps.rb +18 -12
  26. data/lib/mongodb_logger.rb +6 -2
  27. data/lib/mongodb_logger/adapters.rb +3 -0
  28. data/lib/mongodb_logger/adapters/base.rb +45 -0
  29. data/lib/mongodb_logger/adapters/mongo.rb +91 -0
  30. data/lib/mongodb_logger/adapters/moped.rb +95 -0
  31. data/lib/mongodb_logger/logger.rb +39 -71
  32. data/lib/mongodb_logger/replica_set_helper.rb +11 -2
  33. data/lib/mongodb_logger/server.rb +15 -36
  34. data/lib/mongodb_logger/server/model/analytic.rb +54 -37
  35. data/lib/mongodb_logger/server/view_helpers.rb +5 -1
  36. data/lib/mongodb_logger/server/views/analytics.erb +8 -7
  37. data/lib/mongodb_logger/server/views/layout.erb +4 -11
  38. data/lib/mongodb_logger/server/views/overview.erb +6 -6
  39. data/lib/mongodb_logger/server/views/shared/_collection_stats.erb +4 -4
  40. data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +1 -1
  41. data/lib/mongodb_logger/server/views/shared/_log_info.erb +1 -1
  42. data/lib/mongodb_logger/server/views/shared/_tabs.erb +2 -2
  43. data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +4 -4
  44. data/lib/mongodb_logger/server/views/shared/_top_panel.erb +1 -1
  45. data/lib/mongodb_logger/server/views/show_log.erb +11 -1
  46. data/lib/mongodb_logger/server_config.rb +17 -66
  47. data/lib/mongodb_logger/version.rb +1 -1
  48. data/mongodb_logger.gemspec +19 -20
  49. data/spec/javascripts/MongodbLoggerMainSpec.js +2 -2
  50. data/spec/javascripts/support/jasmine.yml +5 -5
  51. data/test/Gemfile_tests +2 -1
  52. data/test/config/samples/database.yml +3 -1
  53. data/test/config/samples/database_no_file_logging.yml +3 -1
  54. data/test/shoulda_macros/log_macros.rb +1 -1
  55. data/test/test.sh +5 -5
  56. data/test/test_helper.rb +26 -18
  57. data/test/unit/mongodb_logger_test.rb +21 -20
  58. metadata +70 -88
  59. data/app/assets/javascripts/vendors/jquery-1.7.1.min.js +0 -4
  60. data/app/assets/javascripts/vendors/jquery-ui-1.8.16.min.js +0 -791
  61. data/mongodb_logger.java.gemspec +0 -43
@@ -2,18 +2,27 @@ module MongodbLogger
2
2
  module ReplicaSetHelper
3
3
  # Use retry alg from mongodb to gobble up connection failures during replica set master vote
4
4
  # Defaults to a 10 second wait
5
- def rescue_connection_failure(max_retries=40)
5
+ def rescue_connection_failure(max_retries = 40)
6
6
  success = false
7
7
  retries = 0
8
8
  while !success
9
9
  begin
10
10
  yield
11
11
  success = true
12
- rescue Mongo::ConnectionFailure => e
12
+ rescue mongo_error_type => e
13
13
  raise e if (retries += 1) >= max_retries
14
14
  sleep 0.25
15
15
  end
16
16
  end
17
17
  end
18
+
19
+ private
20
+
21
+ def mongo_error_type
22
+ return @mongo_error if @mongo_error
23
+ @mongo_error = Mongo::ConnectionFailure if defined?(Mongo) && defined?(Mongo::ConnectionFailure)
24
+ @mongo_error = Moped::SocketError if defined?(Moped) && defined?(Moped::SocketError)
25
+ @mongo_error
26
+ end
18
27
  end
19
28
  end
@@ -57,14 +57,8 @@ module MongodbLogger
57
57
 
58
58
  before do
59
59
  begin
60
- if ServerConfig.db && ServerConfig.collection
61
- @db = ServerConfig.db
62
- @collection = ServerConfig.collection
63
- else
64
- @db = Rails.logger.mongo_connection
65
- @collection = @db[Rails.logger.mongo_collection_name]
66
- end
67
- @collection_stats = @collection.stats
60
+ @mongo_adapter = (ServerConfig.mongo_adapter ? ServerConfig.mongo_adapter : Rails.logger.mongo_adapter)
61
+ @collection_stats = @mongo_adapter.collection_stats
68
62
  rescue => e
69
63
  erb :error, {:layout => false}, :error => "Can't connect to MongoDB!"
70
64
  return false
@@ -89,33 +83,19 @@ module MongodbLogger
89
83
  %w( overview ).each do |page|
90
84
  get "/#{page}/?" do
91
85
  @filter = ServerModel::Filter.new(params[:filter])
92
- @logs = @collection.find(@filter.get_mongo_conditions).sort('$natural', -1).limit(@filter.get_mongo_limit)
86
+ @logs = @mongo_adapter.filter_by_conditions(@filter)
93
87
  show page, !request.xhr?
94
88
  end
95
89
  end
96
90
 
97
91
  get "/tail_logs/?:log_last_id?" do
98
- buffer = []
99
- last_id = nil
100
- if params[:log_last_id] && !params[:log_last_id].blank?
101
- log_last_id = params[:log_last_id]
102
- tail = Mongo::Cursor.new(@collection, :tailable => true, :order => [['$natural', 1]],
103
- :selector => {'_id' => { '$gt' => BSON::ObjectId(log_last_id) }})
104
- while log = tail.next
105
- buffer << partial(:"shared/log", :object => log)
106
- log_last_id = log["_id"].to_s
107
- end
108
- buffer.reverse!
109
- else
110
- @log = @collection.find_one({}, {:sort => ['$natural', -1]})
111
- log_last_id = @log["_id"].to_s unless @log.blank?
112
- end
113
-
114
- content_type :json
115
- { :log_last_id => log_last_id,
116
- :time => Time.now.strftime("%F %T"),
117
- :content => buffer.join("\n"),
118
- :collection_stats => partial(:"shared/collection_stats", :object => @collection_stats) }.to_json
92
+ @info = @mongo_adapter.tail_log_from_params(params)
93
+ @info.merge!(
94
+ :content => @info[:logs].map{|log| partial(:"shared/log", :object => log) }.join("\n"),
95
+ :collection_stats => partial(:"shared/collection_stats", :object => @collection_stats)
96
+ )
97
+ content_type :json
98
+ @info.to_json
119
99
  end
120
100
 
121
101
  get "/changed_filter/:type" do
@@ -133,13 +113,13 @@ module MongodbLogger
133
113
 
134
114
  # log info
135
115
  get "/log/:id" do
136
- @log = @collection.find_one(BSON::ObjectId(params[:id]))
116
+ @log = @mongo_adapter.find_by_id(params[:id])
137
117
  show :show_log, !request.xhr?
138
118
  end
139
119
 
140
120
  # log info right
141
121
  get "/log_info/:id" do
142
- @log = @collection.find_one(BSON::ObjectId(params[:id]))
122
+ @log = @mongo_adapter.find_by_id(params[:id])
143
123
  partial(:"shared/log_info", :object => @log)
144
124
  end
145
125
 
@@ -152,14 +132,13 @@ module MongodbLogger
152
132
  # analytics
153
133
  %w( analytics ).each do |page|
154
134
  get "/#{page}/?" do
155
- @analytic = ServerModel::Analytic.new(@collection, params[:analytic])
135
+ @analytic = ServerModel::Analytic.new(@mongo_adapter, params[:analytic])
156
136
  show page, !request.xhr?
157
137
  end
158
138
  post "/#{page}/?" do
159
- @analytic = ServerModel::Analytic.new(@collection, params[:analytic])
160
- @analytic_data = @analytic.get_data
139
+ @analytic = ServerModel::Analytic.new(@mongo_adapter, params[:analytic])
161
140
  content_type :json
162
- @analytic_data.to_json
141
+ @analytic.get_data.to_json
163
142
  end
164
143
  end
165
144
 
@@ -2,32 +2,22 @@ module MongodbLogger
2
2
  module ServerModel
3
3
  class Analytic
4
4
 
5
- FIXED_PARAMS_ON_FORM = ['type', 'start_date', 'end_date']
5
+ FIXED_PARAMS_ON_FORM = ['type', 'unit', 'start_date', 'end_date']
6
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
7
+ ANALYTIC_UNITS = [[0, "Month"], [1, "Day"], [2, "Hour"]]
8
+
9
+ attr_reader :params, :mongo_adapter
18
10
  FORM_NAME = "analytic"
19
11
 
20
-
21
- def initialize(collection, params)
12
+ def initialize(mongo_adapter, params)
22
13
  FIXED_PARAMS_ON_FORM.each do |key|
23
14
  create_variable(key, nil)
24
15
  end
25
- @collection = collection
16
+ @mongo_adapter = mongo_adapter
26
17
  @params = params
27
18
  @params.each do |k,v|
28
19
  self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
29
20
  end unless @params.blank?
30
-
31
21
  # def values
32
22
  self.start_date ||= Time.now.strftime('%Y-%m-%d')
33
23
  self.end_date ||= Time.now.strftime('%Y-%m-%d')
@@ -43,38 +33,65 @@ module MongodbLogger
43
33
  FORM_NAME
44
34
  end
45
35
 
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})
36
+ def calculate_default_map_reduce(params = {})
37
+ addinional_params = case self.unit.to_i
38
+ when 1
39
+ "day: this.request_time.getDate()"
40
+ when 2
41
+ "day: this.request_time.getDate(), hour: this.request_time.getHours() + 1"
42
+ else
43
+ ""
53
44
  end
54
- @collection.map_reduce(map, reduce_count, {:out => collection_name, :query => conditions, :sort => ['$natural', -1]})
45
+ map = <<EOF
46
+ function() {
47
+ var key = {
48
+ year: this.request_time.getFullYear(),
49
+ month: this.request_time.getMonth() + 1,
50
+ #{addinional_params}
51
+ };
52
+ emit(key, {count: 1});
53
+ }
54
+ EOF
55
+ reduce = <<EOF
56
+ function(key, values) {
57
+ var sum = 0;
58
+ values.forEach(function(f) {
59
+ sum += f.count;
60
+ });
61
+ return {count: sum};
62
+ }
63
+ EOF
64
+ case self.type.to_i
65
+ when 1
66
+ params[:conditions].merge!({:is_exception => true})
67
+ else
68
+ # nothing
69
+ end
70
+
71
+ @mongo_adapter.calculate_mapreduce(map, reduce, {:conditions => params[:conditions]})
55
72
  end
56
73
 
57
74
  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?
75
+ m_start= Date.parse(self.start_date) rescue Date.today
76
+ m_end = Date.parse(self.end_date) rescue Date.today
62
77
 
63
78
  conditions = { :request_time => {
64
79
  '$gte' => Time.utc(m_start.year, m_start.month, m_start.day, 0, 0, 0),
65
80
  '$lte' => Time.utc(m_end.year, m_end.month, m_end.day, 23, 59, 59)
66
81
  }}
67
82
 
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
83
+ all_data = calculate_default_map_reduce(
84
+ :conditions => conditions
85
+ )
76
86
 
77
- {:data => mapreduce_collection.find(), :headers => ANALYTIC_HEADERS[self.type.to_i]}
87
+ {
88
+ :data => (all_data ? all_data.first.last : []),
89
+ :headers => {
90
+ :key => ["year", "month", "day", "hour"],
91
+ :value => ["count"]
92
+ },
93
+ unit: self.unit
94
+ }
78
95
  end
79
96
 
80
97
  end
@@ -11,6 +11,10 @@ module Sinatra::ViewHelpers
11
11
  end
12
12
  end
13
13
 
14
+ def percent_of_userd_memory(collection_stats)
15
+ ((collection_stats[:size] / collection_stats[:storageSize]) * 100).round
16
+ end
17
+
14
18
  def string_from_log_message(message)
15
19
  message.is_a?(Array) ? message.join("\n") : message.to_s
16
20
  end
@@ -19,7 +23,7 @@ module Sinatra::ViewHelpers
19
23
  meta_data = Hash.new
20
24
  log.each do |key, val|
21
25
  # predefined fields
22
- next if [:_id, :messages, :request_time, :ip, :runtime, :application_name, :is_exception, :params, :method, :controller, :action, :path, :url].include?(key.to_sym)
26
+ next if [:_id, :messages, :request_time, :ip, :runtime, :application_name, :is_exception, :params, :method, :controller, :action, :session, :path, :url].include?(key.to_sym)
23
27
  meta_data[key] = val
24
28
  end
25
29
  meta_data
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <div class="unit size1of2">
15
15
  <div class="prm">
16
- <%#= text_field_tag @filter, :action, :placeholder => "Action" %>
16
+ <%= select_tag @analytic, :unit, MongodbLogger::ServerModel::Analytic::ANALYTIC_UNITS %>
17
17
  </div>
18
18
  </div>
19
19
  </div>
@@ -38,11 +38,12 @@
38
38
  </form>
39
39
  </div> <!-- filter -->
40
40
 
41
- <div class="filter-toggle"><span class="arrow-down">Analyze</span></div>
42
-
43
- <div id="analyticData">
44
- <div class="pal txtC">
45
- Select what to analyze
41
+ <div class="filter_toggle filter-toggle"><span class="arrow-down">Analyze</span></div>
42
+ <div style="margin: 10px">
43
+ <div id="analyticData">
44
+ <div class="pal txtC">
45
+ Select what to analyze
46
+ </div>
46
47
  </div>
47
48
  </div>
48
49
 
@@ -51,7 +52,7 @@
51
52
  <div class="unit size1of4">
52
53
  <div class="details">
53
54
 
54
- <div id="log_info">
55
+ <div id="logInfo">
55
56
  <div class="pale h2 pal txtC">
56
57
  Comming soon...
57
58
  </div> <!-- pale h2 -->
@@ -10,19 +10,19 @@
10
10
  <div class="wrapper">
11
11
  <div class="unit-right stats">
12
12
  <div class="unit size2of3">
13
- <div class="ptxs pls"><strong>DB:</strong> <%=h @db.name %></div>
14
- <div class="pls"><strong>Collection:</strong> <%=h @collection.name %></div>
13
+ <div class="ptxs pls"><strong>DB:</strong> <%=h @collection_stats[:db_name] %></div>
14
+ <div class="pls"><strong>Collection:</strong> <%=h @collection_stats[:collection] %></div>
15
15
  </div> <!-- unit -->
16
16
  <div id="collection_stats">
17
17
  <%= partial(:"shared/collection_stats", :object => @collection_stats) %>
18
18
  </div>
19
19
  </div>
20
- <a href="<%=h url_path("overview") %>" class="logo" data-pjax='#main_pjax'><img src="<%= asset_path 'logo.png' %>" alt="MongoDB Logger"></a>
20
+ <a href="<%=h url_path("overview") %>" class="logo" data-pjax='#mainPjax'><img src="<%= asset_path 'logo.png' %>" alt="MongoDB Logger"></a>
21
21
  </div> <!-- wrapper -->
22
22
  </div> <!-- header -->
23
23
  <div class="content">
24
24
  <div class="wrapper">
25
- <div id="main_pjax" class="mainbox">
25
+ <div id="mainPjax" class="mainbox">
26
26
  <%= yield %>
27
27
  </div> <!-- mainbox -->
28
28
  </div> <!-- wrapper -->
@@ -32,12 +32,5 @@
32
32
  <!-- scripts -->
33
33
  <script src="<%= asset_path('mongodb_logger.js') %>" type="text/javascript"></script>
34
34
 
35
- <!-- charts -->
36
- <script type="text/javascript" src="https://www.google.com/jsapi"></script>
37
- <script type="text/javascript">
38
- google.load('visualization', '1', {'packages':['corechart']});
39
- google.setOnLoadCallback(MongodbLoggerMain.init_analytic_charts);
40
- </script>
41
-
42
35
  </body>
43
36
  </html>
@@ -1,4 +1,4 @@
1
- <% if @collection_stats["capped"] && (1 == @collection_stats["capped"] || true == @collection_stats["capped"]) %>
1
+ <% if @collection_stats[:is_capped] %>
2
2
  <% content_for :right_top_panel do %>
3
3
  <%= partial(:"shared/tail_panel") %>
4
4
  <% end %>
@@ -49,7 +49,7 @@
49
49
  </div> <!-- outer -->
50
50
 
51
51
  <div class="outer">
52
- <ul id="more_filter_list">
52
+ <ul id="moreFilterList">
53
53
  <% @filter.more_filters.each_with_index do |f_filter, index| %>
54
54
  <li>
55
55
  <%= partial(:"shared/dynamic_filter", :object => f_filter) %>
@@ -57,7 +57,7 @@
57
57
  <% end %>
58
58
  </ul>
59
59
  <div class="mbs">
60
- <a id="add_more_filter" href="<%=h url_path("add_filter") %>" class="add">+ Add Filter</a>
60
+ <a id="addMoreFilter" href="<%=h url_path("add_filter") %>" class="add">+ Add Filter</a>
61
61
  </div>
62
62
 
63
63
  </div> <!-- outer -->
@@ -84,10 +84,10 @@
84
84
  </form>
85
85
  </div> <!-- filter -->
86
86
 
87
- <div class="filter-toggle"><span class="arrow-down <%= 'rotate' unless @filter.get_mongo_conditions.blank? %>">Filter</span></div>
87
+ <div class="filter_toggle filter-toggle"><span class="arrow-down <%= 'rotate' unless @filter.get_mongo_conditions.blank? %>">Filter</span></div>
88
88
 
89
89
  <% if @logs.count > 0 %>
90
- <table id="logs_list">
90
+ <table id="logsList">
91
91
  <tr>
92
92
  <th>Received</th>
93
93
  <th>Controller</th>
@@ -109,7 +109,7 @@
109
109
  <div class="unit size1of4">
110
110
  <div class="details">
111
111
 
112
- <div id="log_info">
112
+ <div id="logInfo">
113
113
  <div class="pale h2 pal txtC">
114
114
  Please choose log to see details
115
115
  </div> <!-- pale h2 -->
@@ -1,11 +1,11 @@
1
1
  <div class="unit size1of3">
2
2
  <div class="pts prs txtR">
3
- <span class="log-num" title="count of logs"><%=h collection_stats["count"] %></span></div>
3
+ <span class="log-num" title="count of logs"><%=h collection_stats[:count] %></span></div>
4
4
  </div> <!-- unit -->
5
- <% if collection_stats["capped"] && (1 == collection_stats["capped"] || true == collection_stats["capped"]) %>
5
+ <% if collection_stats[:is_capped] %>
6
6
  <div class="progress">
7
- <span class="size"><%=h number_to_human_size(collection_stats["size"]) %> of <%=h number_to_human_size(collection_stats["storageSize"]) %></span>
8
- <div class="used" style="width: <%=((collection_stats["size"].to_f / collection_stats["storageSize"].to_f) * 100).round%>%"></div>
7
+ <span class="size"><%=h number_to_human_size(collection_stats[:size]) %> of <%=h number_to_human_size(collection_stats[:storageSize]) %></span>
8
+ <div class="used" style="width: <%= percent_of_userd_memory(collection_stats) %>%"></div>
9
9
  </div> <!-- progress -->
10
10
  <% else %>
11
11
  <div class="warning"><p>You do not use capped collection for logs.
@@ -2,7 +2,7 @@
2
2
  <div class="unit size1of3">
3
3
  <div class="unit size1of2">
4
4
  <div class="prm">
5
- <%= select_tag dynamic_filter, :type, MongodbLogger::ServerModel::AdditionalFilter::VAR_TYPES, :class => "filter_type", :rel => url_path("changed_filter") %>
5
+ <%= select_tag dynamic_filter, :type, MongodbLogger::ServerModel::AdditionalFilter::VAR_TYPES, :class => "filter_type", "data-url" => url_path("changed_filter") %>
6
6
  </div> <!-- prm -->
7
7
  </div> <!-- unit -->
8
8
  <div class="unit size1of2">
@@ -1,6 +1,6 @@
1
1
  <div class="pas">
2
2
  <div class="unit-right">
3
- <a href="<%=h url_path("log/#{log_info['_id']}") %>" data-pjax='#main_pjax' class="button small grey">More Info</a>
3
+ <a href="<%=h url_path("log/#{log_info['_id']}") %>" data-pjax='#mainPjax' class="button small grey">More Info</a>
4
4
  </div> <!-- unit-right -->
5
5
  <h2 class="phs mvs"><span class="<%= log_info['is_exception'] ? 'failure' : 'success' %>">Message</span></h2>
6
6
  <div class="phs wrap_text">
@@ -1,4 +1,4 @@
1
1
  <ul class="unit">
2
- <li <%= class_if_current(url_path("overview")) %>><a href="<%=h url_path("overview") %>" data-pjax='#main_pjax'>Logs</a></li>
3
- <li <%= class_if_current(url_path("analytics")) %>><a href="<%=h url_path("analytics") %>" data-pjax='#main_pjax'>Analytics</a></li>
2
+ <li <%= class_if_current(url_path("overview")) %>><a href="<%=h url_path("overview") %>" data-pjax='#mainPjax'>Logs</a></li>
3
+ <li <%= class_if_current(url_path("analytics")) %>><a href="<%=h url_path("analytics") %>" data-pjax='#mainPjax'>Analytics</a></li>
4
4
  </ul>
@@ -1,12 +1,12 @@
1
- <div id="tail_logs_block">
1
+ <div id="tailLogsBlock">
2
2
  <div class="initial">
3
- <a id="tail_logs_link" href="#" data-url="<%=h url_path("tail_logs") %>" class="button mts mrs">
3
+ <a id="tailLogsLink" href="#" data-url="<%=h url_path("tail_logs") %>" class="button mts mrs">
4
4
  <span class="start" data-url="<%=h url_path("tail_logs") %>">Tail</span>
5
5
  </a>
6
6
  </div>
7
7
  <div class="info">
8
- <span id="tail_logs_time" class="logs-time mrs"></span>
9
- <a id="tail_logs_stop_link" href="#" class="button negative mts mrs">
8
+ <span id="tailLogsTime" class="logs-time mrs"></span>
9
+ <a id="tailLogsStopLink" href="#" class="button negative mts mrs">
10
10
  <span class="stop">Stop</span>
11
11
  </a>
12
12
  </div>