logster 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +21 -19
  3. data/.rubocop.yml +1 -1
  4. data/.travis.yml +16 -16
  5. data/CHANGELOG.md +224 -172
  6. data/Gemfile +4 -4
  7. data/Guardfile +8 -8
  8. data/LICENSE.txt +22 -22
  9. data/README.md +99 -99
  10. data/Rakefile +21 -21
  11. data/assets/fonts/FontAwesome.otf +0 -0
  12. data/assets/fonts/fontawesome-webfont.eot +0 -0
  13. data/assets/fonts/fontawesome-webfont.svg +639 -639
  14. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  15. data/assets/fonts/fontawesome-webfont.woff +0 -0
  16. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  17. data/assets/images/Icon-144_rounded.png +0 -0
  18. data/assets/images/Icon-144_square.png +0 -0
  19. data/assets/images/icon_144x144.png +0 -0
  20. data/assets/images/icon_64x64.png +0 -0
  21. data/assets/javascript/client-app.js +115 -106
  22. data/assets/stylesheets/client-app.css +1 -1
  23. data/build_client_app.sh +0 -0
  24. data/client-app/.editorconfig +20 -20
  25. data/client-app/.ember-cli +9 -9
  26. data/client-app/.eslintignore +19 -19
  27. data/client-app/.eslintrc.js +46 -46
  28. data/client-app/.gitignore +23 -23
  29. data/client-app/.travis.yml +27 -27
  30. data/client-app/.watchmanconfig +3 -3
  31. data/client-app/README.md +57 -57
  32. data/client-app/app/app.js +0 -0
  33. data/client-app/app/components/actions-menu.js +43 -43
  34. data/client-app/app/components/env-tab.js +80 -80
  35. data/client-app/app/components/message-info.js +0 -0
  36. data/client-app/app/components/message-row.js +0 -0
  37. data/client-app/app/components/panel-resizer.js +0 -0
  38. data/client-app/app/components/patterns-list.js +109 -0
  39. data/client-app/app/components/tab-contents.js +27 -27
  40. data/client-app/app/components/tabbed-section.js +0 -0
  41. data/client-app/app/components/time-formatter.js +0 -0
  42. data/client-app/app/components/update-time.js +0 -0
  43. data/client-app/app/controllers/index.js +22 -6
  44. data/client-app/app/controllers/show.js +0 -0
  45. data/client-app/app/helpers/logster-url.js +12 -0
  46. data/client-app/app/helpers/or.js +7 -0
  47. data/client-app/app/index.html +30 -29
  48. data/client-app/app/initializers/app-init.js +67 -67
  49. data/client-app/app/lib/preload.js +20 -20
  50. data/client-app/app/lib/utilities.js +150 -149
  51. data/client-app/app/models/message-collection.js +0 -0
  52. data/client-app/app/models/message.js +100 -100
  53. data/client-app/app/models/pattern-item.js +25 -0
  54. data/client-app/app/resolver.js +0 -0
  55. data/client-app/app/router.js +1 -0
  56. data/client-app/app/routes/index.js +2 -9
  57. data/client-app/app/routes/settings.js +15 -0
  58. data/client-app/app/routes/show.js +0 -0
  59. data/client-app/app/styles/app.css +633 -527
  60. data/client-app/app/templates/application.hbs +2 -2
  61. data/client-app/app/templates/components/actions-menu.hbs +12 -12
  62. data/client-app/app/templates/components/env-tab.hbs +10 -10
  63. data/client-app/app/templates/components/message-info.hbs +41 -41
  64. data/client-app/app/templates/components/message-row.hbs +15 -15
  65. data/client-app/app/templates/components/panel-resizer.hbs +3 -3
  66. data/client-app/app/templates/components/patterns-list.hbs +25 -0
  67. data/client-app/app/templates/components/tabbed-section.hbs +10 -10
  68. data/client-app/app/templates/components/time-formatter.hbs +1 -1
  69. data/client-app/app/templates/index.hbs +65 -58
  70. data/client-app/app/templates/settings.hbs +26 -0
  71. data/client-app/app/templates/show.hbs +7 -7
  72. data/client-app/config/environment.js +51 -51
  73. data/client-app/config/optional-features.json +3 -3
  74. data/client-app/config/targets.js +18 -18
  75. data/client-app/ember-cli-build.js +29 -29
  76. data/client-app/package-lock.json +11357 -11365
  77. data/client-app/package.json +57 -56
  78. data/client-app/public/assets/images/icon_144x144.png +0 -0
  79. data/client-app/public/assets/images/icon_64x64.png +0 -0
  80. data/client-app/testem.js +25 -25
  81. data/client-app/tests/index.html +34 -34
  82. data/client-app/tests/integration/components/env-tab-test.js +134 -123
  83. data/client-app/tests/integration/components/message-info-test.js +111 -111
  84. data/client-app/tests/integration/components/patterns-list-test.js +56 -0
  85. data/client-app/tests/test-helper.js +8 -8
  86. data/client-app/tests/unit/controllers/index-test.js +12 -12
  87. data/client-app/tests/unit/controllers/show-test.js +12 -12
  88. data/client-app/tests/unit/initializers/app-init-test.js +31 -31
  89. data/client-app/tests/unit/routes/index-test.js +11 -11
  90. data/client-app/tests/unit/routes/show-test.js +11 -11
  91. data/lib/examples/sidekiq_logster_reporter.rb +21 -21
  92. data/lib/logster.rb +59 -54
  93. data/lib/logster/base_store.rb +169 -141
  94. data/lib/logster/cache.rb +20 -0
  95. data/lib/logster/configuration.rb +27 -26
  96. data/lib/logster/defer_logger.rb +14 -14
  97. data/lib/logster/ignore_pattern.rb +65 -65
  98. data/lib/logster/logger.rb +113 -113
  99. data/lib/logster/message.rb +212 -212
  100. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  101. data/lib/logster/middleware/reporter.rb +55 -55
  102. data/lib/logster/middleware/viewer.rb +297 -222
  103. data/lib/logster/pattern.rb +95 -0
  104. data/lib/logster/rails/railtie.rb +63 -63
  105. data/lib/logster/redis_store.rb +584 -566
  106. data/lib/logster/scheduler.rb +54 -54
  107. data/lib/logster/suppression_pattern.rb +17 -0
  108. data/lib/logster/version.rb +3 -3
  109. data/lib/logster/web.rb +14 -14
  110. data/logster.gemspec +35 -35
  111. data/test/examples/test_sidekiq_reporter_example.rb +46 -46
  112. data/test/fake_data/Gemfile +4 -4
  113. data/test/fake_data/generate.rb +10 -10
  114. data/test/logster/middleware/test_reporter.rb +19 -19
  115. data/test/logster/middleware/test_viewer.rb +267 -96
  116. data/test/logster/test_base_store.rb +147 -147
  117. data/test/logster/test_cache.rb +38 -0
  118. data/test/logster/test_defer_logger.rb +34 -34
  119. data/test/logster/test_ignore_pattern.rb +41 -41
  120. data/test/logster/test_logger.rb +100 -86
  121. data/test/logster/test_message.rb +119 -119
  122. data/test/logster/test_pattern.rb +152 -0
  123. data/test/logster/test_redis_rate_limiter.rb +230 -230
  124. data/test/logster/test_redis_store.rb +689 -720
  125. data/test/test_helper.rb +38 -38
  126. data/vendor/assets/javascripts/logster.js.erb +39 -39
  127. metadata +24 -7
@@ -1,55 +1,55 @@
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
- path = env[PATH_INFO]
17
- script_name = env[SCRIPT_NAME]
18
-
19
- if script_name && script_name.length > 0
20
- path = script_name + path
21
- end
22
-
23
- if path == @error_path
24
- Logster.config.current_context.call(env) do
25
- report_js_error(env)
26
- end
27
- return [200, {}, ["OK"]]
28
- end
29
-
30
- @app.call(env)
31
- ensure
32
- Thread.current[Logster::Logger::LOGSTER_ENV] = nil
33
- end
34
-
35
- def report_js_error(env)
36
- req = Rack::Request.new(env)
37
- params = req.params
38
-
39
- message = params["message"] || ""
40
- message << "\nUrl: " << params["url"] if params["url"]
41
- message << "\nLine: " << params["line"] if params["line"]
42
- message << "\nColumn: " << params["column"] if params["column"]
43
- message << "\nWindow Location: " << params["window_location"] if params["window_location"]
44
-
45
- backtrace = params["stacktrace"] || ""
46
- Logster.store.report(::Logger::Severity::WARN,
47
- "javascript",
48
- message,
49
- backtrace: backtrace,
50
- env: env)
51
- end
52
-
53
- end
54
- end
55
- 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
+ path = env[PATH_INFO]
17
+ script_name = env[SCRIPT_NAME]
18
+
19
+ if script_name && script_name.length > 0
20
+ path = script_name + path
21
+ end
22
+
23
+ if path == @error_path
24
+ Logster.config.current_context.call(env) do
25
+ report_js_error(env)
26
+ end
27
+ return [200, {}, ["OK"]]
28
+ end
29
+
30
+ @app.call(env)
31
+ ensure
32
+ Thread.current[Logster::Logger::LOGSTER_ENV] = nil
33
+ end
34
+
35
+ def report_js_error(env)
36
+ req = Rack::Request.new(env)
37
+ params = req.params
38
+
39
+ message = params["message"] || ""
40
+ message << "\nUrl: " << params["url"] if params["url"]
41
+ message << "\nLine: " << params["line"] if params["line"]
42
+ message << "\nColumn: " << params["column"] if params["column"]
43
+ message << "\nWindow Location: " << params["window_location"] if params["window_location"]
44
+
45
+ backtrace = params["stacktrace"] || ""
46
+ Logster.store.report(::Logger::Severity::WARN,
47
+ "javascript",
48
+ message,
49
+ backtrace: backtrace,
50
+ env: env)
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -1,222 +1,297 @@
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) || 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
- preload.merge!(env_expandable_keys: Logster.config.env_expandable_keys)
198
- <<~HTML
199
- <!doctype html>
200
- <html>
201
- <head>
202
- <link rel="shortcut icon" href="#{@logs_path}/images/icon_64x64.png">
203
- <link rel="apple-touch-icon" href="#{@logs_path}/images/icon_144x144.png" />
204
- <title>#{Logster.config.web_title || "Logs"}</title>
205
- <link href='//fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
206
- <link href='//fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
207
- <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes">
208
- #{css("vendor.css")}
209
- #{css("client-app.css")}
210
- #{script("vendor.js")}
211
- <meta id="preloaded-data" data-root-path="#{@logs_path}" data-preloaded="#{to_json_and_escape(preload)}">
212
- <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" />
213
- </head>
214
- <body>
215
- #{script("client-app.js")}
216
- </body>
217
- </html>
218
- HTML
219
- end
220
- end
221
- end
222
- 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) || 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 method_not_allowed("DELETE is needed 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 method_not_allowed("POST is needed 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 =~ /\/settings(\.json)?$/
110
+ json = $1 == ".json"
111
+ if json
112
+ coded_patterns = Logster.store.ignore&.map(&:inspect) || []
113
+ custom_patterns = Logster::SuppressionPattern.find_all(raw: true)
114
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.generate(coded_patterns: coded_patterns, custom_patterns: custom_patterns)]]
115
+ else
116
+ [200, { "Content-Type" => "text/html; charset=utf-8" }, [body(preload_json)]]
117
+ end
118
+ elsif resource =~ /\/patterns\/([a-zA-Z0-9_]+)\.json$/
119
+ unless Logster.config.enable_custom_patterns_via_ui
120
+ return not_allowed("Custom patterns via the UI is disabled. You can enable it by committing this line to your app source code:\nLogster.config.enable_custom_patterns_via_ui = true")
121
+ end
122
+
123
+ set_name = $1
124
+ req = Rack::Request.new(env)
125
+ return method_not_allowed if req.request_method == "GET"
126
+
127
+ update_patterns(set_name, req)
128
+ elsif resource == "/"
129
+ [200, { "Content-Type" => "text/html; charset=utf-8" }, [body(preload_json)]]
130
+ else
131
+ not_found
132
+ end
133
+ else
134
+ @app.call(env)
135
+ end
136
+ end
137
+
138
+ protected
139
+
140
+ def serve_file(env, path)
141
+ env[PATH_INFO] = path
142
+ # accl redirect is going to be trouble, ensure its bypassed
143
+ env['sendfile.type'] = ''
144
+ @fileserver.call(env)
145
+ end
146
+
147
+ def serve_messages(req)
148
+ params = req.params
149
+
150
+ opts = {
151
+ before: params["before"],
152
+ after: params["after"]
153
+ }
154
+
155
+ if (filter = params["filter"])
156
+ filter = filter.split("_").map { |s| s.to_i }
157
+ opts[:severity] = filter
158
+ end
159
+
160
+ if search = params["search"]
161
+ search = (parse_regex(search) || search) if params["regex_search"] == "true"
162
+ opts[:search] = search
163
+ end
164
+
165
+ payload = {
166
+ messages: @store.latest(opts),
167
+ total: @store.count,
168
+ search: params['search'] || '',
169
+ filter: filter || '',
170
+ }
171
+
172
+ json = JSON.generate(payload)
173
+ [200, { "Content-Type" => "application/json" }, [json]]
174
+ end
175
+
176
+ def update_patterns(set_name, req)
177
+ klass = get_class(set_name)
178
+ return not_found("Unknown set name") unless klass
179
+
180
+ request_method = req.request_method
181
+ pattern = req.params["pattern"]
182
+
183
+ record = request_method == "POST" ? klass.new(pattern) : klass.find(pattern)
184
+ return not_found unless record
185
+
186
+ case request_method
187
+ when "POST"
188
+ record.save
189
+ when "PUT"
190
+ record.modify(req.params["new_pattern"])
191
+ when "DELETE"
192
+ record.destroy
193
+ else
194
+ return method_not_allowed("Allowed methods: POST, PUT or DELETE")
195
+ end
196
+
197
+ [200, { "Content-Type" => "application/json" }, [JSON.generate(pattern: record.to_s)]]
198
+ rescue => err
199
+ error_message = err.message
200
+
201
+ unless Logster::Pattern::PatternError === err # likely a bug, give us the backtrace
202
+ error_message += "\n\n#{err.backtrace.join("\n")}"
203
+ return [500, {}, [error_message]]
204
+ end
205
+
206
+ [400, {}, [error_message]]
207
+ end
208
+
209
+ def get_class(set_name)
210
+ case set_name
211
+ when "suppression"
212
+ Logster::SuppressionPattern
213
+ else
214
+ nil
215
+ end
216
+ end
217
+
218
+ def not_found(message = "Not found")
219
+ [404, {}, [message]]
220
+ end
221
+
222
+ def not_allowed(message = "Not allowed")
223
+ [403, {}, [message]]
224
+ end
225
+
226
+ def method_not_allowed(message = "Method not allowed")
227
+ [405, {}, [message]]
228
+ end
229
+
230
+ def parse_regex(string)
231
+ if string =~ /\/(.+)\/(.*)/
232
+ s = $1
233
+ flags = Regexp::IGNORECASE if $2 && $2.include?("i")
234
+ Regexp.new(s, flags) rescue nil
235
+ end
236
+ end
237
+
238
+ def resolve_path(path)
239
+ if path =~ @path_regex
240
+ $3 || "/"
241
+ end
242
+ end
243
+
244
+ def preload_json(extra = {})
245
+ values = {}
246
+ values.merge!(extra)
247
+ end
248
+
249
+ def css(name, attrs = {})
250
+ attrs = attrs.map do |k, v|
251
+ "#{k}='#{v}'"
252
+ end.join(" ")
253
+
254
+ "<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
255
+ end
256
+
257
+ def script(prod, dev = nil)
258
+ name = ENV['DEBUG_JS'] == "1" && dev ? dev : prod
259
+ "<script src='#{@logs_path}/javascript/#{name}'></script>"
260
+ end
261
+
262
+ def to_json_and_escape(payload)
263
+ Rack::Utils.escape_html(JSON.fast_generate(payload))
264
+ end
265
+
266
+ def body(preload)
267
+ root_url = @logs_path
268
+ root_url += "/" if root_url[-1] != "/"
269
+ preload.merge!(
270
+ env_expandable_keys: Logster.config.env_expandable_keys,
271
+ patterns_enabled: Logster.config.enable_custom_patterns_via_ui
272
+ )
273
+ <<~HTML
274
+ <!doctype html>
275
+ <html>
276
+ <head>
277
+ <link rel="shortcut icon" href="#{@logs_path}/images/icon_64x64.png">
278
+ <link rel="apple-touch-icon" href="#{@logs_path}/images/icon_144x144.png" />
279
+ <title>#{Logster.config.web_title || "Logs"}</title>
280
+ <link href='//fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
281
+ <link href='//fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
282
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes">
283
+ #{css("vendor.css")}
284
+ #{css("client-app.css")}
285
+ #{script("vendor.js")}
286
+ <meta id="preloaded-data" data-root-path="#{@logs_path}" data-preloaded="#{to_json_and_escape(preload)}">
287
+ <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" />
288
+ </head>
289
+ <body>
290
+ #{script("client-app.js")}
291
+ </body>
292
+ </html>
293
+ HTML
294
+ end
295
+ end
296
+ end
297
+ end