logster 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +18 -0
- data/assets/javascript/app.js +377 -0
- data/assets/javascript/external/ember.js +44267 -0
- data/assets/javascript/external/ember.min.js +19 -0
- data/assets/javascript/external/handlebars.min.js +28 -0
- data/assets/javascript/external/jquery.min.js +5 -0
- data/assets/javascript/external/lodash.min.js +56 -0
- data/assets/javascript/external/moment.min.js +6 -0
- data/assets/javascript/templates/application.handlebars +1 -0
- data/assets/javascript/templates/index.handlebars +48 -0
- data/assets/javascript/templates/message.handlebars +7 -0
- data/assets/stylesheets/app.css +188 -0
- data/bower_components/ember/.bower.json +22 -0
- data/bower_components/ember/.gitignore +5 -0
- data/bower_components/ember/Makefile +9 -0
- data/bower_components/ember/README.md +12 -0
- data/bower_components/ember/bower.json +11 -0
- data/bower_components/ember/component.json +13 -0
- data/bower_components/ember/composer.json +27 -0
- data/bower_components/ember/ember-template-compiler.js +320 -0
- data/bower_components/ember/ember.js +44267 -0
- data/bower_components/ember/ember.min.js +19 -0
- data/bower_components/ember/ember.prod.js +42649 -0
- data/bower_components/ember/package.json +11 -0
- data/bower_components/handlebars/.bower.json +16 -0
- data/bower_components/handlebars/.gitignore +2 -0
- data/bower_components/handlebars/README.md +11 -0
- data/bower_components/handlebars/bower.json +6 -0
- data/bower_components/handlebars/component.json +9 -0
- data/bower_components/handlebars/composer.json +35 -0
- data/bower_components/handlebars/handlebars-source.gemspec +21 -0
- data/bower_components/handlebars/handlebars.amd.js +2719 -0
- data/bower_components/handlebars/handlebars.amd.min.js +28 -0
- data/bower_components/handlebars/handlebars.js +2746 -0
- data/bower_components/handlebars/handlebars.js.nuspec +17 -0
- data/bower_components/handlebars/handlebars.min.js +28 -0
- data/bower_components/handlebars/handlebars.runtime.amd.js +515 -0
- data/bower_components/handlebars/handlebars.runtime.amd.min.js +27 -0
- data/bower_components/handlebars/handlebars.runtime.js +530 -0
- data/bower_components/handlebars/handlebars.runtime.min.js +27 -0
- data/bower_components/handlebars/lib/handlebars/source.rb +11 -0
- data/bower_components/jquery/.bower.json +37 -0
- data/bower_components/jquery/MIT-LICENSE.txt +21 -0
- data/bower_components/jquery/bower.json +27 -0
- data/bower_components/jquery/dist/jquery.js +9111 -0
- data/bower_components/jquery/dist/jquery.min.js +5 -0
- data/bower_components/jquery/dist/jquery.min.map +1 -0
- data/bower_components/jquery/src/ajax.js +806 -0
- data/bower_components/jquery/src/ajax/jsonp.js +89 -0
- data/bower_components/jquery/src/ajax/load.js +75 -0
- data/bower_components/jquery/src/ajax/parseJSON.js +13 -0
- data/bower_components/jquery/src/ajax/parseXML.js +28 -0
- data/bower_components/jquery/src/ajax/script.js +64 -0
- data/bower_components/jquery/src/ajax/var/nonce.js +5 -0
- data/bower_components/jquery/src/ajax/var/rquery.js +3 -0
- data/bower_components/jquery/src/ajax/xhr.js +130 -0
- data/bower_components/jquery/src/attributes.js +11 -0
- data/bower_components/jquery/src/attributes/attr.js +143 -0
- data/bower_components/jquery/src/attributes/classes.js +158 -0
- data/bower_components/jquery/src/attributes/prop.js +96 -0
- data/bower_components/jquery/src/attributes/support.js +35 -0
- data/bower_components/jquery/src/attributes/val.js +153 -0
- data/bower_components/jquery/src/callbacks.js +205 -0
- data/bower_components/jquery/src/core.js +500 -0
- data/bower_components/jquery/src/core/access.js +60 -0
- data/bower_components/jquery/src/core/init.js +123 -0
- data/bower_components/jquery/src/core/parseHTML.js +39 -0
- data/bower_components/jquery/src/core/ready.js +96 -0
- data/bower_components/jquery/src/core/var/rsingleTag.js +4 -0
- data/bower_components/jquery/src/css.js +455 -0
- data/bower_components/jquery/src/css/addGetHookIf.js +24 -0
- data/bower_components/jquery/src/css/curCSS.js +57 -0
- data/bower_components/jquery/src/css/defaultDisplay.js +69 -0
- data/bower_components/jquery/src/css/hiddenVisibleSelectors.js +15 -0
- data/bower_components/jquery/src/css/support.js +83 -0
- data/bower_components/jquery/src/css/swap.js +28 -0
- data/bower_components/jquery/src/css/var/cssExpand.js +3 -0
- data/bower_components/jquery/src/css/var/getStyles.js +5 -0
- data/bower_components/jquery/src/css/var/isHidden.js +13 -0
- data/bower_components/jquery/src/css/var/rmargin.js +3 -0
- data/bower_components/jquery/src/css/var/rnumnonpx.js +5 -0
- data/bower_components/jquery/src/data.js +175 -0
- data/bower_components/jquery/src/data/Data.js +181 -0
- data/bower_components/jquery/src/data/accepts.js +20 -0
- data/bower_components/jquery/src/data/var/data_priv.js +5 -0
- data/bower_components/jquery/src/data/var/data_user.js +5 -0
- data/bower_components/jquery/src/deferred.js +149 -0
- data/bower_components/jquery/src/deprecated.js +13 -0
- data/bower_components/jquery/src/dimensions.js +50 -0
- data/bower_components/jquery/src/effects.js +642 -0
- data/bower_components/jquery/src/effects/Tween.js +114 -0
- data/bower_components/jquery/src/effects/animatedSelector.js +13 -0
- data/bower_components/jquery/src/event.js +859 -0
- data/bower_components/jquery/src/event/alias.js +39 -0
- data/bower_components/jquery/src/event/support.js +9 -0
- data/bower_components/jquery/src/exports/amd.js +18 -0
- data/bower_components/jquery/src/exports/global.js +32 -0
- data/bower_components/jquery/src/intro.js +44 -0
- data/bower_components/jquery/src/jquery.js +36 -0
- data/bower_components/jquery/src/manipulation.js +583 -0
- data/bower_components/jquery/src/manipulation/_evalUrl.js +18 -0
- data/bower_components/jquery/src/manipulation/support.js +24 -0
- data/bower_components/jquery/src/manipulation/var/rcheckableType.js +3 -0
- data/bower_components/jquery/src/offset.js +204 -0
- data/bower_components/jquery/src/outro.js +1 -0
- data/bower_components/jquery/src/queue.js +142 -0
- data/bower_components/jquery/src/queue/delay.js +22 -0
- data/bower_components/jquery/src/selector-native.js +171 -0
- data/bower_components/jquery/src/selector-sizzle.js +14 -0
- data/bower_components/jquery/src/selector.js +1 -0
- data/bower_components/jquery/src/serialize.js +111 -0
- data/bower_components/jquery/src/sizzle/dist/sizzle.js +2015 -0
- data/bower_components/jquery/src/sizzle/dist/sizzle.min.js +3 -0
- data/bower_components/jquery/src/sizzle/dist/sizzle.min.map +1 -0
- data/bower_components/jquery/src/traversing.js +200 -0
- data/bower_components/jquery/src/traversing/findFilter.js +100 -0
- data/bower_components/jquery/src/traversing/var/rneedsContext.js +6 -0
- data/bower_components/jquery/src/var/arr.js +3 -0
- data/bower_components/jquery/src/var/class2type.js +4 -0
- data/bower_components/jquery/src/var/concat.js +5 -0
- data/bower_components/jquery/src/var/hasOwn.js +5 -0
- data/bower_components/jquery/src/var/indexOf.js +5 -0
- data/bower_components/jquery/src/var/pnum.js +3 -0
- data/bower_components/jquery/src/var/push.js +5 -0
- data/bower_components/jquery/src/var/rnotwhite.js +3 -0
- data/bower_components/jquery/src/var/slice.js +5 -0
- data/bower_components/jquery/src/var/strundefined.js +3 -0
- data/bower_components/jquery/src/var/support.js +4 -0
- data/bower_components/jquery/src/var/toString.js +5 -0
- data/bower_components/jquery/src/var/trim.js +3 -0
- data/bower_components/jquery/src/wrap.js +78 -0
- data/bower_components/lodash/.bower.json +34 -0
- data/bower_components/lodash/LICENSE.txt +22 -0
- data/bower_components/lodash/bower.json +23 -0
- data/bower_components/lodash/dist/lodash.compat.js +7157 -0
- data/bower_components/lodash/dist/lodash.compat.min.js +61 -0
- data/bower_components/lodash/dist/lodash.js +6785 -0
- data/bower_components/lodash/dist/lodash.min.js +56 -0
- data/bower_components/lodash/dist/lodash.underscore.js +4979 -0
- data/bower_components/lodash/dist/lodash.underscore.min.js +39 -0
- data/bower_components/moment/.bower.json +31 -0
- data/bower_components/moment/LICENSE +22 -0
- data/bower_components/moment/bower.json +20 -0
- data/bower_components/moment/lang/ar-ma.js +56 -0
- data/bower_components/moment/lang/ar.js +56 -0
- data/bower_components/moment/lang/bg.js +86 -0
- data/bower_components/moment/lang/br.js +107 -0
- data/bower_components/moment/lang/bs.js +139 -0
- data/bower_components/moment/lang/ca.js +66 -0
- data/bower_components/moment/lang/cs.js +155 -0
- data/bower_components/moment/lang/cv.js +59 -0
- data/bower_components/moment/lang/cy.js +77 -0
- data/bower_components/moment/lang/da.js +56 -0
- data/bower_components/moment/lang/de.js +71 -0
- data/bower_components/moment/lang/el.js +79 -0
- data/bower_components/moment/lang/en-au.js +62 -0
- data/bower_components/moment/lang/en-ca.js +59 -0
- data/bower_components/moment/lang/en-gb.js +63 -0
- data/bower_components/moment/lang/eo.js +65 -0
- data/bower_components/moment/lang/es.js +75 -0
- data/bower_components/moment/lang/et.js +76 -0
- data/bower_components/moment/lang/eu.js +60 -0
- data/bower_components/moment/lang/fa.js +97 -0
- data/bower_components/moment/lang/fi.js +103 -0
- data/bower_components/moment/lang/fo.js +56 -0
- data/bower_components/moment/lang/fr-ca.js +54 -0
- data/bower_components/moment/lang/fr.js +58 -0
- data/bower_components/moment/lang/gl.js +71 -0
- data/bower_components/moment/lang/he.js +77 -0
- data/bower_components/moment/lang/hi.js +105 -0
- data/bower_components/moment/lang/hr.js +140 -0
- data/bower_components/moment/lang/hu.js +105 -0
- data/bower_components/moment/lang/hy-am.js +113 -0
- data/bower_components/moment/lang/id.js +67 -0
- data/bower_components/moment/lang/is.js +124 -0
- data/bower_components/moment/lang/it.js +59 -0
- data/bower_components/moment/lang/ja.js +58 -0
- data/bower_components/moment/lang/ka.js +108 -0
- data/bower_components/moment/lang/km.js +55 -0
- data/bower_components/moment/lang/ko.js +63 -0
- data/bower_components/moment/lang/lb.js +160 -0
- data/bower_components/moment/lang/lt.js +118 -0
- data/bower_components/moment/lang/lv.js +77 -0
- data/bower_components/moment/lang/mk.js +86 -0
- data/bower_components/moment/lang/ml.js +64 -0
- data/bower_components/moment/lang/mr.js +104 -0
- data/bower_components/moment/lang/ms-my.js +66 -0
- data/bower_components/moment/lang/nb.js +57 -0
- data/bower_components/moment/lang/ne.js +105 -0
- data/bower_components/moment/lang/nl.js +67 -0
- data/bower_components/moment/lang/nn.js +56 -0
- data/bower_components/moment/lang/pl.js +98 -0
- data/bower_components/moment/lang/pt-br.js +56 -0
- data/bower_components/moment/lang/pt.js +60 -0
- data/bower_components/moment/lang/ro.js +72 -0
- data/bower_components/moment/lang/ru.js +163 -0
- data/bower_components/moment/lang/sk.js +156 -0
- data/bower_components/moment/lang/sl.js +144 -0
- data/bower_components/moment/lang/sq.js +61 -0
- data/bower_components/moment/lang/sr-cyr.js +106 -0
- data/bower_components/moment/lang/sr.js +106 -0
- data/bower_components/moment/lang/sv.js +63 -0
- data/bower_components/moment/lang/ta.js +112 -0
- data/bower_components/moment/lang/th.js +58 -0
- data/bower_components/moment/lang/tl-ph.js +58 -0
- data/bower_components/moment/lang/tr.js +93 -0
- data/bower_components/moment/lang/tzm-la.js +55 -0
- data/bower_components/moment/lang/tzm.js +55 -0
- data/bower_components/moment/lang/uk.js +157 -0
- data/bower_components/moment/lang/uz.js +55 -0
- data/bower_components/moment/lang/vi.js +62 -0
- data/bower_components/moment/lang/zh-cn.js +108 -0
- data/bower_components/moment/lang/zh-tw.js +84 -0
- data/bower_components/moment/min/langs.js +5991 -0
- data/bower_components/moment/min/langs.min.js +3 -0
- data/bower_components/moment/min/moment-with-langs.js +7993 -0
- data/bower_components/moment/min/moment-with-langs.min.js +9 -0
- data/bower_components/moment/min/moment.min.js +6 -0
- data/bower_components/moment/moment.js +2489 -0
- data/bower_components/moment/readme.md +368 -0
- data/lib/logster.rb +9 -0
- data/lib/logster/logger.rb +31 -0
- data/lib/logster/message.rb +42 -0
- data/lib/logster/middleware/reporter.rb +13 -0
- data/lib/logster/middleware/viewer.rb +122 -0
- data/lib/logster/rails/railtie.rb +39 -0
- data/lib/logster/redis_store.rb +124 -0
- data/lib/logster/version.rb +3 -0
- data/logster.gemspec +30 -0
- data/test/logster/middleware/test_viewer.rb +34 -0
- data/test/logster/test_redis_store.rb +112 -0
- data/test/test_helper.rb +6 -0
- data/website/Gemfile +6 -0
- data/website/config.ru +2 -0
- data/website/data/data.json +1 -0
- data/website/docker_container/logster.yml +95 -0
- data/website/sample.rb +85 -0
- data/website/scripts/persist_logs.rb +13 -0
- metadata +375 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Logster
|
4
|
+
module Middleware
|
5
|
+
class Viewer
|
6
|
+
|
7
|
+
PATH_INFO = "PATH_INFO".freeze
|
8
|
+
|
9
|
+
def initialize(app, config)
|
10
|
+
@app = app
|
11
|
+
@logs_path = config[:path] || "/logs"
|
12
|
+
@path_regex = Regexp.new("(#{@logs_path}$)|(#{@logs_path}(/.*))$")
|
13
|
+
|
14
|
+
@store = config[:store] or raise ArgumentError.new("store")
|
15
|
+
|
16
|
+
@assets_path = File.expand_path("../../../../assets", __FILE__)
|
17
|
+
@fileserver = Rack::File.new(@assets_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
path = env[PATH_INFO]
|
22
|
+
|
23
|
+
if resource = resolve_path(path)
|
24
|
+
|
25
|
+
if resource =~ /\.js$|\.handlebars$|\.css$/
|
26
|
+
env[PATH_INFO] = resource
|
27
|
+
@fileserver.call(env)
|
28
|
+
elsif resource.start_with?("/messages.json")
|
29
|
+
serve_messages(Rack::Request.new(env))
|
30
|
+
elsif resource == "/"
|
31
|
+
[200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload_json)]]
|
32
|
+
else
|
33
|
+
[404, {}, ["Not found"]]
|
34
|
+
end
|
35
|
+
else
|
36
|
+
@app.call(env)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def serve_messages(req)
|
43
|
+
opts = {
|
44
|
+
before: req["before"],
|
45
|
+
after: req["after"]
|
46
|
+
}
|
47
|
+
|
48
|
+
if(filter = req["filter"])
|
49
|
+
filter = filter.split("_").map{|s| s.to_i}
|
50
|
+
opts[:severity] = filter
|
51
|
+
end
|
52
|
+
|
53
|
+
payload = {
|
54
|
+
messages: @store.latest(opts),
|
55
|
+
total: @store.count
|
56
|
+
}
|
57
|
+
|
58
|
+
json = JSON.generate(payload)
|
59
|
+
[200, {"Content-Type" => "application/json"}, [json]]
|
60
|
+
end
|
61
|
+
|
62
|
+
def resolve_path(path)
|
63
|
+
if path =~ @path_regex
|
64
|
+
$3 || "/"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def preload_json
|
69
|
+
end
|
70
|
+
|
71
|
+
def css(name, attrs={})
|
72
|
+
attrs = attrs.map do |k,v|
|
73
|
+
"#{k}='#{v}'"
|
74
|
+
end.join(" ")
|
75
|
+
|
76
|
+
"<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
|
77
|
+
end
|
78
|
+
|
79
|
+
def script(prod, dev=nil)
|
80
|
+
name = ENV['DEBUG_JS'] == "1" && dev ? dev : prod
|
81
|
+
"<script src='#{@logs_path}/javascript/#{name}'></script>"
|
82
|
+
end
|
83
|
+
|
84
|
+
def handlebars(name)
|
85
|
+
val = File.read("#{@assets_path}/javascript/templates/#{name}.handlebars")
|
86
|
+
<<JS
|
87
|
+
<script>
|
88
|
+
Ember.TEMPLATES[#{name.inspect}] = Ember.Handlebars.compile(#{val.inspect});
|
89
|
+
</script>
|
90
|
+
JS
|
91
|
+
end
|
92
|
+
|
93
|
+
def body(preload)
|
94
|
+
<<HTML
|
95
|
+
<html>
|
96
|
+
<head>
|
97
|
+
#{css("app.css")}
|
98
|
+
#{script("external/moment.min.js")}
|
99
|
+
#{script("external/jquery.min.js")}
|
100
|
+
#{script("external/handlebars.min.js")}
|
101
|
+
#{script("external/lodash.min.js")}
|
102
|
+
#{script("external/ember.min.js", "external/ember.js")}
|
103
|
+
#{handlebars("application")}
|
104
|
+
#{handlebars("index")}
|
105
|
+
#{handlebars("message")}
|
106
|
+
<script>
|
107
|
+
window.Logger = {
|
108
|
+
rootPath: "#{@logs_path}"
|
109
|
+
};
|
110
|
+
</script>
|
111
|
+
</head>
|
112
|
+
<body>
|
113
|
+
#{script("app.js")}
|
114
|
+
</body>
|
115
|
+
</html>
|
116
|
+
HTML
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Logster::Rails
|
2
|
+
|
3
|
+
def self.set_logger(config)
|
4
|
+
return unless Rails.env.development?
|
5
|
+
|
6
|
+
if defined?(Redis)
|
7
|
+
require 'logster/middleware/viewer'
|
8
|
+
require 'logster/redis_store'
|
9
|
+
|
10
|
+
store = Logster::RedisStore.new
|
11
|
+
logger = Logster::Logger.new(store)
|
12
|
+
|
13
|
+
::Rails.logger = config.logger = logger
|
14
|
+
else
|
15
|
+
Rails.logger.warn "Not loading logster, Redis missing"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.initialize!(app)
|
20
|
+
return unless Rails.env.development?
|
21
|
+
|
22
|
+
if Logster::Logger === Rails.logger
|
23
|
+
app.middleware.use Logster::Middleware::Viewer, store: Rails.logger.store
|
24
|
+
|
25
|
+
app.config.colorize_logging = false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Railtie < ::Rails::Railtie
|
30
|
+
|
31
|
+
config.before_initialize do
|
32
|
+
Logster::Rails.set_logger(config)
|
33
|
+
end
|
34
|
+
|
35
|
+
initializer "logster.configure_rails_initialization" do |app|
|
36
|
+
Logster::Rails.initialize!(app)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Logster
|
4
|
+
class RedisStore
|
5
|
+
|
6
|
+
attr_accessor :max_backlog, :dedup, :max_retention, :skip_empty
|
7
|
+
|
8
|
+
def initialize(redis = nil)
|
9
|
+
@redis = redis || Redis.new
|
10
|
+
@max_backlog = 1000
|
11
|
+
@dedup = false
|
12
|
+
@max_retention = 60 * 60 * 24 * 7
|
13
|
+
@skip_empty = true
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def report(severity, progname, message)
|
18
|
+
return if (!message || (String === message && message.empty?)) && skip_empty
|
19
|
+
|
20
|
+
message = Message.new(severity, progname, message)
|
21
|
+
@redis.rpush(list_key, message.to_json)
|
22
|
+
|
23
|
+
# TODO make it atomic
|
24
|
+
if @redis.llen(list_key) > @max_backlog
|
25
|
+
@redis.lpop(list_key)
|
26
|
+
end
|
27
|
+
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def count
|
32
|
+
@redis.llen(list_key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def latest(opts={})
|
36
|
+
limit = opts[:limit] || 50
|
37
|
+
severity = opts[:severity]
|
38
|
+
before = opts[:before]
|
39
|
+
after = opts[:after]
|
40
|
+
start = -limit
|
41
|
+
finish = -1
|
42
|
+
|
43
|
+
if before || after
|
44
|
+
# inefficient may change to sorted list, also timing issues
|
45
|
+
found = nil
|
46
|
+
find = before || after
|
47
|
+
|
48
|
+
while !found
|
49
|
+
items = @redis.lrange(list_key, start, finish)
|
50
|
+
|
51
|
+
break unless items && items.length > 0
|
52
|
+
|
53
|
+
found = items.index do |i|
|
54
|
+
Message.from_json(i).key == find
|
55
|
+
end
|
56
|
+
|
57
|
+
if items.length < limit
|
58
|
+
found += limit - items.length if found
|
59
|
+
break
|
60
|
+
end
|
61
|
+
break if found
|
62
|
+
start -= limit
|
63
|
+
finish -= limit
|
64
|
+
end
|
65
|
+
|
66
|
+
if found
|
67
|
+
if before
|
68
|
+
offset = -(limit - found)
|
69
|
+
else
|
70
|
+
offset = found + 1
|
71
|
+
end
|
72
|
+
|
73
|
+
start += offset
|
74
|
+
finish += offset
|
75
|
+
|
76
|
+
finish = -1 if finish > -1
|
77
|
+
return [] if start > -1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
results = []
|
82
|
+
|
83
|
+
direction = after ? 1 : -1
|
84
|
+
|
85
|
+
begin
|
86
|
+
rows = @redis.lrange(list_key, start, finish) || []
|
87
|
+
|
88
|
+
temp = []
|
89
|
+
|
90
|
+
rows.each do |s|
|
91
|
+
row = Message.from_json(s)
|
92
|
+
break if before && before == row.key
|
93
|
+
row = nil if severity && !severity.include?(row.severity)
|
94
|
+
temp << row if row
|
95
|
+
end
|
96
|
+
|
97
|
+
if direction == -1
|
98
|
+
results = temp + results
|
99
|
+
else
|
100
|
+
results += temp
|
101
|
+
end
|
102
|
+
|
103
|
+
start += limit * direction
|
104
|
+
finish += limit * direction
|
105
|
+
|
106
|
+
finish = -1 if finish > -1
|
107
|
+
end while rows.length > 0 && results.length < limit && start < 0
|
108
|
+
|
109
|
+
results
|
110
|
+
end
|
111
|
+
|
112
|
+
def clear(severities=nil)
|
113
|
+
@redis.del(list_key)
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
|
119
|
+
def list_key
|
120
|
+
@list_key ||= "__LOGSTER__LOG"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
data/logster.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'logster/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "logster"
|
8
|
+
spec.version = Logster::VERSION
|
9
|
+
spec.authors = ["UI for viewing logs in Rack"]
|
10
|
+
spec.email = ["sam.saffron@gmail.com"]
|
11
|
+
spec.summary = %q{UI for viewing logs in Rack}
|
12
|
+
spec.description = %q{UI for viewing logs in Rack}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# NOTE dependency on rack is not explicit, this enables us to use
|
22
|
+
# logster outside of rack (for reporting)
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rack"
|
27
|
+
spec.add_development_dependency "redis"
|
28
|
+
spec.add_development_dependency "guard"
|
29
|
+
spec.add_development_dependency "guard-minitest"
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
require 'rack'
|
3
|
+
require 'logster/redis_store'
|
4
|
+
require 'logster/middleware/viewer'
|
5
|
+
|
6
|
+
class TestViewer < Minitest::Test
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
end
|
10
|
+
|
11
|
+
def viewer
|
12
|
+
@viewer ||= begin
|
13
|
+
store = Logster::RedisStore.new
|
14
|
+
Logster::Middleware::Viewer.new(nil, store: store, path: "/logsie")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_path_resolution
|
19
|
+
assert_nil(viewer.send(:resolve_path, "/logs"))
|
20
|
+
assert_equal("/",viewer.send(:resolve_path, "/logsie"))
|
21
|
+
assert_equal("/",viewer.send(:resolve_path, "/logsie/"))
|
22
|
+
assert_equal("/hello/world",viewer.send(:resolve_path, "/logsie/hello/world"))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_assets
|
26
|
+
env = {}
|
27
|
+
env["PATH_INFO"] = "/logsie/javascript/external/jquery.min.js"
|
28
|
+
env["REQUEST_METHOD"] = "GET"
|
29
|
+
|
30
|
+
result, = viewer.call(env)
|
31
|
+
assert_equal(200, result)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'logster/redis_store'
|
3
|
+
|
4
|
+
class TestRedisStore < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@store = Logster::RedisStore.new(Redis.new)
|
8
|
+
@store.clear
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@store.clear
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_latest
|
16
|
+
@store.report(Logger::WARN, "test", "IGNORE")
|
17
|
+
@store.report(Logger::WARN, "test", "This is a warning")
|
18
|
+
@store.report(Logger::WARN, "test", "This is another warning")
|
19
|
+
|
20
|
+
latest = @store.latest(limit: 2)
|
21
|
+
|
22
|
+
assert_equal(2, latest.length)
|
23
|
+
assert_equal("This is a warning", latest[0].message)
|
24
|
+
assert_equal("This is another warning", latest[1].message)
|
25
|
+
assert_equal(Logger::WARN, latest[1].severity)
|
26
|
+
assert_equal("test", latest[1].progname)
|
27
|
+
assert(!latest[1].key.nil?)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_latest_after
|
31
|
+
10.times do |i|
|
32
|
+
@store.report(Logger::WARN, "test", "A#{i}")
|
33
|
+
end
|
34
|
+
|
35
|
+
message = @store.latest[-1]
|
36
|
+
|
37
|
+
3.times do |i|
|
38
|
+
@store.report(Logger::WARN, "test", i.to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
message = @store.latest(after: message.key, limit: 3)[0]
|
42
|
+
|
43
|
+
assert_equal("0", message.message)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_latest_before
|
47
|
+
10.times do
|
48
|
+
@store.report(Logger::WARN, "test", "A")
|
49
|
+
end
|
50
|
+
10.times do
|
51
|
+
@store.report(Logger::WARN, "test", "B")
|
52
|
+
end
|
53
|
+
10.times do
|
54
|
+
@store.report(Logger::WARN, "test", "C")
|
55
|
+
end
|
56
|
+
|
57
|
+
messages = @store.latest(limit: 10)
|
58
|
+
assert_equal("C", messages[0].message)
|
59
|
+
assert_equal(10, messages.length)
|
60
|
+
|
61
|
+
messages = @store.latest(limit: 10, before: messages[0].key)
|
62
|
+
assert_equal("B", messages[0].message)
|
63
|
+
assert_equal(10, messages.length)
|
64
|
+
|
65
|
+
messages = @store.latest(limit: 10, before: messages[0].key)
|
66
|
+
assert_equal("A", messages[0].message)
|
67
|
+
assert_equal(10, messages.length)
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_backlog
|
72
|
+
@store.max_backlog = 1
|
73
|
+
@store.report(Logger::WARN, "test", "A")
|
74
|
+
@store.report(Logger::WARN, "test", "B")
|
75
|
+
|
76
|
+
latest = @store.latest
|
77
|
+
|
78
|
+
assert_equal(1, latest.length)
|
79
|
+
assert_equal("B", latest[0].message)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_filter_latest
|
83
|
+
@store.report(Logger::INFO, "test", "A")
|
84
|
+
@store.report(Logger::WARN, "test", "B")
|
85
|
+
|
86
|
+
messages = @store.latest
|
87
|
+
assert_equal(2, messages.length)
|
88
|
+
|
89
|
+
messages = @store.latest(after: messages.last.key)
|
90
|
+
assert_equal(0, messages.length)
|
91
|
+
|
92
|
+
10.times do
|
93
|
+
@store.report(Logger::INFO, "test", "A")
|
94
|
+
end
|
95
|
+
@store.report(Logger::ERROR, "test", "C")
|
96
|
+
10.times do
|
97
|
+
@store.report(Logger::INFO, "test", "A")
|
98
|
+
end
|
99
|
+
|
100
|
+
latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2)
|
101
|
+
|
102
|
+
assert_equal(2, latest.length)
|
103
|
+
assert_equal("B", latest[0].message)
|
104
|
+
assert_equal("C", latest[1].message)
|
105
|
+
|
106
|
+
@store.report(Logger::ERROR, "test", "E")
|
107
|
+
# respects after
|
108
|
+
latest = @store.latest(severity: [Logger::ERROR, Logger::WARN], limit: 2, after: latest[1].key)
|
109
|
+
assert_equal(1, latest.length);
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|