logster 1.2.11 → 1.3.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -17
  3. data/.travis.yml +15 -16
  4. data/CHANGELOG.md +130 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -96
  9. data/Rakefile +24 -23
  10. data/assets/fonts/FontAwesome.otf +0 -0
  11. data/assets/fonts/fontawesome-webfont.eot +0 -0
  12. data/assets/fonts/fontawesome-webfont.svg +639 -639
  13. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  14. data/assets/fonts/fontawesome-webfont.woff +0 -0
  15. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  16. data/assets/images/Icon-144_rounded.png +0 -0
  17. data/assets/images/Icon-144_square.png +0 -0
  18. data/assets/images/icon_144x144.png +0 -0
  19. data/assets/images/icon_64x64.png +0 -0
  20. data/assets/javascript/client-app.js +81 -0
  21. data/assets/javascript/vendor.js +5302 -0
  22. data/assets/stylesheets/client-app.css +1 -0
  23. data/assets/stylesheets/vendor.css +4 -0
  24. data/build_client_app.sh +12 -0
  25. data/client-app/.editorconfig +20 -0
  26. data/client-app/.ember-cli +9 -0
  27. data/client-app/.eslintignore +19 -0
  28. data/client-app/.eslintrc.js +46 -0
  29. data/client-app/.gitignore +23 -0
  30. data/client-app/.travis.yml +27 -0
  31. data/client-app/.watchmanconfig +3 -0
  32. data/client-app/README.md +57 -0
  33. data/client-app/app/app.js +14 -0
  34. data/client-app/app/components/message-info.js +18 -0
  35. data/client-app/app/components/message-row.js +45 -0
  36. data/client-app/app/components/panel-resizer.js +75 -0
  37. data/client-app/app/components/tab-contents.js +27 -0
  38. data/client-app/app/components/tab-link.js +5 -0
  39. data/client-app/app/components/tabbed-section.js +32 -0
  40. data/client-app/app/components/time-formatter.js +25 -0
  41. data/client-app/app/components/update-time.js +21 -0
  42. data/client-app/app/controllers/index.js +83 -0
  43. data/client-app/app/controllers/show.js +13 -0
  44. data/client-app/app/index.html +29 -0
  45. data/client-app/app/initializers/app-init.js +55 -0
  46. data/client-app/app/lib/preload.js +14 -0
  47. data/client-app/app/lib/utilities.js +140 -0
  48. data/client-app/app/models/message-collection.js +158 -0
  49. data/client-app/app/models/message.js +99 -0
  50. data/client-app/app/resolver.js +3 -0
  51. data/client-app/app/router.js +14 -0
  52. data/client-app/app/routes/index.js +53 -0
  53. data/client-app/app/routes/show.js +14 -0
  54. data/{assets/stylesheets → client-app/app/styles}/app.css +387 -390
  55. data/{assets/javascript → client-app/app}/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -0
  57. data/{assets/javascript → client-app/app/templates}/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -0
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -0
  60. data/{assets/javascript → client-app/app}/templates/index.hbs +57 -57
  61. data/{assets/javascript → client-app/app}/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -0
  63. data/client-app/config/optional-features.json +3 -0
  64. data/client-app/config/targets.js +18 -0
  65. data/client-app/ember-cli-build.js +29 -0
  66. data/client-app/package-lock.json +11365 -0
  67. data/client-app/package.json +56 -0
  68. data/client-app/testem.js +25 -0
  69. data/client-app/tests/index.html +34 -0
  70. data/client-app/tests/integration/components/message-info-test.js +26 -0
  71. data/client-app/tests/integration/components/message-row-test.js +26 -0
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -0
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -0
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -0
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -0
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -0
  77. data/client-app/tests/integration/components/update-time-test.js +26 -0
  78. data/client-app/tests/test-helper.js +8 -0
  79. data/client-app/tests/unit/controllers/index-test.js +12 -0
  80. data/client-app/tests/unit/controllers/show-test.js +12 -0
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -0
  82. data/client-app/tests/unit/routes/index-test.js +11 -0
  83. data/client-app/tests/unit/routes/show-test.js +11 -0
  84. data/lib/examples/sidekiq_logster_reporter.rb +21 -21
  85. data/lib/logster.rb +54 -54
  86. data/lib/logster/base_store.rb +130 -130
  87. data/lib/logster/configuration.rb +25 -25
  88. data/lib/logster/ignore_pattern.rb +65 -65
  89. data/lib/logster/logger.rb +102 -101
  90. data/lib/logster/message.rb +227 -226
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -54
  93. data/lib/logster/middleware/viewer.rb +220 -251
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -477
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -33
  99. data/test/examples/test_sidekiq_reporter_example.rb +46 -46
  100. data/test/fake_data/Gemfile +4 -4
  101. data/test/fake_data/generate.rb +10 -10
  102. data/test/logster/middleware/test_reporter.rb +21 -21
  103. data/test/logster/middleware/test_viewer.rb +96 -70
  104. data/test/logster/test_base_store.rb +147 -147
  105. data/test/logster/test_ignore_pattern.rb +41 -41
  106. data/test/logster/test_logger.rb +74 -74
  107. data/test/logster/test_message.rb +34 -34
  108. data/test/logster/test_redis_rate_limiter.rb +230 -230
  109. data/test/logster/test_redis_store.rb +427 -414
  110. data/test/test_helper.rb +38 -37
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +83 -24
  113. data/assets/javascript/app.js +0 -817
  114. data/assets/javascript/components/message-info.hbs +0 -47
  115. data/assets/javascript/components/panel-resizer.hbs +0 -0
  116. data/assets/javascript/components/tab-contents.hbs +0 -1
  117. data/assets/javascript/components/tab-link.hbs +0 -1
  118. data/assets/javascript/components/tabbed-section.hbs +0 -6
  119. data/assets/javascript/external/ember-template-compiler.js +0 -22346
  120. data/assets/javascript/external/ember.js +0 -58500
  121. data/assets/javascript/external/ember.min.js +0 -17
  122. data/assets/javascript/external/jquery.min.js +0 -5
  123. data/assets/javascript/external/lodash.min.js +0 -87
  124. data/assets/javascript/external/moment.min.js +0 -6
  125. data/assets/stylesheets/font-awesome.min.css +0 -4
  126. data/bower.json +0 -25
@@ -1,37 +1,38 @@
1
- require 'minitest'
2
- require 'minitest/unit'
3
- require 'minitest/autorun'
4
- require 'minitest/pride'
5
- require 'redis'
6
- require 'logster'
7
- require 'logster/base_store'
8
- require 'timecop'
9
-
10
- class Logster::TestStore < Logster::BaseStore
11
- attr_accessor :reported
12
- def initialize
13
- @reported = []
14
- end
15
-
16
- def save(message)
17
- @reported << message
18
- end
19
-
20
- def count
21
- @reported.count
22
- end
23
-
24
- def clear
25
- @reported = []
26
- end
27
-
28
- def clear_all
29
- @reported = []
30
- end
31
-
32
- def check_rate_limits(severity)
33
- # Do nothing
34
- end
35
-
36
- # get, protect, unprotect: unimplemented
37
- end
1
+ require 'minitest'
2
+ require 'minitest/unit'
3
+ require 'minitest/autorun'
4
+ require 'minitest/pride'
5
+ require 'redis'
6
+ require 'logster'
7
+ require 'logster/base_store'
8
+ require 'timecop'
9
+ require 'byebug'
10
+
11
+ class Logster::TestStore < Logster::BaseStore
12
+ attr_accessor :reported
13
+ def initialize
14
+ @reported = []
15
+ end
16
+
17
+ def save(message)
18
+ @reported << message
19
+ end
20
+
21
+ def count
22
+ @reported.count
23
+ end
24
+
25
+ def clear
26
+ @reported = []
27
+ end
28
+
29
+ def clear_all
30
+ @reported = []
31
+ end
32
+
33
+ def check_rate_limits(severity)
34
+ # Do nothing
35
+ end
36
+
37
+ # get, protect, unprotect: unimplemented
38
+ end
@@ -1,39 +1,39 @@
1
- (function() {
2
- var lastReport = null;
3
-
4
- if (!window.Logster) {
5
- window.Logster = {
6
- enabled: true
7
- };
8
- }
9
-
10
- window.onerror = function(message, url, line, column, errorObj) {
11
- // never bother reporting more than once a minute
12
- if (lastReport && new Date() - lastReport < 1000 * 60) {
13
- return;
14
- }
15
- if (!Logster.enabled) {
16
- return;
17
- }
18
-
19
- lastReport = new Date();
20
-
21
- var err = {
22
- message: message,
23
- url: url,
24
- line: line,
25
- column: column,
26
- window_location: window.location && (window.location + "")
27
- };
28
-
29
- if (errorObj && errorObj.stack) {
30
- err.stacktrace = errorObj.stack;
31
- }
32
-
33
- $.ajax("<%= Logster.config.subdirectory %>" + "/report_js_error", {
34
- data: err,
35
- type: "POST",
36
- cache: false
37
- });
38
- };
39
- })();
1
+ (function() {
2
+ var lastReport = null;
3
+
4
+ if (!window.Logster) {
5
+ window.Logster = {
6
+ enabled: true
7
+ };
8
+ }
9
+
10
+ window.onerror = function(message, url, line, column, errorObj) {
11
+ // never bother reporting more than once a minute
12
+ if (lastReport && new Date() - lastReport < 1000 * 60) {
13
+ return;
14
+ }
15
+ if (!Logster.enabled) {
16
+ return;
17
+ }
18
+
19
+ lastReport = new Date();
20
+
21
+ var err = {
22
+ message: message,
23
+ url: url,
24
+ line: line,
25
+ column: column,
26
+ window_location: window.location && (window.location + "")
27
+ };
28
+
29
+ if (errorObj && errorObj.stack) {
30
+ err.stacktrace = errorObj.stack;
31
+ }
32
+
33
+ $.ajax("<%= Logster.config.subdirectory %>" + "/report_js_error", {
34
+ data: err,
35
+ type: "POST",
36
+ cache: false
37
+ });
38
+ };
39
+ })();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logster
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.11
4
+ version: 1.3.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - UI for viewing logs in Rack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-13 00:00:00.000000000 Z
11
+ date: 2018-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: UI for viewing logs in Rack
112
126
  email:
113
127
  - sam.saffron@gmail.com
@@ -133,25 +147,70 @@ files:
133
147
  - assets/images/Icon-144_square.png
134
148
  - assets/images/icon_144x144.png
135
149
  - assets/images/icon_64x64.png
136
- - assets/javascript/app.js
137
- - assets/javascript/components/message-info.hbs
138
- - assets/javascript/components/message-row.hbs
139
- - assets/javascript/components/panel-resizer.hbs
140
- - assets/javascript/components/tab-contents.hbs
141
- - assets/javascript/components/tab-link.hbs
142
- - assets/javascript/components/tabbed-section.hbs
143
- - assets/javascript/external/ember-template-compiler.js
144
- - assets/javascript/external/ember.js
145
- - assets/javascript/external/ember.min.js
146
- - assets/javascript/external/jquery.min.js
147
- - assets/javascript/external/lodash.min.js
148
- - assets/javascript/external/moment.min.js
149
- - assets/javascript/templates/application.hbs
150
- - assets/javascript/templates/index.hbs
151
- - assets/javascript/templates/show.hbs
152
- - assets/stylesheets/app.css
153
- - assets/stylesheets/font-awesome.min.css
154
- - bower.json
150
+ - assets/javascript/client-app.js
151
+ - assets/javascript/vendor.js
152
+ - assets/stylesheets/client-app.css
153
+ - assets/stylesheets/vendor.css
154
+ - build_client_app.sh
155
+ - client-app/.editorconfig
156
+ - client-app/.ember-cli
157
+ - client-app/.eslintignore
158
+ - client-app/.eslintrc.js
159
+ - client-app/.gitignore
160
+ - client-app/.travis.yml
161
+ - client-app/.watchmanconfig
162
+ - client-app/README.md
163
+ - client-app/app/app.js
164
+ - client-app/app/components/message-info.js
165
+ - client-app/app/components/message-row.js
166
+ - client-app/app/components/panel-resizer.js
167
+ - client-app/app/components/tab-contents.js
168
+ - client-app/app/components/tab-link.js
169
+ - client-app/app/components/tabbed-section.js
170
+ - client-app/app/components/time-formatter.js
171
+ - client-app/app/components/update-time.js
172
+ - client-app/app/controllers/index.js
173
+ - client-app/app/controllers/show.js
174
+ - client-app/app/index.html
175
+ - client-app/app/initializers/app-init.js
176
+ - client-app/app/lib/preload.js
177
+ - client-app/app/lib/utilities.js
178
+ - client-app/app/models/message-collection.js
179
+ - client-app/app/models/message.js
180
+ - client-app/app/resolver.js
181
+ - client-app/app/router.js
182
+ - client-app/app/routes/index.js
183
+ - client-app/app/routes/show.js
184
+ - client-app/app/styles/app.css
185
+ - client-app/app/templates/application.hbs
186
+ - client-app/app/templates/components/message-info.hbs
187
+ - client-app/app/templates/components/message-row.hbs
188
+ - client-app/app/templates/components/tabbed-section.hbs
189
+ - client-app/app/templates/components/time-formatter.hbs
190
+ - client-app/app/templates/index.hbs
191
+ - client-app/app/templates/show.hbs
192
+ - client-app/config/environment.js
193
+ - client-app/config/optional-features.json
194
+ - client-app/config/targets.js
195
+ - client-app/ember-cli-build.js
196
+ - client-app/package-lock.json
197
+ - client-app/package.json
198
+ - client-app/testem.js
199
+ - client-app/tests/index.html
200
+ - client-app/tests/integration/components/message-info-test.js
201
+ - client-app/tests/integration/components/message-row-test.js
202
+ - client-app/tests/integration/components/panel-resizer-test.js
203
+ - client-app/tests/integration/components/tab-contents-test.js
204
+ - client-app/tests/integration/components/tab-link-test.js
205
+ - client-app/tests/integration/components/tabbed-section-test.js
206
+ - client-app/tests/integration/components/time-formatter-test.js
207
+ - client-app/tests/integration/components/update-time-test.js
208
+ - client-app/tests/test-helper.js
209
+ - client-app/tests/unit/controllers/index-test.js
210
+ - client-app/tests/unit/controllers/show-test.js
211
+ - client-app/tests/unit/initializers/app-init-test.js
212
+ - client-app/tests/unit/routes/index-test.js
213
+ - client-app/tests/unit/routes/show-test.js
155
214
  - lib/examples/sidekiq_logster_reporter.rb
156
215
  - lib/logster.rb
157
216
  - lib/logster/base_store.rb
@@ -195,12 +254,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
195
254
  version: '0'
196
255
  required_rubygems_version: !ruby/object:Gem::Requirement
197
256
  requirements:
198
- - - ">="
257
+ - - ">"
199
258
  - !ruby/object:Gem::Version
200
- version: '0'
259
+ version: 1.3.1
201
260
  requirements: []
202
261
  rubyforge_project:
203
- rubygems_version: 2.7.6
262
+ rubygems_version: 2.7.7
204
263
  signing_key:
205
264
  specification_version: 4
206
265
  summary: UI for viewing logs in Rack
@@ -1,817 +0,0 @@
1
- moment.lang('en', {
2
- relativeTime : {
3
- future: "in %s",
4
- past: "%s ago",
5
- s: "secs",
6
- m: "a min",
7
- mm: "%d mins",
8
- h: "an hr",
9
- hh: "%d hrs",
10
- d: "a day",
11
- dd: "%d days",
12
- M: "a mth",
13
- MM: "%d mths",
14
- y: "a yr",
15
- yy: "%d yrs"
16
- }
17
- });
18
-
19
-
20
- App = Ember.Application.create({
21
- });
22
-
23
- App.ajax = function(url, settings) {
24
- settings = settings || {};
25
- settings.headers = settings.headers || {};
26
- settings.headers["X-SILENCE-LOGGER"] = true;
27
- return $.ajax(Logger.rootPath + url, settings);
28
- };
29
-
30
- App.preloadOrAjax = function(url, settings) {
31
- var preloaded = Logger.preload[url];
32
- if (preloaded) {
33
- // return a pseudo-XHR
34
- return {
35
- success: function(callback) {
36
- setTimeout(function() {
37
- callback(preloaded);
38
- }, 0);
39
- return this;
40
- },
41
- error: function() { return this; }
42
- };
43
- } else {
44
- return App.ajax(url, settings);
45
- }
46
- };
47
-
48
- App.Router.map(function() {
49
- this.route("index", { path: "/" });
50
- this.route("show", { path: "/show/:id" });
51
- });
52
-
53
- var entityMap = {
54
- "&": "&amp;",
55
- "<": "&lt;",
56
- ">": "&gt;",
57
- '"': '&quot;',
58
- "'": '&#39;',
59
- "/": '&#x2F;'
60
- };
61
-
62
- function escapeHtml(string) {
63
- return String(string).replace(/[&<>"'\/]/g, function (s) {
64
- return entityMap[s];
65
- });
66
- }
67
-
68
- function buildArrayString(array) {
69
- var buffer = [];
70
- _.each(array, function(v) {
71
- if (v === null) {
72
- buffer.push('null');
73
- } else if (Object.prototype.toString.call(v) === '[object Array]') {
74
- buffer.push(buildArrayString(v));
75
- } else {
76
- buffer.push(escapeHtml(v.toString()));
77
- }
78
- });
79
- return '[' + buffer.join(', ') + ']';
80
- }
81
-
82
- function buildHashString(hash, recurse) {
83
- if (!hash) return '';
84
-
85
- var buffer = [],
86
- hashes = [];
87
- _.each(hash, function(v, k) {
88
-
89
- if (v === null) {
90
- buffer.push('null');
91
- } else if (Object.prototype.toString.call(v) === '[object Array]') {
92
- buffer.push("<tr><td>" + escapeHtml(k) + "</td><td>" + buildArrayString(v) + "</td></tr>");
93
- } else if (typeof v === "object") {
94
- hashes.push(k);
95
- } else {
96
- buffer.push("<tr><td>" + escapeHtml(k) + "</td><td>" + escapeHtml(v) + "</td></tr>");
97
- }
98
- });
99
-
100
- if (_.size(hashes) > 0) {
101
- _.each(hashes, function(k1) {
102
- var v = hash[k1];
103
- buffer.push("<tr><td></td><td><table>");
104
- buffer.push("<td>" + escapeHtml(k1) + "</td><td>" + buildHashString(v, true) + "</td>");
105
- buffer.push("</table></td></tr>");
106
- });
107
- }
108
- var className = recurse?"": "env-table";
109
- return "<table class='"+ className +"'>" + buffer.join("\n") + "</table>";
110
- }
111
-
112
- App.Message = Ember.Object.extend({
113
-
114
- MAX_LEN: 200,
115
-
116
- expand: function() {
117
- this.set("expanded", true);
118
- },
119
-
120
- solve: function() {
121
- return App.ajax("/solve/" + this.get('key'), { type: "PUT" });
122
- },
123
-
124
- "delete": function() {
125
- return App.ajax("/message/" + this.get('key'), { type: "DELETE" });
126
- },
127
-
128
- protect: function() {
129
- this.set('protected', true);
130
- return App.ajax("/protect/" + this.get('key'), { type: "PUT" });
131
- },
132
- unprotect: function() {
133
- this.set('protected', false);
134
- return App.ajax("/unprotect/" + this.get('key'), { type: "DELETE" });
135
- },
136
-
137
- showCount: function() {
138
- return this.get('count') > 1;
139
- }.property('count'),
140
-
141
- hasMore: function() {
142
- var message = this.get("message");
143
- var expanded = this.get("expanded");
144
-
145
- return !expanded && message.length > this.MAX_LEN;
146
- }.property("message", "expanded"),
147
-
148
- shareUrl: function() {
149
- return Logger.rootPath + "/show/" + this.get('key');
150
- }.property("key"),
151
-
152
- displayMessage: function() {
153
- var message = this.get("message");
154
- var expanded = this.get("expanded");
155
-
156
- if (!expanded && message.length > this.MAX_LEN) {
157
- message = message.substr(0, this.MAX_LEN);
158
- }
159
- return message;
160
- }.property("message", "expanded"),
161
-
162
- updateFromObject: function(other) {
163
- // XXX Only updatable property is count right now
164
- this.set('count', other.get('count'));
165
- },
166
-
167
- canSolve: function() {
168
- var backtrace = this.get("backtrace");
169
- return this.get("env.application_version") && backtrace && (backtrace.length > 0);
170
- }.property(),
171
-
172
- envTable: function() {
173
- return buildHashString(this.get('env'));
174
- }.property("env"),
175
-
176
-
177
- rowClass: function() {
178
- switch (this.get("severity")) {
179
- case 0:
180
- return "debug";
181
- case 1:
182
- return "info";
183
- case 2:
184
- return "warn";
185
- case 3:
186
- return "error";
187
- case 4:
188
- return "fatal";
189
- }
190
- }.property("severity"),
191
-
192
- glyph: function() {
193
- switch (this.get("severity")) {
194
- case 0:
195
- return "";
196
- case 1:
197
- return "";
198
- case 2:
199
- return "<i class='fa fa-exclamation-circle warning'></i>";
200
- case 3:
201
- return "<i class='fa fa-times-circle error'></i>";
202
- case 4:
203
- return "<i class='fa fa-times-circle fatal'></i>";
204
- }
205
- }.property("severity")
206
- });
207
-
208
- App.MessageCollection = Em.Object.extend({
209
-
210
- messages: Em.A(),
211
- currentMessage: null,
212
- total: 0,
213
-
214
- solve: function(message) {
215
- var self = this;
216
- message.solve().then(function(){
217
- self.reload();
218
- });
219
- },
220
-
221
- "delete": function(message){
222
- var messages = this.get('messages');
223
- var idx = messages.indexOf(message);
224
- message.delete();
225
- message.set('selected', false);
226
- this.set('total', this.get('total')-1);
227
- this.get('messages').removeObject(message);
228
-
229
- if (idx > 0) {
230
- message = messages[idx-1];
231
- message.set('selected', true);
232
- this.set('currentMessage', message);
233
- } else {
234
- if (this.get('total') > 0) {
235
- message = messages[0];
236
- message.set('selected', true);
237
- this.set('currentMessage', message);
238
- } else {
239
- this.reload();
240
- }
241
- }
242
-
243
- },
244
-
245
- load: function(opts) {
246
- var self = this;
247
- opts = opts || {};
248
-
249
- var data = {
250
- filter: this.get("filter").join("_")
251
- };
252
-
253
- search = this.get("search");
254
- if (!_.isEmpty(search)) {
255
- data.search = search;
256
- var regexSearch = this.get("regexSearch");
257
- if(regexSearch) {
258
- data.regex_search = "true";
259
- }
260
- }
261
-
262
- if(opts.before){
263
- data.before = opts.before;
264
- }
265
-
266
- if (opts.after){
267
- data.after = opts.after;
268
- }
269
-
270
- App.ajax("/messages.json", {
271
- data: data
272
- }).success(function(data) {
273
- // guard against race: ensure the results we're trying to apply
274
- // match the current search terms
275
- if (Ember.compare(data.filter, self.get('filter')) != 0) { return; }
276
- if (Ember.compare(data.search, self.get('search')) != 0) { return; }
277
-
278
- if (data.messages.length > 0) {
279
- var newRows = self.toMessages(data.messages);
280
- var messages = self.get("messages");
281
- if (opts.before) {
282
- messages.unshiftObjects(newRows);
283
- } else {
284
- newRows.forEach(function(nmsg) {
285
- messages.forEach(function(emsg, idx) {
286
- if (emsg.key == nmsg.key) {
287
- messages.removeObject(emsg);
288
- if (self.get('currentMessage') === emsg) {
289
- // TODO would updateFromJson() work here?
290
- self.set('currentMessage', nmsg);
291
- nmsg.set('selected', emsg.get('selected'));
292
- }
293
- }
294
- });
295
- });
296
- messages.addObjects(newRows);
297
- if (newRows.length > 0) {
298
- App.increaseTitleCount(newRows.length);
299
- }
300
- }
301
- }
302
- self.set("total", data.total);
303
- });
304
- },
305
-
306
- reload: function(){
307
- this.set("total", 0);
308
- this.get("messages").clear();
309
-
310
- this.load();
311
- },
312
-
313
- loadMore: function(){
314
-
315
- var messages = this.get("messages");
316
- if (messages.length === 0) {
317
- this.load({});
318
- return;
319
- }
320
-
321
- var lastKey = messages[messages.length-1].get("key");
322
- this.load({
323
- after: lastKey
324
- });
325
- },
326
-
327
- moreBefore: function(){
328
- return this.get("totalBefore") > 0;
329
- }.property("totalBefore"),
330
-
331
- totalBefore: function() {
332
- return this.get("total") - this.get("messages").length;
333
- }.property("total", "messages.[]"),
334
-
335
- showMoreBefore: function() {
336
- var messages = this.get("messages");
337
- var firstKey = messages[0].get("key");
338
-
339
- this.load({
340
- before: firstKey
341
- });
342
- },
343
-
344
- regexSearch: function() {
345
- search = this.get("search");
346
- if( search &&
347
- search.length > 2 &&
348
- search[0] === "/"
349
- ){
350
- var match = search.match(/\/(.*)\/(.*)/);
351
- if(match && match.length === 3){
352
- try {
353
- return new RegExp(match[1], match[2]);
354
- } catch(err) {
355
- // don't care
356
- }
357
- }
358
- }
359
- }.property("search"),
360
-
361
- toMessages: function(messages){
362
- return messages.map(function(m){
363
- return App.Message.create(m);
364
- });
365
- }
366
- });
367
-
368
- App.resetTitleCount = function() {
369
- App.titleCount = 0;
370
- document.title = App.title || document.title;
371
- };
372
-
373
- (function(){
374
- var hiddenProperty;
375
- var visibilitychange;
376
-
377
- $.each(["","webkit","ms","moz","ms"], function(index, prefix){
378
- var check = prefix + (prefix === "" ? "hidden" : "Hidden");
379
- if(document[check] !== undefined && !hiddenProperty ){
380
- hiddenProperty = check;
381
- visibilitychange = prefix + "visibilitychange";
382
- }
383
- });
384
-
385
- App.isHidden = function() {
386
- if (hiddenProperty !== undefined){
387
- return document[hiddenProperty];
388
- } else {
389
- return !document.hasFocus;
390
- }
391
- };
392
-
393
- console.log(visibilitychange);
394
- document.addEventListener(visibilitychange, function(){
395
- console.log("BLA +" + App.isHidden());
396
- if (!App.isHidden()) {
397
- App.resetTitleCount();
398
- }
399
- }, false);
400
- })();
401
-
402
-
403
- App.increaseTitleCount = function(increment){
404
- if (!App.isHidden()){
405
- return;
406
- }
407
- App.title = App.title || document.title;
408
- App.titleCount = App.titleCount || 0;
409
- App.titleCount += increment;
410
- document.title = App.title + " (" + App.titleCount + ")";
411
- };
412
-
413
- App.IndexRoute = Em.Route.extend({
414
- model: function(){
415
- // TODO from preload json?
416
- return App.MessageCollection.create();
417
- },
418
-
419
- setupController: function(controller, model) {
420
- this._super(controller, model);
421
- controller.setProperties({
422
- "showDebug": true,
423
- "showInfo": true,
424
- "showWarn": true,
425
- "showErr": true,
426
- "showFatal": true,
427
- "search": ''
428
- });
429
- controller.set("initialized", true);
430
- model.reload();
431
-
432
- var times = 0;
433
- var backoff = 1;
434
-
435
- this.refreshInterval = setInterval(function(){
436
- times += 1;
437
- var hidden = App.isHidden();
438
- var load = !hidden;
439
-
440
- if (hidden) {
441
- if (times % backoff === 0) {
442
- load = true;
443
- if (backoff<20) { backoff++; }
444
- }
445
- }
446
- // refresh a lot less aggressively in background
447
- if (load) {
448
- model.loadMore();
449
- if (!hidden) {
450
- backoff = 1;
451
- }
452
- }
453
-
454
- }, 3000);
455
- },
456
-
457
- deactivate: function(){
458
- clearInterval(this.refreshInterval);
459
- }
460
- });
461
-
462
- App.ShowRoute = Em.Route.extend({
463
- model: function(params) {
464
- var self = this;
465
- return new Promise(function(resolve, reject) {
466
- App.preloadOrAjax("/show/" + params.id + ".json").success(function(json) {
467
- resolve(App.Message.create(json));
468
- }).error(reject);
469
- });
470
- }
471
- });
472
-
473
- App.IndexController = Em.Controller.extend({
474
-
475
- currentMessage: Em.computed.alias('model.currentMessage'),
476
-
477
- actions: {
478
- expandMessage: function(message){
479
- message.expand();
480
- },
481
-
482
- selectMessage: function(message) {
483
- var old = this.get("currentMessage");
484
- if (old) {
485
- old.set("selected",false);
486
- }
487
-
488
- message.set('selected', true);
489
- this.set('currentMessage', message);
490
- },
491
-
492
- showMoreBefore: function(){
493
- this.get('model').showMoreBefore();
494
- },
495
-
496
- loadMore: function(){
497
- return this.get('model').loadMore();
498
- },
499
-
500
- clear: function() {
501
- var self = this;
502
- if (confirm("Clear the logs?\n\nCancel = No, OK = Clear")) {
503
- App.ajax("/clear", { type: "POST" }).success(function() {
504
- self.get('model').reload();
505
- });
506
- }
507
- },
508
-
509
- removeMessage: function(msg) {
510
- var messages = this.get('model');
511
- messages.delete(msg);
512
- },
513
-
514
- solveMessage: function(msg) {
515
- var messages = this.get('model');
516
- messages.solve(msg);
517
- }
518
- },
519
-
520
- filterChanged: function(){
521
- var severities = ["Debug", "Info", "Warn", "Err", "Fatal"];
522
- var filter = [];
523
- for(var i=0; i<5; i++){
524
- if(this.get("show" + severities[i])){
525
- filter.push(i);
526
- }
527
- }
528
-
529
- // always show unknown, rare
530
- filter.push(5);
531
- var model = this.get("model");
532
- model.set("filter", filter);
533
- if(this.get("initialized")){
534
- model.reload();
535
- }
536
- }.observes(
537
- "showDebug",
538
- "showInfo",
539
- "showWarn",
540
- "showErr",
541
- "showFatal"
542
- ),
543
-
544
- searchChanged: function(){
545
- var search = this.get("search");
546
- var model = this.get("model");
547
- model.set("search", search);
548
-
549
- if(this.get("initialized")){
550
- model.reload();
551
- }
552
- }.observes(
553
- "search"
554
- )
555
-
556
- });
557
-
558
- App.ShowController = Em.Controller.extend({
559
- actions: {
560
- protect: function(message) {
561
- this.get('model').protect();
562
- },
563
-
564
- unprotect: function(message) {
565
- this.get('model').unprotect();
566
- }
567
- }
568
- });
569
-
570
- App.PanelResizerComponent = Em.Component.extend({
571
- classNames: ['divider'],
572
- divideView: function(fromTop, win){
573
- var $win = win || $(window);
574
- var height = $win.height();
575
- var fromBottom = $win.height() - fromTop;
576
-
577
- if (fromTop < 100 || fromTop + 100 > height) {
578
- return;
579
- }
580
-
581
-
582
- this.topPanel.css("bottom", fromBottom + 5);
583
- this.bottomPanel.css("height", fromBottom - 15);
584
- this.divider.css("bottom", fromBottom - 5);
585
- },
586
-
587
- didInsertElement: function(){
588
- var self = this;
589
-
590
- // inspired by http://plugins.jquery.com/misc/textarea.js
591
- this.topPanel = $("#top-panel");
592
- this.divider = $(".divider");
593
- this.bottomPanel = $("#bottom-panel");
594
-
595
- var $win = $(window),
596
- resizing = false;
597
-
598
- var performDrag = function(e){
599
- if(!resizing) { return; }
600
- self.divideView(e.clientY, $win);
601
- };
602
-
603
- var endDrag = function(){
604
- $("#overlay").remove();
605
- resizing = false;
606
-
607
- if(localStorage){
608
- localStorage.logster_divider_bottom = parseInt(self.divider.css("bottom"),10);
609
- }
610
-
611
- $(document)
612
- .unbind('mousemove', performDrag)
613
- .unbind('mouseup', endDrag);
614
- };
615
-
616
- self.divider.on("mousedown", function(){
617
- $("<div id='overlay'></div>").appendTo($("body"));
618
- resizing = true;
619
- $(document)
620
- .mousemove(_.throttle(performDrag,25))
621
- .mouseup(endDrag);
622
- }).append("<div class='line-1'></div><div class='line-2'></div><div class='line-3'></div>");
623
-
624
-
625
- Em.run.next(function(){
626
- if(localStorage && localStorage.logster_divider_bottom){
627
- var fromTop = $win.height() - parseInt(localStorage.logster_divider_bottom,10);
628
- self.divideView(fromTop, $win);
629
- }
630
- });
631
- },
632
-
633
- willDestroyElement: function(){
634
- $(".divider").off("mousedown");
635
- }
636
- });
637
-
638
-
639
- App.MessageRowComponent = Em.Component.extend({
640
-
641
- tagName: "tr",
642
-
643
- classNameBindings: ["model.rowClass", ":message-row", "model.selected:selected"],
644
-
645
- click: function() {
646
- this.sendAction('selectedMessage', this.get('model'));
647
- },
648
-
649
- willInsertElement: function(){
650
- if (App.MessageRowComponent._checkedBottom) {
651
- return;
652
- }
653
-
654
- var $topPanel = $("#top-panel");
655
-
656
- var scrollTop = $topPanel.scrollTop();
657
- var height = $topPanel.height();
658
- var scrollHeight = $topPanel[0].scrollHeight;
659
-
660
- App.MessageRowComponent._stickToBottom = scrollHeight - 20 < height + scrollTop;
661
- App.MessageRowComponent._checkedBottom = true;
662
- },
663
-
664
- didInsertElement: function(){
665
- var self = this;
666
- var $topPanel = $("#top-panel");
667
- Em.run.next(function(){
668
- App.MessageRowComponent._checkedBottom = false;
669
-
670
- if (App.MessageRowComponent._stickToBottom){
671
- App.MessageRowComponent._stickToBottom = false;
672
- $topPanel.scrollTop($topPanel[0].scrollHeight - $topPanel.height());
673
- }
674
- });
675
- }
676
- });
677
-
678
- App.UpdateTimeComponent = Em.Component.extend({
679
- didInsertElement: function(){
680
- var updateTimes = function(){
681
- $('.auto-update-time').each(function(){
682
- var timestamp = parseInt(this.getAttribute('data-timestamp'),10);
683
- var elem = this;
684
-
685
- var text = App.formatTime(timestamp);
686
-
687
- if(text !== elem.innerText) {
688
- elem.innerText = text;
689
- }
690
-
691
- });
692
- Em.run.later(updateTimes, 60000);
693
- };
694
-
695
- Em.run.later(updateTimes, 60000);
696
- }
697
- });
698
-
699
- App.TimeFormatterComponent = Ember.Component.extend({
700
- tagName: 'span',
701
- classNames: 'auto-update-time',
702
- attributeBindings: ['data-timestamp', 'title'],
703
-
704
- title: function(){
705
- return this.get('moment').format();
706
- }.property(),
707
-
708
- "data-timestamp": function(){
709
- return this.get('timestamp');
710
- }.property(),
711
-
712
- moment: function(){
713
- return moment(this.get("timestamp"));
714
- }.property(),
715
-
716
- render: function(buffer){
717
- buffer.push(App.formatTime(this.get('timestamp')));
718
- },
719
- });
720
-
721
- App.formatTime = function(timestamp){
722
- var formatted;
723
- var time = moment(timestamp);
724
- var now = moment();
725
-
726
- if (time.diff(now.startOf('day')) > 0) {
727
- formatted = time.format('h:mm a');
728
- } else {
729
- if (time.diff(now.startOf('week')) > 0) {
730
- formatted = time.format('dd h:mm a');
731
- } else {
732
- if (time.diff(now.startOf('year')) > 0) {
733
- formatted = time.format('D MMM h:mm a');
734
- } else {
735
- formatted = time.format('D MMM YY');
736
- }
737
- }
738
- }
739
-
740
- return formatted;
741
- };
742
-
743
- App.TabbedSectionComponent = Ember.Component.extend({
744
- tabs: Em.A(),
745
- selectTab: function(view) {
746
- if (view.get('isLink')) {
747
- this.triggerAction(view.get('action'));
748
- return;
749
- }
750
-
751
- var selected = this.get("selected");
752
- if (selected) {
753
- selected.set("active", false);
754
- }
755
- this.set("selected", view);
756
- view.set("active", true);
757
- },
758
- addTab: function(tab) {
759
- this.get("tabs").addObject(tab);
760
- if (!this.get("selected") && !tab.get('isLink')) {
761
- this.selectTab(tab);
762
- }
763
- },
764
- removeTab: function(tab) {
765
- if (this.get("selected") === tab) {
766
- this.set("selected", null);
767
- }
768
- this.get("tabs").removeObject(tab);
769
- }
770
- });
771
-
772
- App.TabContentsComponent = Ember.Component.extend({
773
- classNameBindings: ["active", ":content"],
774
- isLink: false,
775
-
776
- invokeParent: function(name) {
777
- var current = this.get("parentView");
778
- while (current && !current[name]) {
779
- current = current.get("parentView");
780
- }
781
- if (current) {
782
- current[name](this);
783
- }
784
- },
785
-
786
- didInsertElement: function() {
787
- this.invokeParent("addTab");
788
- if (this.get("defaultTab")) {
789
- this.invokeParent("selectTab");
790
- }
791
- },
792
- willDestroyElement: function() {
793
- this.invokeParent("removeTab");
794
- },
795
-
796
- });
797
-
798
- App.MessageInfoComponent = Ember.Component.extend({
799
- actions: {
800
- protect: function(){
801
- this.get('currentMessage').protect();
802
- },
803
- unprotect: function(){
804
- this.get('currentMessage').unprotect();
805
- },
806
- "remove": function(){
807
- this.sendAction("removeMessage", this.get('currentMessage'));
808
- },
809
- solve: function() {
810
- this.sendAction("solveMessage", this.get('currentMessage'));
811
- }
812
- }
813
- });
814
-
815
- App.TabLinkComponent = App.TabContentsComponent.extend({
816
- isLink: true
817
- });