logster 2.4.2 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -0
- data/Guardfile +2 -0
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/assets/javascript/client-app.js +69 -53
- data/assets/javascript/vendor.js +580 -559
- data/assets/stylesheets/client-app.css +1 -1
- data/client-app/README.md +2 -2
- data/client-app/app/components/env-tab.js +16 -36
- data/client-app/app/components/message-row.js +1 -1
- data/client-app/app/components/page-nav.js +30 -0
- data/client-app/app/components/patterns-list.js +2 -1
- data/client-app/app/controllers/index.js +68 -92
- data/client-app/app/controllers/show.js +6 -0
- data/client-app/app/models/group.js +20 -0
- data/client-app/app/models/message-collection.js +159 -57
- data/client-app/app/routes/index.js +0 -2
- data/client-app/app/routes/settings.js +3 -1
- data/client-app/app/styles/app.css +17 -2
- data/client-app/app/templates/components/env-tab.hbs +5 -7
- data/client-app/app/templates/components/message-info.hbs +13 -8
- data/client-app/app/templates/components/page-nav.hbs +13 -0
- data/client-app/app/templates/components/patterns-list.hbs +6 -4
- data/client-app/app/templates/index.hbs +45 -11
- data/client-app/app/templates/settings.hbs +10 -1
- data/client-app/app/templates/show.hbs +2 -0
- data/client-app/package-lock.json +2817 -1215
- data/client-app/package.json +12 -12
- data/client-app/tests/integration/components/env-tab-test.js +29 -8
- data/client-app/tests/integration/components/message-info-test.js +10 -2
- data/lib/examples/sidekiq_logster_reporter.rb +2 -0
- data/lib/logster.rb +2 -2
- data/lib/logster/base_store.rb +40 -4
- data/lib/logster/cache.rb +9 -8
- data/lib/logster/defer_logger.rb +2 -0
- data/lib/logster/group.rb +124 -0
- data/lib/logster/grouping_pattern.rb +29 -0
- data/lib/logster/ignore_pattern.rb +2 -0
- data/lib/logster/logger.rb +2 -0
- data/lib/logster/message.rb +3 -1
- data/lib/logster/middleware/reporter.rb +2 -2
- data/lib/logster/middleware/viewer.rb +12 -1
- data/lib/logster/pattern.rb +13 -0
- data/lib/logster/redis_store.rb +99 -10
- data/lib/logster/scheduler.rb +2 -0
- data/lib/logster/suppression_pattern.rb +5 -2
- data/lib/logster/version.rb +1 -1
- data/lib/logster/web.rb +2 -0
- data/logster.gemspec +4 -1
- data/test/examples/test_sidekiq_reporter_example.rb +2 -0
- data/test/fake_data/Gemfile +2 -0
- data/test/fake_data/generate.rb +2 -0
- data/test/logster/middleware/test_viewer.rb +3 -1
- data/test/logster/test_base_store.rb +2 -0
- data/test/logster/test_cache.rb +19 -12
- data/test/logster/test_defer_logger.rb +2 -0
- data/test/logster/test_group.rb +92 -0
- data/test/logster/test_ignore_pattern.rb +2 -0
- data/test/logster/test_logger.rb +3 -1
- data/test/logster/test_message.rb +2 -0
- data/test/logster/test_pattern.rb +2 -2
- data/test/logster/test_redis_rate_limiter.rb +2 -0
- data/test/logster/test_redis_store.rb +253 -0
- data/test/test_helper.rb +6 -0
- metadata +26 -6
data/client-app/package.json
CHANGED
@@ -18,20 +18,19 @@
|
|
18
18
|
"test": "ember test"
|
19
19
|
},
|
20
20
|
"devDependencies": {
|
21
|
-
"jquery": "3.4.1",
|
22
21
|
"@ember/optional-features": "^0.6.3",
|
23
22
|
"broccoli-asset-rev": "^2.7.0",
|
24
23
|
"ember-ajax": "^5.0.0",
|
25
|
-
"ember-cli": "
|
24
|
+
"ember-cli": "^3.8.3",
|
26
25
|
"ember-cli-app-version": "^3.2.0",
|
27
|
-
"ember-cli-babel": "^7.
|
28
|
-
"ember-cli-dependency-checker": "^3.
|
26
|
+
"ember-cli-babel": "^7.12.0",
|
27
|
+
"ember-cli-dependency-checker": "^3.2.0",
|
29
28
|
"ember-cli-eslint": "^4.2.3",
|
30
|
-
"ember-cli-htmlbars": "^3.
|
29
|
+
"ember-cli-htmlbars": "^3.1.0",
|
31
30
|
"ember-cli-htmlbars-inline-precompile": "^1.0.3",
|
32
31
|
"ember-cli-inject-live-reload": "^1.8.2",
|
33
32
|
"ember-cli-sri": "^2.1.1",
|
34
|
-
"ember-cli-template-lint": "^1.0.0-beta.
|
33
|
+
"ember-cli-template-lint": "^1.0.0-beta.3",
|
35
34
|
"ember-cli-uglify": "^2.1.0",
|
36
35
|
"ember-data": "~3.8.0",
|
37
36
|
"ember-export-application-global": "^2.0.0",
|
@@ -39,19 +38,20 @@
|
|
39
38
|
"ember-load-initializers": "^1.1.0",
|
40
39
|
"ember-maybe-import-regenerator": "^0.1.6",
|
41
40
|
"ember-qunit": "^3.4.1",
|
42
|
-
"ember-resolver": "^5.0
|
43
|
-
"ember-source": "
|
41
|
+
"ember-resolver": "^5.3.0",
|
42
|
+
"ember-source": "^3.8.3",
|
44
43
|
"ember-welcome-page": "^3.2.0",
|
45
|
-
"eslint-plugin-ember": "^5.
|
44
|
+
"eslint-plugin-ember": "^5.4.0",
|
45
|
+
"jquery": "3.4.1",
|
46
46
|
"loader.js": "^4.7.0",
|
47
|
-
"prettier": "^1.
|
48
|
-
"qunit-dom": "^0.8.
|
47
|
+
"prettier": "^1.19.1",
|
48
|
+
"qunit-dom": "^0.8.5"
|
49
49
|
},
|
50
50
|
"engines": {
|
51
51
|
"node": "6.* || 8.* || >= 10.*"
|
52
52
|
},
|
53
53
|
"dependencies": {
|
54
|
-
"lodash": "
|
54
|
+
"lodash": "^4.17.15",
|
55
55
|
"moment": "~2.22.2"
|
56
56
|
}
|
57
57
|
}
|
@@ -35,11 +35,18 @@ module("Integration | Component | env-tab", function(hooks) {
|
|
35
35
|
setupRenderingTest(hooks);
|
36
36
|
|
37
37
|
test("it renders", async function(assert) {
|
38
|
-
this.set("
|
39
|
-
|
38
|
+
const callback = newPosition => this.set("envPosition", newPosition);
|
39
|
+
this.setProperties({
|
40
|
+
message,
|
41
|
+
callback,
|
42
|
+
envPosition: 0
|
43
|
+
});
|
44
|
+
await render(
|
45
|
+
hbs`{{env-tab message=message envChangedAction=callback currentEnvPosition=envPosition}}`
|
46
|
+
);
|
40
47
|
|
41
48
|
assert.equal(
|
42
|
-
find(".
|
49
|
+
find(".current-number").textContent,
|
43
50
|
"1/2",
|
44
51
|
"shows the current over the total number of env objects"
|
45
52
|
);
|
@@ -71,14 +78,21 @@ module("Integration | Component | env-tab", function(hooks) {
|
|
71
78
|
});
|
72
79
|
|
73
80
|
test("it works correctly", async function(assert) {
|
74
|
-
this.set("
|
75
|
-
|
81
|
+
const callback = newPosition => this.set("envPosition", newPosition);
|
82
|
+
this.setProperties({
|
83
|
+
message,
|
84
|
+
callback,
|
85
|
+
envPosition: 0
|
86
|
+
});
|
87
|
+
await render(
|
88
|
+
hbs`{{env-tab message=message envChangedAction=callback currentEnvPosition=envPosition}}`
|
89
|
+
);
|
76
90
|
|
77
91
|
const buttons = findAll("button.nav-btn");
|
78
92
|
await click(buttons[2]);
|
79
93
|
|
80
94
|
assert.equal(
|
81
|
-
find(".
|
95
|
+
find(".current-number").textContent,
|
82
96
|
"2/2",
|
83
97
|
"shows the current over the total number of env objects"
|
84
98
|
);
|
@@ -108,8 +122,15 @@ module("Integration | Component | env-tab", function(hooks) {
|
|
108
122
|
env_expandable_keys: ["env_key_2", "default_expanded"]
|
109
123
|
});
|
110
124
|
init();
|
111
|
-
this.set("
|
112
|
-
|
125
|
+
const callback = newPosition => this.set("envPosition", newPosition);
|
126
|
+
this.setProperties({
|
127
|
+
message: message3,
|
128
|
+
callback,
|
129
|
+
envPosition: 0
|
130
|
+
});
|
131
|
+
await render(
|
132
|
+
hbs`{{env-tab message=message envChangedAction=callback currentEnvPosition=envPosition}}`
|
133
|
+
);
|
113
134
|
|
114
135
|
const trs = findAll(".env-table tr");
|
115
136
|
const expandable = trs[0];
|
@@ -17,14 +17,22 @@ module("Integration | Component | message-info", function(hooks) {
|
|
17
17
|
setupRenderingTest(hooks);
|
18
18
|
|
19
19
|
test("it renders", async function(assert) {
|
20
|
+
const callback = newPosition => this.set("currentEnvPosition", newPosition);
|
20
21
|
this.setProperties({
|
21
22
|
actionsInMenu: true,
|
22
23
|
showTitle: false,
|
23
|
-
|
24
|
+
envPosition: 0,
|
25
|
+
message,
|
26
|
+
callback
|
24
27
|
});
|
25
28
|
|
26
29
|
await render(
|
27
|
-
hbs`{{message-info
|
30
|
+
hbs`{{message-info
|
31
|
+
currentMessage=message
|
32
|
+
showTitle=showTitle
|
33
|
+
currentEnvPosition=envPosition
|
34
|
+
envChangedAction=callback
|
35
|
+
actionsInMenu=actionsInMenu}}`
|
28
36
|
);
|
29
37
|
let activeTab = find(".message-info .content.active pre");
|
30
38
|
assert.equal(
|
data/lib/logster.rb
CHANGED
@@ -7,6 +7,8 @@ require 'logster/web'
|
|
7
7
|
require 'logster/ignore_pattern'
|
8
8
|
require 'logster/pattern'
|
9
9
|
require 'logster/suppression_pattern'
|
10
|
+
require 'logster/grouping_pattern'
|
11
|
+
require 'logster/group'
|
10
12
|
require 'logster/cache'
|
11
13
|
|
12
14
|
if defined? Redis
|
@@ -17,8 +19,6 @@ else
|
|
17
19
|
end
|
18
20
|
|
19
21
|
module Logster
|
20
|
-
PATTERNS = [SuppressionPattern]
|
21
|
-
|
22
22
|
def self.logger=(logger)
|
23
23
|
@logger = logger
|
24
24
|
end
|
data/lib/logster/base_store.rb
CHANGED
@@ -115,22 +115,39 @@ module Logster
|
|
115
115
|
|
116
116
|
# increments the number of messages that have been suppressed by a pattern
|
117
117
|
def increment_ignore_count(pattern)
|
118
|
+
not_implemented
|
118
119
|
end
|
119
120
|
|
120
121
|
# removes number of suppressed messages by a pattern
|
121
122
|
def remove_ignore_count(pattern)
|
123
|
+
not_implemented
|
122
124
|
end
|
123
125
|
|
124
126
|
# returns a hash that maps patterns to the number of messages they
|
125
127
|
# have suppressed
|
126
128
|
def get_all_ignore_count
|
127
|
-
|
129
|
+
not_implemented
|
128
130
|
end
|
129
131
|
|
130
132
|
def rate_limited?(ip_address, perform: false, limit: 60)
|
131
133
|
not_implemented
|
132
134
|
end
|
133
135
|
|
136
|
+
# find all pattern groups; returns an array of Logster::Group
|
137
|
+
def find_pattern_groups(load_messages: true)
|
138
|
+
not_implemented
|
139
|
+
end
|
140
|
+
|
141
|
+
# saves an instance of Logster::Group
|
142
|
+
def save_pattern_group(group)
|
143
|
+
not_implemented
|
144
|
+
end
|
145
|
+
|
146
|
+
# removes the Logster::Group instance associated with the given pattern
|
147
|
+
def remove_pattern_group(pattern)
|
148
|
+
not_implemented
|
149
|
+
end
|
150
|
+
|
134
151
|
def report(severity, progname, msg, opts = {})
|
135
152
|
return if (!msg || (String === msg && msg.empty?)) && skip_empty
|
136
153
|
return if level && severity < level
|
@@ -164,7 +181,7 @@ module Logster
|
|
164
181
|
end
|
165
182
|
|
166
183
|
if Logster.config.enable_custom_patterns_via_ui || allow_custom_patterns
|
167
|
-
custom_ignore = @patterns_cache.fetch do
|
184
|
+
custom_ignore = @patterns_cache.fetch(Logster::SuppressionPattern::CACHE_KEY) do
|
168
185
|
Logster::SuppressionPattern.find_all(store: self)
|
169
186
|
end
|
170
187
|
return if custom_ignore.any? do |pattern|
|
@@ -194,10 +211,29 @@ module Logster
|
|
194
211
|
save message
|
195
212
|
message
|
196
213
|
end
|
214
|
+
|
215
|
+
message = similar || message
|
216
|
+
|
217
|
+
if Logster.config.enable_custom_patterns_via_ui || allow_custom_patterns
|
218
|
+
grouping_patterns = @patterns_cache.fetch(Logster::GroupingPattern::CACHE_KEY) do
|
219
|
+
Logster::GroupingPattern.find_all(store: self)
|
220
|
+
end
|
221
|
+
|
222
|
+
grouping_patterns.each do |pattern|
|
223
|
+
if message =~ pattern
|
224
|
+
group = find_pattern_groups() { |pat| pat == pattern }[0]
|
225
|
+
group ||= Logster::Group.new(pattern.inspect)
|
226
|
+
group.add_message(message)
|
227
|
+
save_pattern_group(group) if group.changed?
|
228
|
+
break
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
message
|
197
233
|
end
|
198
234
|
|
199
|
-
def
|
200
|
-
@patterns_cache.clear
|
235
|
+
def clear_patterns_cache(key)
|
236
|
+
@patterns_cache.clear(key)
|
201
237
|
end
|
202
238
|
|
203
239
|
private
|
data/lib/logster/cache.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Logster
|
2
4
|
class Cache
|
3
5
|
def initialize(age = 2)
|
4
6
|
@age = age
|
5
|
-
@hash = {
|
7
|
+
@hash = {}
|
6
8
|
end
|
7
9
|
|
8
|
-
def fetch
|
9
|
-
if !@hash.key?(
|
10
|
-
@hash[
|
11
|
-
@hash[:created_at] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
10
|
+
def fetch(key)
|
11
|
+
if !@hash.key?(key) || @hash[key][:created_at] + @age < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
12
|
+
@hash[key] = { data: yield, created_at: Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
12
13
|
end
|
13
|
-
@hash[:data]
|
14
|
+
@hash[key][:data]
|
14
15
|
end
|
15
16
|
|
16
|
-
def clear
|
17
|
-
@hash.delete(
|
17
|
+
def clear(key)
|
18
|
+
@hash.delete(key)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
data/lib/logster/defer_logger.rb
CHANGED
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logster
|
4
|
+
class Group
|
5
|
+
MAX_SIZE = 100
|
6
|
+
|
7
|
+
attr_reader :key, :messages_keys, :timestamp, :messages
|
8
|
+
attr_accessor :changed
|
9
|
+
|
10
|
+
def initialize(key, messages_keys = [], timestamp: 0)
|
11
|
+
@key = key
|
12
|
+
@messages_keys = messages_keys || []
|
13
|
+
@timestamp = timestamp
|
14
|
+
@changed = true
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_json(json)
|
18
|
+
hash = JSON.parse(json)
|
19
|
+
group = new(
|
20
|
+
hash["key"],
|
21
|
+
hash["messages_keys"],
|
22
|
+
timestamp: hash["timestamp"] || 0
|
23
|
+
)
|
24
|
+
group.changed = false
|
25
|
+
group
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.max_size
|
29
|
+
(defined?(@max_size) && @max_size) || MAX_SIZE
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_h
|
33
|
+
{
|
34
|
+
key: @key,
|
35
|
+
messages_keys: @messages_keys,
|
36
|
+
timestamp: @timestamp
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h_web
|
41
|
+
{
|
42
|
+
regex: @key,
|
43
|
+
count: self.count,
|
44
|
+
timestamp: @timestamp,
|
45
|
+
messages: @messages,
|
46
|
+
severity: -1,
|
47
|
+
group: true
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_json(opts = nil)
|
52
|
+
JSON.fast_generate(self.to_h, opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_message(message)
|
56
|
+
if !@messages_keys.include?(message.key)
|
57
|
+
@messages_keys.unshift(message.key)
|
58
|
+
@changed = true
|
59
|
+
end
|
60
|
+
if @timestamp < message.timestamp
|
61
|
+
@timestamp = message.timestamp
|
62
|
+
@messages_keys.unshift(@messages_keys.slice!(@messages_keys.index(message.key)))
|
63
|
+
@changed = true
|
64
|
+
end
|
65
|
+
if self.count > max_size
|
66
|
+
@messages_keys.slice!(max_size..-1)
|
67
|
+
@changed = true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove_message(message)
|
72
|
+
index = @messages_keys.index(message.key)
|
73
|
+
if index
|
74
|
+
@messages_keys.slice!(index)
|
75
|
+
@changed = true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def messages=(messages)
|
80
|
+
messages.compact!
|
81
|
+
messages.uniq!(&:key)
|
82
|
+
if messages.size > 0
|
83
|
+
messages.sort_by!(&:timestamp)
|
84
|
+
messages.reverse!
|
85
|
+
messages.slice!(max_size..-1) if messages.size > max_size
|
86
|
+
@messages = messages
|
87
|
+
before = @messages_keys.sort
|
88
|
+
@messages_keys = @messages.map(&:key)
|
89
|
+
@timestamp = @messages[0].timestamp
|
90
|
+
@changed = before != @messages_keys.sort
|
91
|
+
else
|
92
|
+
@messages_keys = []
|
93
|
+
@messages = []
|
94
|
+
@timestamp = 0
|
95
|
+
@changed = true
|
96
|
+
end
|
97
|
+
@messages
|
98
|
+
end
|
99
|
+
|
100
|
+
def changed?
|
101
|
+
@changed
|
102
|
+
end
|
103
|
+
|
104
|
+
def count
|
105
|
+
@messages_keys.size
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def max_size
|
111
|
+
self.class.max_size
|
112
|
+
end
|
113
|
+
|
114
|
+
GroupWeb = Struct.new(*%i[regex count timestamp messages row_id]) do
|
115
|
+
def to_json(opts = nil)
|
116
|
+
JSON.fast_generate(self.to_h.merge(severity: -1, group: true), opts)
|
117
|
+
end
|
118
|
+
|
119
|
+
def key
|
120
|
+
self.regex # alias for testing convenience
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logster
|
4
|
+
class GroupingPattern < Pattern
|
5
|
+
CACHE_KEY = :grouping
|
6
|
+
def self.set_name
|
7
|
+
"__LOGSTER__grouping_patterns_set".freeze
|
8
|
+
end
|
9
|
+
|
10
|
+
def save(args = {})
|
11
|
+
super
|
12
|
+
existing_groups = @store.find_pattern_groups
|
13
|
+
group = Logster::Group.new(self.to_s)
|
14
|
+
messages = @store.get_all_messages(with_env: false)
|
15
|
+
messages.select! do |m|
|
16
|
+
m.message =~ self.pattern && existing_groups.none? { |g| g.messages_keys.include?(m.key) }
|
17
|
+
end
|
18
|
+
group.messages = messages
|
19
|
+
@store.save_pattern_group(group) if group.changed?
|
20
|
+
@store.clear_patterns_cache(CACHE_KEY)
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy(clear_cache: true) # arg used in tests
|
24
|
+
super()
|
25
|
+
@store.remove_pattern_group(self.pattern)
|
26
|
+
@store.clear_patterns_cache(CACHE_KEY) if clear_cache
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|