logster 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/assets/javascript/app.js +26 -21
- data/lib/logster/base_store.rb +80 -0
- data/lib/logster/redis_store.rb +6 -28
- data/lib/logster/version.rb +1 -1
- data/test/examples/test_sidekiq_reporter_example.rb +21 -6
- data/test/logster/middleware/test_reporter.rb +1 -1
- data/test/logster/test_base_store.rb +94 -0
- data/test/logster/test_redis_store.rb +1 -1
- data/test/test_helper.rb +15 -22
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 817153c3885fd064575528496f299e302802edff
|
4
|
+
data.tar.gz: 2adf2a219859d1d5a1b7163fa98714a3e0d353fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40a5c76579e0f5145e3cdb490daab9550dd30e12d3e6be4609774aa045f46d33f3465ba20bcd0a1fe350de3000f92a9bff54c94cdb7032cbc1eccabb88765ea4
|
7
|
+
data.tar.gz: 33401bae4031a18e2d0e40f22679acfc1ebf0cb8515df2ea9084ca06e0eccb82a781ee34abeadf5dc4a5592c3327c77f246623b7724a40959ea330a6f4768df8
|
data/assets/javascript/app.js
CHANGED
@@ -45,7 +45,7 @@ App.preloadOrAjax = function(url, settings) {
|
|
45
45
|
}
|
46
46
|
};
|
47
47
|
|
48
|
-
App.Router.map(function(){
|
48
|
+
App.Router.map(function() {
|
49
49
|
this.route("index", { path: "/" });
|
50
50
|
this.route("show", { path: "/show/:id" });
|
51
51
|
});
|
@@ -67,7 +67,7 @@ App.Message = Ember.Object.extend({
|
|
67
67
|
return App.ajax("/unprotect/" + this.get('key'), { type: "DELETE" });
|
68
68
|
},
|
69
69
|
|
70
|
-
hasMore: function(){
|
70
|
+
hasMore: function() {
|
71
71
|
var message = this.get("message");
|
72
72
|
var expanded = this.get("expanded");
|
73
73
|
|
@@ -82,32 +82,37 @@ App.Message = Ember.Object.extend({
|
|
82
82
|
return Logger.rootPath + (this.get('protected') ? '/unprotect/' : '/protect/') + this.get('key');
|
83
83
|
}.property("key"),
|
84
84
|
|
85
|
-
displayMessage: function(){
|
85
|
+
displayMessage: function() {
|
86
86
|
var message = this.get("message");
|
87
87
|
var expanded = this.get("expanded");
|
88
88
|
|
89
|
-
if(!expanded && message.length > this.MAX_LEN){
|
90
|
-
message = message.substr(0,this.MAX_LEN);
|
89
|
+
if (!expanded && message.length > this.MAX_LEN) {
|
90
|
+
message = message.substr(0, this.MAX_LEN);
|
91
91
|
}
|
92
92
|
return message;
|
93
|
-
}.property("message","expanded"),
|
93
|
+
}.property("message", "expanded"),
|
94
94
|
|
95
|
-
envDebug: function(){
|
95
|
+
envDebug: function() {
|
96
96
|
var env = this.get("env");
|
97
|
-
if(env){
|
98
|
-
var buffer = []
|
99
|
-
|
100
|
-
|
97
|
+
if (env) {
|
98
|
+
var buffer = [],
|
99
|
+
hashes = [];
|
100
|
+
_.each(env, function(v, k) {
|
101
|
+
if (typeof v === "object") {
|
102
|
+
hashes.push(k);
|
103
|
+
} else {
|
101
104
|
buffer.push(k + ": " + v);
|
102
105
|
}
|
103
106
|
});
|
104
107
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
if (_.size(hashes) > 0) {
|
109
|
+
_.each(hashes, function(k1) {
|
110
|
+
v1 = env[k1];
|
111
|
+
buffer.push("");
|
112
|
+
buffer.push(k1 + ":");
|
113
|
+
_.each(v1, function(v2, k2) {
|
114
|
+
buffer.push(" " + k2 + ": " + v2);
|
115
|
+
})
|
111
116
|
});
|
112
117
|
}
|
113
118
|
return buffer.join("\n");
|
@@ -116,7 +121,7 @@ App.Message = Ember.Object.extend({
|
|
116
121
|
}.property("env"),
|
117
122
|
|
118
123
|
rowClass: function() {
|
119
|
-
switch(this.get("severity")){
|
124
|
+
switch (this.get("severity")) {
|
120
125
|
case 0:
|
121
126
|
return "debug";
|
122
127
|
case 1:
|
@@ -130,8 +135,8 @@ App.Message = Ember.Object.extend({
|
|
130
135
|
}
|
131
136
|
}.property("severity"),
|
132
137
|
|
133
|
-
glyph: function(){
|
134
|
-
switch(this.get("severity")){
|
138
|
+
glyph: function() {
|
139
|
+
switch (this.get("severity")) {
|
135
140
|
case 0:
|
136
141
|
return "";
|
137
142
|
case 1:
|
@@ -151,7 +156,7 @@ App.MessageCollection = Em.Object.extend({
|
|
151
156
|
messages: Em.A(),
|
152
157
|
total: 0,
|
153
158
|
|
154
|
-
load: function(opts){
|
159
|
+
load: function(opts) {
|
155
160
|
var self = this;
|
156
161
|
opts = opts || {};
|
157
162
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module Logster
|
3
|
+
class BaseStore
|
4
|
+
|
5
|
+
attr_accessor :level, :max_retention, :skip_empty, :ignore
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@dedup = false
|
9
|
+
@max_retention = 60 * 60 * 24 * 7
|
10
|
+
@skip_empty = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def save(message)
|
14
|
+
not_implemented
|
15
|
+
end
|
16
|
+
|
17
|
+
def count
|
18
|
+
not_implemented
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear
|
22
|
+
not_implemented
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear_all
|
26
|
+
not_implemented
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(message_key)
|
30
|
+
not_implemented
|
31
|
+
end
|
32
|
+
|
33
|
+
def protect(message_key)
|
34
|
+
not_implemented
|
35
|
+
end
|
36
|
+
|
37
|
+
def unprotect(message_key)
|
38
|
+
not_implemented
|
39
|
+
end
|
40
|
+
|
41
|
+
def report(severity, progname, message, opts = {})
|
42
|
+
return if (!message || (String === message && message.empty?)) && skip_empty
|
43
|
+
return if level && severity < level
|
44
|
+
return if ignore && ignore.any? { |pattern| message =~ pattern}
|
45
|
+
|
46
|
+
message = Logster::Message.new(severity, progname, message, opts[:timestamp])
|
47
|
+
|
48
|
+
env = opts[:env]
|
49
|
+
backtrace = opts[:backtrace]
|
50
|
+
|
51
|
+
if env
|
52
|
+
if env[:backtrace]
|
53
|
+
# Special - passing backtrace through env
|
54
|
+
backtrace = env.delete(:backtrace)
|
55
|
+
end
|
56
|
+
|
57
|
+
message.populate_from_env(env)
|
58
|
+
end
|
59
|
+
|
60
|
+
if backtrace
|
61
|
+
if backtrace.respond_to? :join
|
62
|
+
backtrace = backtrace.join("\n")
|
63
|
+
end
|
64
|
+
message.backtrace = backtrace
|
65
|
+
else
|
66
|
+
message.backtrace = caller.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
save message
|
70
|
+
|
71
|
+
message
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def not_implemented
|
77
|
+
raise "Not Implemented"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/logster/redis_store.rb
CHANGED
@@ -1,38 +1,18 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'logster/base_store'
|
2
3
|
|
3
4
|
module Logster
|
4
|
-
class RedisStore
|
5
|
+
class RedisStore < BaseStore
|
5
6
|
|
6
|
-
attr_accessor :
|
7
|
-
:dedup, :max_retention, :skip_empty,
|
8
|
-
:ignore
|
7
|
+
attr_accessor :redis, :max_backlog
|
9
8
|
|
10
9
|
def initialize(redis = nil)
|
10
|
+
super()
|
11
11
|
@redis = redis || Redis.new
|
12
12
|
@max_backlog = 1000
|
13
|
-
@dedup = false
|
14
|
-
@max_retention = 60 * 60 * 24 * 7
|
15
|
-
@skip_empty = true
|
16
13
|
end
|
17
14
|
|
18
|
-
|
19
|
-
def report(severity, progname, message, opts = nil)
|
20
|
-
return if (!message || (String === message && message.empty?)) && skip_empty
|
21
|
-
return if level && severity < level
|
22
|
-
return if @ignore && @ignore.any?{|pattern| message =~ pattern}
|
23
|
-
|
24
|
-
message = Logster::Message.new(severity, progname, message, (opts && opts[:timestamp]))
|
25
|
-
|
26
|
-
if opts && backtrace = opts[:backtrace]
|
27
|
-
message.backtrace = backtrace
|
28
|
-
else
|
29
|
-
message.backtrace = caller.join("\n")
|
30
|
-
end
|
31
|
-
|
32
|
-
if opts && env = opts[:env]
|
33
|
-
message.populate_from_env(env)
|
34
|
-
end
|
35
|
-
|
15
|
+
def save(message)
|
36
16
|
# multi for integrity
|
37
17
|
@redis.multi do
|
38
18
|
@redis.hset(hash_key, message.key, message.to_json)
|
@@ -40,14 +20,12 @@ module Logster
|
|
40
20
|
end
|
41
21
|
|
42
22
|
# TODO make it atomic
|
43
|
-
if @redis.llen(list_key) >
|
23
|
+
if @redis.llen(list_key) > max_backlog
|
44
24
|
removed_key = @redis.lpop(list_key)
|
45
25
|
if removed_key && !@redis.sismember(protected_key, removed_key)
|
46
26
|
@redis.hdel(hash_key, removed_key)
|
47
27
|
end
|
48
28
|
end
|
49
|
-
|
50
|
-
message
|
51
29
|
end
|
52
30
|
|
53
31
|
def count
|
data/lib/logster/version.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
2
|
require 'logster/logger'
|
3
|
+
require 'logster/redis_store'
|
3
4
|
require 'logger'
|
4
5
|
require 'examples/sidekiq_logster_reporter'
|
5
6
|
|
6
7
|
class TestSidekiqReporter < MiniTest::Test
|
7
8
|
|
8
9
|
def setup
|
9
|
-
Logster.store = @store = Logster::
|
10
|
+
Logster.store = @store = Logster::RedisStore.new(Redis.new)
|
10
11
|
Logster.logger = @logger = Logster::Logger.new(Logster.store)
|
12
|
+
@store.clear_all
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
@store.clear_all
|
11
17
|
end
|
12
18
|
|
13
19
|
def test_sidekiq_handler_example
|
@@ -18,14 +24,23 @@ class TestSidekiqReporter < MiniTest::Test
|
|
18
24
|
rescue => e
|
19
25
|
error = e
|
20
26
|
end
|
27
|
+
trace = error.backtrace
|
21
28
|
|
22
29
|
handler.call(error, code: "Test", something_important: "Foo", params: { article_id: 20 })
|
23
30
|
|
24
|
-
|
31
|
+
report = @store.latest[0]
|
32
|
+
|
33
|
+
# Message is right format
|
34
|
+
assert_equal("Job exception: TypeError\n", report.message)
|
35
|
+
|
36
|
+
# A backtrace is joined()
|
37
|
+
assert_equal(trace.join("\n"), report.backtrace)
|
38
|
+
# The backtrace is deleted from the env
|
39
|
+
assert_nil(report.env['backtrace'])
|
40
|
+
assert_nil(report.env[:backtrace])
|
25
41
|
|
26
|
-
|
27
|
-
assert_equal("
|
28
|
-
assert_equal(
|
29
|
-
assert_equal(20, error.env[:params][:article_id])
|
42
|
+
# The env is in the report
|
43
|
+
assert_equal("Test", report.env['code'])
|
44
|
+
assert_equal(20, report.env['params']['article_id'])
|
30
45
|
end
|
31
46
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'logster/base_store'
|
3
|
+
|
4
|
+
class TestBaseStore < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@store = Logster::TestStore.new
|
8
|
+
@store.clear_all
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@store.clear_all
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_report_skip_empty
|
16
|
+
@store.skip_empty = true
|
17
|
+
@store.report(Logger::WARN, "test", nil)
|
18
|
+
@store.report(Logger::WARN, "test", '')
|
19
|
+
@store.report(Logger::WARN, "test", "foo") #
|
20
|
+
@store.skip_empty = false
|
21
|
+
@store.report(Logger::WARN, "test", nil) #
|
22
|
+
|
23
|
+
assert_equal(2, @store.count)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_report_skip_level
|
27
|
+
@store.level = nil
|
28
|
+
@store.report(Logger::DEBUG, "test", "A") #
|
29
|
+
@store.level = Logger::WARN
|
30
|
+
@store.report(Logger::DEBUG, "test", "A")
|
31
|
+
@store.report(Logger::INFO, "test", "B")
|
32
|
+
@store.report(Logger::WARN, "test", "C") #
|
33
|
+
@store.report(Logger::ERROR, "test", "D") #
|
34
|
+
assert_equal(3, @store.count)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_report_skip_ignore
|
38
|
+
@store.report(Logger::WARN, "test", "Can't verify CSRF token authenticity")
|
39
|
+
@store.report(Logger::FATAL, "test", "ActiveRecord::RecordNotFound (Couldn't find Upload with 'id'=9947)")
|
40
|
+
@store.report(Logger::WARN, "test", "B")
|
41
|
+
@store.ignore = [
|
42
|
+
/^ActiveRecord::RecordNotFound \(Couldn't find Upload/,
|
43
|
+
/^Can't verify CSRF token authenticity/
|
44
|
+
]
|
45
|
+
@store.report(Logger::WARN, "test", "Can't verify CSRF token authenticity")
|
46
|
+
@store.report(Logger::FATAL, "test", "ActiveRecord::RecordNotFound (Couldn't find Upload with 'id'=9947)")
|
47
|
+
@store.report(Logger::FATAL, "test", "ActiveRecord::RecordNotFound (Couldn't find Upload with 'id'=9489+78946947)")
|
48
|
+
@store.report(Logger::WARN, "test", "B")
|
49
|
+
|
50
|
+
assert_equal(4, @store.count)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_timestamp
|
54
|
+
time = Time.now - 24*60*60
|
55
|
+
message = @store.report(Logger::WARN, "test", "B", timestamp: time)
|
56
|
+
|
57
|
+
assert_equal(time, message.timestamp)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_backtrace
|
61
|
+
# Create an error with a backtrace
|
62
|
+
error = TypeError.new
|
63
|
+
begin
|
64
|
+
raise error
|
65
|
+
rescue => e
|
66
|
+
error = e
|
67
|
+
end
|
68
|
+
|
69
|
+
# Backtrace can be passed via backtrace param or env
|
70
|
+
message = @store.report(Logger::WARN, "test", "A", backtrace: error.backtrace)
|
71
|
+
assert_equal(error.backtrace.join("\n"), message.backtrace)
|
72
|
+
message = @store.report(Logger::WARN, "test", "B", env: {backtrace: error.backtrace})
|
73
|
+
assert_equal(error.backtrace.join("\n"), message.backtrace)
|
74
|
+
|
75
|
+
# Via env takes priority
|
76
|
+
message = @store.report(Logger::WARN, "test", "C", backtrace: "Garbage", env: {backtrace: error.backtrace})
|
77
|
+
assert_equal(error.backtrace.join("\n"), message.backtrace)
|
78
|
+
|
79
|
+
# Backtrace is always a string
|
80
|
+
# Cannot do an equal assert here, because it uses `caller` when not provided
|
81
|
+
message = @store.report(Logger::WARN, "test", "D", backtrace: nil)
|
82
|
+
assert_kind_of(String, message.backtrace)
|
83
|
+
message = @store.report(Logger::WARN, "test", "E", env: {backtrace: nil})
|
84
|
+
assert_kind_of(String, message.backtrace)
|
85
|
+
message = @store.report(Logger::WARN, "test", "F", backtrace: nil, env: {backtrace: nil})
|
86
|
+
assert_kind_of(String, message.backtrace)
|
87
|
+
message = @store.report(Logger::WARN, "test", "G")
|
88
|
+
assert_kind_of(String, message.backtrace)
|
89
|
+
|
90
|
+
# Arrays are turned into strings via join \n
|
91
|
+
message = @store.report(Logger::WARN, "test", "H", backtrace: ["Foo", "Bar"])
|
92
|
+
assert_equal("Foo\nBar", message.backtrace)
|
93
|
+
end
|
94
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -4,36 +4,29 @@ require 'minitest/autorun'
|
|
4
4
|
require 'minitest/pride'
|
5
5
|
require 'logster'
|
6
6
|
require 'redis'
|
7
|
+
require 'logster/base_store'
|
7
8
|
|
8
|
-
|
9
|
-
class Logster::TestStore
|
9
|
+
class Logster::TestStore < Logster::BaseStore
|
10
10
|
attr_accessor :reported
|
11
11
|
def initialize
|
12
12
|
@reported = []
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
backtrace = opts[:backtrace]
|
19
|
-
if env && !backtrace
|
20
|
-
backtrace = env[:backtrace]
|
21
|
-
end
|
22
|
-
|
23
|
-
message = Logster::Message.new(severity, progname, message)
|
24
|
-
|
25
|
-
if backtrace
|
26
|
-
message.backtrace = backtrace
|
27
|
-
else
|
28
|
-
message.backtrace = caller.join("\n")
|
29
|
-
end
|
15
|
+
def save(message)
|
16
|
+
@reported << message
|
17
|
+
end
|
30
18
|
|
31
|
-
|
32
|
-
|
33
|
-
|
19
|
+
def count
|
20
|
+
@reported.count
|
21
|
+
end
|
34
22
|
|
35
|
-
|
23
|
+
def clear
|
24
|
+
@reported = []
|
25
|
+
end
|
36
26
|
|
37
|
-
|
27
|
+
def clear_all
|
28
|
+
@reported = []
|
38
29
|
end
|
30
|
+
|
31
|
+
# get, protect, unprotect: unimplemented
|
39
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- UI for viewing logs in Rack
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- bower.json
|
127
127
|
- lib/examples/sidekiq_logster_reporter.rb
|
128
128
|
- lib/logster.rb
|
129
|
+
- lib/logster/base_store.rb
|
129
130
|
- lib/logster/configuration.rb
|
130
131
|
- lib/logster/logger.rb
|
131
132
|
- lib/logster/message.rb
|
@@ -140,6 +141,7 @@ files:
|
|
140
141
|
- test/examples/test_sidekiq_reporter_example.rb
|
141
142
|
- test/logster/middleware/test_reporter.rb
|
142
143
|
- test/logster/middleware/test_viewer.rb
|
144
|
+
- test/logster/test_base_store.rb
|
143
145
|
- test/logster/test_logger.rb
|
144
146
|
- test/logster/test_redis_store.rb
|
145
147
|
- test/test_helper.rb
|
@@ -172,6 +174,7 @@ test_files:
|
|
172
174
|
- test/examples/test_sidekiq_reporter_example.rb
|
173
175
|
- test/logster/middleware/test_reporter.rb
|
174
176
|
- test/logster/middleware/test_viewer.rb
|
177
|
+
- test/logster/test_base_store.rb
|
175
178
|
- test/logster/test_logger.rb
|
176
179
|
- test/logster/test_redis_store.rb
|
177
180
|
- test/test_helper.rb
|