logster 1.2.11 → 1.3.pre

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 (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
- });