logster 2.21.0 → 3.0.0

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/README.md +29 -14
  4. data/assets/javascript/main-B82IoCiW.js +1 -0
  5. data/assets/javascript/modules-4-12-BHA4lR2U.js +1 -0
  6. data/assets/javascript/vendor.js +11 -5260
  7. data/assets/logster-config.json +18 -0
  8. data/assets/manifest.json +23 -0
  9. data/assets/stylesheets/main-CgAFFyi8.css +1 -0
  10. data/lib/logster/configuration.rb +1 -0
  11. data/lib/logster/middleware/reporter.rb +34 -3
  12. data/lib/logster/middleware/viewer.rb +204 -32
  13. data/lib/logster/rails/railtie.rb +4 -20
  14. data/lib/logster/redis_store.rb +0 -2
  15. data/lib/logster/version.rb +1 -1
  16. data/lib/logster.rb +1 -1
  17. metadata +17 -186
  18. data/.github/workflows/ci.yml +0 -140
  19. data/.gitignore +0 -3
  20. data/.rubocop.yml +0 -12
  21. data/.streerc +0 -2
  22. data/Gemfile +0 -10
  23. data/Guardfile +0 -10
  24. data/Rakefile +0 -24
  25. data/assets/javascript/.gitkeep +0 -0
  26. data/assets/javascript/chunk.524.b7d0b89d25457a72409c.js +0 -22
  27. data/assets/javascript/chunk.582.5a04ae4713e692cd335a.js +0 -22
  28. data/assets/javascript/chunk.747.a730c497582bb6742a6e.js +0 -579
  29. data/assets/javascript/chunk.761.64949d89942c829e5c1b.js +0 -1213
  30. data/assets/javascript/client-app.js +0 -1389
  31. data/assets/stylesheets/.gitkeep +0 -0
  32. data/assets/stylesheets/client-app.css +0 -1
  33. data/assets/stylesheets/vendor.css +0 -1
  34. data/build_client_app.sh +0 -10
  35. data/client-app/.editorconfig +0 -19
  36. data/client-app/.ember-cli +0 -9
  37. data/client-app/.eslintignore +0 -20
  38. data/client-app/.eslintrc +0 -10
  39. data/client-app/.gitignore +0 -23
  40. data/client-app/.prettierignore +0 -21
  41. data/client-app/.prettierrc +0 -1
  42. data/client-app/.template-lintrc.js +0 -10
  43. data/client-app/.watchmanconfig +0 -3
  44. data/client-app/README.md +0 -56
  45. data/client-app/app/app.js +0 -12
  46. data/client-app/app/components/actions-menu.js +0 -50
  47. data/client-app/app/components/back-to-site-link.js +0 -9
  48. data/client-app/app/components/back-trace.js +0 -153
  49. data/client-app/app/components/env-tab.js +0 -68
  50. data/client-app/app/components/message-info.js +0 -151
  51. data/client-app/app/components/message-row.js +0 -46
  52. data/client-app/app/components/page-nav.js +0 -42
  53. data/client-app/app/components/panel-resizer.js +0 -108
  54. data/client-app/app/components/patterns-list.js +0 -142
  55. data/client-app/app/components/tab-contents.js +0 -23
  56. data/client-app/app/components/tabbed-section.js +0 -45
  57. data/client-app/app/components/time-formatter.js +0 -36
  58. data/client-app/app/controllers/index.js +0 -288
  59. data/client-app/app/controllers/show.js +0 -39
  60. data/client-app/app/helpers/logster-url.js +0 -12
  61. data/client-app/app/helpers/or.js +0 -7
  62. data/client-app/app/index.html +0 -31
  63. data/client-app/app/initializers/app-init.js +0 -71
  64. data/client-app/app/lib/decorators.js +0 -13
  65. data/client-app/app/lib/preload.js +0 -43
  66. data/client-app/app/lib/utilities.js +0 -230
  67. data/client-app/app/models/group.js +0 -34
  68. data/client-app/app/models/message-collection.js +0 -303
  69. data/client-app/app/models/message.js +0 -128
  70. data/client-app/app/models/pattern-item.js +0 -32
  71. data/client-app/app/resolver.js +0 -3
  72. data/client-app/app/router.js +0 -13
  73. data/client-app/app/routes/index.js +0 -64
  74. data/client-app/app/routes/settings.js +0 -32
  75. data/client-app/app/routes/show.js +0 -16
  76. data/client-app/app/services/events.js +0 -4
  77. data/client-app/app/styles/app.css +0 -898
  78. data/client-app/app/templates/application.hbs +0 -1
  79. data/client-app/app/templates/components/actions-menu.hbs +0 -31
  80. data/client-app/app/templates/components/back-to-site-link.hbs +0 -8
  81. data/client-app/app/templates/components/back-trace.hbs +0 -15
  82. data/client-app/app/templates/components/env-tab.hbs +0 -10
  83. data/client-app/app/templates/components/message-info.hbs +0 -86
  84. data/client-app/app/templates/components/message-row.hbs +0 -32
  85. data/client-app/app/templates/components/page-nav.hbs +0 -37
  86. data/client-app/app/templates/components/panel-resizer.hbs +0 -3
  87. data/client-app/app/templates/components/patterns-list.hbs +0 -78
  88. data/client-app/app/templates/components/tabbed-section.hbs +0 -18
  89. data/client-app/app/templates/components/time-formatter.hbs +0 -1
  90. data/client-app/app/templates/index.hbs +0 -192
  91. data/client-app/app/templates/settings.hbs +0 -47
  92. data/client-app/app/templates/show.hbs +0 -13
  93. data/client-app/config/ember-cli-update.json +0 -18
  94. data/client-app/config/environment.js +0 -51
  95. data/client-app/config/icons.js +0 -28
  96. data/client-app/config/optional-features.json +0 -6
  97. data/client-app/config/targets.js +0 -26
  98. data/client-app/ember-cli-build.js +0 -34
  99. data/client-app/package.json +0 -76
  100. data/client-app/preload-json-manager.rb +0 -35
  101. data/client-app/public/assets/images/icon_144x144.png +0 -0
  102. data/client-app/public/assets/images/icon_64x64.png +0 -0
  103. data/client-app/testem.js +0 -23
  104. data/client-app/tests/index.html +0 -41
  105. data/client-app/tests/integration/components/back-to-site-link-test.js +0 -20
  106. data/client-app/tests/integration/components/back-trace-test.js +0 -138
  107. data/client-app/tests/integration/components/env-tab-test.js +0 -220
  108. data/client-app/tests/integration/components/message-info-test.js +0 -122
  109. data/client-app/tests/integration/components/patterns-list-test.js +0 -76
  110. data/client-app/tests/test-helper.js +0 -12
  111. data/client-app/tests/unit/controllers/index-test.js +0 -77
  112. data/client-app/tests/unit/controllers/show-test.js +0 -12
  113. data/client-app/tests/unit/routes/index-test.js +0 -11
  114. data/client-app/tests/unit/routes/show-test.js +0 -11
  115. data/client-app/yarn.lock +0 -9905
  116. data/gemfiles/rails_6.1.gemfile +0 -12
  117. data/gemfiles/rails_7.0.gemfile +0 -12
  118. data/gemfiles/rails_7.1.gemfile +0 -9
  119. data/gemfiles/rails_7.2.gemfile +0 -9
  120. data/logster.gemspec +0 -43
  121. data/test/dummy/config/application.rb +0 -31
  122. data/test/dummy/config/boot.rb +0 -6
  123. data/test/dummy/config/environment.rb +0 -6
  124. data/test/examples/test_sidekiq_reporter_example.rb +0 -47
  125. data/test/fake_data/Gemfile +0 -6
  126. data/test/fake_data/generate.rb +0 -23
  127. data/test/logster/middleware/test_reporter.rb +0 -84
  128. data/test/logster/middleware/test_viewer.rb +0 -495
  129. data/test/logster/test_base_store.rb +0 -224
  130. data/test/logster/test_cache.rb +0 -39
  131. data/test/logster/test_defer_logger.rb +0 -36
  132. data/test/logster/test_group.rb +0 -92
  133. data/test/logster/test_ignore_pattern.rb +0 -42
  134. data/test/logster/test_logger.rb +0 -177
  135. data/test/logster/test_message.rb +0 -269
  136. data/test/logster/test_pattern.rb +0 -144
  137. data/test/logster/test_railtie.rb +0 -21
  138. data/test/logster/test_redis_rate_limiter.rb +0 -246
  139. data/test/logster/test_redis_store.rb +0 -1165
  140. data/test/test_helper.rb +0 -66
@@ -1,1165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../test_helper"
4
- require "logster/redis_store"
5
- require "rack"
6
-
7
- class TestRedisStore < Minitest::Test
8
- def setup
9
- @store = Logster::RedisStore.new(Redis.new)
10
- @store.clear_all
11
- end
12
-
13
- def teardown
14
- @store.clear_all
15
- end
16
-
17
- def test_delete
18
- env = { test_env: "this is env" }
19
- msg = @store.report(Logger::WARN, "test", "testing", env: env)
20
- @store.delete(msg)
21
- latest = @store.latest
22
-
23
- assert_equal(0, latest.length)
24
- assert_nil(@store.get_env(msg.key))
25
- end
26
-
27
- def test_delete_with_custom_grouping_patterns
28
- Logster.config.enable_custom_patterns_via_ui = true
29
- Logster::GroupingPattern.new(/delete/, store: @store).save
30
- msg1 = @store.report(Logger::WARN, "", "this will be deleted")
31
- msg2 = @store.report(Logger::WARN, "", "delete this plz")
32
-
33
- groups = @store.find_pattern_groups
34
- assert_equal 1, groups.size
35
- assert_equal [msg2.key, msg1.key], groups[0].messages_keys
36
-
37
- @store.delete(msg1)
38
- groups = @store.find_pattern_groups
39
- assert_equal 1, groups.size
40
- assert_equal [msg2.key], groups[0].messages_keys
41
-
42
- @store.delete(msg2)
43
- groups = @store.find_pattern_groups
44
- assert_equal 0, groups.size
45
- ensure
46
- Logster.config.enable_custom_patterns_via_ui = false
47
- end
48
-
49
- def test_bulk_delete_with_custom_grouping_patterns
50
- Logster.config.enable_custom_patterns_via_ui = true
51
- Logster::GroupingPattern.new(/delete/, store: @store).save
52
- keys = []
53
- gkeys = []
54
- 6.times do |n|
55
- m = @store.report(Logger::WARN, "", "#{n} delete")
56
- keys << m.key
57
- gkeys << m.grouping_key
58
- end
59
-
60
- groups = @store.find_pattern_groups
61
- assert_equal 1, groups.size
62
- assert_equal keys.reverse, groups[0].messages_keys
63
-
64
- @store.bulk_delete(keys[0..2], gkeys[0..2])
65
- groups = @store.find_pattern_groups
66
- assert_equal 1, groups.size
67
- assert_equal keys[3..5].reverse, groups[0].messages_keys
68
-
69
- @store.bulk_delete(keys, gkeys)
70
- groups = @store.find_pattern_groups
71
- assert_equal 0, groups.size
72
- ensure
73
- Logster.config.enable_custom_patterns_via_ui = false
74
- end
75
-
76
- def test_latest
77
- @store.report(Logger::WARN, "test", "IGNORE")
78
- @store.report(Logger::WARN, "test", "This is a warning")
79
- @store.report(Logger::WARN, "test", "This is another warning")
80
-
81
- latest = @store.latest(limit: 2)
82
-
83
- assert_equal(2, latest.length)
84
- assert_equal("This is a warning", latest[0].message)
85
- assert_equal("This is another warning", latest[1].message)
86
- assert_equal(Logger::WARN, latest[1].severity)
87
- assert_equal("test", latest[1].progname)
88
- assert(!latest[1].key.nil?)
89
- end
90
-
91
- def test_latest_after
92
- 10.times { |i| @store.report(Logger::WARN, "test", "A#{i}") }
93
-
94
- message = @store.latest[-1]
95
-
96
- 3.times { |i| @store.report(Logger::WARN, "test", i.to_s) }
97
-
98
- message = @store.latest(after: message.key, limit: 3)[0]
99
-
100
- assert_equal("0", message.message)
101
- end
102
-
103
- def test_latest_before
104
- 10.times { @store.report(Logger::WARN, "test", "A") }
105
- 10.times { @store.report(Logger::WARN, "test", "B") }
106
- 10.times { @store.report(Logger::WARN, "test", "C") }
107
-
108
- messages = @store.latest(limit: 10)
109
- assert_equal("C", messages[0].message)
110
- assert_equal(10, messages.length)
111
-
112
- messages = @store.latest(limit: 10, before: messages[0].key)
113
- assert_equal("B", messages[0].message)
114
- assert_equal(10, messages.length)
115
-
116
- messages = @store.latest(limit: 10, before: messages[0].key)
117
- assert_equal("A", messages[0].message)
118
- assert_equal(10, messages.length)
119
- end
120
-
121
- def test_latest_with_custom_grouping
122
- Logster.config.enable_custom_patterns_via_ui = true
123
- Logster::GroupingPattern.new(/group 1/, store: @store).save
124
- Logster::GroupingPattern.new(/group 2/, store: @store).save
125
- msg1 = @store.report(Logger::WARN, "", "first message")
126
- group_1_keys = []
127
- 3.times { |n| group_1_keys << @store.report(Logger::WARN, "", "group 1 #{n}").key }
128
- msg2 = @store.report(Logger::WARN, "", "second message")
129
- group_1_keys << @store.report(Logger::WARN, "", "group 1 3").key
130
- msg3 = @store.report(Logger::WARN, "", "third message")
131
- group_2_keys = []
132
- 3.times { |n| group_2_keys << @store.report(Logger::WARN, "", "group 2 #{n}").key }
133
- msg4 = @store.report(Logger::WARN, "", "fourth message")
134
-
135
- results = @store.latest
136
- assert_equal [msg1.key, msg2.key, "/group 1/", msg3.key, "/group 2/", msg4.key],
137
- results.map(&:key)
138
- groups = results.select { |r| r.class == Logster::Group::GroupWeb }
139
- assert_equal([group_1_keys.last, group_2_keys.last], groups.map(&:row_id))
140
- assert_equal 4, groups[0].messages.size
141
- assert_equal 3, groups[1].messages.size
142
-
143
- results = @store.latest(before: groups[0].row_id, known_groups: groups.map(&:key))
144
- assert_equal [msg1.key, msg2.key], results.map(&:key)
145
-
146
- results = @store.latest(before: groups[1].row_id, known_groups: [groups[1].key])
147
- assert_equal [msg1.key, msg2.key, "/group 1/", msg3.key], results.map(&:key)
148
-
149
- results = @store.latest(before: msg2.key, known_groups: groups.map(&:key))
150
- assert_equal [msg1.key], results.map(&:key)
151
-
152
- results = @store.latest(after: groups[0].row_id)
153
- assert_equal [msg3.key, "/group 2/", msg4.key], results.map(&:key)
154
-
155
- results = @store.latest(after: msg2.key)
156
- assert_equal ["/group 1/", msg3.key, "/group 2/", msg4.key], results.map(&:key)
157
- assert_equal 4, results[0].messages.size
158
-
159
- results = @store.latest(after: msg4.key)
160
- assert_equal 0, results.size
161
-
162
- group_2_keys << @store.report(Logger::WARN, "", "group 2 3").key
163
- results = @store.latest(after: msg4.key)
164
- assert_equal ["/group 2/"], results.map(&:key)
165
- assert_equal group_2_keys.last, results[0].row_id
166
- assert_equal 4, results[0].messages.size
167
- ensure
168
- Logster.config.enable_custom_patterns_via_ui = false
169
- end
170
-
171
- def test_get
172
- a_env = { "a_message" => "A MESSAGE" }
173
- a_message = @store.report(Logger::WARN, "test", "A", env: a_env)
174
- b_message = @store.report(Logger::WARN, "test", "B")
175
- @store.report(Logger::WARN, "test", "C")
176
-
177
- a_message = @store.get(a_message.key)
178
- assert_equal("A", a_message.message)
179
- assert_equal("B", b_message.message)
180
- assert(a_env <= a_message.env)
181
-
182
- a_message = @store.get(a_message.key, load_env: false)
183
- assert_equal("A", a_message.message)
184
- assert_nil(a_message.env)
185
- end
186
-
187
- def test_save_saves_env_separately
188
- env = { "myenv" => "thisisenv" }
189
- message = @store.report(Logger::WARN, "test", "title", env: env)
190
- message = @store.get(message.key, load_env: false)
191
- assert_nil(message.env)
192
-
193
- message = @store.get(message.key)
194
- assert(env <= message.env)
195
-
196
- assert(env <= @store.get_env(message.key))
197
- end
198
-
199
- def test_bulk_get
200
- keys = []
201
-
202
- 5.times do |n|
203
- env = n == 0 ? nil : { "test_#{n}" => "envsss" }
204
- keys << @store.report(Logger::WARN, "progname", "test_#{n}", env: env).key
205
- end
206
-
207
- messages = @store.bulk_get(keys)
208
-
209
- 5.times do |n|
210
- msg = messages[n]
211
- assert_equal("test_#{n}", msg.message)
212
- if n == 0
213
- assert_equal(Logster::Message.default_env.merge("time" => msg.timestamp), msg.env)
214
- else
215
- assert({ "test_#{n}" => "envsss" } <= msg.env)
216
- end
217
- assert_equal(msg.timestamp, msg.env["time"])
218
- end
219
- end
220
-
221
- def test_get_env
222
- env = { "my_little_env" => "some value" }
223
- message = @store.report(Logger::WARN, "test", "A", env: env)
224
- assert(env <= @store.get_env(message.key))
225
- assert_nil(@store.get_env("nonexistentkey"))
226
- end
227
-
228
- def test_replace_and_bump
229
- old_env = { "old_env" => "old value" }
230
- message = @store.report(Logger::WARN, "test", "A", env: old_env)
231
-
232
- extra_env = { "saved_env" => "saved value!" }
233
- similar = @store.report(Logger::WARN, "test", "A", env: extra_env)
234
- message.merge_similar_message(similar)
235
-
236
- @store.replace_and_bump(message)
237
-
238
- message = @store.get(message.key)
239
- assert(extra_env <= message.env[0])
240
- assert(old_env <= message.env[1])
241
- end
242
-
243
- def test_ensure_env_doesnt_exceed_50_item
244
- Logster.config.allow_grouping = true
245
- message = nil
246
- 52.times { |n| message = @store.report(Logger::WARN, "", "mssage", env: { a: n }) }
247
- message = @store.get(message.key)
248
- assert_equal(52, message.count)
249
- assert_equal(50, message.env.size)
250
- assert_equal((2..51).to_a, message.env.map { |e| e[:a] || e["a"] }.sort)
251
- ensure
252
- Logster.config.allow_grouping = false
253
- end
254
-
255
- def test_merging_performance
256
- Logster.config.allow_grouping = true
257
- backtrace = "fake backtrace"
258
- env = [{ "some_env" => "some env" }] * 50
259
- new_env = { "some_key" => "1234442" }
260
-
261
- @store.report(Logger::WARN, "", "title", backtrace: backtrace, env: env, count: 50)
262
-
263
- message = @store.report(Logger::WARN, "", "title", backtrace: backtrace, env: new_env)
264
- # env is nil cause we don't need to fetch it from redis
265
- # we just send the newly added envs to redis and it'll
266
- # take care of prepending them to the existing envs
267
- assert_nil(message.env)
268
-
269
- message = @store.get(message.key)
270
- assert_instance_of(Array, message.env)
271
- assert_equal(50, message.env.size)
272
- assert_equal(51, message.count)
273
- assert(new_env <= message.env[0])
274
- ensure
275
- Logster.config.allow_grouping = false
276
- end
277
-
278
- def test_backlog
279
- env = { "backlog_test" => "BACKLOG" }
280
- @store.max_backlog = 1
281
- deleted_msg = @store.report(Logger::WARN, "test", "A")
282
- @store.report(Logger::WARN, "test", "A")
283
- @store.report(Logger::WARN, "test", "A")
284
- @store.report(Logger::WARN, "test", "B", env: env)
285
-
286
- latest = @store.latest
287
-
288
- assert_equal(1, latest.length)
289
- assert_equal("B", latest[0].message)
290
- assert(env <= latest[0].env)
291
- assert_nil(@store.get(deleted_msg.key))
292
- assert_nil(@store.get_env(deleted_msg.key))
293
- end
294
-
295
- def test_save_unsave
296
- @store.max_backlog = 3
297
- @store.report(Logger::WARN, "test", "A")
298
- b_message = @store.report(Logger::WARN, "test", "B")
299
- @store.protect b_message.key
300
- c_message = @store.report(Logger::WARN, "test", "C")
301
- @store.protect c_message.key
302
- @store.report(Logger::WARN, "test", "D")
303
-
304
- latest = @store.latest
305
-
306
- assert_equal(3, latest.length)
307
- assert_equal("B", latest[0].message)
308
- assert_equal("C", latest[1].message)
309
- assert_equal(true, latest[1].protected)
310
- assert_equal("D", latest[2].message)
311
-
312
- # Saved messages still accessible by key
313
- assert_equal("B", @store.get(b_message.key).message)
314
- assert_equal(true, @store.get(b_message.key).protected)
315
-
316
- # Unsave does not delete message if still recent
317
- @store.unprotect c_message.key
318
- assert_equal("C", @store.get(c_message.key).message)
319
- assert_equal(false, @store.get(c_message.key).protected)
320
- end
321
-
322
- def test_clear
323
- env = { "clear_env" => "cllleear" }
324
- @store.max_backlog = 25
325
- a_message =
326
- @store.report(Logger::WARN, "test", "A", timestamp: Time.now - (24 * 60 * 60), env: env)
327
- @store.protect a_message.key
328
- 20.times { @store.report(Logger::WARN, "test", "B", env: env) }
329
- c_message =
330
- @store.report(Logger::WARN, "test", "C", timestamp: Time.now + (24 * 60 * 60), env: env)
331
- @store.protect c_message.key
332
- d_message = @store.report(Logger::WARN, "test", "D", env: env)
333
- 10.times { @store.report(Logger::WARN, "test", "E", env: env) }
334
-
335
- latest = @store.latest
336
- assert_equal(25, latest.length)
337
-
338
- @store.clear
339
-
340
- # Protected messages are still accessible by their key
341
- assert_equal("C", @store.get(c_message.key).message)
342
- assert(env <= @store.get_env(c_message.key))
343
- # Unprotected messages are gone
344
- assert_nil(@store.get(d_message.key))
345
- assert_nil(@store.get_env(d_message.key))
346
-
347
- # The latest list is rebuilt with protected messages, earliest first
348
- # Including messages that previously fell off (A)
349
- latest = @store.latest
350
- assert_equal(2, latest.length)
351
- assert_equal("A", latest[0].message)
352
- assert_equal("C", latest[1].message)
353
- assert(env <= latest[0].env)
354
- assert(env <= latest[1].env)
355
- end
356
-
357
- def test_clear_deletes_pattern_groups_if_not_protected
358
- Logster.config.enable_custom_patterns_via_ui = true
359
- Logster.config.allow_grouping = true
360
- Logster::GroupingPattern.new(/discourse/, store: @store).save
361
- Logster::GroupingPattern.new(/logster/, store: @store).save
362
- msg = @store.report(Logger::WARN, "", "discourse")
363
- @store.protect(msg.key)
364
- @store.report(Logger::WARN, "", "logster")
365
- groups = @store.find_pattern_groups
366
- assert_equal 2, groups.size
367
-
368
- @store.clear
369
- groups = @store.find_pattern_groups
370
- assert_equal 1, groups.size
371
- assert_equal msg.key, groups[0].messages_keys[0]
372
- assert_equal "/discourse/", groups[0].key
373
-
374
- @store.unprotect(msg.key)
375
- @store.clear
376
- groups = @store.find_pattern_groups
377
- assert_equal 0, groups.size
378
- ensure
379
- Logster.config.enable_custom_patterns_via_ui = false
380
- Logster.config.allow_grouping = false
381
- end
382
-
383
- def test_hash_cleanup
384
- @store.max_backlog = 2
385
- a_message = @store.report(Logger::WARN, "test", "A")
386
- @store.report(Logger::WARN, "test", "B")
387
- @store.report(Logger::WARN, "test", "C")
388
-
389
- assert_nil(@store.get(a_message.key))
390
- end
391
-
392
- def test_filter_latest
393
- @store.report(Logger::INFO, "test", "A")
394
- @store.report(Logger::WARN, "test", "B")
395
-
396
- messages = @store.latest
397
- assert_equal(2, messages.length)
398
-
399
- messages = @store.latest(after: messages.last.key)
400
- assert_equal(0, messages.length)
401
-
402
- 10.times { @store.report(Logger::INFO, "test", "A") }
403
- @store.report(Logger::ERROR, "test", "C")
404
- 10.times { @store.report(Logger::INFO, "test", "A") }
405
-
406
- latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2)
407
-
408
- assert_equal(2, latest.length)
409
- assert_equal("B", latest[0].message)
410
- assert_equal("C", latest[1].message)
411
-
412
- @store.report(Logger::ERROR, "test", "E")
413
- # respects after
414
- latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2, after: latest[1].key)
415
- assert_equal(1, latest.length)
416
- end
417
-
418
- def test_search
419
- @store.report(Logger::INFO, "test", "ABCDEFG")
420
- @store.report(Logger::INFO, "test", "TUVWXYZ")
421
-
422
- messages = @store.latest
423
- assert_equal(2, messages.length)
424
-
425
- latest = @store.latest(search: "TUVWXYZ")
426
-
427
- assert_equal(1, latest.length)
428
- assert_equal("TUVWXYZ", latest[0].message)
429
- end
430
-
431
- def test_search_works_with_invalid_regex_chars
432
- @store.report(Logger::INFO, "test", "ABCDEFG\\")
433
- @store.report(Logger::INFO, "test", "TUVWXYZ")
434
-
435
- result = @store.latest(search: "EFG\\")
436
-
437
- assert_equal(1, result.size)
438
- assert_equal("ABCDEFG\\", result[0].message)
439
- end
440
-
441
- def test_search_exclude_results
442
- @store.report(Logger::INFO, "test", "ABCDEFG")
443
- @store.report(Logger::INFO, "test", "TUVWXYZ")
444
-
445
- messages = @store.latest
446
- assert_equal(2, messages.length)
447
-
448
- latest = @store.latest(search: "-ABCD")
449
-
450
- assert_equal(1, latest.length)
451
- assert_equal("TUVWXYZ", latest[0].message)
452
- end
453
-
454
- def test_regex_search
455
- @store.report(Logger::INFO, "test", "pattern_1")
456
- @store.report(Logger::INFO, "test", "pattern_2")
457
-
458
- messages = @store.latest
459
- assert_equal(2, messages.length)
460
-
461
- latest = @store.latest(search: /^pattern_[1]$/)
462
-
463
- assert_equal(1, latest.length)
464
- end
465
-
466
- def test_env_search
467
- @store.report(Logger::INFO, "test", "message ABCD", env: { cluster: "business5" })
468
- @store.report(Logger::INFO, "test", "message WXYZ", env: { cluster: "business7" })
469
-
470
- messages = @store.latest
471
- assert_equal(2, messages.length)
472
-
473
- latest = @store.latest(search: "business5")
474
-
475
- assert_equal(1, latest.length)
476
- assert_equal("message ABCD", latest[0].message)
477
-
478
- latest = @store.latest(search: "-business5")
479
-
480
- assert_equal(1, latest.length)
481
- assert_equal("message WXYZ", latest[0].message)
482
-
483
- latest = @store.latest(search: /business/)
484
-
485
- assert_equal(2, latest.length)
486
- assert_equal(["message ABCD", "message WXYZ"], latest.map(&:message).sort)
487
- end
488
-
489
- def test_array_env_search_preserve_env
490
- m1_original_env = [{ cluster: "business5" }, { cluster: "standard3" }]
491
- m2_original_env = [{ cluster: "business2" }, { cluster: "standard7" }]
492
-
493
- @store.report(Logger::INFO, "test", "message ABCD", env: m1_original_env, count: 2)
494
- @store.report(Logger::INFO, "test", "message WXYZ", env: m2_original_env, count: 2)
495
-
496
- messages = @store.latest
497
- assert_equal(2, messages.length)
498
-
499
- m1_key = messages[0].key
500
- m2_key = messages[1].key
501
-
502
- messages = @store.latest(search: "business")
503
- assert_equal(2, messages.size)
504
-
505
- # any hashes that don't match should be stripped from the env
506
- # array but only temporarily until it's sent to the client
507
- # env array should remain untouched in redis memory
508
- assert_equal(["business5"], messages[0].env.map { |env| env["cluster"] })
509
- assert_equal(1, messages[0].count)
510
- assert_equal(["business2"], messages[1].env.map { |env| env["cluster"] })
511
- assert_equal(1, messages[1].count)
512
-
513
- m1 = @store.get(m1_key)
514
- m2 = @store.get(m2_key)
515
- # original env should preserved in redis memory
516
- assert_equal(%w[business5 standard3], m1.env.map { |env| env["cluster"] })
517
- assert_equal(%w[business2 standard7], m2.env.map { |env| env["cluster"] })
518
- end
519
-
520
- def test_both_env_and_title_match_search
521
- @store.report(Logger::INFO, "test", "message", env: [{ cluster: "business15" }])
522
- @store.report(Logger::INFO, "test", "message2", env: { cluster: "business15" })
523
-
524
- messages = @store.latest
525
- assert_equal(2, messages.size)
526
-
527
- messages = @store.latest(search: "-business15")
528
- assert_equal(0, messages.size)
529
- end
530
-
531
- def test_data_kept_intact_on_report_when_env_matches_an_ignore_pattern
532
- begin
533
- Logster.config.allow_grouping = true
534
- backtrace = caller
535
- message =
536
- @store.report(
537
- Logger::WARN,
538
- "",
539
- "my error",
540
- env: {
541
- whatever: "something",
542
- backtrace: backtrace,
543
- },
544
- )
545
-
546
- @store.ignore = [Logster::IgnorePattern.new("business")]
547
- @store.report(
548
- Logger::WARN,
549
- "",
550
- "my error",
551
- env: {
552
- cluster: "business17",
553
- backtrace: backtrace,
554
- },
555
- )
556
-
557
- message = @store.get(message.key)
558
- assert(Array === message.env)
559
- assert_equal(2, message.env.size)
560
- # message2 shouldn't vanish even if
561
- # its env matches an ignore pattern
562
- # however it should be merged with message1
563
- assert_equal("business17", message.env[0]["cluster"])
564
- ensure
565
- # reset so it doesn't affect other tests
566
- @store.ignore = nil
567
- Logster.config.allow_grouping = false
568
- end
569
- end
570
-
571
- def test_array_env_negative_search
572
- @store.report(
573
- Logger::INFO,
574
- "test",
575
- "message ABCD",
576
- env: [{ cluster: "business5" }, { cluster: "standard3" }],
577
- count: 2,
578
- )
579
- @store.report(
580
- Logger::INFO,
581
- "test",
582
- "message WXYZ",
583
- env: [{ cluster: "business2" }, { cluster: "standard7" }],
584
- count: 2,
585
- )
586
-
587
- messages = @store.latest
588
- assert_equal(2, messages.length)
589
-
590
- messages = @store.latest(search: "-business")
591
- assert_equal(2, messages.size)
592
-
593
- assert_equal(["standard3"], messages[0].env.map { |env| env["cluster"] })
594
- assert_equal(1, messages[0].count)
595
- assert_equal(["standard7"], messages[1].env.map { |env| env["cluster"] })
596
- assert_equal(1, messages[1].count)
597
- end
598
-
599
- def test_negative_search_MUST_not_match_title_in_order_to_include_message
600
- @store.report(
601
- Logger::INFO,
602
- "test",
603
- "message ABCD",
604
- env: [{ cluster: "business5" }, { cluster: "standard3" }],
605
- count: 2,
606
- )
607
-
608
- messages = @store.latest(search: "-ABCD")
609
- assert_equal(0, messages.size) # cause title has ABCD
610
- end
611
-
612
- def test_positive_search_looks_at_title_OR_env
613
- @store.report(
614
- Logger::INFO,
615
- "test",
616
- "message",
617
- env: [{ cluster: "business5 ABCDEFG" }, { cluster: "standard3" }],
618
- count: 2,
619
- )
620
-
621
- messages = @store.latest(search: "ABCDEFG")
622
- assert_equal(1, messages.size)
623
- assert_equal(1, messages[0].env.size)
624
- assert_equal("business5 ABCDEFG", messages[0].env[0]["cluster"])
625
- end
626
-
627
- def test_backtrace
628
- @store.report(Logger::INFO, "test", "pattern_1")
629
- message = @store.latest(limit: 1).first
630
- assert_match("test_backtrace", message.backtrace)
631
- end
632
-
633
- def test_ignore
634
- @store.ignore = [/^test/]
635
- @store.report(Logger::INFO, "test", "test it")
636
- @store.report(Logger::INFO, "test", " test it")
637
-
638
- assert_equal(1, @store.latest.count)
639
- end
640
-
641
- def test_solve
642
- Logster.config.application_version = "abc"
643
-
644
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
645
- m = @store.report(Logger::WARN, "application", "test error2", backtrace: "backtrace1")
646
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace2")
647
-
648
- assert_equal(3, @store.latest.count)
649
-
650
- @store.solve(m.key)
651
-
652
- assert_equal(1, @store.latest.count)
653
-
654
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
655
- @store.report(
656
- Logger::WARN,
657
- "application",
658
- "test error1",
659
- backtrace: "backtrace1",
660
- env: {
661
- "application_version" => "xyz",
662
- },
663
- )
664
-
665
- assert_equal(2, @store.latest.count)
666
- ensure
667
- Logster.config.application_version = nil
668
- end
669
-
670
- def test_solve_grouped
671
- Logster.config.allow_grouping = true
672
- @store.report(
673
- Logger::WARN,
674
- "application",
675
- "test error1",
676
- backtrace: "backtrace1",
677
- env: {
678
- "application_version" => "xyz",
679
- },
680
- )
681
- m =
682
- @store.report(
683
- Logger::WARN,
684
- "application",
685
- "test error1",
686
- backtrace: "backtrace1",
687
- env: {
688
- "application_version" => "efg",
689
- },
690
- )
691
-
692
- assert_equal(1, @store.latest.count)
693
-
694
- @store.solve(m.key)
695
-
696
- @store.report(
697
- Logger::WARN,
698
- "application",
699
- "test error1",
700
- backtrace: "backtrace1",
701
- env: {
702
- "application_version" => "xyz",
703
- },
704
- )
705
- @store.report(
706
- Logger::WARN,
707
- "application",
708
- "test error1",
709
- backtrace: "backtrace1",
710
- env: {
711
- "application_version" => "efg",
712
- },
713
- )
714
-
715
- assert_equal(0, @store.latest.count)
716
- ensure
717
- Logster.config.allow_grouping = false
718
- end
719
-
720
- def test_clears_solved
721
- m =
722
- @store.report(
723
- Logger::WARN,
724
- "application",
725
- "test error2",
726
- backtrace: "backtrace1",
727
- env: {
728
- "application_version" => "abc",
729
- },
730
- )
731
- @store.solve(m.key)
732
-
733
- assert_equal(1, @store.solved.length)
734
-
735
- @store.clear
736
- assert_equal(0, @store.solved.length)
737
- end
738
-
739
- def test_solving_with_some_missing_version
740
- m =
741
- @store.report(
742
- Logger::WARN,
743
- "application",
744
- "test error1",
745
- backtrace: "backtrace1",
746
- env: {
747
- "application_version" => "xyz",
748
- },
749
- )
750
- @store.report(Logger::WARN, "application", "test error1", backtrace: "backtrace1")
751
-
752
- @store.solve(m.key)
753
-
754
- assert_equal(1, @store.latest.count)
755
- end
756
-
757
- def test_env
758
- env =
759
- Rack::MockRequest.env_for("/test").merge(
760
- "HTTP_HOST" => "www.site.com",
761
- "HTTP_USER_AGENT" => "SOME WHERE",
762
- "rack.input" => StringIO.new("test"),
763
- )
764
-
765
- orig = env.dup
766
- orig["test"] = "tests"
767
- orig["test1"] = "tests1"
768
- Logster.add_to_env(env, "test", "tests")
769
- Logster.add_to_env(env, "test1", "tests1")
770
-
771
- orig.delete_if { |k, v| !%w[HTTP_HOST REQUEST_METHOD HTTP_USER_AGENT test test1].include? k }
772
-
773
- @store.report(Logger::INFO, "test", "test", env: env)
774
-
775
- env = @store.latest.last.env
776
-
777
- env.delete "hostname"
778
- env.delete "process_id"
779
-
780
- assert_equal(orig, env)
781
- end
782
-
783
- def test_custom_ignore_patterns_work_with_per_store_config
784
- Logster.config.enable_custom_patterns_via_ui = false
785
- @store.allow_custom_patterns = true
786
- Logster::SuppressionPattern.new("/testtesttest/", store: @store).save
787
- @store.report(Logger::INFO, "test", "testtesttesttest")
788
- latest = @store.latest
789
- assert_equal(0, latest.size)
790
-
791
- @store.allow_custom_patterns = false
792
- @store.report(Logger::INFO, "test", "testtesttesttest")
793
- latest = @store.latest
794
- assert_equal(1, latest.size)
795
- assert_equal("testtesttesttest", latest.first.message)
796
- end
797
-
798
- def test_suppressed_logs_are_counted
799
- @store.ignore = [
800
- /store ignore/,
801
- Logster::IgnorePattern.new(/ignore pattern/),
802
- "an ignore string",
803
- ]
804
- @store.allow_custom_patterns = true
805
- Logster::SuppressionPattern.new(/sup pattern/, store: @store).save
806
-
807
- 2.times do
808
- @store.report(Logger::INFO, "test", "this is store ignore")
809
- @store.report(Logger::INFO, "test", "this is ignore pattern")
810
- @store.report(Logger::INFO, "test", "this is sup pattern")
811
- @store.report(Logger::INFO, "test", "this is an ignore string")
812
- end
813
-
814
- ignore_pattern = Logster::IgnorePattern.new(/ignore pattern/)
815
- hash = @store.get_all_ignore_count
816
- assert_equal("2", hash[ignore_pattern.to_s])
817
- assert_equal("2", hash[/sup pattern/.inspect])
818
- assert_equal("2", hash[/store ignore/.inspect])
819
- assert_equal("2", hash["an ignore string"])
820
-
821
- @store.remove_ignore_count(ignore_pattern.to_s)
822
- hash = @store.get_all_ignore_count
823
- assert_nil(hash[ignore_pattern.to_s])
824
- end
825
-
826
- def test_rate_limits
827
- %w[minute hour].each do |duration|
828
- begin
829
- called = false
830
-
831
- assert_instance_of(
832
- Logster::RedisRateLimiter,
833
- @store.public_send("register_rate_limit_per_#{duration}", Logger::WARN, 0) do
834
- called = true
835
- end,
836
- )
837
-
838
- @store.report(Logger::WARN, "test", "test")
839
- assert called
840
- ensure
841
- reset_redis
842
- end
843
- end
844
- end
845
-
846
- def test_rate_limits_only_checks_when_message_is_bumped_or_saved
847
- Logster.config.allow_grouping = true
848
- Logster.config.application_version = "abc"
849
-
850
- @store.ignore = [/^ActiveRecord::RecordNotFound/]
851
- rate_limit = @store.register_rate_limit_per_minute(Logger::WARN, 0)
852
-
853
- message = @store.report(Logger::WARN, "message 1", "Error!", backtrace: "here")
854
- assert_equal(1, rate_limit.retrieve_rate)
855
-
856
- @store.report(Logger::WARN, "message 1", "Error!", backtrace: "here")
857
- assert_equal(2, rate_limit.retrieve_rate)
858
-
859
- @store.solve(message.key)
860
- @store.report(Logger::WARN, "message 1", "Error!", backtrace: "here")
861
- assert_equal(2, rate_limit.retrieve_rate)
862
-
863
- @store.report(Logger::WARN, "message 2", "Error!")
864
- assert_equal(3, rate_limit.retrieve_rate)
865
-
866
- @store.report(Logger::WARN, "message 3", "ActiveRecord::RecordNotFound")
867
- assert_equal(3, rate_limit.retrieve_rate)
868
- ensure
869
- Logster.config.allow_grouping = false
870
- Logster.config.application_version = nil
871
- reset_redis
872
- end
873
-
874
- def test_rate_limits_with_prefix
875
- begin
876
- time = Time.now
877
- Timecop.freeze(time)
878
- current_namespace = "first"
879
- @store.redis_prefix = Proc.new { current_namespace }
880
-
881
- called_first = 0
882
- called_second = 0
883
-
884
- @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_first += 1 }
885
- @store.report(Logger::WARN, "test", "test")
886
- assert_equal(1, called_first)
887
-
888
- current_namespace = "second"
889
- @store.register_rate_limit_per_minute(Logger::WARN, 0) { called_second += 1 }
890
- @store.report(Logger::WARN, "test", "test")
891
- assert_equal(1, called_first)
892
- assert_equal(1, called_second)
893
-
894
- Timecop.freeze(time + 10) do
895
- current_namespace = "first"
896
- @store.report(Logger::WARN, "test", "test")
897
-
898
- assert_equal(2, called_first)
899
- assert_equal(1, called_second)
900
- end
901
- ensure
902
- reset_redis
903
- end
904
- end
905
-
906
- def test_suppression_patterns_are_cached
907
- @store.allow_custom_patterns = true
908
- rec = Logster::SuppressionPattern.new(/forest/, store: @store)
909
- rec.save
910
-
911
- @store.report(Logger::INFO, "test", "littleforest")
912
- latest = @store.latest
913
- assert_equal(0, latest.size)
914
-
915
- rec.destroy(clear_cache: false)
916
- @store.report(Logger::INFO, "test", "anotherforest")
917
- assert_equal(0, @store.latest.size)
918
-
919
- Process.stub :clock_gettime, Process.clock_gettime(Process::CLOCK_MONOTONIC) + 3 do
920
- @store.report(Logger::INFO, "test", "myforest")
921
- latest = @store.latest
922
- assert_equal(1, latest.size)
923
- assert_equal("myforest", latest.first.message)
924
- end
925
- end
926
-
927
- def test_ensure_messages_meet_config_size_limits_when_messages_are_saved
928
- config_reset(
929
- maximum_message_size_bytes: 300,
930
- max_env_bytes: 30,
931
- max_env_count_per_message: 5,
932
- ) do
933
- env = [{ aaa: 111, bbb: 222, ccc: 333, ddd: 444 }] * 7
934
- message =
935
- @store.report(
936
- Logger::WARN,
937
- "",
938
- "test",
939
- backtrace: "aa\n" * 100,
940
- env: env.dup,
941
- timestamp: 777,
942
- )
943
- message = @store.get(message.key)
944
- assert_operator(message.to_json(exclude_env: true).bytesize, :<, 300)
945
- assert_equal(5, message.env.size)
946
- message.env.each do |e|
947
- assert_operator(e.to_json.bytesize, :<=, 30)
948
- assert_equal({ "aaa" => 111, "time" => 777 }, e)
949
- end
950
- end
951
- end
952
-
953
- def test_ensure_messages_meet_config_size_limits_when_merged_together
954
- config_reset(max_env_bytes: 30, max_env_count_per_message: 5, allow_grouping: true) do
955
- env = [{ a: 1, aa: 22, aaa: 333, aaaa: 4444 }] * 3
956
- env_2 = [{ b: 1, bb: 22, bbb: 333, bbbb: 4444 }] * 3
957
- @store.report(Logger::WARN, "", "test", backtrace: "aa\n" * 100, env: env.dup, timestamp: 777)
958
- message =
959
- @store.report(
960
- Logger::WARN,
961
- "",
962
- "test",
963
- backtrace: "aa\n" * 100,
964
- env: env_2.dup,
965
- timestamp: 777,
966
- )
967
- message = @store.get(message.key)
968
- assert_equal(5, message.env.size)
969
- message
970
- .env
971
- .first(3)
972
- .each do |e|
973
- assert_operator(e.to_json.bytesize, :<=, 30)
974
- assert_equal({ "b" => 1, "bb" => 22, "time" => 777 }, e)
975
- end
976
- message
977
- .env
978
- .last(2)
979
- .each do |e|
980
- assert_operator(e.to_json.bytesize, :<=, 30)
981
- assert_equal({ "a" => 1, "aa" => 22, "time" => 777 }, e)
982
- end
983
- end
984
- end
985
-
986
- def test_custom_grouping_patterns
987
- Logster.config.enable_custom_patterns_via_ui = true
988
- Logster::GroupingPattern.new(/delete/, store: @store).save
989
- msg1 = @store.report(Logger::WARN, "", "delete this plz", timestamp: 1)
990
- msg2 = @store.report(Logger::WARN, "", "delete that plz", timestamp: 2)
991
- group = @store.find_pattern_groups(load_messages: true)[0]
992
- assert_equal 2, group.count
993
- assert_equal "/delete/", group.key
994
- assert_equal [msg2.key, msg1.key], group.messages_keys
995
- assert_equal msg2.timestamp, group.timestamp
996
- ensure
997
- Logster.config.enable_custom_patterns_via_ui = false
998
- end
999
-
1000
- def test_custom_grouping_patterns_with_similar_messages_grouping
1001
- Logster.config.enable_custom_patterns_via_ui = true
1002
- Logster.config.allow_grouping = true
1003
- Logster::GroupingPattern.new(/delete/, store: @store).save
1004
- backtrace = caller
1005
- @store.report(Logger::WARN, "", "delete this plz", backtrace: backtrace, timestamp: 1)
1006
- msg2 = @store.report(Logger::WARN, "", "delete that plz", backtrace: backtrace, timestamp: 2)
1007
- msg3 = @store.report(Logger::WARN, "", "delete this plz", backtrace: backtrace, timestamp: 3)
1008
- group = @store.find_pattern_groups(load_messages: false)[0]
1009
- assert_equal 2, group.count
1010
- assert_equal [msg3.key, msg2.key], group.messages_keys
1011
- assert_equal msg3.timestamp, group.timestamp
1012
- ensure
1013
- Logster.config.enable_custom_patterns_via_ui = false
1014
- Logster.config.allow_grouping = false
1015
- end
1016
-
1017
- def test_a_single_message_can_be_in_one_grouping_pattern
1018
- Logster.config.enable_custom_patterns_via_ui = true
1019
- Logster::GroupingPattern.new(/delete/, store: @store).save
1020
- Logster::GroupingPattern.new(/env/, store: @store).save
1021
- @store.report(Logger::WARN, "", "delete and env")
1022
- groups = @store.find_pattern_groups
1023
- assert_equal 1, groups.size
1024
- assert_includes %w[/delete/ /env/], groups[0].key
1025
- ensure
1026
- Logster.config.enable_custom_patterns_via_ui = false
1027
- end
1028
-
1029
- def test_find_pattern_groups_works_correctly
1030
- Logster.config.enable_custom_patterns_via_ui = true
1031
- with_search = Logster::GroupingPattern.new(/with search/, store: @store)
1032
- with_search.save
1033
- Logster::GroupingPattern.new(/pattern group/, store: @store).save
1034
-
1035
- groups = @store.find_pattern_groups
1036
- assert_equal 0, groups.size # because there are no messages yet
1037
-
1038
- 2.times do |n|
1039
- @store.report(Logger::WARN, "", "with search #{n}")
1040
- @store.report(Logger::WARN, "", "pattern group #{n}")
1041
- end
1042
- groups = @store.find_pattern_groups
1043
- assert_equal 2, groups.size
1044
- groups.each do |g|
1045
- assert_equal 2, g.count
1046
- assert_nil g.messages
1047
- end
1048
-
1049
- groups = @store.find_pattern_groups(load_messages: true)
1050
- assert_equal 2, groups.size
1051
- groups.each do |g|
1052
- assert_equal 2, g.count
1053
- assert_equal 2, g.messages.size
1054
- g.messages.each { |m| assert Logster::Message === m }
1055
- end
1056
-
1057
- groups = @store.find_pattern_groups(load_messages: true) { |pat| pat == with_search.pattern }
1058
- assert_equal 1, groups.size
1059
- assert_equal 2, groups[0].count
1060
- assert groups[0].messages.all? { |m| m.message =~ /with search/ }
1061
- ensure
1062
- Logster.config.enable_custom_patterns_via_ui = false
1063
- end
1064
-
1065
- def test_trimming_backlog_removes_messages_from_custom_grouping
1066
- prev_max_backlog = @store.max_backlog
1067
- @store.max_backlog = 4
1068
- Logster.config.enable_custom_patterns_via_ui = true
1069
- Logster::GroupingPattern.new(/trim/, store: @store).save
1070
- keys = []
1071
- 5.times { |n| keys << @store.report(Logger::WARN, "", "trim backlog #{n}").key }
1072
- groups = @store.find_pattern_groups
1073
- assert_equal 1, groups.size
1074
- assert_equal 4, groups[0].messages_keys.size
1075
- assert_equal 5, groups[0].count
1076
- assert_equal keys[1..-1].reverse, groups[0].messages_keys
1077
- ensure
1078
- @store.max_backlog = prev_max_backlog
1079
- Logster.config.enable_custom_patterns_via_ui = false
1080
- end
1081
-
1082
- def test_adding_grouping_pattern_works_retroactively
1083
- Logster.config.enable_custom_patterns_via_ui = true
1084
- @store.report(Logger::WARN, "", "trim this plz")
1085
- @store.report(Logger::WARN, "", "trim that plz")
1086
- Logster::GroupingPattern.new(/trim/, store: @store).save
1087
- results = @store.latest
1088
- assert_equal 1, results.size
1089
- assert_equal 2, results[0].messages.size
1090
-
1091
- @store.report(Logger::WARN, "", "trim this more plz")
1092
- results = @store.latest
1093
- assert_equal 1, results.size
1094
- assert_equal 3, results[0].messages.size
1095
- ensure
1096
- Logster.config.enable_custom_patterns_via_ui = false
1097
- end
1098
-
1099
- def test_adding_grouping_pattern_doesnt_add_a_message_to_more_than_one_group
1100
- Logster.config.enable_custom_patterns_via_ui = true
1101
- @store.report(Logger::WARN, "", "trim this plz")
1102
- @store.report(Logger::WARN, "", "trim this plz 2")
1103
- Logster::GroupingPattern.new(/trim/, store: @store).save
1104
- Logster::GroupingPattern.new(/this/, store: @store).save
1105
- groups = @store.find_pattern_groups
1106
- assert_equal 1, groups.size
1107
- assert_equal 2, groups[0].count
1108
- ensure
1109
- Logster.config.enable_custom_patterns_via_ui = false
1110
- end
1111
-
1112
- def test_latest_doesnt_include_rows_that_are_removed_from_grouping_patterns_due_to_max_size
1113
- Logster.config.enable_custom_patterns_via_ui = true
1114
- Logster::Group.instance_variable_set(:@max_size, 5)
1115
- msg1 = @store.report(Logger::WARN, "", "first message")
1116
- msg2 = @store.report(Logger::WARN, "", "second message")
1117
- Logster::GroupingPattern.new(/noisy/, store: @store).save
1118
-
1119
- grouped = []
1120
- 7.times do |n|
1121
- grouped << @store.report(Logger::WARN, "", "noisy message #{n}", timestamp: n).key
1122
- end
1123
- msg3 = @store.report(Logger::WARN, "", "third message")
1124
- results = @store.latest
1125
-
1126
- assert_equal [msg1.key, msg2.key, "/noisy/", msg3.key], results.map(&:key)
1127
- assert_equal grouped.reverse.first(5), results[2].messages.map(&:key)
1128
- ensure
1129
- Logster.config.enable_custom_patterns_via_ui = false
1130
- Logster::Group.remove_instance_variable(:@max_size)
1131
- end
1132
-
1133
- def test_truncated_messages_when_they_are_similar_can_still_be_merged
1134
- config_reset(allow_grouping: true) do
1135
- backtrace = "a" * Logster.config.maximum_message_size_bytes
1136
- title = "sasasas"
1137
- msg = @store.report(Logger::WARN, "", title, backtrace: backtrace.dup)
1138
- msg2 = @store.report(Logger::WARN, "", title, backtrace: backtrace.dup)
1139
- assert_equal(msg.key, msg2.key)
1140
- assert_operator(
1141
- msg.to_json(exclude_env: true).bytesize,
1142
- :<=,
1143
- Logster.config.maximum_message_size_bytes,
1144
- )
1145
- assert_operator(msg.backtrace.size, :<, backtrace.size)
1146
- end
1147
- end
1148
-
1149
- private
1150
-
1151
- def config_reset(configs)
1152
- defaults = {}
1153
- configs.each do |k, v|
1154
- defaults[k] = Logster.config.public_send(k)
1155
- Logster.config.public_send("#{k}=", v)
1156
- end
1157
- yield
1158
- ensure
1159
- defaults.each { |k, v| Logster.config.public_send("#{k}=", v) }
1160
- end
1161
-
1162
- def reset_redis
1163
- @store.clear_all
1164
- end
1165
- end