logster 2.12.1 → 2.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -0
- data/.streerc +2 -0
- data/CHANGELOG.md +10 -1
- data/Gemfile +1 -1
- data/assets/javascript/{chunk.143.2faa04830259ce9aa59a.js → chunk.143.91d07e8cdd5c4b9e4731.js} +4 -4
- data/assets/javascript/{chunk.178.ca5ade1d8cbdbfbe6d72.js → chunk.178.16d0c9057345120bdba1.js} +3 -3
- data/assets/javascript/client-app.js +4 -2
- data/client-app/app/components/back-trace.js +4 -0
- data/client-app/package.json +1 -1
- data/client-app/preload-json-manager.rb +10 -17
- data/client-app/tests/integration/components/back-trace-test.js +17 -0
- data/client-app/yarn.lock +22 -22
- data/lib/examples/sidekiq_logster_reporter.rb +5 -7
- data/lib/logster/base_store.rb +26 -22
- data/lib/logster/cache.rb +2 -1
- data/lib/logster/configuration.rb +3 -3
- data/lib/logster/defer_logger.rb +2 -4
- data/lib/logster/group.rb +17 -20
- data/lib/logster/ignore_pattern.rb +1 -2
- data/lib/logster/logger.rb +18 -16
- data/lib/logster/message.rb +53 -57
- data/lib/logster/middleware/debug_exceptions.rb +12 -10
- data/lib/logster/middleware/reporter.rb +17 -26
- data/lib/logster/middleware/viewer.rb +77 -97
- data/lib/logster/pattern.rb +4 -7
- data/lib/logster/rails/railtie.rb +10 -13
- data/lib/logster/redis_rate_limiter.rb +2 -7
- data/lib/logster/redis_store.rb +79 -99
- data/lib/logster/scheduler.rb +1 -5
- data/lib/logster/suppression_pattern.rb +7 -5
- data/lib/logster/version.rb +1 -1
- data/lib/logster/web.rb +1 -1
- data/lib/logster.rb +15 -17
- data/logster.gemspec +14 -14
- data/test/examples/test_sidekiq_reporter_example.rb +8 -9
- data/test/fake_data/generate.rb +14 -3
- data/test/logster/middleware/test_reporter.rb +9 -7
- data/test/logster/middleware/test_viewer.rb +117 -101
- data/test/logster/test_base_store.rb +79 -58
- data/test/logster/test_cache.rb +5 -11
- data/test/logster/test_defer_logger.rb +3 -3
- data/test/logster/test_group.rb +14 -18
- data/test/logster/test_ignore_pattern.rb +2 -3
- data/test/logster/test_logger.rb +14 -14
- data/test/logster/test_message.rb +29 -31
- data/test/logster/test_pattern.rb +7 -15
- data/test/logster/test_redis_rate_limiter.rb +35 -21
- data/test/logster/test_redis_store.rb +239 -151
- data/test/test_helper.rb +9 -9
- metadata +19 -4
data/lib/logster/message.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "digest/sha1"
|
4
|
+
require "securerandom"
|
5
5
|
|
6
6
|
module Logster
|
7
7
|
class Message
|
8
8
|
LOGSTER_ENV = "_logster_env".freeze
|
9
|
-
ALLOWED_ENV = %w
|
9
|
+
ALLOWED_ENV = %w[
|
10
10
|
HTTP_HOST
|
11
11
|
REQUEST_URI
|
12
12
|
REQUEST_METHOD
|
@@ -19,9 +19,17 @@ module Logster
|
|
19
19
|
process_id
|
20
20
|
application_version
|
21
21
|
time
|
22
|
-
|
23
|
-
|
24
|
-
attr_accessor :timestamp,
|
22
|
+
]
|
23
|
+
|
24
|
+
attr_accessor :timestamp,
|
25
|
+
:severity,
|
26
|
+
:progname,
|
27
|
+
:key,
|
28
|
+
:backtrace,
|
29
|
+
:count,
|
30
|
+
:protected,
|
31
|
+
:first_timestamp,
|
32
|
+
:env_buffer
|
25
33
|
attr_reader :message, :env
|
26
34
|
|
27
35
|
def initialize(severity, progname, message, timestamp = nil, key = nil, count: 1)
|
@@ -46,7 +54,7 @@ module Logster
|
|
46
54
|
key: @key,
|
47
55
|
backtrace: @backtrace,
|
48
56
|
count: @count,
|
49
|
-
protected: @protected
|
57
|
+
protected: @protected,
|
50
58
|
}
|
51
59
|
|
52
60
|
h[:first_timestamp] = @first_timestamp if @first_timestamp
|
@@ -62,11 +70,14 @@ module Logster
|
|
62
70
|
|
63
71
|
def self.from_json(json)
|
64
72
|
parsed = ::JSON.parse(json)
|
65
|
-
msg =
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
73
|
+
msg =
|
74
|
+
new(
|
75
|
+
parsed["severity"],
|
76
|
+
parsed["progname"],
|
77
|
+
parsed["message"],
|
78
|
+
parsed["timestamp"],
|
79
|
+
parsed["key"],
|
80
|
+
)
|
70
81
|
msg.backtrace = parsed["backtrace"]
|
71
82
|
msg.env = parsed["env"]
|
72
83
|
msg.count = parsed["count"]
|
@@ -80,40 +91,39 @@ module Logster
|
|
80
91
|
end
|
81
92
|
|
82
93
|
def self.hostname
|
83
|
-
@hostname ||=
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
94
|
+
@hostname ||=
|
95
|
+
begin
|
96
|
+
command = Logster.config.use_full_hostname ? `hostname -f` : `hostname`
|
97
|
+
command.strip!
|
98
|
+
command
|
99
|
+
rescue StandardError
|
100
|
+
"<unknown>"
|
101
|
+
end
|
90
102
|
end
|
91
103
|
|
92
104
|
def populate_from_env(env)
|
93
105
|
env ||= {}
|
94
106
|
if Array === env
|
95
|
-
env =
|
96
|
-
|
97
|
-
|
98
|
-
single_env
|
107
|
+
env =
|
108
|
+
env.map do |single_env|
|
109
|
+
single_env = self.class.default_env.merge(single_env)
|
110
|
+
if !single_env.key?("time") && !single_env.key?(:time)
|
111
|
+
single_env["time"] = @timestamp || get_timestamp
|
112
|
+
end
|
113
|
+
single_env
|
99
114
|
end
|
100
|
-
single_env
|
101
|
-
end
|
102
115
|
else
|
103
116
|
env = self.class.default_env.merge(env)
|
104
|
-
if !env.key?("time") && !env.key?(:time)
|
105
|
-
env["time"] = @timestamp || get_timestamp
|
106
|
-
end
|
117
|
+
env["time"] = @timestamp || get_timestamp if !env.key?("time") && !env.key?(:time)
|
107
118
|
end
|
108
119
|
self.env = Message.populate_from_env(env)
|
109
120
|
end
|
110
121
|
|
111
122
|
def self.default_env
|
112
|
-
env = {
|
113
|
-
|
114
|
-
"
|
115
|
-
|
116
|
-
env["application_version"] = Logster.config.application_version if Logster.config.application_version
|
123
|
+
env = { "hostname" => hostname, "process_id" => Process.pid }
|
124
|
+
env[
|
125
|
+
"application_version"
|
126
|
+
] = Logster.config.application_version if Logster.config.application_version
|
117
127
|
env
|
118
128
|
end
|
119
129
|
|
@@ -138,9 +148,7 @@ module Logster
|
|
138
148
|
versions.compact!
|
139
149
|
|
140
150
|
if backtrace && backtrace.length > 0
|
141
|
-
versions.map
|
142
|
-
Digest::SHA1.hexdigest "#{version} #{backtrace}"
|
143
|
-
end
|
151
|
+
versions.map { |version| Digest::SHA1.hexdigest "#{version} #{backtrace}" }
|
144
152
|
end
|
145
153
|
end
|
146
154
|
|
@@ -167,9 +175,7 @@ module Logster
|
|
167
175
|
|
168
176
|
def self.populate_from_env(env)
|
169
177
|
if Array === env
|
170
|
-
env.map
|
171
|
-
self.populate_env_helper(single_env)
|
172
|
-
end
|
178
|
+
env.map { |single_env| self.populate_env_helper(single_env) }
|
173
179
|
else
|
174
180
|
self.populate_env_helper(env)
|
175
181
|
end
|
@@ -194,9 +200,7 @@ module Logster
|
|
194
200
|
end
|
195
201
|
end
|
196
202
|
scrubbed["params"] = params if params.length > 0
|
197
|
-
ALLOWED_ENV.map { |k|
|
198
|
-
scrubbed[k] = env[k] if env[k]
|
199
|
-
}
|
203
|
+
ALLOWED_ENV.map { |k| scrubbed[k] = env[k] if env[k] }
|
200
204
|
scrubbed
|
201
205
|
end
|
202
206
|
end
|
@@ -218,7 +222,7 @@ module Logster
|
|
218
222
|
IgnorePattern.new(pattern, nil).matches? self
|
219
223
|
when IgnorePattern
|
220
224
|
pattern.matches? self
|
221
|
-
|
225
|
+
else
|
222
226
|
nil
|
223
227
|
end
|
224
228
|
end
|
@@ -228,9 +232,7 @@ module Logster
|
|
228
232
|
params.map! { |p| scrub_params(p) }
|
229
233
|
params
|
230
234
|
elsif Hash === params
|
231
|
-
params.each
|
232
|
-
params[k] = scrub_params(v)
|
233
|
-
end
|
235
|
+
params.each { |k, v| params[k] = scrub_params(v) }
|
234
236
|
params
|
235
237
|
elsif String === params
|
236
238
|
scrubbed = params.scrub if !params.valid_encoding?
|
@@ -241,9 +243,7 @@ module Logster
|
|
241
243
|
end
|
242
244
|
|
243
245
|
def drop_redundant_envs(limit)
|
244
|
-
if Array === env
|
245
|
-
env.slice!(limit..-1)
|
246
|
-
end
|
246
|
+
env.slice!(limit..-1) if Array === env
|
247
247
|
end
|
248
248
|
|
249
249
|
def apply_env_size_limit(size_limit)
|
@@ -268,9 +268,7 @@ module Logster
|
|
268
268
|
|
269
269
|
def truncate_backtrace(bytes_limit)
|
270
270
|
@backtrace = @backtrace.byteslice(0...bytes_limit)
|
271
|
-
while !@backtrace[-1].valid_encoding? && @backtrace.size > 1
|
272
|
-
@backtrace.slice!(-1)
|
273
|
-
end
|
271
|
+
@backtrace.slice!(-1) while !@backtrace[-1].valid_encoding? && @backtrace.size > 1
|
274
272
|
end
|
275
273
|
|
276
274
|
protected
|
@@ -278,10 +276,8 @@ module Logster
|
|
278
276
|
def truncate_env(env, limit)
|
279
277
|
if JSON.fast_generate(env).bytesize > limit
|
280
278
|
sizes = {}
|
281
|
-
braces =
|
282
|
-
env.each
|
283
|
-
sizes[k] = JSON.fast_generate(k => v).bytesize - braces
|
284
|
-
end
|
279
|
+
braces = "{}".bytesize
|
280
|
+
env.each { |k, v| sizes[k] = JSON.fast_generate(k => v).bytesize - braces }
|
285
281
|
sorted = env.keys.sort { |a, b| sizes[a] <=> sizes[b] }
|
286
282
|
|
287
283
|
kept_keys = []
|
@@ -296,7 +292,7 @@ module Logster
|
|
296
292
|
sum += sizes[time_key]
|
297
293
|
sorted.delete(time_key)
|
298
294
|
end
|
299
|
-
comma =
|
295
|
+
comma = ",".bytesize
|
300
296
|
|
301
297
|
sorted.each do |k|
|
302
298
|
extra = kept_keys.size == 0 ? 0 : comma
|
@@ -13,15 +13,17 @@ class Logster::Middleware::DebugExceptions < ActionDispatch::DebugExceptions
|
|
13
13
|
|
14
14
|
exception = wrapper.exception
|
15
15
|
|
16
|
-
Logster
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
Logster
|
17
|
+
.config
|
18
|
+
.current_context
|
19
|
+
.call(env) do
|
20
|
+
Logster.logger.add_with_opts(
|
21
|
+
::Logger::Severity::FATAL,
|
22
|
+
"#{exception.class} (#{exception})\n#{wrapper.application_trace.join("\n")}",
|
23
|
+
"web-exception",
|
24
|
+
backtrace: wrapper.full_trace.join("\n"),
|
25
|
+
env: env,
|
26
|
+
)
|
27
|
+
end
|
26
28
|
end
|
27
29
|
end
|
@@ -3,13 +3,12 @@
|
|
3
3
|
module Logster
|
4
4
|
module Middleware
|
5
5
|
class Reporter
|
6
|
-
|
7
6
|
PATH_INFO = "PATH_INFO"
|
8
7
|
SCRIPT_NAME = "SCRIPT_NAME"
|
9
8
|
|
10
9
|
def initialize(app, config = {})
|
11
10
|
@app = app
|
12
|
-
@error_path = Logster.config.subdirectory +
|
11
|
+
@error_path = Logster.config.subdirectory + "/report_js_error"
|
13
12
|
end
|
14
13
|
|
15
14
|
def call(env)
|
@@ -18,26 +17,24 @@ module Logster
|
|
18
17
|
path = env[PATH_INFO]
|
19
18
|
script_name = env[SCRIPT_NAME]
|
20
19
|
|
21
|
-
if script_name && script_name.length > 0
|
22
|
-
path = script_name + path
|
23
|
-
end
|
20
|
+
path = script_name + path if script_name && script_name.length > 0
|
24
21
|
|
25
22
|
if path == @error_path
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
return 403, {}, ["Access Denied"] if !Logster.config.enable_js_error_reporting
|
24
|
+
|
25
|
+
Logster
|
26
|
+
.config
|
27
|
+
.current_context
|
28
|
+
.call(env) do
|
29
|
+
if Logster.config.rate_limit_error_reporting
|
30
|
+
req = Rack::Request.new(env)
|
31
|
+
if Logster.store.rate_limited?(req.ip, perform: true)
|
32
|
+
return 429, {}, ["Rate Limited"]
|
33
|
+
end
|
36
34
|
end
|
35
|
+
report_js_error(env)
|
37
36
|
end
|
38
|
-
|
39
|
-
end
|
40
|
-
return [200, {}, ["OK"]]
|
37
|
+
return 200, {}, ["OK"]
|
41
38
|
end
|
42
39
|
|
43
40
|
@app.call(env)
|
@@ -59,20 +56,14 @@ module Logster
|
|
59
56
|
backtrace = params["stacktrace"] || ""
|
60
57
|
|
61
58
|
severity = ::Logger::Severity::WARN
|
62
|
-
if params["severity"] &&
|
63
|
-
::Logger::Severity.const_defined?(params["severity"].upcase)
|
59
|
+
if params["severity"] && ::Logger::Severity.const_defined?(params["severity"].upcase)
|
64
60
|
severity = ::Logger::Severity.const_get(params["severity"].upcase)
|
65
61
|
end
|
66
62
|
|
67
|
-
Logster.store.report(severity,
|
68
|
-
"javascript",
|
69
|
-
message,
|
70
|
-
backtrace: backtrace,
|
71
|
-
env: env)
|
63
|
+
Logster.store.report(severity, "javascript", message, backtrace: backtrace, env: env)
|
72
64
|
|
73
65
|
true
|
74
66
|
end
|
75
|
-
|
76
67
|
end
|
77
68
|
end
|
78
69
|
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "json"
|
4
4
|
|
5
5
|
module Logster
|
6
6
|
module Middleware
|
7
7
|
class Viewer
|
8
|
-
|
9
8
|
PATH_INFO = "PATH_INFO".freeze
|
10
9
|
SCRIPT_NAME = "SCRIPT_NAME".freeze
|
11
10
|
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
@@ -25,39 +24,29 @@ module Logster
|
|
25
24
|
path = env[PATH_INFO]
|
26
25
|
script_name = env[SCRIPT_NAME]
|
27
26
|
|
28
|
-
if script_name && script_name.length > 0
|
29
|
-
path = script_name + path
|
30
|
-
end
|
27
|
+
path = script_name + path if script_name && script_name.length > 0
|
31
28
|
|
32
29
|
if resource = resolve_path(path)
|
33
|
-
if resource =~
|
30
|
+
if resource =~
|
31
|
+
/\.ico$|\.js$|\.png|\.handlebars$|\.css$|\.woff$|\.ttf$|\.woff2$|\.svg$|\.otf$|\.eot$/
|
34
32
|
serve_file(env, resource)
|
35
|
-
|
36
33
|
elsif resource.start_with?("/messages.json") && env[REQUEST_METHOD] == "POST"
|
37
34
|
serve_messages(Rack::Request.new(env))
|
38
|
-
|
39
|
-
|
40
|
-
if env[REQUEST_METHOD] != "DELETE"
|
41
|
-
return method_not_allowed("DELETE")
|
42
|
-
end
|
35
|
+
elsif resource =~ %r{/message/([0-9a-f]+)$}
|
36
|
+
return method_not_allowed("DELETE") if env[REQUEST_METHOD] != "DELETE"
|
43
37
|
|
44
38
|
key = $1
|
45
39
|
message = Logster.store.get(key)
|
46
|
-
unless message
|
47
|
-
return [404, {}, ["Message not found"]]
|
48
|
-
end
|
40
|
+
return 404, {}, ["Message not found"] unless message
|
49
41
|
|
50
42
|
Logster.store.delete(message)
|
51
43
|
[301, { "Location" => "#{@logs_path}/" }, []]
|
52
|
-
|
53
|
-
elsif resource =~ /\/(un)?protect\/([0-9a-f]+)$/
|
44
|
+
elsif resource =~ %r{/(un)?protect/([0-9a-f]+)$}
|
54
45
|
off = $1 == "un"
|
55
46
|
key = $2
|
56
47
|
|
57
48
|
message = Logster.store.get(key)
|
58
|
-
unless message
|
59
|
-
return [404, {}, ["Message not found"]]
|
60
|
-
end
|
49
|
+
return 404, {}, ["Message not found"] unless message
|
61
50
|
|
62
51
|
if off
|
63
52
|
if Logster.store.unprotect(key)
|
@@ -72,34 +61,25 @@ module Logster
|
|
72
61
|
[500, {}, ["Failed"]]
|
73
62
|
end
|
74
63
|
end
|
75
|
-
|
76
|
-
elsif resource =~ /\/solve\/([0-9a-f]+)$/
|
64
|
+
elsif resource =~ %r{/solve/([0-9a-f]+)$}
|
77
65
|
key = $1
|
78
66
|
|
79
67
|
message = Logster.store.get(key)
|
80
|
-
unless message
|
81
|
-
return [404, {}, ["Message not found"]]
|
82
|
-
end
|
68
|
+
return 404, {}, ["Message not found"] unless message
|
83
69
|
|
84
70
|
Logster.store.solve(key)
|
85
71
|
|
86
72
|
[301, { "Location" => "#{@logs_path}" }, []]
|
87
|
-
|
88
|
-
|
89
|
-
if env[REQUEST_METHOD] != "POST"
|
90
|
-
return method_not_allowed("POST")
|
91
|
-
end
|
73
|
+
elsif resource =~ %r{/clear$}
|
74
|
+
return method_not_allowed("POST") if env[REQUEST_METHOD] != "POST"
|
92
75
|
Logster.store.clear
|
93
76
|
[200, {}, ["Messages cleared"]]
|
94
|
-
|
95
|
-
elsif resource =~ /\/show\/([0-9a-f]+)(\.json)?$/
|
77
|
+
elsif resource =~ %r{/show/([0-9a-f]+)(\.json)?$}
|
96
78
|
key = $1
|
97
79
|
json = $2 == ".json"
|
98
80
|
|
99
81
|
message = Logster.store.get(key)
|
100
|
-
unless message
|
101
|
-
return [404, {}, ["Message not found"]]
|
102
|
-
end
|
82
|
+
return 404, {}, ["Message not found"] unless message
|
103
83
|
|
104
84
|
if json
|
105
85
|
[200, { "content-type" => "application/json; charset=utf-8" }, [message.to_json]]
|
@@ -107,8 +87,7 @@ module Logster
|
|
107
87
|
preload = { "/show/#{key}" => message }
|
108
88
|
[200, { "content-type" => "text/html; charset=utf-8" }, [body(preload)]]
|
109
89
|
end
|
110
|
-
|
111
|
-
elsif resource =~ /\/settings(\.json)?$/
|
90
|
+
elsif resource =~ %r{/settings(\.json)?$}
|
112
91
|
json = $1 == ".json"
|
113
92
|
if json
|
114
93
|
ignore_count = Logster.store.get_all_ignore_count
|
@@ -120,21 +99,30 @@ module Logster
|
|
120
99
|
suppression << { value: string_pattern, count: count, hard: true }
|
121
100
|
end
|
122
101
|
|
123
|
-
Logster::SuppressionPattern
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
102
|
+
Logster::SuppressionPattern
|
103
|
+
.find_all(raw: true)
|
104
|
+
.each do |pattern|
|
105
|
+
count = ignore_count[pattern] || 0
|
106
|
+
suppression << { value: pattern, count: count }
|
107
|
+
end
|
108
|
+
|
109
|
+
grouping =
|
110
|
+
Logster::GroupingPattern.find_all(raw: true).map { |pattern| { value: pattern } }
|
111
|
+
[
|
112
|
+
200,
|
113
|
+
{ "content-type" => "application/json; charset=utf-8" },
|
114
|
+
[JSON.generate(suppression: suppression, grouping: grouping)],
|
115
|
+
]
|
132
116
|
else
|
133
117
|
[200, { "content-type" => "text/html; charset=utf-8" }, [body]]
|
134
118
|
end
|
135
|
-
elsif resource =~
|
119
|
+
elsif resource =~ %r{/patterns/([a-zA-Z0-9_]+)\.json$}
|
136
120
|
unless Logster.config.enable_custom_patterns_via_ui
|
137
|
-
return
|
121
|
+
return(
|
122
|
+
not_allowed(
|
123
|
+
"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",
|
124
|
+
)
|
125
|
+
)
|
138
126
|
end
|
139
127
|
|
140
128
|
set_name = $1
|
@@ -147,14 +135,16 @@ module Logster
|
|
147
135
|
return method_not_allowed("PUT") if req.request_method != "PUT"
|
148
136
|
pattern = nil
|
149
137
|
if [true, "true"].include?(req.params["hard"])
|
150
|
-
pattern =
|
151
|
-
|
152
|
-
|
153
|
-
|
138
|
+
pattern =
|
139
|
+
Logster.store.ignore.find do |patt|
|
140
|
+
str = Regexp === patt ? patt.inspect : patt.to_s
|
141
|
+
str == req.params["pattern"]
|
142
|
+
end
|
154
143
|
else
|
155
|
-
pattern =
|
156
|
-
|
157
|
-
|
144
|
+
pattern =
|
145
|
+
Logster::SuppressionPattern
|
146
|
+
.find_all(raw: true)
|
147
|
+
.find { |patt| patt == req.params["pattern"] }
|
158
148
|
end
|
159
149
|
return not_found("Pattern not found") unless pattern
|
160
150
|
pattern = Regexp === pattern ? pattern.inspect : pattern.to_s
|
@@ -162,7 +152,7 @@ module Logster
|
|
162
152
|
[200, {}, ["OK"]]
|
163
153
|
elsif resource == "/"
|
164
154
|
[200, { "content-type" => "text/html; charset=utf-8" }, [body]]
|
165
|
-
elsif resource =~
|
155
|
+
elsif resource =~ %r{/fetch-env/([0-9a-f]+)\.json$}
|
166
156
|
key = $1
|
167
157
|
env = Logster.store.get_env(key)
|
168
158
|
if env
|
@@ -170,18 +160,21 @@ module Logster
|
|
170
160
|
else
|
171
161
|
not_found
|
172
162
|
end
|
173
|
-
elsif resource ==
|
163
|
+
elsif resource == "/solve-group"
|
174
164
|
return not_allowed unless Logster.config.enable_custom_patterns_via_ui
|
175
165
|
req = Rack::Request.new(env)
|
176
166
|
return method_not_allowed("POST") if req.request_method != "POST"
|
177
|
-
group =
|
178
|
-
patt.inspect == req.params["regex"]
|
179
|
-
end.first
|
167
|
+
group =
|
168
|
+
Logster.store.find_pattern_groups { |patt| patt.inspect == req.params["regex"] }.first
|
180
169
|
return not_found("No such pattern group exists") if !group
|
181
170
|
group.messages_keys.each { |k| Logster.store.solve(k) }
|
182
171
|
[200, {}, []]
|
183
|
-
elsif resource ==
|
184
|
-
[
|
172
|
+
elsif resource == "/development-preload.json" && ENV["LOGSTER_ENV"] == "development"
|
173
|
+
[
|
174
|
+
200,
|
175
|
+
{ "content-type" => "application/json; charset=utf-8" },
|
176
|
+
[JSON.generate(preloaded_data)],
|
177
|
+
]
|
185
178
|
else
|
186
179
|
not_found
|
187
180
|
end
|
@@ -195,17 +188,14 @@ module Logster
|
|
195
188
|
def serve_file(env, path)
|
196
189
|
env[PATH_INFO] = path
|
197
190
|
# accl redirect is going to be trouble, ensure its bypassed
|
198
|
-
env[
|
191
|
+
env["sendfile.type"] = ""
|
199
192
|
@fileserver.call(env)
|
200
193
|
end
|
201
194
|
|
202
195
|
def serve_messages(req)
|
203
196
|
params = req.params
|
204
197
|
|
205
|
-
opts = {
|
206
|
-
before: params["before"],
|
207
|
-
after: params["after"]
|
208
|
-
}
|
198
|
+
opts = { before: params["before"], after: params["after"] }
|
209
199
|
|
210
200
|
if (filter = params["filter"])
|
211
201
|
filter = filter.split("_").map { |s| s.to_i }
|
@@ -217,16 +207,14 @@ module Logster
|
|
217
207
|
opts[:search] = search
|
218
208
|
end
|
219
209
|
search = opts[:search]
|
220
|
-
if params["known_groups"]
|
221
|
-
opts[:known_groups] = params["known_groups"]
|
222
|
-
end
|
210
|
+
opts[:known_groups] = params["known_groups"] if params["known_groups"]
|
223
211
|
opts[:with_env] = (String === search && search.size > 0) || Regexp === search
|
224
212
|
|
225
213
|
payload = {
|
226
214
|
messages: @store.latest(opts),
|
227
215
|
total: @store.count,
|
228
|
-
search: params[
|
229
|
-
filter: filter ||
|
216
|
+
search: params["search"] || "",
|
217
|
+
filter: filter || "",
|
230
218
|
}
|
231
219
|
|
232
220
|
json = JSON.generate(payload)
|
@@ -246,7 +234,8 @@ module Logster
|
|
246
234
|
case request_method
|
247
235
|
when "POST"
|
248
236
|
args = {}
|
249
|
-
if Logster::SuppressionPattern === record &&
|
237
|
+
if Logster::SuppressionPattern === record &&
|
238
|
+
[true, "true"].include?(req.params["retroactive"])
|
250
239
|
args[:retroactive] = true
|
251
240
|
end
|
252
241
|
record.save(args)
|
@@ -264,7 +253,7 @@ module Logster
|
|
264
253
|
|
265
254
|
unless Logster::Pattern::PatternError === err # likely a bug, give us the backtrace
|
266
255
|
error_message += "\n\n#{err.backtrace.join("\n")}"
|
267
|
-
return
|
256
|
+
return 500, {}, [error_message]
|
268
257
|
end
|
269
258
|
|
270
259
|
[400, {}, [error_message]]
|
@@ -290,36 +279,34 @@ module Logster
|
|
290
279
|
end
|
291
280
|
|
292
281
|
def method_not_allowed(allowed_methods)
|
293
|
-
if Array === allowed_methods
|
294
|
-
allowed_methods = allowed_methods.join(", ")
|
295
|
-
end
|
282
|
+
allowed_methods = allowed_methods.join(", ") if Array === allowed_methods
|
296
283
|
[405, { "allow" => allowed_methods }, []]
|
297
284
|
end
|
298
285
|
|
299
286
|
def parse_regex(string)
|
300
|
-
if string =~
|
287
|
+
if string =~ %r{/(.+)/(.*)}
|
301
288
|
s = $1
|
302
289
|
flags = Regexp::IGNORECASE if $2 && $2.include?("i")
|
303
|
-
|
290
|
+
begin
|
291
|
+
Regexp.new(s, flags)
|
292
|
+
rescue StandardError
|
293
|
+
nil
|
294
|
+
end
|
304
295
|
end
|
305
296
|
end
|
306
297
|
|
307
298
|
def resolve_path(path)
|
308
|
-
if path =~ @path_regex
|
309
|
-
$3 || "/"
|
310
|
-
end
|
299
|
+
$3 || "/" if path =~ @path_regex
|
311
300
|
end
|
312
301
|
|
313
302
|
def css(name, attrs = {})
|
314
|
-
attrs = attrs.map
|
315
|
-
"#{k}='#{v}'"
|
316
|
-
end.join(" ")
|
303
|
+
attrs = attrs.map { |k, v| "#{k}='#{v}'" }.join(" ")
|
317
304
|
|
318
305
|
"<link rel='stylesheet' type='text/css' href='#{@logs_path}/stylesheets/#{name}' #{attrs}>"
|
319
306
|
end
|
320
307
|
|
321
308
|
def script(prod, dev = nil)
|
322
|
-
name = ENV[
|
309
|
+
name = ENV["DEBUG_JS"] == "1" && dev ? dev : prod
|
323
310
|
"<script src='#{@logs_path}/javascript/#{name}'></script>"
|
324
311
|
end
|
325
312
|
|
@@ -331,30 +318,23 @@ module Logster
|
|
331
318
|
gems_data = []
|
332
319
|
Gem::Specification.find_all do |gem|
|
333
320
|
url = gem.metadata["source_code_uri"] || gem.homepage
|
334
|
-
if url && url.match(
|
335
|
-
gems_data << { name: gem.name, url: url }
|
336
|
-
end
|
321
|
+
gems_data << { name: gem.name, url: url } if url && url.match(%r{^https?://github.com/})
|
337
322
|
end
|
338
|
-
{
|
339
|
-
gems_data: gems_data,
|
340
|
-
directories: Logster.config.project_directories
|
341
|
-
}
|
323
|
+
{ gems_data: gems_data, directories: Logster.config.project_directories }
|
342
324
|
end
|
343
325
|
|
344
326
|
def preloaded_data
|
345
327
|
preload = {
|
346
328
|
env_expandable_keys: Logster.config.env_expandable_keys,
|
347
329
|
patterns_enabled: Logster.config.enable_custom_patterns_via_ui,
|
348
|
-
application_version: Logster.config.application_version
|
330
|
+
application_version: Logster.config.application_version,
|
349
331
|
}
|
350
332
|
backtrace_links_enabled = Logster.config.enable_backtrace_links
|
351
333
|
gems_dir = Logster.config.gems_dir
|
352
334
|
gems_dir += "/" if gems_dir[-1] != "/"
|
353
335
|
preload.merge!(gems_dir: gems_dir, backtrace_links_enabled: backtrace_links_enabled)
|
354
336
|
|
355
|
-
if backtrace_links_enabled
|
356
|
-
preload.merge!(preload_backtrace_data)
|
357
|
-
end
|
337
|
+
preload.merge!(preload_backtrace_data) if backtrace_links_enabled
|
358
338
|
preload
|
359
339
|
end
|
360
340
|
|