logster 2.12.1 → 2.13.0
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.
- 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
|
|