logster 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
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