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,414 +1,427 @@
1
- require_relative '../test_helper'
2
- require 'logster/redis_store'
3
- require 'rack'
4
-
5
- class TestRedisStore < Minitest::Test
6
-
7
- def setup
8
- @store = Logster::RedisStore.new(Redis.new)
9
- @store.clear_all
10
- end
11
-
12
- def teardown
13
- @store.clear_all
14
- end
15
-
16
- def test_delete
17
- msg = @store.report(Logger::WARN, "test", "testing")
18
- @store.delete(msg)
19
- latest = @store.latest
20
-
21
- assert_equal(0,latest.length)
22
- end
23
-
24
- def test_latest
25
- @store.report(Logger::WARN, "test", "IGNORE")
26
- @store.report(Logger::WARN, "test", "This is a warning")
27
- @store.report(Logger::WARN, "test", "This is another warning")
28
-
29
- latest = @store.latest(limit: 2)
30
-
31
- assert_equal(2, latest.length)
32
- assert_equal("This is a warning", latest[0].message)
33
- assert_equal("This is another warning", latest[1].message)
34
- assert_equal(Logger::WARN, latest[1].severity)
35
- assert_equal("test", latest[1].progname)
36
- assert(!latest[1].key.nil?)
37
- end
38
-
39
- def test_latest_after
40
- 10.times do |i|
41
- @store.report(Logger::WARN, "test", "A#{i}")
42
- end
43
-
44
- message = @store.latest[-1]
45
-
46
- 3.times do |i|
47
- @store.report(Logger::WARN, "test", i.to_s)
48
- end
49
-
50
- message = @store.latest(after: message.key, limit: 3)[0]
51
-
52
- assert_equal("0", message.message)
53
- end
54
-
55
- def test_latest_before
56
- 10.times do
57
- @store.report(Logger::WARN, "test", "A")
58
- end
59
- 10.times do
60
- @store.report(Logger::WARN, "test", "B")
61
- end
62
- 10.times do
63
- @store.report(Logger::WARN, "test", "C")
64
- end
65
-
66
- messages = @store.latest(limit: 10)
67
- assert_equal("C", messages[0].message)
68
- assert_equal(10, messages.length)
69
-
70
- messages = @store.latest(limit: 10, before: messages[0].key)
71
- assert_equal("B", messages[0].message)
72
- assert_equal(10, messages.length)
73
-
74
- messages = @store.latest(limit: 10, before: messages[0].key)
75
- assert_equal("A", messages[0].message)
76
- assert_equal(10, messages.length)
77
-
78
- end
79
-
80
- def test_get
81
- a_message = @store.report(Logger::WARN, "test", "A")
82
- b_message = @store.report(Logger::WARN, "test", "B")
83
- @store.report(Logger::WARN, "test", "C")
84
-
85
- assert_equal("A", @store.get(a_message.key).message)
86
- assert_equal("B", @store.get(b_message.key).message)
87
- end
88
-
89
- def test_backlog
90
- @store.max_backlog = 1
91
- @store.report(Logger::WARN, "test", "A")
92
- @store.report(Logger::WARN, "test", "A")
93
- @store.report(Logger::WARN, "test", "A")
94
- @store.report(Logger::WARN, "test", "B")
95
-
96
- latest = @store.latest
97
-
98
- assert_equal(1, latest.length)
99
- assert_equal("B", latest[0].message)
100
- end
101
-
102
- def test_save_unsave
103
- @store.max_backlog = 3
104
- @store.report(Logger::WARN, "test", "A")
105
- b_message = @store.report(Logger::WARN, "test", "B")
106
- @store.protect b_message.key
107
- c_message = @store.report(Logger::WARN, "test", "C")
108
- @store.protect c_message.key
109
- @store.report(Logger::WARN, "test", "D")
110
-
111
- latest = @store.latest
112
-
113
- assert_equal(3, latest.length)
114
- assert_equal("B", latest[0].message)
115
- assert_equal("C", latest[1].message)
116
- assert_equal(true, latest[1].protected)
117
- assert_equal("D", latest[2].message)
118
-
119
- # Saved messages still accessible by key
120
- assert_equal("B", @store.get(b_message.key).message)
121
- assert_equal(true, @store.get(b_message.key).protected)
122
-
123
- # Unsave does not delete message if still recent
124
- @store.unprotect c_message.key
125
- assert_equal("C", @store.get(c_message.key).message)
126
- assert_equal(false, @store.get(c_message.key).protected)
127
- end
128
-
129
- def test_clear
130
- @store.max_backlog = 25
131
- a_message = @store.report(Logger::WARN, "test", "A", timestamp: Time.now - (24*60*60))
132
- @store.protect a_message.key
133
- 20.times do
134
- @store.report(Logger::WARN, "test", "B")
135
- end
136
- c_message = @store.report(Logger::WARN, "test", "C", timestamp: Time.now + (24*60*60))
137
- @store.protect c_message.key
138
- d_message = @store.report(Logger::WARN, "test", "D")
139
- 10.times do
140
- @store.report(Logger::WARN, "test", "E")
141
- end
142
-
143
- latest = @store.latest
144
- assert_equal(25, latest.length)
145
-
146
- @store.clear
147
-
148
- # Protected messages are still accessible by their key
149
- assert_equal("C", @store.get(c_message.key).message)
150
- # Unprotected messages are gone
151
- assert_nil(@store.get(d_message.key))
152
-
153
- # The latest list is rebuilt with protected messages, earliest first
154
- # Including messages that previously fell off (A)
155
- latest = @store.latest
156
- assert_equal(2, latest.length)
157
- assert_equal("A", latest[0].message)
158
- assert_equal("C", latest[1].message)
159
- end
160
-
161
- def test_hash_cleanup
162
- @store.max_backlog = 2
163
- a_message = @store.report(Logger::WARN, "test", "A")
164
- @store.report(Logger::WARN, "test", "B")
165
- @store.report(Logger::WARN, "test", "C")
166
-
167
- assert_nil(@store.get(a_message.key))
168
- end
169
-
170
- def test_filter_latest
171
- @store.report(Logger::INFO, "test", "A")
172
- @store.report(Logger::WARN, "test", "B")
173
-
174
- messages = @store.latest
175
- assert_equal(2, messages.length)
176
-
177
- messages = @store.latest(after: messages.last.key)
178
- assert_equal(0, messages.length)
179
-
180
- 10.times do
181
- @store.report(Logger::INFO, "test", "A")
182
- end
183
- @store.report(Logger::ERROR, "test", "C")
184
- 10.times do
185
- @store.report(Logger::INFO, "test", "A")
186
- end
187
-
188
- latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2)
189
-
190
- assert_equal(2, latest.length)
191
- assert_equal("B", latest[0].message)
192
- assert_equal("C", latest[1].message)
193
-
194
- @store.report(Logger::ERROR, "test", "E")
195
- # respects after
196
- latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2, after: latest[1].key)
197
- assert_equal(1, latest.length);
198
- end
199
-
200
- def test_search
201
- @store.report(Logger::INFO, "test", "A")
202
- @store.report(Logger::INFO, "test", "B")
203
-
204
- messages = @store.latest
205
- assert_equal(2, messages.length)
206
-
207
- latest = @store.latest(search: "B")
208
-
209
- assert_equal(1, latest.length)
210
- end
211
-
212
- def test_regex_search
213
- @store.report(Logger::INFO, "test", "pattern_1")
214
- @store.report(Logger::INFO, "test", "pattern_2")
215
-
216
- messages = @store.latest
217
- assert_equal(2, messages.length)
218
-
219
- latest = @store.latest(search: /^pattern_[1]$/)
220
-
221
- assert_equal(1, latest.length)
222
- end
223
-
224
- def test_backtrace
225
- @store.report(Logger::INFO, "test", "pattern_1")
226
- message = @store.latest(limit: 1).first
227
- assert_match("test_backtrace", message.backtrace)
228
- end
229
-
230
- def test_ignore
231
- @store.ignore = [/^test/]
232
- @store.report(Logger::INFO, "test", "test it")
233
- @store.report(Logger::INFO, "test", " test it")
234
-
235
- assert_equal(1, @store.latest.count)
236
- end
237
-
238
- def test_solve
239
- Logster.config.application_version = "abc"
240
-
241
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
242
- m = @store.report(Logger::WARN, "application", "test error2", backtrace: "backtrace1")
243
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace2")
244
-
245
- assert_equal(3, @store.latest.count)
246
-
247
- @store.solve(m.key)
248
-
249
- assert_equal(1, @store.latest.count)
250
-
251
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
252
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
253
-
254
- assert_equal(2, @store.latest.count)
255
-
256
- ensure
257
- Logster.config.application_version = nil
258
- end
259
-
260
- def test_solve_grouped
261
- Logster.config.allow_grouping = true
262
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
263
- m = @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "efg"})
264
-
265
- assert_equal(1, @store.latest.count)
266
-
267
- @store.solve(m.key)
268
-
269
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
270
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "efg"})
271
-
272
- assert_equal(0, @store.latest.count)
273
-
274
- ensure
275
- Logster.config.allow_grouping = false
276
- end
277
-
278
- def test_clears_solved
279
- m = @store.report(Logger::WARN, "application", "test error2", backtrace: "backtrace1", env: {"application_version" => "abc"})
280
- @store.solve(m.key)
281
-
282
- assert_equal(1, @store.solved.length)
283
-
284
- @store.clear
285
- assert_equal(0, @store.solved.length)
286
- end
287
-
288
- def test_solving_with_some_missing_version
289
-
290
- m=@store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
291
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
292
-
293
- @store.solve(m.key)
294
-
295
- assert_equal(1, @store.latest.count)
296
- end
297
-
298
- def test_env
299
- env = Rack::MockRequest.env_for("/test").merge({
300
- "HTTP_HOST" => "www.site.com",
301
- "HTTP_USER_AGENT" => "SOME WHERE"
302
- })
303
- orig = env.dup
304
- orig["test"] = "tests"
305
- orig["test1"] = "tests1"
306
- Logster.add_to_env(env,"test","tests")
307
- Logster.add_to_env(env,"test1","tests1")
308
-
309
- orig.delete_if do |k,v|
310
- !%w{
311
- HTTP_HOST
312
- REQUEST_METHOD
313
- HTTP_USER_AGENT
314
- test
315
- test1
316
- }.include? k
317
- end
318
-
319
- @store.report(Logger::INFO, "test", "test", env: env)
320
-
321
- env = @store.latest.last.env
322
-
323
- env.delete "hostname"
324
- env.delete "process_id"
325
-
326
- assert_equal(orig, env)
327
- end
328
-
329
- def test_rate_limits
330
- %w{minute hour}.each do |duration|
331
- begin
332
- called = false
333
-
334
- assert_instance_of(
335
- Logster::RedisRateLimiter,
336
- @store.public_send("register_rate_limit_per_#{duration}", Logger::WARN, 0) do
337
- called = true
338
- end
339
- )
340
-
341
- @store.report(Logger::WARN, "test", "test")
342
- assert called
343
- ensure
344
- reset_redis
345
- end
346
- end
347
- end
348
-
349
- def test_rate_limits_only_checks_when_message_is_bumped_or_saved
350
- Logster.config.allow_grouping = true
351
- Logster.config.application_version = 'abc'
352
-
353
- @store.ignore = [/^ActiveRecord::RecordNotFound/]
354
- rate_limit = @store.register_rate_limit_per_minute(Logger::WARN, 0)
355
-
356
- message = @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
357
- assert_equal(1, rate_limit.retrieve_rate)
358
-
359
- @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
360
- assert_equal(2, rate_limit.retrieve_rate)
361
-
362
- @store.solve(message.key)
363
- @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
364
- assert_equal(2, rate_limit.retrieve_rate)
365
-
366
- @store.report(Logger::WARN, 'message 2', "Error!")
367
- assert_equal(3, rate_limit.retrieve_rate)
368
-
369
- @store.report(Logger::WARN, 'message 3', "ActiveRecord::RecordNotFound")
370
- assert_equal(3, rate_limit.retrieve_rate)
371
- ensure
372
- Logster.config.allow_grouping = false
373
- Logster.config.application_version = nil
374
- reset_redis
375
- end
376
-
377
- def test_rate_limits_with_prefix
378
- begin
379
- time = Time.now
380
- Timecop.freeze(time)
381
- current_namespace = 'first'
382
- @store.redis_prefix = Proc.new { current_namespace }
383
-
384
- called_first = 0
385
- called_second = 0
386
-
387
- @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_first += 1 }
388
- @store.report(Logger::WARN, "test", "test")
389
- assert_equal(1, called_first)
390
-
391
- current_namespace = 'second'
392
- @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_second += 1 }
393
- @store.report(Logger::WARN, "test", "test")
394
- assert_equal(1, called_first)
395
- assert_equal(1, called_second)
396
-
397
- Timecop.freeze(time + 10) do
398
- current_namespace = 'first'
399
- @store.report(Logger::WARN, "test", "test")
400
-
401
- assert_equal(2, called_first)
402
- assert_equal(1, called_second)
403
- end
404
- ensure
405
- reset_redis
406
- end
407
- end
408
-
409
- private
410
-
411
- def reset_redis
412
- @store.redis.flushall
413
- end
414
- end
1
+ require_relative '../test_helper'
2
+ require 'logster/redis_store'
3
+ require 'rack'
4
+
5
+ class TestRedisStore < Minitest::Test
6
+
7
+ def setup
8
+ @store = Logster::RedisStore.new(Redis.new)
9
+ @store.clear_all
10
+ end
11
+
12
+ def teardown
13
+ @store.clear_all
14
+ end
15
+
16
+ def test_delete
17
+ msg = @store.report(Logger::WARN, "test", "testing")
18
+ @store.delete(msg)
19
+ latest = @store.latest
20
+
21
+ assert_equal(0,latest.length)
22
+ end
23
+
24
+ def test_latest
25
+ @store.report(Logger::WARN, "test", "IGNORE")
26
+ @store.report(Logger::WARN, "test", "This is a warning")
27
+ @store.report(Logger::WARN, "test", "This is another warning")
28
+
29
+ latest = @store.latest(limit: 2)
30
+
31
+ assert_equal(2, latest.length)
32
+ assert_equal("This is a warning", latest[0].message)
33
+ assert_equal("This is another warning", latest[1].message)
34
+ assert_equal(Logger::WARN, latest[1].severity)
35
+ assert_equal("test", latest[1].progname)
36
+ assert(!latest[1].key.nil?)
37
+ end
38
+
39
+ def test_latest_after
40
+ 10.times do |i|
41
+ @store.report(Logger::WARN, "test", "A#{i}")
42
+ end
43
+
44
+ message = @store.latest[-1]
45
+
46
+ 3.times do |i|
47
+ @store.report(Logger::WARN, "test", i.to_s)
48
+ end
49
+
50
+ message = @store.latest(after: message.key, limit: 3)[0]
51
+
52
+ assert_equal("0", message.message)
53
+ end
54
+
55
+ def test_latest_before
56
+ 10.times do
57
+ @store.report(Logger::WARN, "test", "A")
58
+ end
59
+ 10.times do
60
+ @store.report(Logger::WARN, "test", "B")
61
+ end
62
+ 10.times do
63
+ @store.report(Logger::WARN, "test", "C")
64
+ end
65
+
66
+ messages = @store.latest(limit: 10)
67
+ assert_equal("C", messages[0].message)
68
+ assert_equal(10, messages.length)
69
+
70
+ messages = @store.latest(limit: 10, before: messages[0].key)
71
+ assert_equal("B", messages[0].message)
72
+ assert_equal(10, messages.length)
73
+
74
+ messages = @store.latest(limit: 10, before: messages[0].key)
75
+ assert_equal("A", messages[0].message)
76
+ assert_equal(10, messages.length)
77
+
78
+ end
79
+
80
+ def test_get
81
+ a_message = @store.report(Logger::WARN, "test", "A")
82
+ b_message = @store.report(Logger::WARN, "test", "B")
83
+ @store.report(Logger::WARN, "test", "C")
84
+
85
+ assert_equal("A", @store.get(a_message.key).message)
86
+ assert_equal("B", @store.get(b_message.key).message)
87
+ end
88
+
89
+ def test_backlog
90
+ @store.max_backlog = 1
91
+ @store.report(Logger::WARN, "test", "A")
92
+ @store.report(Logger::WARN, "test", "A")
93
+ @store.report(Logger::WARN, "test", "A")
94
+ @store.report(Logger::WARN, "test", "B")
95
+
96
+ latest = @store.latest
97
+
98
+ assert_equal(1, latest.length)
99
+ assert_equal("B", latest[0].message)
100
+ end
101
+
102
+ def test_save_unsave
103
+ @store.max_backlog = 3
104
+ @store.report(Logger::WARN, "test", "A")
105
+ b_message = @store.report(Logger::WARN, "test", "B")
106
+ @store.protect b_message.key
107
+ c_message = @store.report(Logger::WARN, "test", "C")
108
+ @store.protect c_message.key
109
+ @store.report(Logger::WARN, "test", "D")
110
+
111
+ latest = @store.latest
112
+
113
+ assert_equal(3, latest.length)
114
+ assert_equal("B", latest[0].message)
115
+ assert_equal("C", latest[1].message)
116
+ assert_equal(true, latest[1].protected)
117
+ assert_equal("D", latest[2].message)
118
+
119
+ # Saved messages still accessible by key
120
+ assert_equal("B", @store.get(b_message.key).message)
121
+ assert_equal(true, @store.get(b_message.key).protected)
122
+
123
+ # Unsave does not delete message if still recent
124
+ @store.unprotect c_message.key
125
+ assert_equal("C", @store.get(c_message.key).message)
126
+ assert_equal(false, @store.get(c_message.key).protected)
127
+ end
128
+
129
+ def test_clear
130
+ @store.max_backlog = 25
131
+ a_message = @store.report(Logger::WARN, "test", "A", timestamp: Time.now - (24*60*60))
132
+ @store.protect a_message.key
133
+ 20.times do
134
+ @store.report(Logger::WARN, "test", "B")
135
+ end
136
+ c_message = @store.report(Logger::WARN, "test", "C", timestamp: Time.now + (24*60*60))
137
+ @store.protect c_message.key
138
+ d_message = @store.report(Logger::WARN, "test", "D")
139
+ 10.times do
140
+ @store.report(Logger::WARN, "test", "E")
141
+ end
142
+
143
+ latest = @store.latest
144
+ assert_equal(25, latest.length)
145
+
146
+ @store.clear
147
+
148
+ # Protected messages are still accessible by their key
149
+ assert_equal("C", @store.get(c_message.key).message)
150
+ # Unprotected messages are gone
151
+ assert_nil(@store.get(d_message.key))
152
+
153
+ # The latest list is rebuilt with protected messages, earliest first
154
+ # Including messages that previously fell off (A)
155
+ latest = @store.latest
156
+ assert_equal(2, latest.length)
157
+ assert_equal("A", latest[0].message)
158
+ assert_equal("C", latest[1].message)
159
+ end
160
+
161
+ def test_hash_cleanup
162
+ @store.max_backlog = 2
163
+ a_message = @store.report(Logger::WARN, "test", "A")
164
+ @store.report(Logger::WARN, "test", "B")
165
+ @store.report(Logger::WARN, "test", "C")
166
+
167
+ assert_nil(@store.get(a_message.key))
168
+ end
169
+
170
+ def test_filter_latest
171
+ @store.report(Logger::INFO, "test", "A")
172
+ @store.report(Logger::WARN, "test", "B")
173
+
174
+ messages = @store.latest
175
+ assert_equal(2, messages.length)
176
+
177
+ messages = @store.latest(after: messages.last.key)
178
+ assert_equal(0, messages.length)
179
+
180
+ 10.times do
181
+ @store.report(Logger::INFO, "test", "A")
182
+ end
183
+ @store.report(Logger::ERROR, "test", "C")
184
+ 10.times do
185
+ @store.report(Logger::INFO, "test", "A")
186
+ end
187
+
188
+ latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2)
189
+
190
+ assert_equal(2, latest.length)
191
+ assert_equal("B", latest[0].message)
192
+ assert_equal("C", latest[1].message)
193
+
194
+ @store.report(Logger::ERROR, "test", "E")
195
+ # respects after
196
+ latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2, after: latest[1].key)
197
+ assert_equal(1, latest.length);
198
+ end
199
+
200
+ def test_search
201
+ @store.report(Logger::INFO, "test", "A")
202
+ @store.report(Logger::INFO, "test", "B")
203
+
204
+ messages = @store.latest
205
+ assert_equal(2, messages.length)
206
+
207
+ latest = @store.latest(search: "B")
208
+
209
+ assert_equal(1, latest.length)
210
+ end
211
+
212
+ def test_search_exclude_results
213
+ @store.report(Logger::INFO, "test", "A")
214
+ @store.report(Logger::INFO, "test", "B")
215
+
216
+ messages = @store.latest
217
+ assert_equal(2, messages.length)
218
+
219
+ latest = @store.latest(search: "-A")
220
+
221
+ assert_equal(1, latest.length)
222
+ assert_equal("B", latest[0].message)
223
+ end
224
+
225
+ def test_regex_search
226
+ @store.report(Logger::INFO, "test", "pattern_1")
227
+ @store.report(Logger::INFO, "test", "pattern_2")
228
+
229
+ messages = @store.latest
230
+ assert_equal(2, messages.length)
231
+
232
+ latest = @store.latest(search: /^pattern_[1]$/)
233
+
234
+ assert_equal(1, latest.length)
235
+ end
236
+
237
+ def test_backtrace
238
+ @store.report(Logger::INFO, "test", "pattern_1")
239
+ message = @store.latest(limit: 1).first
240
+ assert_match("test_backtrace", message.backtrace)
241
+ end
242
+
243
+ def test_ignore
244
+ @store.ignore = [/^test/]
245
+ @store.report(Logger::INFO, "test", "test it")
246
+ @store.report(Logger::INFO, "test", " test it")
247
+
248
+ assert_equal(1, @store.latest.count)
249
+ end
250
+
251
+ def test_solve
252
+ Logster.config.application_version = "abc"
253
+
254
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
255
+ m = @store.report(Logger::WARN, "application", "test error2", backtrace: "backtrace1")
256
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace2")
257
+
258
+ assert_equal(3, @store.latest.count)
259
+
260
+ @store.solve(m.key)
261
+
262
+ assert_equal(1, @store.latest.count)
263
+
264
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
265
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
266
+
267
+ assert_equal(2, @store.latest.count)
268
+
269
+ ensure
270
+ Logster.config.application_version = nil
271
+ end
272
+
273
+ def test_solve_grouped
274
+ Logster.config.allow_grouping = true
275
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
276
+ m = @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "efg"})
277
+
278
+ assert_equal(1, @store.latest.count)
279
+
280
+ @store.solve(m.key)
281
+
282
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
283
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "efg"})
284
+
285
+ assert_equal(0, @store.latest.count)
286
+
287
+ ensure
288
+ Logster.config.allow_grouping = false
289
+ end
290
+
291
+ def test_clears_solved
292
+ m = @store.report(Logger::WARN, "application", "test error2", backtrace: "backtrace1", env: {"application_version" => "abc"})
293
+ @store.solve(m.key)
294
+
295
+ assert_equal(1, @store.solved.length)
296
+
297
+ @store.clear
298
+ assert_equal(0, @store.solved.length)
299
+ end
300
+
301
+ def test_solving_with_some_missing_version
302
+
303
+ m=@store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1", env: { "application_version" => "xyz"})
304
+ @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
305
+
306
+ @store.solve(m.key)
307
+
308
+ assert_equal(1, @store.latest.count)
309
+ end
310
+
311
+ def test_env
312
+ env = Rack::MockRequest.env_for("/test").merge({
313
+ "HTTP_HOST" => "www.site.com",
314
+ "HTTP_USER_AGENT" => "SOME WHERE"
315
+ })
316
+ orig = env.dup
317
+ orig["test"] = "tests"
318
+ orig["test1"] = "tests1"
319
+ Logster.add_to_env(env,"test","tests")
320
+ Logster.add_to_env(env,"test1","tests1")
321
+
322
+ orig.delete_if do |k,v|
323
+ !%w{
324
+ HTTP_HOST
325
+ REQUEST_METHOD
326
+ HTTP_USER_AGENT
327
+ test
328
+ test1
329
+ }.include? k
330
+ end
331
+
332
+ @store.report(Logger::INFO, "test", "test", env: env)
333
+
334
+ env = @store.latest.last.env
335
+
336
+ env.delete "hostname"
337
+ env.delete "process_id"
338
+
339
+ assert_equal(orig, env)
340
+ end
341
+
342
+ def test_rate_limits
343
+ %w{minute hour}.each do |duration|
344
+ begin
345
+ called = false
346
+
347
+ assert_instance_of(
348
+ Logster::RedisRateLimiter,
349
+ @store.public_send("register_rate_limit_per_#{duration}", Logger::WARN, 0) do
350
+ called = true
351
+ end
352
+ )
353
+
354
+ @store.report(Logger::WARN, "test", "test")
355
+ assert called
356
+ ensure
357
+ reset_redis
358
+ end
359
+ end
360
+ end
361
+
362
+ def test_rate_limits_only_checks_when_message_is_bumped_or_saved
363
+ Logster.config.allow_grouping = true
364
+ Logster.config.application_version = 'abc'
365
+
366
+ @store.ignore = [/^ActiveRecord::RecordNotFound/]
367
+ rate_limit = @store.register_rate_limit_per_minute(Logger::WARN, 0)
368
+
369
+ message = @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
370
+ assert_equal(1, rate_limit.retrieve_rate)
371
+
372
+ @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
373
+ assert_equal(2, rate_limit.retrieve_rate)
374
+
375
+ @store.solve(message.key)
376
+ @store.report(Logger::WARN, 'message 1', "Error!", backtrace: 'here')
377
+ assert_equal(2, rate_limit.retrieve_rate)
378
+
379
+ @store.report(Logger::WARN, 'message 2', "Error!")
380
+ assert_equal(3, rate_limit.retrieve_rate)
381
+
382
+ @store.report(Logger::WARN, 'message 3', "ActiveRecord::RecordNotFound")
383
+ assert_equal(3, rate_limit.retrieve_rate)
384
+ ensure
385
+ Logster.config.allow_grouping = false
386
+ Logster.config.application_version = nil
387
+ reset_redis
388
+ end
389
+
390
+ def test_rate_limits_with_prefix
391
+ begin
392
+ time = Time.now
393
+ Timecop.freeze(time)
394
+ current_namespace = 'first'
395
+ @store.redis_prefix = Proc.new { current_namespace }
396
+
397
+ called_first = 0
398
+ called_second = 0
399
+
400
+ @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_first += 1 }
401
+ @store.report(Logger::WARN, "test", "test")
402
+ assert_equal(1, called_first)
403
+
404
+ current_namespace = 'second'
405
+ @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_second += 1 }
406
+ @store.report(Logger::WARN, "test", "test")
407
+ assert_equal(1, called_first)
408
+ assert_equal(1, called_second)
409
+
410
+ Timecop.freeze(time + 10) do
411
+ current_namespace = 'first'
412
+ @store.report(Logger::WARN, "test", "test")
413
+
414
+ assert_equal(2, called_first)
415
+ assert_equal(1, called_second)
416
+ end
417
+ ensure
418
+ reset_redis
419
+ end
420
+ end
421
+
422
+ private
423
+
424
+ def reset_redis
425
+ @store.redis.flushall
426
+ end
427
+ end