logster 0.8.4.3.pre → 0.8.4.4.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/assets/javascript/app.js +22 -0
- data/assets/javascript/components/message-info.hbs +15 -0
- data/assets/javascript/components/tab-contents.hbs +0 -14
- data/assets/javascript/templates/index.hbs +2 -2
- data/assets/stylesheets/app.css +69 -9
- data/lib/logster/base_store.rb +4 -0
- data/lib/logster/message.rb +11 -2
- data/lib/logster/middleware/viewer.rb +14 -0
- data/lib/logster/redis_store.rb +9 -3
- data/lib/logster/version.rb +1 -1
- data/test/logster/test_message.rb +19 -1
- data/test/logster/test_redis_store.rb +8 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26758317e1dfa2cb38fd7932d7ffc2f9fd073c96
|
4
|
+
data.tar.gz: 58b3c563e7cb4232417b798bfcad902d3fe88621
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47d950c4d8cf793f2d0999040c973bd5bf6d4a6c692135fe3ee549f79549e72c6a908f322ae2724eb4b55a99db2db797164d369371a9af917d20032952d275e0
|
7
|
+
data.tar.gz: dbbfee1e1e49871c6256def779f97f3675c74f0a0fccc0ff2f37ed930a8bc85274dd3a46ef3c7a240edec908f635c72a023ee996e965e8d26e39f52e29c8559f
|
data/assets/javascript/app.js
CHANGED
@@ -101,6 +101,10 @@ App.Message = Ember.Object.extend({
|
|
101
101
|
this.set("expanded", true);
|
102
102
|
},
|
103
103
|
|
104
|
+
"delete": function() {
|
105
|
+
return App.ajax("/message/" + this.get('key'), { type: "DELETE" });
|
106
|
+
},
|
107
|
+
|
104
108
|
protect: function() {
|
105
109
|
this.set('protected', true);
|
106
110
|
return App.ajax("/protect/" + this.get('key'), { type: "PUT" });
|
@@ -181,6 +185,13 @@ App.MessageCollection = Em.Object.extend({
|
|
181
185
|
currentMessage: null,
|
182
186
|
total: 0,
|
183
187
|
|
188
|
+
"delete": function(message){
|
189
|
+
message.delete();
|
190
|
+
this.get('messages').removeObject(message);
|
191
|
+
this.set('currentMessage', null);
|
192
|
+
this.set('total', this.get('total')-1);
|
193
|
+
},
|
194
|
+
|
184
195
|
load: function(opts) {
|
185
196
|
var self = this;
|
186
197
|
opts = opts || {};
|
@@ -372,6 +383,11 @@ App.IndexController = Em.Controller.extend({
|
|
372
383
|
});
|
373
384
|
}
|
374
385
|
},
|
386
|
+
|
387
|
+
removeMessage: function(msg) {
|
388
|
+
var messages = this.get('model');
|
389
|
+
messages.delete(msg);
|
390
|
+
}
|
375
391
|
},
|
376
392
|
|
377
393
|
filterChanged: function(){
|
@@ -650,12 +666,18 @@ App.TabContentsComponent = Ember.Component.extend({
|
|
650
666
|
this.invokeParent("removeTab");
|
651
667
|
},
|
652
668
|
|
669
|
+
});
|
670
|
+
|
671
|
+
App.MessageInfoComponent = Ember.Component.extend({
|
653
672
|
actions: {
|
654
673
|
protect: function(){
|
655
674
|
this.get('currentMessage').protect();
|
656
675
|
},
|
657
676
|
unprotect: function(){
|
658
677
|
this.get('currentMessage').unprotect();
|
678
|
+
},
|
679
|
+
"remove": function(){
|
680
|
+
this.sendAction("removeMessage", this.get('currentMessage'));
|
659
681
|
}
|
660
682
|
}
|
661
683
|
});
|
@@ -25,4 +25,19 @@
|
|
25
25
|
{{/tab-contents}}
|
26
26
|
{{/if}}
|
27
27
|
{{/tabbed-section}}
|
28
|
+
|
29
|
+
{{#if currentMessage}}
|
30
|
+
<div class='message-actions'>
|
31
|
+
|
32
|
+
{{#unless currentMessage.protected}}
|
33
|
+
<button {{action 'remove'}} class="delete btn"><i class='fa fa-trash-o'></i>Delete</button>
|
34
|
+
|
35
|
+
<button {{action 'protect'}} class="protect btn"><i class='fa fa-lock'></i>Protect</button>
|
36
|
+
{{else}}
|
37
|
+
<button {{action 'unprotect'}} class="unprotect btn"><i class='fa fa-unlock'></i>Unprotect</button>
|
38
|
+
{{/unless}}
|
39
|
+
<a href="{{currentMessage.shareUrl}}" class="share btn">Share</a>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
{{/if}}
|
28
43
|
</div>
|
@@ -1,15 +1 @@
|
|
1
1
|
{{yield}}
|
2
|
-
{{#if currentMessage}}
|
3
|
-
<div class='message-actions'>
|
4
|
-
|
5
|
-
{{#unless currentMessage.protected}}
|
6
|
-
<i class='fa fa-lock'></i>
|
7
|
-
<a href {{action 'protect'}} class="protect">Protect</a>
|
8
|
-
{{else}}
|
9
|
-
<i class='fa fa-unlock'></i>
|
10
|
-
<a href {{action 'unprotect'}} class="protect">Unprotect</a>
|
11
|
-
{{/unless}}
|
12
|
-
<a href="{{currentMessage.shareUrl}}" class="share">Share</a>
|
13
|
-
</div>
|
14
|
-
|
15
|
-
{{/if}}
|
@@ -23,7 +23,7 @@
|
|
23
23
|
</div>
|
24
24
|
{{panel-resizer}}
|
25
25
|
<div id="bottom-panel">
|
26
|
-
{{message-info currentMessage=currentMessage}}
|
26
|
+
{{message-info currentMessage=currentMessage removeMessage="removeMessage"}}
|
27
27
|
|
28
28
|
<div class="action-panel">
|
29
29
|
<label class="debug">
|
@@ -52,6 +52,6 @@
|
|
52
52
|
<label class="search">
|
53
53
|
{{input type="textfield" placeholder="Search" value=search}}
|
54
54
|
</label>
|
55
|
-
<a class="clear" href {{action "clear"}}>Clear logs</a>
|
55
|
+
<a class="clear btn danger" href {{action "clear"}}><i class='fa fa-trash-o'></i> Clear logs</a>
|
56
56
|
</div>
|
57
57
|
</div>
|
data/assets/stylesheets/app.css
CHANGED
@@ -145,15 +145,40 @@ tr.show-more {
|
|
145
145
|
bottom: 10px;
|
146
146
|
}
|
147
147
|
|
148
|
+
#bottom-panel.full button.delete {
|
149
|
+
display: none;
|
150
|
+
}
|
151
|
+
|
152
|
+
#bottom-panel.full .message-actions {
|
153
|
+
position: fixed;
|
154
|
+
height: 40px;
|
155
|
+
width: 100%;
|
156
|
+
left: 0;
|
157
|
+
bottom: 0;
|
158
|
+
background-color: #eee;
|
159
|
+
border-top: 1px solid #dfdfdf;
|
160
|
+
padding-left: 10px;
|
161
|
+
}
|
162
|
+
|
163
|
+
#bottom-panel.full .message-actions button {
|
164
|
+
margin-top: 10px;
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
|
148
169
|
.message-actions {
|
149
|
-
position:
|
150
|
-
bottom:
|
151
|
-
right:
|
170
|
+
position: absolute;
|
171
|
+
bottom: 3px;
|
172
|
+
right: 30px;
|
152
173
|
}
|
153
174
|
|
154
|
-
.message-actions
|
155
|
-
|
156
|
-
|
175
|
+
.message-actions button {
|
176
|
+
margin-right: 7px;
|
177
|
+
}
|
178
|
+
|
179
|
+
.message-actions .share {
|
180
|
+
text-decoration: none;
|
181
|
+
color: #333;
|
157
182
|
}
|
158
183
|
|
159
184
|
.divider {
|
@@ -224,9 +249,8 @@ tr.show-more {
|
|
224
249
|
}
|
225
250
|
|
226
251
|
.action-panel .clear {
|
227
|
-
position:
|
228
|
-
|
229
|
-
margin-left: 50px;
|
252
|
+
position: absolute;
|
253
|
+
right: 30px;
|
230
254
|
vertical-align: middle;
|
231
255
|
}
|
232
256
|
|
@@ -306,3 +330,39 @@ tr.show-more {
|
|
306
330
|
border-top: 1px solid #f1f1f1;
|
307
331
|
background-color: #f1f1f1;
|
308
332
|
}
|
333
|
+
|
334
|
+
|
335
|
+
.btn {
|
336
|
+
display: inline-block;
|
337
|
+
margin: 0;
|
338
|
+
padding: 2px 12px;
|
339
|
+
font-weight: 500;
|
340
|
+
font-size: 1em;
|
341
|
+
line-height: 18px;
|
342
|
+
text-align: center;
|
343
|
+
cursor: pointer;
|
344
|
+
transition: all .25s;
|
345
|
+
background-color: #DDD;
|
346
|
+
text-decoration: none;
|
347
|
+
border: none;
|
348
|
+
color: #333;
|
349
|
+
font-weight: normal;
|
350
|
+
}
|
351
|
+
|
352
|
+
.btn:hover {
|
353
|
+
color: #000;
|
354
|
+
background-color: #ccc;
|
355
|
+
}
|
356
|
+
|
357
|
+
.btn .fa {
|
358
|
+
margin-right: 7px;
|
359
|
+
}
|
360
|
+
|
361
|
+
.btn:active {
|
362
|
+
text-shadow: none;
|
363
|
+
}
|
364
|
+
|
365
|
+
.btn.danger:hover {
|
366
|
+
background-color: #c63c1b;
|
367
|
+
color: #EEE;
|
368
|
+
}
|
data/lib/logster/base_store.rb
CHANGED
data/lib/logster/message.rb
CHANGED
@@ -19,7 +19,7 @@ module Logster
|
|
19
19
|
process_id
|
20
20
|
}
|
21
21
|
|
22
|
-
attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected
|
22
|
+
attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected, :first_timestamp
|
23
23
|
|
24
24
|
def initialize(severity, progname, message, timestamp = nil, key = nil)
|
25
25
|
@timestamp = timestamp || get_timestamp
|
@@ -33,7 +33,7 @@ module Logster
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def to_h
|
36
|
-
{
|
36
|
+
h = {
|
37
37
|
message: @message,
|
38
38
|
progname: @progname,
|
39
39
|
severity: @severity,
|
@@ -44,6 +44,12 @@ module Logster
|
|
44
44
|
env: @env,
|
45
45
|
protected: @protected
|
46
46
|
}
|
47
|
+
|
48
|
+
if @first_timestamp
|
49
|
+
h[:first_timestamp] = @first_timestamp
|
50
|
+
end
|
51
|
+
|
52
|
+
h
|
47
53
|
end
|
48
54
|
|
49
55
|
def to_json(opts = nil)
|
@@ -61,6 +67,7 @@ module Logster
|
|
61
67
|
msg.env = parsed["env"]
|
62
68
|
msg.count = parsed["count"]
|
63
69
|
msg.protected = parsed["protected"]
|
70
|
+
msg.first_timestamp = parsed["first_timestamp"]
|
64
71
|
msg
|
65
72
|
end
|
66
73
|
|
@@ -90,6 +97,8 @@ module Logster
|
|
90
97
|
end
|
91
98
|
|
92
99
|
def merge_similar_message(other)
|
100
|
+
self.first_timestamp ||= self.timestamp
|
101
|
+
self.timestamp = [self.timestamp,other.timestamp].max
|
93
102
|
other_env = JSON.load JSON.fast_generate other.env
|
94
103
|
other_env.keys.each do |env_key|
|
95
104
|
self.env[env_key] = Message.env_merge_helper(self.env[env_key], other_env[env_key])
|
@@ -38,6 +38,20 @@ module Logster
|
|
38
38
|
elsif resource.start_with?("/messages.json")
|
39
39
|
serve_messages(Rack::Request.new(env))
|
40
40
|
|
41
|
+
elsif resource =~ /\/message\/([0-9a-f]+)$/
|
42
|
+
if env[REQUEST_METHOD] != "DELETE"
|
43
|
+
return [405, {}, ["GET not allowed for /clear"]]
|
44
|
+
end
|
45
|
+
|
46
|
+
key = $1
|
47
|
+
message = Logster.store.get(key)
|
48
|
+
unless message
|
49
|
+
return [404, {}, ["Message not found"]]
|
50
|
+
end
|
51
|
+
|
52
|
+
Logster.store.delete(message)
|
53
|
+
return [301, {"Location" => "#{@logs_path}/"}, []]
|
54
|
+
|
41
55
|
elsif resource =~ /\/(un)?protect\/([0-9a-f]+)$/
|
42
56
|
off = $1 == "un"
|
43
57
|
key = $2
|
data/lib/logster/redis_store.rb
CHANGED
@@ -25,6 +25,14 @@ module Logster
|
|
25
25
|
true
|
26
26
|
end
|
27
27
|
|
28
|
+
def delete(msg)
|
29
|
+
@redis.multi do
|
30
|
+
@redis.hdel(hash_key, msg.key)
|
31
|
+
@redis.hdel(grouping_key, msg.grouping_key)
|
32
|
+
@redis.lrem(list_key, -1, msg.key)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
28
36
|
def replace_and_bump(message)
|
29
37
|
# TODO make it atomic
|
30
38
|
exists = @redis.hexists(hash_key, message.key)
|
@@ -130,9 +138,7 @@ module Logster
|
|
130
138
|
json = @redis.hget(hash_key, message_key)
|
131
139
|
return nil unless json
|
132
140
|
|
133
|
-
|
134
|
-
# message.protected = @redis.sismember(protected_key, message_key)
|
135
|
-
message
|
141
|
+
Message.from_json(json)
|
136
142
|
end
|
137
143
|
|
138
144
|
def protect(message_key)
|
data/lib/logster/version.rb
CHANGED
@@ -1,6 +1,24 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
|
-
require 'logster/
|
2
|
+
require 'logster/message'
|
3
3
|
|
4
4
|
class TestMessage < MiniTest::Test
|
5
5
|
|
6
|
+
def test_merge_similar
|
7
|
+
msg1 = Logster::Message.new(0, '', 'test', 10)
|
8
|
+
msg1.populate_from_env(a: "1", b: "2")
|
9
|
+
|
10
|
+
msg2 = Logster::Message.new(0, '', 'test', 20)
|
11
|
+
msg2.populate_from_env(a: "2", c: "3")
|
12
|
+
|
13
|
+
assert_equal(msg2.grouping_key, msg1.grouping_key)
|
14
|
+
|
15
|
+
msg1.merge_similar_message(msg2)
|
16
|
+
|
17
|
+
msg1 = Logster::Message.from_json(msg1.to_json)
|
18
|
+
|
19
|
+
assert_equal(20, msg1.timestamp)
|
20
|
+
assert_equal(10, msg1.first_timestamp)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
6
24
|
end
|
@@ -13,6 +13,14 @@ class TestRedisStore < Minitest::Test
|
|
13
13
|
@store.clear_all
|
14
14
|
end
|
15
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
|
+
|
16
24
|
def test_latest
|
17
25
|
@store.report(Logger::WARN, "test", "IGNORE")
|
18
26
|
@store.report(Logger::WARN, "test", "This is a warning")
|