logster 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -18
  3. data/.travis.yml +15 -15
  4. data/CHANGELOG.md +137 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -99
  9. data/Rakefile +24 -24
  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 -81
  21. data/assets/javascript/vendor.js +5302 -5302
  22. data/assets/stylesheets/client-app.css +0 -0
  23. data/assets/stylesheets/vendor.css +3 -3
  24. data/build_client_app.sh +12 -12
  25. data/client-app/.editorconfig +20 -20
  26. data/client-app/.ember-cli +9 -9
  27. data/client-app/.eslintignore +19 -19
  28. data/client-app/.eslintrc.js +46 -46
  29. data/client-app/.gitignore +23 -23
  30. data/client-app/.travis.yml +27 -27
  31. data/client-app/.watchmanconfig +3 -3
  32. data/client-app/README.md +57 -57
  33. data/client-app/app/app.js +14 -14
  34. data/client-app/app/components/message-info.js +18 -18
  35. data/client-app/app/components/message-row.js +45 -45
  36. data/client-app/app/components/panel-resizer.js +75 -75
  37. data/client-app/app/components/tab-contents.js +27 -27
  38. data/client-app/app/components/tab-link.js +5 -5
  39. data/client-app/app/components/tabbed-section.js +32 -32
  40. data/client-app/app/components/time-formatter.js +25 -25
  41. data/client-app/app/components/update-time.js +21 -21
  42. data/client-app/app/controllers/index.js +83 -83
  43. data/client-app/app/controllers/show.js +13 -13
  44. data/client-app/app/index.html +29 -29
  45. data/client-app/app/initializers/app-init.js +55 -55
  46. data/client-app/app/lib/preload.js +14 -14
  47. data/client-app/app/lib/utilities.js +140 -140
  48. data/client-app/app/models/message-collection.js +158 -158
  49. data/client-app/app/models/message.js +99 -99
  50. data/client-app/app/resolver.js +3 -3
  51. data/client-app/app/router.js +14 -14
  52. data/client-app/app/routes/index.js +53 -53
  53. data/client-app/app/routes/show.js +14 -14
  54. data/client-app/app/styles/app.css +387 -387
  55. data/client-app/app/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -44
  57. data/client-app/app/templates/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -10
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -1
  60. data/client-app/app/templates/index.hbs +57 -57
  61. data/client-app/app/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -51
  63. data/client-app/config/optional-features.json +3 -3
  64. data/client-app/config/targets.js +18 -18
  65. data/client-app/ember-cli-build.js +29 -29
  66. data/client-app/package-lock.json +11365 -11365
  67. data/client-app/package.json +56 -56
  68. data/client-app/testem.js +25 -25
  69. data/client-app/tests/index.html +34 -34
  70. data/client-app/tests/integration/components/message-info-test.js +26 -26
  71. data/client-app/tests/integration/components/message-row-test.js +26 -26
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -26
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -26
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -26
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -26
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -26
  77. data/client-app/tests/integration/components/update-time-test.js +26 -26
  78. data/client-app/tests/test-helper.js +8 -8
  79. data/client-app/tests/unit/controllers/index-test.js +12 -12
  80. data/client-app/tests/unit/controllers/show-test.js +12 -12
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -31
  82. data/client-app/tests/unit/routes/index-test.js +11 -11
  83. data/client-app/tests/unit/routes/show-test.js +11 -11
  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 +108 -102
  90. data/lib/logster/message.rb +227 -227
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -56
  93. data/lib/logster/middleware/viewer.rb +220 -220
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -481
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -34
  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 -96
  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 +80 -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 -427
  110. data/test/test_helper.rb +38 -38
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +3 -3
@@ -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,56 +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
- 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
+ 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,220 +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
- 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
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