atatus 1.0.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 +7 -0
- data/.gitignore +16 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +57 -0
- data/LICENSE +65 -0
- data/LICENSE-THIRD-PARTY +205 -0
- data/README.md +13 -0
- data/Rakefile +19 -0
- data/atatus.gemspec +36 -0
- data/atatus.yml +2 -0
- data/bench/.gitignore +2 -0
- data/bench/app.rb +53 -0
- data/bench/benchmark.rb +36 -0
- data/bench/report.rb +55 -0
- data/bench/rubyprof.rb +39 -0
- data/bench/stackprof.rb +23 -0
- data/bin/build_docs +5 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bin/with_framework +7 -0
- data/lib/atatus.rb +325 -0
- data/lib/atatus/agent.rb +260 -0
- data/lib/atatus/central_config.rb +141 -0
- data/lib/atatus/central_config/cache_control.rb +34 -0
- data/lib/atatus/collector/base.rb +329 -0
- data/lib/atatus/collector/builder.rb +317 -0
- data/lib/atatus/collector/transport.rb +72 -0
- data/lib/atatus/config.rb +248 -0
- data/lib/atatus/config/bytes.rb +25 -0
- data/lib/atatus/config/duration.rb +23 -0
- data/lib/atatus/config/options.rb +134 -0
- data/lib/atatus/config/regexp_list.rb +13 -0
- data/lib/atatus/context.rb +33 -0
- data/lib/atatus/context/request.rb +11 -0
- data/lib/atatus/context/request/socket.rb +19 -0
- data/lib/atatus/context/request/url.rb +42 -0
- data/lib/atatus/context/response.rb +22 -0
- data/lib/atatus/context/user.rb +42 -0
- data/lib/atatus/context_builder.rb +97 -0
- data/lib/atatus/deprecations.rb +22 -0
- data/lib/atatus/error.rb +22 -0
- data/lib/atatus/error/exception.rb +46 -0
- data/lib/atatus/error/log.rb +24 -0
- data/lib/atatus/error_builder.rb +76 -0
- data/lib/atatus/instrumenter.rb +224 -0
- data/lib/atatus/internal_error.rb +6 -0
- data/lib/atatus/logging.rb +55 -0
- data/lib/atatus/metadata.rb +19 -0
- data/lib/atatus/metadata/process_info.rb +18 -0
- data/lib/atatus/metadata/service_info.rb +61 -0
- data/lib/atatus/metadata/system_info.rb +35 -0
- data/lib/atatus/metadata/system_info/container_info.rb +121 -0
- data/lib/atatus/metadata/system_info/hw_info.rb +118 -0
- data/lib/atatus/metadata/system_info/os_info.rb +31 -0
- data/lib/atatus/metrics.rb +98 -0
- data/lib/atatus/metrics/cpu_mem.rb +240 -0
- data/lib/atatus/metrics/vm.rb +60 -0
- data/lib/atatus/metricset.rb +19 -0
- data/lib/atatus/middleware.rb +76 -0
- data/lib/atatus/naively_hashable.rb +21 -0
- data/lib/atatus/normalizers.rb +68 -0
- data/lib/atatus/normalizers/action_controller.rb +27 -0
- data/lib/atatus/normalizers/action_mailer.rb +26 -0
- data/lib/atatus/normalizers/action_view.rb +77 -0
- data/lib/atatus/normalizers/active_record.rb +45 -0
- data/lib/atatus/opentracing.rb +346 -0
- data/lib/atatus/rails.rb +61 -0
- data/lib/atatus/railtie.rb +30 -0
- data/lib/atatus/span.rb +125 -0
- data/lib/atatus/span/context.rb +40 -0
- data/lib/atatus/span_helpers.rb +44 -0
- data/lib/atatus/spies.rb +86 -0
- data/lib/atatus/spies/action_dispatch.rb +28 -0
- data/lib/atatus/spies/delayed_job.rb +68 -0
- data/lib/atatus/spies/elasticsearch.rb +36 -0
- data/lib/atatus/spies/faraday.rb +70 -0
- data/lib/atatus/spies/http.rb +44 -0
- data/lib/atatus/spies/json.rb +22 -0
- data/lib/atatus/spies/mongo.rb +87 -0
- data/lib/atatus/spies/net_http.rb +70 -0
- data/lib/atatus/spies/rake.rb +45 -0
- data/lib/atatus/spies/redis.rb +27 -0
- data/lib/atatus/spies/sequel.rb +47 -0
- data/lib/atatus/spies/sidekiq.rb +89 -0
- data/lib/atatus/spies/sinatra.rb +41 -0
- data/lib/atatus/spies/tilt.rb +27 -0
- data/lib/atatus/sql_summarizer.rb +35 -0
- data/lib/atatus/stacktrace.rb +16 -0
- data/lib/atatus/stacktrace/frame.rb +52 -0
- data/lib/atatus/stacktrace_builder.rb +104 -0
- data/lib/atatus/subscriber.rb +77 -0
- data/lib/atatus/trace_context.rb +85 -0
- data/lib/atatus/transaction.rb +100 -0
- data/lib/atatus/transport/base.rb +174 -0
- data/lib/atatus/transport/connection.rb +156 -0
- data/lib/atatus/transport/connection/http.rb +116 -0
- data/lib/atatus/transport/connection/proxy_pipe.rb +75 -0
- data/lib/atatus/transport/filters.rb +43 -0
- data/lib/atatus/transport/filters/secrets_filter.rb +74 -0
- data/lib/atatus/transport/serializers.rb +93 -0
- data/lib/atatus/transport/serializers/context_serializer.rb +85 -0
- data/lib/atatus/transport/serializers/error_serializer.rb +77 -0
- data/lib/atatus/transport/serializers/metadata_serializer.rb +70 -0
- data/lib/atatus/transport/serializers/metricset_serializer.rb +28 -0
- data/lib/atatus/transport/serializers/span_serializer.rb +80 -0
- data/lib/atatus/transport/serializers/transaction_serializer.rb +37 -0
- data/lib/atatus/transport/worker.rb +73 -0
- data/lib/atatus/util.rb +42 -0
- data/lib/atatus/util/inflector.rb +93 -0
- data/lib/atatus/util/lru_cache.rb +48 -0
- data/lib/atatus/util/prefixed_logger.rb +18 -0
- data/lib/atatus/util/throttle.rb +35 -0
- data/lib/atatus/version.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +190 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'http'
|
|
4
|
+
require 'concurrent'
|
|
5
|
+
require 'zlib'
|
|
6
|
+
|
|
7
|
+
require 'atatus/transport/connection/proxy_pipe'
|
|
8
|
+
|
|
9
|
+
module Atatus
|
|
10
|
+
module Transport
|
|
11
|
+
class Connection
|
|
12
|
+
# @api private
|
|
13
|
+
class Http
|
|
14
|
+
include Logging
|
|
15
|
+
|
|
16
|
+
def initialize(config)
|
|
17
|
+
@config = config
|
|
18
|
+
@closed = Concurrent::AtomicBoolean.new
|
|
19
|
+
|
|
20
|
+
@rd, @wr = ProxyPipe.pipe(compress: @config.http_compression?)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def open(url, headers: {}, ssl_context: nil)
|
|
24
|
+
@request = open_request_in_thread(url, headers, ssl_context)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.open(config, url, headers: {}, ssl_context: nil)
|
|
28
|
+
new(config).tap do |http|
|
|
29
|
+
http.open(url, headers: headers, ssl_context: ssl_context)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def write(str)
|
|
34
|
+
@wr.write(str)
|
|
35
|
+
@wr.bytes_sent
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def close(reason)
|
|
39
|
+
return if closed?
|
|
40
|
+
|
|
41
|
+
debug '%s: Closing request with reason %s', thread_str, reason
|
|
42
|
+
@closed.make_true
|
|
43
|
+
|
|
44
|
+
@wr&.close(reason)
|
|
45
|
+
return if @request.nil? || @request&.join(5)
|
|
46
|
+
|
|
47
|
+
error(
|
|
48
|
+
'%s: APM Server not responding in time, terminating request',
|
|
49
|
+
thread_str
|
|
50
|
+
)
|
|
51
|
+
@request.kill
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def closed?
|
|
55
|
+
@closed.true?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def inspect
|
|
59
|
+
format(
|
|
60
|
+
'%s closed: %s>',
|
|
61
|
+
super.split.first,
|
|
62
|
+
closed?
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def thread_str
|
|
69
|
+
format('[THREAD:%s]', Thread.current.object_id)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# rubocop:disable Metrics/LineLength
|
|
73
|
+
def open_request_in_thread(url, headers, ssl_context)
|
|
74
|
+
client = build_client(headers)
|
|
75
|
+
|
|
76
|
+
debug '%s: Opening new request', thread_str
|
|
77
|
+
Thread.new do
|
|
78
|
+
begin
|
|
79
|
+
post(client, url, ssl_context)
|
|
80
|
+
rescue Exception => e
|
|
81
|
+
error "Couldn't establish connection to APM Server:\n%p", e.inspect
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
# rubocop:enable Metrics/LineLength
|
|
86
|
+
|
|
87
|
+
def build_client(headers)
|
|
88
|
+
client = HTTP.headers(headers)
|
|
89
|
+
return client unless @config.proxy_address && @config.proxy_port
|
|
90
|
+
|
|
91
|
+
client.via(
|
|
92
|
+
@config.proxy_address,
|
|
93
|
+
@config.proxy_port,
|
|
94
|
+
@config.proxy_username,
|
|
95
|
+
@config.proxy_password,
|
|
96
|
+
@config.proxy_headers
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def post(client, url, ssl_context)
|
|
101
|
+
resp = client.post(
|
|
102
|
+
url,
|
|
103
|
+
body: @rd,
|
|
104
|
+
ssl_context: ssl_context
|
|
105
|
+
).flush
|
|
106
|
+
|
|
107
|
+
if resp&.status == 202
|
|
108
|
+
debug 'APM Server responded with status 202'
|
|
109
|
+
elsif resp
|
|
110
|
+
error "APM Server responded with an error:\n%p", resp.body.to_s
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'concurrent'
|
|
4
|
+
require 'zlib'
|
|
5
|
+
|
|
6
|
+
module Atatus
|
|
7
|
+
module Transport
|
|
8
|
+
class Connection
|
|
9
|
+
# @api private
|
|
10
|
+
class ProxyPipe
|
|
11
|
+
def initialize(enc = nil, compress: true)
|
|
12
|
+
rd, wr = IO.pipe(enc)
|
|
13
|
+
|
|
14
|
+
@read = rd
|
|
15
|
+
@write = Write.new(wr, compress: compress)
|
|
16
|
+
|
|
17
|
+
# Http.rb<4 calls rewind on the request bodies, but IO::Pipe raises
|
|
18
|
+
# ~mikker
|
|
19
|
+
return if HTTP::VERSION.to_i >= 4
|
|
20
|
+
def rd.rewind; end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :read, :write
|
|
24
|
+
|
|
25
|
+
# @api private
|
|
26
|
+
class Write
|
|
27
|
+
include Logging
|
|
28
|
+
|
|
29
|
+
def initialize(io, compress: true)
|
|
30
|
+
@io = io
|
|
31
|
+
@compress = compress
|
|
32
|
+
@bytes_sent = Concurrent::AtomicFixnum.new(0)
|
|
33
|
+
@config = Atatus.agent&.config # this is silly, fix Logging
|
|
34
|
+
|
|
35
|
+
return unless compress
|
|
36
|
+
enable_compression!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :io
|
|
40
|
+
|
|
41
|
+
def enable_compression!
|
|
42
|
+
io.binmode
|
|
43
|
+
@io = Zlib::GzipWriter.new(io)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def close(reason = nil)
|
|
47
|
+
debug("Closing writer with reason #{reason}")
|
|
48
|
+
io.close
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def closed?
|
|
52
|
+
io.closed?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write(str)
|
|
56
|
+
io.puts(str).tap do
|
|
57
|
+
@bytes_sent.update do |curr|
|
|
58
|
+
@compress ? io.tell : curr + str.bytesize
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def bytes_sent
|
|
64
|
+
@bytes_sent.value
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.pipe(*args)
|
|
69
|
+
pipe = new(*args)
|
|
70
|
+
[pipe.read, pipe.write]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'atatus/transport/filters/secrets_filter'
|
|
4
|
+
|
|
5
|
+
module Atatus
|
|
6
|
+
module Transport
|
|
7
|
+
# @api private
|
|
8
|
+
module Filters
|
|
9
|
+
SKIP = :skip
|
|
10
|
+
|
|
11
|
+
def self.new(config)
|
|
12
|
+
Container.new(config)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @api private
|
|
16
|
+
class Container
|
|
17
|
+
def initialize(config)
|
|
18
|
+
@filters = { secrets: SecretsFilter.new(config) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add(key, filter)
|
|
22
|
+
@filters[key] = filter
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def remove(key)
|
|
26
|
+
@filters.delete(key)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def apply!(payload)
|
|
30
|
+
@filters.reduce(payload) do |result, (_key, filter)|
|
|
31
|
+
result = filter.call(result)
|
|
32
|
+
break SKIP if result.nil?
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def length
|
|
38
|
+
@filters.length
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Atatus
|
|
4
|
+
module Transport
|
|
5
|
+
module Filters
|
|
6
|
+
# @api private
|
|
7
|
+
class SecretsFilter
|
|
8
|
+
FILTERED = '[FILTERED]'
|
|
9
|
+
|
|
10
|
+
KEY_FILTERS = [
|
|
11
|
+
/passw(or)?d/i,
|
|
12
|
+
/auth/i,
|
|
13
|
+
/^pw$/,
|
|
14
|
+
/secret/i,
|
|
15
|
+
/token/i,
|
|
16
|
+
/api[-._]?key/i,
|
|
17
|
+
/session[-._]?id/i,
|
|
18
|
+
/(set[-_])?cookie/i
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
VALUE_FILTERS = [
|
|
22
|
+
# (probably) credit card number
|
|
23
|
+
/^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
26
|
+
def initialize(config)
|
|
27
|
+
@config = config
|
|
28
|
+
@key_filters = KEY_FILTERS + config.custom_key_filters
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def call(payload)
|
|
32
|
+
strip_from! payload.dig(:transaction, :context, :request, :headers)
|
|
33
|
+
strip_from! payload.dig(:transaction, :context, :request, :env)
|
|
34
|
+
strip_from! payload.dig(:transaction, :context, :request, :cookies)
|
|
35
|
+
strip_from! payload.dig(:transaction, :context, :response, :headers)
|
|
36
|
+
strip_from! payload.dig(:error, :context, :request, :headers)
|
|
37
|
+
strip_from! payload.dig(:error, :context, :response, :headers)
|
|
38
|
+
strip_from! payload.dig(:transaction, :context, :request, :body)
|
|
39
|
+
|
|
40
|
+
payload
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
44
|
+
def strip_from!(obj)
|
|
45
|
+
return unless obj && obj.is_a?(Hash)
|
|
46
|
+
|
|
47
|
+
obj.each do |k, v|
|
|
48
|
+
if filter_key?(k)
|
|
49
|
+
next obj[k] = FILTERED
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
case v
|
|
53
|
+
when Hash
|
|
54
|
+
strip_from!(v)
|
|
55
|
+
when String
|
|
56
|
+
if filter_value?(v)
|
|
57
|
+
obj[k] = FILTERED
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
63
|
+
|
|
64
|
+
def filter_key?(key)
|
|
65
|
+
@key_filters.any? { |regex| key.match regex }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def filter_value?(value)
|
|
69
|
+
VALUE_FILTERS.any? { |regex| value.match regex }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Atatus
|
|
6
|
+
module Transport
|
|
7
|
+
# @api private
|
|
8
|
+
module Serializers
|
|
9
|
+
# @api private
|
|
10
|
+
class UnrecognizedResource < InternalError; end
|
|
11
|
+
|
|
12
|
+
# @api private
|
|
13
|
+
class Serializer
|
|
14
|
+
def initialize(config)
|
|
15
|
+
@config = config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_reader :config
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def ms(micros)
|
|
23
|
+
micros.to_f / 1_000
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def keyword_field(value)
|
|
27
|
+
Util.truncate(value)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def keyword_object(hash)
|
|
31
|
+
return unless hash
|
|
32
|
+
|
|
33
|
+
hash.tap do |h|
|
|
34
|
+
h.each { |k, v| hash[k] = keyword_field(v) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def mixed_object(hash)
|
|
39
|
+
return unless hash
|
|
40
|
+
|
|
41
|
+
hash.tap do |h|
|
|
42
|
+
h.each do |k, v|
|
|
43
|
+
hash[k] = v.is_a?(String) ? keyword_field(v) : v
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @api private
|
|
50
|
+
class Container
|
|
51
|
+
def initialize(config)
|
|
52
|
+
@transaction = Serializers::TransactionSerializer.new(config)
|
|
53
|
+
@span = Serializers::SpanSerializer.new(config)
|
|
54
|
+
@error = Serializers::ErrorSerializer.new(config)
|
|
55
|
+
@metadata = Serializers::MetadataSerializer.new(config)
|
|
56
|
+
@metricset = Serializers::MetricsetSerializer.new(config)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
attr_reader :transaction, :span, :error, :metadata, :metricset
|
|
60
|
+
|
|
61
|
+
# rubocop:disable Metrics/MethodLength
|
|
62
|
+
def serialize(resource)
|
|
63
|
+
case resource
|
|
64
|
+
when Transaction
|
|
65
|
+
transaction.build(resource)
|
|
66
|
+
when Span
|
|
67
|
+
span.build(resource)
|
|
68
|
+
when Error
|
|
69
|
+
error.build(resource)
|
|
70
|
+
when Metricset
|
|
71
|
+
metricset.build(resource)
|
|
72
|
+
when Metadata
|
|
73
|
+
metadata.build(resource)
|
|
74
|
+
else
|
|
75
|
+
raise UnrecognizedResource, resource.inspect
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
# rubocop:enable Metrics/MethodLength
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.new(config)
|
|
82
|
+
Container.new(config)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
require 'atatus/transport/serializers/context_serializer'
|
|
89
|
+
require 'atatus/transport/serializers/transaction_serializer'
|
|
90
|
+
require 'atatus/transport/serializers/span_serializer'
|
|
91
|
+
require 'atatus/transport/serializers/error_serializer'
|
|
92
|
+
require 'atatus/transport/serializers/metricset_serializer'
|
|
93
|
+
require 'atatus/transport/serializers/metadata_serializer'
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Atatus
|
|
4
|
+
module Transport
|
|
5
|
+
module Serializers
|
|
6
|
+
# @api private
|
|
7
|
+
class ContextSerializer < Serializer
|
|
8
|
+
def build(context)
|
|
9
|
+
return nil if context.nil? || context.empty?
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
custom: context.custom,
|
|
13
|
+
tags: mixed_object(context.labels),
|
|
14
|
+
request: build_request(context.request),
|
|
15
|
+
response: build_response(context.response),
|
|
16
|
+
user: build_user(context.user)
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# rubocop:disable Metrics/MethodLength
|
|
23
|
+
def build_request(request)
|
|
24
|
+
return unless request
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
body: request.body,
|
|
28
|
+
cookies: request.cookies,
|
|
29
|
+
env: request.env,
|
|
30
|
+
headers: request.headers,
|
|
31
|
+
http_version: keyword_field(request.http_version),
|
|
32
|
+
method: keyword_field(request.method),
|
|
33
|
+
socket: build_socket(request.socket),
|
|
34
|
+
url: build_url(request.url)
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
# rubocop:enable Metrics/MethodLength
|
|
38
|
+
|
|
39
|
+
def build_response(response)
|
|
40
|
+
return unless response
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
status_code: response.status_code.to_i,
|
|
44
|
+
headers: response.headers,
|
|
45
|
+
headers_sent: response.headers_sent,
|
|
46
|
+
finished: response.finished
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_user(user)
|
|
51
|
+
return if !user || user.empty?
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
id: keyword_field(user.id),
|
|
55
|
+
email: keyword_field(user.email),
|
|
56
|
+
username: keyword_field(user.username)
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def build_socket(socket)
|
|
61
|
+
return unless socket
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
remote_addr: socket.remote_addr,
|
|
65
|
+
encrypted: socket.encrypted
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_url(url)
|
|
70
|
+
return unless url
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
protocol: keyword_field(url.protocol),
|
|
74
|
+
full: keyword_field(url.full),
|
|
75
|
+
hostname: keyword_field(url.hostname),
|
|
76
|
+
port: keyword_field(url.port),
|
|
77
|
+
pathname: keyword_field(url.pathname),
|
|
78
|
+
search: keyword_field(url.search),
|
|
79
|
+
hash: keyword_field(url.hash)
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|