logster 1.3.4 → 1.4.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/Rakefile +0 -3
- data/assets/javascript/client-app.js +41 -33
- data/assets/stylesheets/client-app.css +1 -1
- data/client-app/app/components/env-tab.js +44 -0
- data/client-app/app/components/message-row.js +1 -1
- data/client-app/app/components/panel-resizer.js +4 -5
- data/client-app/app/controllers/index.js +15 -2
- data/client-app/app/models/message-collection.js +25 -5
- data/client-app/app/models/message.js +9 -8
- data/client-app/app/styles/app.css +63 -54
- data/client-app/app/templates/components/env-tab.hbs +10 -0
- data/client-app/app/templates/components/message-info.hbs +1 -1
- data/client-app/app/templates/components/message-row.hbs +10 -12
- data/client-app/app/templates/index.hbs +9 -16
- data/client-app/tests/integration/components/env-tab-test.js +73 -0
- data/lib/logster/base_store.rb +2 -5
- data/lib/logster/ignore_pattern.rb +1 -1
- data/lib/logster/logger.rb +1 -1
- data/lib/logster/message.rb +53 -27
- data/lib/logster/redis_store.rb +58 -7
- data/lib/logster/version.rb +1 -1
- data/test/logster/test_message.rb +59 -0
- data/test/logster/test_redis_store.rb +130 -7
- metadata +7 -4
@@ -0,0 +1,10 @@
|
|
1
|
+
{{#if isEnvArray}}
|
2
|
+
<div class="nav-controls">
|
3
|
+
<button disabled={{disableBackButtons}} {{action "bigJump" "back"}} class="btn nav-btn no-text"><i class="fa fa-fast-backward"></i></button>
|
4
|
+
<button disabled={{disableBackButtons}} {{action "takeStep" "back"}} class="btn nav-btn no-text"><i class="fa fa-backward"></i></button>
|
5
|
+
<span class="env-number">{{current}}/{{message.env.length}}</span>
|
6
|
+
<button disabled={{disableForwardButtons}} {{action "takeStep" "front"}} class="btn nav-btn no-text"><i class="fa fa-forward"></i></button>
|
7
|
+
<button disabled={{disableForwardButtons}} {{action "bigJump" "front"}} class="btn nav-btn no-text"><i class="fa fa-fast-forward"></i></button>
|
8
|
+
</div>
|
9
|
+
{{/if}}
|
10
|
+
{{{html}}}
|
@@ -1,17 +1,15 @@
|
|
1
|
-
<
|
1
|
+
<div class="count">
|
2
2
|
{{#if model.showCount}}
|
3
|
-
|
3
|
+
{{model.count}}
|
4
4
|
{{/if}}
|
5
|
-
</
|
6
|
-
<
|
7
|
-
<
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
</td>
|
12
|
-
<td class='protected'>
|
5
|
+
</div>
|
6
|
+
<div class="severity">{{{model.glyph}}}</div>
|
7
|
+
<div class="message-body">
|
8
|
+
{{model.displayMessage}}
|
9
|
+
</div>
|
10
|
+
<div class='protected'>
|
13
11
|
{{#if model.protected}}
|
14
12
|
<i title="message is protected, clearing will not remove it" class='fa fa-lock'></i>
|
15
13
|
{{/if}}
|
16
|
-
</
|
17
|
-
<
|
14
|
+
</div>
|
15
|
+
<div class="time">{{time-formatter timestamp=model.timestamp}}</div>
|
@@ -1,25 +1,18 @@
|
|
1
1
|
<div id='top-panel'>
|
2
|
-
<
|
3
|
-
<thead>
|
4
|
-
<tr>
|
5
|
-
<th class="count"></th>
|
6
|
-
<th class="severity"></th>
|
7
|
-
<th class="info"></th>
|
8
|
-
<th class="protected"></th>
|
9
|
-
<th class="time"></th>
|
10
|
-
</tr>
|
11
|
-
</thead>
|
12
|
-
<tbody>
|
2
|
+
<div id="log-table">
|
13
3
|
{{#if model.moreBefore}}
|
14
|
-
<
|
15
|
-
|
16
|
-
|
4
|
+
<div {{action "showMoreBefore"}} class="show-more">
|
5
|
+
{{#if model.hideCountInLoadMore}}
|
6
|
+
Load more
|
7
|
+
{{else}}
|
8
|
+
Select to see {{model.totalBefore}} more
|
9
|
+
{{/if}}
|
10
|
+
</div>
|
17
11
|
{{/if}}
|
18
12
|
{{#each model.messages as |message|}}
|
19
13
|
{{message-row model=message selectedMessage=(action "selectMessage")}}
|
20
14
|
{{/each}}
|
21
|
-
|
22
|
-
</table>
|
15
|
+
</div>
|
23
16
|
</div>
|
24
17
|
<div id="bottom-panel">
|
25
18
|
{{message-info
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import { module, test } from 'qunit';
|
2
|
+
import { setupRenderingTest } from 'ember-qunit';
|
3
|
+
import { render, find, findAll, click } from '@ember/test-helpers';
|
4
|
+
import hbs from 'htmlbars-inline-precompile';
|
5
|
+
import Message from "client-app/models/message";
|
6
|
+
|
7
|
+
const message = Message.create({
|
8
|
+
env: [
|
9
|
+
{ a: "aa", b: "bb" },
|
10
|
+
{ c: "cc", d: "dd" }
|
11
|
+
]
|
12
|
+
})
|
13
|
+
|
14
|
+
const message2 = Message.create({
|
15
|
+
env: { e: "ee", f: "ff" }
|
16
|
+
});
|
17
|
+
|
18
|
+
function reduceToContent(node) {
|
19
|
+
return Array.from(node.childNodes).reduce((ac, cr) => `${ac.textContent}: ${cr.textContent}`);
|
20
|
+
}
|
21
|
+
|
22
|
+
module('Integration | Component | env-tab', function(hooks) {
|
23
|
+
setupRenderingTest(hooks);
|
24
|
+
|
25
|
+
test('it renders', async function(assert) {
|
26
|
+
this.set("message", message);
|
27
|
+
await render(hbs`{{env-tab message=message}}`);
|
28
|
+
|
29
|
+
assert.equal(find(".env-number").textContent, "1/2", "shows the current over the total number of env objects");
|
30
|
+
let trs = findAll("tr");
|
31
|
+
assert.equal(trs.length, 2);
|
32
|
+
assert.equal(reduceToContent(trs[0]), 'a: aa', "has the right content");
|
33
|
+
assert.equal(reduceToContent(trs[1]), 'b: bb', "has the right content");
|
34
|
+
|
35
|
+
const buttons = findAll("button.nav-btn");
|
36
|
+
// at first page, you can't go back
|
37
|
+
assert.ok(buttons[0].disabled, "back buttons are disabled");
|
38
|
+
assert.ok(buttons[1].disabled, "back buttons are disabled");
|
39
|
+
|
40
|
+
assert.notOk(buttons[2].disabled, "forward buttons are not disabled");
|
41
|
+
assert.notOk(buttons[3].disabled, "forward buttons are not disabled");
|
42
|
+
|
43
|
+
this.set("message", message2);
|
44
|
+
assert.dom("button").doesNotExist("doesn't show buttons for non-array env");
|
45
|
+
|
46
|
+
trs = findAll("tr");
|
47
|
+
assert.equal(trs.length, 2);
|
48
|
+
assert.equal(reduceToContent(trs[0]), 'e: ee', "has the right content");
|
49
|
+
assert.equal(reduceToContent(trs[1]), 'f: ff', "has the right content");
|
50
|
+
});
|
51
|
+
|
52
|
+
test('it works correctly', async function(assert) {
|
53
|
+
this.set("message", message);
|
54
|
+
await render(hbs`{{env-tab message=message}}`);
|
55
|
+
|
56
|
+
const buttons = findAll("button.nav-btn");
|
57
|
+
await click(buttons[2]);
|
58
|
+
|
59
|
+
assert.equal(find(".env-number").textContent, "2/2", "shows the current over the total number of env objects");
|
60
|
+
|
61
|
+
const trs = findAll("tr");
|
62
|
+
assert.equal(trs.length, 2);
|
63
|
+
assert.equal(reduceToContent(trs[0]), 'c: cc', "has the right content");
|
64
|
+
assert.equal(reduceToContent(trs[1]), 'd: dd', "has the right content");
|
65
|
+
|
66
|
+
// at last page, you can't go forward but you can go back
|
67
|
+
assert.notOk(buttons[0].disabled, "back buttons are not disabled");
|
68
|
+
assert.notOk(buttons[1].disabled, "back buttons are not disabled");
|
69
|
+
|
70
|
+
assert.ok(buttons[2].disabled, "forward buttons are disabled");
|
71
|
+
assert.ok(buttons[3].disabled, "forward buttons are disabled");
|
72
|
+
});
|
73
|
+
});
|
data/lib/logster/base_store.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module Logster
|
3
2
|
class BaseStore
|
4
3
|
|
@@ -79,12 +78,11 @@ module Logster
|
|
79
78
|
return if (!msg || (String === msg && msg.empty?)) && skip_empty
|
80
79
|
return if level && severity < level
|
81
80
|
|
82
|
-
message = Logster::Message.new(severity, progname, msg, opts[:timestamp])
|
81
|
+
message = Logster::Message.new(severity, progname, msg, opts[:timestamp], count: opts[:count])
|
83
82
|
|
84
83
|
env = opts[:env] || {}
|
85
84
|
backtrace = opts[:backtrace]
|
86
|
-
|
87
|
-
if env[:backtrace]
|
85
|
+
if Hash === env && env[:backtrace]
|
88
86
|
# Special - passing backtrace through env
|
89
87
|
backtrace = env.delete(:backtrace)
|
90
88
|
end
|
@@ -110,7 +108,6 @@ module Logster
|
|
110
108
|
end
|
111
109
|
|
112
110
|
if similar
|
113
|
-
similar.count += 1
|
114
111
|
similar.merge_similar_message(message)
|
115
112
|
|
116
113
|
replace_and_bump similar
|
@@ -35,7 +35,7 @@ module Logster
|
|
35
35
|
when Regexp
|
36
36
|
message.to_s =~ pattern
|
37
37
|
when String
|
38
|
-
message.to_s
|
38
|
+
message.to_s =~ Regexp.new(pattern, Regexp::IGNORECASE)
|
39
39
|
when Hash
|
40
40
|
if Hash === message
|
41
41
|
compare_hash(message, pattern)
|
data/lib/logster/logger.rb
CHANGED
@@ -57,7 +57,7 @@ module Logster
|
|
57
57
|
(ol && ol[Thread.current.object_id]) || @level
|
58
58
|
end
|
59
59
|
|
60
|
-
def add_with_opts(severity, message, progname, opts=nil, &block)
|
60
|
+
def add_with_opts(severity, message, progname=progname(), opts=nil, &block)
|
61
61
|
if severity < level
|
62
62
|
return true
|
63
63
|
end
|
data/lib/logster/message.rb
CHANGED
@@ -23,14 +23,14 @@ module Logster
|
|
23
23
|
|
24
24
|
attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected, :first_timestamp
|
25
25
|
|
26
|
-
def initialize(severity, progname, message, timestamp = nil, key = nil)
|
26
|
+
def initialize(severity, progname, message, timestamp = nil, key = nil, count: 1)
|
27
27
|
@timestamp = timestamp || get_timestamp
|
28
28
|
@severity = severity
|
29
29
|
@progname = progname
|
30
30
|
@message = message
|
31
31
|
@key = key || SecureRandom.hex
|
32
32
|
@backtrace = nil
|
33
|
-
@count = 1
|
33
|
+
@count = count || 1
|
34
34
|
@protected = false
|
35
35
|
@first_timestamp = nil
|
36
36
|
end
|
@@ -80,7 +80,14 @@ module Logster
|
|
80
80
|
|
81
81
|
def populate_from_env(env)
|
82
82
|
env ||= {}
|
83
|
-
|
83
|
+
if Array === env
|
84
|
+
env = env.map do |single_env|
|
85
|
+
self.class.default_env.merge(single_env)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
env = self.class.default_env.merge(env)
|
89
|
+
end
|
90
|
+
@env = Message.populate_from_env(env)
|
84
91
|
end
|
85
92
|
|
86
93
|
def self.default_env
|
@@ -104,8 +111,13 @@ module Logster
|
|
104
111
|
|
105
112
|
# todo - memoize?
|
106
113
|
def solved_keys
|
107
|
-
if
|
108
|
-
|
114
|
+
if Array === env
|
115
|
+
versions = env.map { |single_env| single_env["application_version"] }
|
116
|
+
else
|
117
|
+
versions = env["application_version"]
|
118
|
+
end
|
119
|
+
|
120
|
+
if versions && backtrace && backtrace.length > 0
|
109
121
|
versions = [versions] if String === versions
|
110
122
|
|
111
123
|
versions.map do |version|
|
@@ -121,35 +133,49 @@ module Logster
|
|
121
133
|
def merge_similar_message(other)
|
122
134
|
self.first_timestamp ||= self.timestamp
|
123
135
|
self.timestamp = [self.timestamp,other.timestamp].max
|
136
|
+
self.count += other.count || 1
|
137
|
+
|
124
138
|
other_env = JSON.load JSON.fast_generate other.env
|
125
|
-
|
126
|
-
self.env
|
139
|
+
if Array === self.env
|
140
|
+
Array === other_env ? self.env.concat(other_env) : self.env << other_env
|
141
|
+
else
|
142
|
+
Array === other_env ? self.env = [self.env, *other_env] : self.env = [self.env, other_env]
|
127
143
|
end
|
128
144
|
end
|
129
145
|
|
130
146
|
def self.populate_from_env(env)
|
147
|
+
if Array === env
|
148
|
+
env.map do |single_env|
|
149
|
+
self.populate_env_helper(single_env)
|
150
|
+
end
|
151
|
+
else
|
152
|
+
self.populate_env_helper(env)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.populate_env_helper(env)
|
131
157
|
env[LOGSTER_ENV] ||= begin
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
158
|
+
unless env.include? "rack.input"
|
159
|
+
# Not a web request
|
160
|
+
return env
|
161
|
+
end
|
162
|
+
scrubbed = default_env
|
163
|
+
request = Rack::Request.new(env)
|
164
|
+
params = {}
|
165
|
+
request.params.each do |k,v|
|
166
|
+
if k.include? "password"
|
167
|
+
params[k] = "[redacted]"
|
168
|
+
elsif Array === v
|
169
|
+
params[k] = v[0..20]
|
170
|
+
else
|
171
|
+
params[k] = v && v[0..100]
|
147
172
|
end
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
173
|
+
end
|
174
|
+
scrubbed["params"] = params if params.length > 0
|
175
|
+
ALLOWED_ENV.map{ |k|
|
176
|
+
scrubbed[k] = env[k] if env[k]
|
177
|
+
}
|
178
|
+
scrubbed
|
153
179
|
end
|
154
180
|
end
|
155
181
|
|
data/lib/logster/redis_store.rb
CHANGED
@@ -423,18 +423,69 @@ module Logster
|
|
423
423
|
[start, finish]
|
424
424
|
end
|
425
425
|
|
426
|
+
def get_search(search)
|
427
|
+
exclude = false
|
428
|
+
if String === search && search[0] == "-"
|
429
|
+
exclude = true
|
430
|
+
search = search.sub("-", "")
|
431
|
+
end
|
432
|
+
[search, exclude]
|
433
|
+
end
|
434
|
+
|
426
435
|
def filter_search(row, search)
|
436
|
+
search, exclude = get_search(search)
|
427
437
|
return row unless row && search
|
428
438
|
|
429
|
-
if
|
430
|
-
row if row
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
439
|
+
if exclude
|
440
|
+
row if !(row =~ search) && filter_env!(row, search, exclude)
|
441
|
+
else
|
442
|
+
row if row =~ search || filter_env!(row, search)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def filter_env!(message, search, exclude = false)
|
447
|
+
if Array === message.env
|
448
|
+
array_env_matches?(message, search, exclude)
|
449
|
+
else
|
450
|
+
if exclude
|
451
|
+
!env_matches?(message.env, search)
|
452
|
+
else
|
453
|
+
env_matches?(message.env, search)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def env_matches?(env, search)
|
459
|
+
return false unless env && search
|
460
|
+
|
461
|
+
env.values.any? do |value|
|
462
|
+
if Hash === value
|
463
|
+
env_matches?(value, search)
|
464
|
+
else
|
465
|
+
case search
|
466
|
+
when Regexp
|
467
|
+
value.to_s =~ search
|
468
|
+
when String
|
469
|
+
value.to_s =~ Regexp.new(search, Regexp::IGNORECASE)
|
470
|
+
else
|
471
|
+
false
|
472
|
+
end
|
473
|
+
end
|
436
474
|
end
|
475
|
+
end
|
437
476
|
|
477
|
+
def array_env_matches?(message, search, exclude)
|
478
|
+
matches = message.env.select do |env|
|
479
|
+
if exclude
|
480
|
+
!env_matches?(env, search)
|
481
|
+
else
|
482
|
+
env_matches?(env, search)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
return false if matches.empty?
|
486
|
+
message.env = matches
|
487
|
+
message.count = matches.size
|
488
|
+
true
|
438
489
|
end
|
439
490
|
|
440
491
|
def check_rate_limits(severity)
|
data/lib/logster/version.rb
CHANGED
@@ -18,6 +18,43 @@ class TestMessage < MiniTest::Test
|
|
18
18
|
|
19
19
|
assert_equal(20, msg1.timestamp)
|
20
20
|
assert_equal(10, msg1.first_timestamp)
|
21
|
+
|
22
|
+
assert Array === msg1.env
|
23
|
+
assert_equal(msg1.env.size, 2)
|
24
|
+
assert({ "a" => "1", "b" => "2" } <= msg1.env[0])
|
25
|
+
assert({ "a" => "2", "c" => "3" } <= msg1.env[1])
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_merge_messages_both_with_array_envs
|
29
|
+
msg1 = Logster::Message.new(0, '', 'test', 10)
|
30
|
+
msg1.env = [{ a: "aa", b: "bb" }, { c: "cc", d: "dd" }]
|
31
|
+
|
32
|
+
msg2 = Logster::Message.new(0, '', 'test', 20)
|
33
|
+
msg2.env = [{ e: "ee", f: "ff" }, { g: "gg", h: "hh" }]
|
34
|
+
|
35
|
+
msg1.merge_similar_message(msg2)
|
36
|
+
msg1 = Logster::Message.from_json(msg1.to_json)
|
37
|
+
|
38
|
+
# new env should be an array, but it should never have
|
39
|
+
# another array of envs within itself (hence flatten(1))
|
40
|
+
assert_equal(msg1.env.size, 4)
|
41
|
+
assert_equal(msg1.env.map(&:keys).flatten(1), %w{a b c d e f g h})
|
42
|
+
assert_equal(msg1.env.map(&:values).flatten(1), %w{aa bb cc dd ee ff gg hh})
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_merge_messages_one_with_array_envs
|
46
|
+
msg1 = Logster::Message.new(0, '', 'test', 10)
|
47
|
+
msg1.env = [{ a: "aa", b: "bb" }, { c: "cc", d: "dd" }]
|
48
|
+
|
49
|
+
msg2 = Logster::Message.new(0, '', 'test', 20)
|
50
|
+
msg2.env = { e: "ee", f: "ff" }
|
51
|
+
|
52
|
+
msg1.merge_similar_message(msg2)
|
53
|
+
msg1 = Logster::Message.from_json(msg1.to_json)
|
54
|
+
|
55
|
+
assert_equal(msg1.env.size, 3)
|
56
|
+
assert_equal(msg1.env.map(&:keys).flatten(1), %w{a b c d e f})
|
57
|
+
assert_equal(msg1.env.map(&:values).flatten(1), %w{aa bb cc dd ee ff})
|
21
58
|
end
|
22
59
|
|
23
60
|
def test_adds_application_version
|
@@ -31,4 +68,26 @@ class TestMessage < MiniTest::Test
|
|
31
68
|
Logster.config.application_version = nil
|
32
69
|
end
|
33
70
|
|
71
|
+
def test_merging_sums_count_for_both_messages
|
72
|
+
msg1 = Logster::Message.new(0, '', 'test', 10, count: 15)
|
73
|
+
msg2 = Logster::Message.new(0, '', 'test', 20, count: 13)
|
74
|
+
msg2.env = {}
|
75
|
+
|
76
|
+
assert_equal(msg1.grouping_key, msg2.grouping_key)
|
77
|
+
|
78
|
+
msg1.merge_similar_message(msg2)
|
79
|
+
msg1 = Logster::Message.from_json(msg1.to_json)
|
80
|
+
assert_equal(msg1.count, 15 + 13)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_populate_from_env_works_on_array
|
84
|
+
msg = Logster::Message.new(0, '', 'test', 10)
|
85
|
+
hash = { "custom_key" => "key" }
|
86
|
+
msg.populate_from_env([hash])
|
87
|
+
|
88
|
+
msg = Logster::Message.from_json(msg.to_json)
|
89
|
+
assert Array === msg.env
|
90
|
+
assert_equal(msg.env.size, 1)
|
91
|
+
assert hash <= msg.env[0]
|
92
|
+
end
|
34
93
|
end
|