logster 1.3.0 → 1.3.1

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -18
  3. data/.travis.yml +15 -15
  4. data/CHANGELOG.md +137 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -99
  9. data/Rakefile +24 -24
  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 -81
  21. data/assets/javascript/vendor.js +5302 -5302
  22. data/assets/stylesheets/client-app.css +0 -0
  23. data/assets/stylesheets/vendor.css +3 -3
  24. data/build_client_app.sh +12 -12
  25. data/client-app/.editorconfig +20 -20
  26. data/client-app/.ember-cli +9 -9
  27. data/client-app/.eslintignore +19 -19
  28. data/client-app/.eslintrc.js +46 -46
  29. data/client-app/.gitignore +23 -23
  30. data/client-app/.travis.yml +27 -27
  31. data/client-app/.watchmanconfig +3 -3
  32. data/client-app/README.md +57 -57
  33. data/client-app/app/app.js +14 -14
  34. data/client-app/app/components/message-info.js +18 -18
  35. data/client-app/app/components/message-row.js +45 -45
  36. data/client-app/app/components/panel-resizer.js +75 -75
  37. data/client-app/app/components/tab-contents.js +27 -27
  38. data/client-app/app/components/tab-link.js +5 -5
  39. data/client-app/app/components/tabbed-section.js +32 -32
  40. data/client-app/app/components/time-formatter.js +25 -25
  41. data/client-app/app/components/update-time.js +21 -21
  42. data/client-app/app/controllers/index.js +83 -83
  43. data/client-app/app/controllers/show.js +13 -13
  44. data/client-app/app/index.html +29 -29
  45. data/client-app/app/initializers/app-init.js +55 -55
  46. data/client-app/app/lib/preload.js +14 -14
  47. data/client-app/app/lib/utilities.js +140 -140
  48. data/client-app/app/models/message-collection.js +158 -158
  49. data/client-app/app/models/message.js +99 -99
  50. data/client-app/app/resolver.js +3 -3
  51. data/client-app/app/router.js +14 -14
  52. data/client-app/app/routes/index.js +53 -53
  53. data/client-app/app/routes/show.js +14 -14
  54. data/client-app/app/styles/app.css +387 -387
  55. data/client-app/app/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -44
  57. data/client-app/app/templates/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -10
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -1
  60. data/client-app/app/templates/index.hbs +57 -57
  61. data/client-app/app/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -51
  63. data/client-app/config/optional-features.json +3 -3
  64. data/client-app/config/targets.js +18 -18
  65. data/client-app/ember-cli-build.js +29 -29
  66. data/client-app/package-lock.json +11365 -11365
  67. data/client-app/package.json +56 -56
  68. data/client-app/testem.js +25 -25
  69. data/client-app/tests/index.html +34 -34
  70. data/client-app/tests/integration/components/message-info-test.js +26 -26
  71. data/client-app/tests/integration/components/message-row-test.js +26 -26
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -26
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -26
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -26
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -26
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -26
  77. data/client-app/tests/integration/components/update-time-test.js +26 -26
  78. data/client-app/tests/test-helper.js +8 -8
  79. data/client-app/tests/unit/controllers/index-test.js +12 -12
  80. data/client-app/tests/unit/controllers/show-test.js +12 -12
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -31
  82. data/client-app/tests/unit/routes/index-test.js +11 -11
  83. data/client-app/tests/unit/routes/show-test.js +11 -11
  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 +108 -102
  90. data/lib/logster/message.rb +227 -227
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -56
  93. data/lib/logster/middleware/viewer.rb +220 -220
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -481
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -34
  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 -96
  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 +80 -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 -427
  110. data/test/test_helper.rb +38 -38
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +3 -3
@@ -1,427 +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_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
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