logster 1.2.11 → 1.3.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -17
  3. data/.travis.yml +15 -16
  4. data/CHANGELOG.md +130 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -96
  9. data/Rakefile +24 -23
  10. data/assets/fonts/FontAwesome.otf +0 -0
  11. data/assets/fonts/fontawesome-webfont.eot +0 -0
  12. data/assets/fonts/fontawesome-webfont.svg +639 -639
  13. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  14. data/assets/fonts/fontawesome-webfont.woff +0 -0
  15. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  16. data/assets/images/Icon-144_rounded.png +0 -0
  17. data/assets/images/Icon-144_square.png +0 -0
  18. data/assets/images/icon_144x144.png +0 -0
  19. data/assets/images/icon_64x64.png +0 -0
  20. data/assets/javascript/client-app.js +81 -0
  21. data/assets/javascript/vendor.js +5302 -0
  22. data/assets/stylesheets/client-app.css +1 -0
  23. data/assets/stylesheets/vendor.css +4 -0
  24. data/build_client_app.sh +12 -0
  25. data/client-app/.editorconfig +20 -0
  26. data/client-app/.ember-cli +9 -0
  27. data/client-app/.eslintignore +19 -0
  28. data/client-app/.eslintrc.js +46 -0
  29. data/client-app/.gitignore +23 -0
  30. data/client-app/.travis.yml +27 -0
  31. data/client-app/.watchmanconfig +3 -0
  32. data/client-app/README.md +57 -0
  33. data/client-app/app/app.js +14 -0
  34. data/client-app/app/components/message-info.js +18 -0
  35. data/client-app/app/components/message-row.js +45 -0
  36. data/client-app/app/components/panel-resizer.js +75 -0
  37. data/client-app/app/components/tab-contents.js +27 -0
  38. data/client-app/app/components/tab-link.js +5 -0
  39. data/client-app/app/components/tabbed-section.js +32 -0
  40. data/client-app/app/components/time-formatter.js +25 -0
  41. data/client-app/app/components/update-time.js +21 -0
  42. data/client-app/app/controllers/index.js +83 -0
  43. data/client-app/app/controllers/show.js +13 -0
  44. data/client-app/app/index.html +29 -0
  45. data/client-app/app/initializers/app-init.js +55 -0
  46. data/client-app/app/lib/preload.js +14 -0
  47. data/client-app/app/lib/utilities.js +140 -0
  48. data/client-app/app/models/message-collection.js +158 -0
  49. data/client-app/app/models/message.js +99 -0
  50. data/client-app/app/resolver.js +3 -0
  51. data/client-app/app/router.js +14 -0
  52. data/client-app/app/routes/index.js +53 -0
  53. data/client-app/app/routes/show.js +14 -0
  54. data/{assets/stylesheets → client-app/app/styles}/app.css +387 -390
  55. data/{assets/javascript → client-app/app}/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -0
  57. data/{assets/javascript → client-app/app/templates}/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -0
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -0
  60. data/{assets/javascript → client-app/app}/templates/index.hbs +57 -57
  61. data/{assets/javascript → client-app/app}/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -0
  63. data/client-app/config/optional-features.json +3 -0
  64. data/client-app/config/targets.js +18 -0
  65. data/client-app/ember-cli-build.js +29 -0
  66. data/client-app/package-lock.json +11365 -0
  67. data/client-app/package.json +56 -0
  68. data/client-app/testem.js +25 -0
  69. data/client-app/tests/index.html +34 -0
  70. data/client-app/tests/integration/components/message-info-test.js +26 -0
  71. data/client-app/tests/integration/components/message-row-test.js +26 -0
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -0
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -0
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -0
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -0
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -0
  77. data/client-app/tests/integration/components/update-time-test.js +26 -0
  78. data/client-app/tests/test-helper.js +8 -0
  79. data/client-app/tests/unit/controllers/index-test.js +12 -0
  80. data/client-app/tests/unit/controllers/show-test.js +12 -0
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -0
  82. data/client-app/tests/unit/routes/index-test.js +11 -0
  83. data/client-app/tests/unit/routes/show-test.js +11 -0
  84. data/lib/examples/sidekiq_logster_reporter.rb +21 -21
  85. data/lib/logster.rb +54 -54
  86. data/lib/logster/base_store.rb +130 -130
  87. data/lib/logster/configuration.rb +25 -25
  88. data/lib/logster/ignore_pattern.rb +65 -65
  89. data/lib/logster/logger.rb +102 -101
  90. data/lib/logster/message.rb +227 -226
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -54
  93. data/lib/logster/middleware/viewer.rb +220 -251
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -477
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -33
  99. data/test/examples/test_sidekiq_reporter_example.rb +46 -46
  100. data/test/fake_data/Gemfile +4 -4
  101. data/test/fake_data/generate.rb +10 -10
  102. data/test/logster/middleware/test_reporter.rb +21 -21
  103. data/test/logster/middleware/test_viewer.rb +96 -70
  104. data/test/logster/test_base_store.rb +147 -147
  105. data/test/logster/test_ignore_pattern.rb +41 -41
  106. data/test/logster/test_logger.rb +74 -74
  107. data/test/logster/test_message.rb +34 -34
  108. data/test/logster/test_redis_rate_limiter.rb +230 -230
  109. data/test/logster/test_redis_store.rb +427 -414
  110. data/test/test_helper.rb +38 -37
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +83 -24
  113. data/assets/javascript/app.js +0 -817
  114. data/assets/javascript/components/message-info.hbs +0 -47
  115. data/assets/javascript/components/panel-resizer.hbs +0 -0
  116. data/assets/javascript/components/tab-contents.hbs +0 -1
  117. data/assets/javascript/components/tab-link.hbs +0 -1
  118. data/assets/javascript/components/tabbed-section.hbs +0 -6
  119. data/assets/javascript/external/ember-template-compiler.js +0 -22346
  120. data/assets/javascript/external/ember.js +0 -58500
  121. data/assets/javascript/external/ember.min.js +0 -17
  122. data/assets/javascript/external/jquery.min.js +0 -5
  123. data/assets/javascript/external/lodash.min.js +0 -87
  124. data/assets/javascript/external/moment.min.js +0 -6
  125. data/assets/stylesheets/font-awesome.min.css +0 -4
  126. data/bower.json +0 -25
@@ -1,26 +1,26 @@
1
- class Logster::Middleware::DebugExceptions < ActionDispatch::DebugExceptions
2
- private
3
-
4
- def log_error(request_or_env, wrapper)
5
- env =
6
- if Rails::VERSION::MAJOR > 4
7
- request_or_env.env
8
- else
9
- request_or_env
10
- end
11
-
12
- exception = wrapper.exception
13
-
14
- Logster.config.current_context.call(env) do
15
- location = exception.backtrace[0]
16
- exception_string = exception.to_s
17
-
18
- Logster.logger.add_with_opts(::Logger::Severity::FATAL,
19
- exception.class.to_s << " (" << exception_string << ")\n#{location}",
20
- "web-exception",
21
- backtrace: exception.backtrace.join("\n"),
22
- env: env)
23
- end
24
-
25
- end
26
- end
1
+ class Logster::Middleware::DebugExceptions < ActionDispatch::DebugExceptions
2
+ private
3
+
4
+ def log_error(request_or_env, wrapper)
5
+ env =
6
+ if Rails::VERSION::MAJOR > 4
7
+ request_or_env.env
8
+ else
9
+ request_or_env
10
+ end
11
+
12
+ exception = wrapper.exception
13
+
14
+ Logster.config.current_context.call(env) do
15
+ location = exception.backtrace[0]
16
+ exception_string = exception.to_s
17
+
18
+ Logster.logger.add_with_opts(::Logger::Severity::FATAL,
19
+ exception.class.to_s << " (" << exception_string << ")\n#{location}",
20
+ "web-exception",
21
+ backtrace: exception.backtrace.join("\n"),
22
+ env: env)
23
+ end
24
+
25
+ end
26
+ end
@@ -1,54 +1,56 @@
1
- module Logster
2
- module Middleware
3
- class Reporter
4
-
5
- PATH_INFO = "PATH_INFO".freeze
6
- SCRIPT_NAME = "SCRIPT_NAME".freeze
7
-
8
- def initialize(app, config={})
9
- @app = app
10
- @error_path = Logster.config.subdirectory + '/report_js_error'
11
- end
12
-
13
- def call(env)
14
- Thread.current[Logster::Logger::LOGSTER_ENV] = env
15
-
16
-
17
- path = env[PATH_INFO]
18
- script_name = env[SCRIPT_NAME]
19
-
20
- if script_name && script_name.length > 0
21
- path = script_name + path
22
- end
23
-
24
- if path == @error_path
25
- Logster.config.current_context.call(env) do
26
- report_js_error(env)
27
- end
28
- return [200,{},["OK"]]
29
- end
30
-
31
- @app.call(env)
32
- ensure
33
- Thread.current[Logster::Logger::LOGSTER_ENV] = nil
34
- end
35
-
36
- def report_js_error(env)
37
- req = Rack::Request.new(env)
38
- message = req["message"] || ""
39
- message << "\nUrl: " << req["url"] if req["url"]
40
- message << "\nLine: " << req["line"] if req["line"]
41
- message << "\nColumn: " << req["column"] if req["column"]
42
- message << "\nWindow Location: " << req["window_location"] if req["window_location"]
43
-
44
- backtrace = req["stacktrace"] || ""
45
- Logster.store.report(::Logger::Severity::WARN,
46
- "javascript",
47
- message,
48
- backtrace: backtrace,
49
- env: env)
50
- end
51
-
52
- end
53
- end
54
- end
1
+ module Logster
2
+ module Middleware
3
+ class Reporter
4
+
5
+ PATH_INFO = "PATH_INFO".freeze
6
+ SCRIPT_NAME = "SCRIPT_NAME".freeze
7
+
8
+ def initialize(app, config={})
9
+ @app = app
10
+ @error_path = Logster.config.subdirectory + '/report_js_error'
11
+ end
12
+
13
+ def call(env)
14
+ Thread.current[Logster::Logger::LOGSTER_ENV] = env
15
+
16
+
17
+ path = env[PATH_INFO]
18
+ script_name = env[SCRIPT_NAME]
19
+
20
+ if script_name && script_name.length > 0
21
+ path = script_name + path
22
+ end
23
+
24
+ if path == @error_path
25
+ Logster.config.current_context.call(env) do
26
+ report_js_error(env)
27
+ end
28
+ return [200,{},["OK"]]
29
+ end
30
+
31
+ @app.call(env)
32
+ ensure
33
+ Thread.current[Logster::Logger::LOGSTER_ENV] = nil
34
+ end
35
+
36
+ def report_js_error(env)
37
+ req = Rack::Request.new(env)
38
+ params = req.params
39
+
40
+ message = params["message"] || ""
41
+ message << "\nUrl: " << params["url"] if params["url"]
42
+ message << "\nLine: " << params["line"] if params["line"]
43
+ message << "\nColumn: " << params["column"] if params["column"]
44
+ message << "\nWindow Location: " << params["window_location"] if params["window_location"]
45
+
46
+ backtrace = params["stacktrace"] || ""
47
+ Logster.store.report(::Logger::Severity::WARN,
48
+ "javascript",
49
+ message,
50
+ backtrace: backtrace,
51
+ env: env)
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -1,251 +1,220 @@
1
- require 'json'
2
-
3
- module Logster
4
- module Middleware
5
- class Viewer
6
-
7
- PATH_INFO = "PATH_INFO".freeze
8
- SCRIPT_NAME = "SCRIPT_NAME".freeze
9
- REQUEST_METHOD = "REQUEST_METHOD".freeze
10
-
11
- def initialize(app)
12
- @app = app
13
-
14
- @logs_path = Logster.config.subdirectory
15
- @path_regex = Regexp.new("^(#{@logs_path}$)|^(#{@logs_path}(/.*))$")
16
- @store = Logster.store or raise ArgumentError.new("store")
17
-
18
- @assets_path = File.expand_path("../../../../assets", __FILE__)
19
- @fileserver = Rack::File.new(@assets_path)
20
- end
21
-
22
- def call(env)
23
- path = env[PATH_INFO]
24
- script_name = env[SCRIPT_NAME]
25
-
26
- if script_name && script_name.length > 0
27
- path = script_name + path
28
- end
29
-
30
- if resource = resolve_path(path)
31
-
32
- if resource =~ /\.ico$|\.js$|\.png|\.handlebars$|\.css$|\.woff$|\.ttf$|\.woff2$|\.svg$|\.otf$|\.eot$/
33
- env[PATH_INFO] = resource
34
- # accl redirect is going to be trouble, ensure its bypassed
35
- env['sendfile.type'] = ''
36
- @fileserver.call(env)
37
-
38
- elsif resource.start_with?("/messages.json")
39
- serve_messages(Rack::Request.new(env))
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
-
55
- elsif resource =~ /\/(un)?protect\/([0-9a-f]+)$/
56
- off = $1 == "un"
57
- key = $2
58
-
59
- message = Logster.store.get(key)
60
- unless message
61
- return [404, {}, ["Message not found"]]
62
- end
63
-
64
- if off
65
- if Logster.store.unprotect(key)
66
- return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=false"}, []]
67
- else
68
- return [500, {}, ["Failed"]]
69
- end
70
- else
71
- if Logster.store.protect(key)
72
- return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=true"}, []]
73
- else
74
- return [500, {}, ["Failed"]]
75
- end
76
- end
77
-
78
- elsif resource =~ /\/solve\/([0-9a-f]+)$/
79
- key = $1
80
-
81
- message = Logster.store.get(key)
82
- unless message
83
- return [404, {}, ["Message not found"]]
84
- end
85
-
86
- Logster.store.solve(key)
87
-
88
- return [301, {"Location" => "#{@logs_path}"}, []]
89
-
90
- elsif resource =~ /\/clear$/
91
- if env[REQUEST_METHOD] != "POST"
92
- return [405, {}, ["GET not allowed for /clear"]]
93
- end
94
- Logster.store.clear
95
- return [200, {}, ["Messages cleared"]]
96
-
97
- elsif resource =~ /\/show\/([0-9a-f]+)(\.json)?$/
98
- key = $1
99
- json = $2 == ".json"
100
-
101
- message = Logster.store.get(key)
102
- unless message
103
- return [404, {}, ["Message not found"]]
104
- end
105
-
106
- if json
107
- [200, {"Content-Type" => "application/json; charset=utf-8"}, [message.to_json]]
108
- else
109
- preload = preload_json({"/show/#{key}.json" => message})
110
- [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload)]]
111
- end
112
-
113
- elsif resource == "/"
114
- [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload_json)]]
115
-
116
- else
117
- [404, {}, ["Not found"]]
118
- end
119
- else
120
- @app.call(env)
121
- end
122
- end
123
-
124
- protected
125
-
126
- def serve_messages(req)
127
- opts = {
128
- before: req["before"],
129
- after: req["after"]
130
- }
131
-
132
- if(filter = req["filter"])
133
- filter = filter.split("_").map{|s| s.to_i}
134
- opts[:severity] = filter
135
- end
136
-
137
- if search = req["search"]
138
- search = (parse_regex(search) || search) if req["regex_search"] == "true"
139
- opts[:search] = search
140
- end
141
-
142
- payload = {
143
- messages: @store.latest(opts),
144
- total: @store.count,
145
- search: req['search'] || '',
146
- filter: filter || '',
147
- }
148
-
149
- json = JSON.generate(payload)
150
- [200, {"Content-Type" => "application/json"}, [json]]
151
- end
152
-
153
- def parse_regex(string)
154
- if string =~ /\/(.+)\/(.*)/
155
- s = $1
156
- flags = Regexp::IGNORECASE if $2 && $2.include?("i")
157
- Regexp.new(s, flags) rescue nil
158
- end
159
- end
160
-
161
- def resolve_path(path)
162
- if path =~ @path_regex
163
- $3 || "/"
164
- end
165
- end
166
-
167
- def preload_json(extra={})
168
- values = {}
169
- values.merge!(extra)
170
- end
171
-
172
- def css(name, attrs={})
173
- attrs = attrs.map do |k,v|
174
- "#{k}='#{v}'"
175
- end.join(" ")
176
-
177
- "<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
178
- end
179
-
180
- def script(prod, dev=nil)
181
- name = ENV['DEBUG_JS'] == "1" && dev ? dev : prod
182
- "<script src='#{@logs_path}/javascript/#{name}'></script>"
183
- end
184
-
185
- def component(name)
186
- ember_template("components/#{name}", "components/" << name)
187
- end
188
-
189
- def template(name)
190
- ember_template("templates/#{name}", name)
191
- end
192
-
193
- def ember_template(location, name)
194
- val = File.read("#{@assets_path}/javascript/#{location}.hbs")
195
- <<JS
196
- <script>
197
- Ember.TEMPLATES[#{name.inspect}] = Ember.Handlebars.compile(#{val.inspect});
198
- </script>
199
- JS
200
- end
201
-
202
- def body(preload)
203
- <<HTML
204
- <!doctype html>
205
- <html>
206
- <head>
207
- <link rel="shortcut icon" href="#{@logs_path}/images/icon_64x64.png">
208
- <link rel="apple-touch-icon" href="#{@logs_path}/images/icon_144x144.png" />
209
- <title>#{Logster.config.web_title || "Logs"}</title>
210
- <link href='//fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
211
- <link href='//fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
212
- #{css("app.css")}
213
- #{css("font-awesome.min.css")}
214
- #{script("external/moment.min.js")}
215
- #{script("external/jquery.min.js")}
216
- #{script("external/lodash.min.js")}
217
- #{script("external/ember-template-compiler.js")}
218
- #{script("external/ember.min.js", "external/ember.js")}
219
- #{template("application")}
220
- #{component("message-row")}
221
- #{component("message-info")}
222
- #{component("tabbed-section")}
223
- #{component("tab-contents")}
224
- #{component("tab-link")}
225
- #{component("panel-resizer")}
226
- #{template("index")}
227
- #{template("show")}
228
- <script>
229
- window.Logger = {
230
- rootPath: "#{@logs_path}",
231
- preload: #{JSON.fast_generate(preload).gsub("</", "<\\/")}
232
- };
233
- </script>
234
- </head>
235
- <body>
236
- #{script("app.js")}
237
- <script>
238
- App.Router.reopen({
239
- rootURL: Logger.rootPath,
240
- location: 'history'
241
- });
242
- </script>
243
- </body>
244
- </html>
245
- HTML
246
- end
247
-
248
- end
249
- end
250
-
251
- end
1
+ require 'json'
2
+
3
+ module Logster
4
+ module Middleware
5
+ class Viewer
6
+
7
+ PATH_INFO = "PATH_INFO".freeze
8
+ SCRIPT_NAME = "SCRIPT_NAME".freeze
9
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
10
+
11
+ def initialize(app)
12
+ @app = app
13
+
14
+ @logs_path = Logster.config.subdirectory
15
+ @path_regex = Regexp.new("^(#{@logs_path}$)|^(#{@logs_path}(/.*))$")
16
+ @store = Logster.store or raise ArgumentError.new("store")
17
+
18
+ @assets_path = File.expand_path("../../../../assets", __FILE__)
19
+ @fileserver = Rack::File.new(@assets_path)
20
+ end
21
+
22
+ def call(env)
23
+ path = env[PATH_INFO]
24
+ script_name = env[SCRIPT_NAME]
25
+
26
+ if script_name && script_name.length > 0
27
+ path = script_name + path
28
+ end
29
+
30
+ if resource = resolve_path(path)
31
+ if resource =~ /\.ico$|\.js$|\.png|\.handlebars$|\.css$|\.woff$|\.ttf$|\.woff2$|\.svg$|\.otf$|\.eot$/
32
+ serve_file(env, resource)
33
+
34
+ elsif resource.start_with?("/messages.json")
35
+ serve_messages(Rack::Request.new(env))
36
+
37
+ elsif resource =~ /\/message\/([0-9a-f]+)$/
38
+ if env[REQUEST_METHOD] != "DELETE"
39
+ return [405, {}, ["GET not allowed for /clear"]]
40
+ end
41
+
42
+ key = $1
43
+ message = Logster.store.get(key)
44
+ unless message
45
+ return [404, {}, ["Message not found"]]
46
+ end
47
+
48
+ Logster.store.delete(message)
49
+ return [301, {"Location" => "#{@logs_path}/"}, []]
50
+
51
+ elsif resource =~ /\/(un)?protect\/([0-9a-f]+)$/
52
+ off = $1 == "un"
53
+ key = $2
54
+
55
+ message = Logster.store.get(key)
56
+ unless message
57
+ return [404, {}, ["Message not found"]]
58
+ end
59
+
60
+ if off
61
+ if Logster.store.unprotect(key)
62
+ return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=false"}, []]
63
+ else
64
+ return [500, {}, ["Failed"]]
65
+ end
66
+ else
67
+ if Logster.store.protect(key)
68
+ return [301, {"Location" => "#{@logs_path}/show/#{key}?protected=true"}, []]
69
+ else
70
+ return [500, {}, ["Failed"]]
71
+ end
72
+ end
73
+
74
+ elsif resource =~ /\/solve\/([0-9a-f]+)$/
75
+ key = $1
76
+
77
+ message = Logster.store.get(key)
78
+ unless message
79
+ return [404, {}, ["Message not found"]]
80
+ end
81
+
82
+ Logster.store.solve(key)
83
+
84
+ return [301, {"Location" => "#{@logs_path}"}, []]
85
+
86
+ elsif resource =~ /\/clear$/
87
+ if env[REQUEST_METHOD] != "POST"
88
+ return [405, {}, ["GET not allowed for /clear"]]
89
+ end
90
+ Logster.store.clear
91
+ return [200, {}, ["Messages cleared"]]
92
+
93
+ elsif resource =~ /\/show\/([0-9a-f]+)(\.json)?$/
94
+ key = $1
95
+ json = $2 == ".json"
96
+
97
+ message = Logster.store.get(key)
98
+ unless message
99
+ return [404, {}, ["Message not found"]]
100
+ end
101
+
102
+ if json
103
+ [200, {"Content-Type" => "application/json; charset=utf-8"}, [message.to_json]]
104
+ else
105
+ preload = preload_json({"/show/#{key}" => message})
106
+ [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload)]]
107
+ end
108
+
109
+ elsif resource == "/"
110
+ [200, {"Content-Type" => "text/html; charset=utf-8"}, [body(preload_json)]]
111
+
112
+ else
113
+ [404, {}, ["Not found"]]
114
+ end
115
+ else
116
+ @app.call(env)
117
+ end
118
+ end
119
+
120
+ protected
121
+
122
+ def serve_file(env, path)
123
+ env[PATH_INFO] = path
124
+ # accl redirect is going to be trouble, ensure its bypassed
125
+ env['sendfile.type'] = ''
126
+ @fileserver.call(env)
127
+ end
128
+
129
+ def serve_messages(req)
130
+ params = req.params
131
+
132
+ opts = {
133
+ before: params["before"],
134
+ after: params["after"]
135
+ }
136
+
137
+ if(filter = params["filter"])
138
+ filter = filter.split("_").map{|s| s.to_i}
139
+ opts[:severity] = filter
140
+ end
141
+
142
+ if search = params["search"]
143
+ search = (parse_regex(search) || search) if params["regex_search"] == "true"
144
+ opts[:search] = search
145
+ end
146
+
147
+ payload = {
148
+ messages: @store.latest(opts),
149
+ total: @store.count,
150
+ search: params['search'] || '',
151
+ filter: filter || '',
152
+ }
153
+
154
+ json = JSON.generate(payload)
155
+ [200, {"Content-Type" => "application/json"}, [json]]
156
+ end
157
+
158
+ def parse_regex(string)
159
+ if string =~ /\/(.+)\/(.*)/
160
+ s = $1
161
+ flags = Regexp::IGNORECASE if $2 && $2.include?("i")
162
+ Regexp.new(s, flags) rescue nil
163
+ end
164
+ end
165
+
166
+ def resolve_path(path)
167
+ if path =~ @path_regex
168
+ $3 || "/"
169
+ end
170
+ end
171
+
172
+ def preload_json(extra={})
173
+ values = {}
174
+ values.merge!(extra)
175
+ end
176
+
177
+ def css(name, attrs={})
178
+ attrs = attrs.map do |k,v|
179
+ "#{k}='#{v}'"
180
+ end.join(" ")
181
+
182
+ "<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
183
+ end
184
+
185
+ def script(prod, dev=nil)
186
+ name = ENV['DEBUG_JS'] == "1" && dev ? dev : prod
187
+ "<script src='#{@logs_path}/javascript/#{name}'></script>"
188
+ end
189
+
190
+ def to_json_and_escape(payload)
191
+ Rack::Utils.escape_html(JSON.fast_generate(payload))
192
+ end
193
+
194
+ def body(preload)
195
+ root_url = @logs_path
196
+ root_url += "/" if root_url[-1] != "/"
197
+ <<~HTML
198
+ <!doctype html>
199
+ <html>
200
+ <head>
201
+ <link rel="shortcut icon" href="#{@logs_path}/images/icon_64x64.png">
202
+ <link rel="apple-touch-icon" href="#{@logs_path}/images/icon_144x144.png" />
203
+ <title>#{Logster.config.web_title || "Logs"}</title>
204
+ <link href='//fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
205
+ <link href='//fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
206
+ #{css("vendor.css")}
207
+ #{css("client-app.css")}
208
+ #{script("vendor.js")}
209
+ <meta id="preloaded-data" data-root-path="#{@logs_path}" data-preloaded="#{to_json_and_escape(preload)}">
210
+ <meta name="client-app/config/environment" content="%7B%22modulePrefix%22%3A%22client-app%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22#{root_url}%22%2C%22locationType%22%3A%22history%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%7D%2C%22APP%22%3A%7B%22name%22%3A%22client-app%22%2C%22version%22%3A%220.0.0+8c60a18b%22%7D%2C%22exportApplicationGlobal%22%3Afalse%7D" />
211
+ </head>
212
+ <body>
213
+ #{script("client-app.js")}
214
+ </body>
215
+ </html>
216
+ HTML
217
+ end
218
+ end
219
+ end
220
+ end