atatus 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus
|
4
|
+
# @api private
|
5
|
+
class TraceContext
|
6
|
+
class InvalidTraceparentHeader < StandardError; end
|
7
|
+
|
8
|
+
VERSION = '00'
|
9
|
+
HEX_REGEX = /[^[:xdigit:]]/.freeze
|
10
|
+
|
11
|
+
TRACE_ID_LENGTH = 16
|
12
|
+
ID_LENGTH = 8
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
version: VERSION,
|
16
|
+
trace_id: nil,
|
17
|
+
span_id: nil,
|
18
|
+
id: nil,
|
19
|
+
recorded: true
|
20
|
+
)
|
21
|
+
@version = version
|
22
|
+
@trace_id = trace_id || hex(TRACE_ID_LENGTH)
|
23
|
+
# TODO: rename to parent_id with next major version bump
|
24
|
+
@parent_id = span_id
|
25
|
+
@id = id || hex(ID_LENGTH)
|
26
|
+
@recorded = recorded
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :version, :id, :trace_id, :parent_id, :recorded
|
30
|
+
|
31
|
+
alias :recorded? :recorded
|
32
|
+
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
34
|
+
def self.parse(header)
|
35
|
+
raise InvalidTraceparentHeader unless header.length == 55
|
36
|
+
raise InvalidTraceparentHeader unless header[0..1] == VERSION
|
37
|
+
|
38
|
+
new.tap do |t|
|
39
|
+
t.version, t.trace_id, t.parent_id, t.flags =
|
40
|
+
header.split('-').tap do |values|
|
41
|
+
values[-1] = Util.hex_to_bits(values[-1])
|
42
|
+
end
|
43
|
+
|
44
|
+
raise InvalidTraceparentHeader if HEX_REGEX =~ t.trace_id
|
45
|
+
raise InvalidTraceparentHeader if HEX_REGEX =~ t.parent_id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# rubocop:enable Metrics/AbcSize
|
49
|
+
|
50
|
+
def flags=(flags)
|
51
|
+
@flags = flags
|
52
|
+
|
53
|
+
self.recorded = flags[7] == '1'
|
54
|
+
end
|
55
|
+
|
56
|
+
def flags
|
57
|
+
format('0000000%d', recorded? ? 1 : 0)
|
58
|
+
end
|
59
|
+
|
60
|
+
def hex_flags
|
61
|
+
format('%02x', flags.to_i(2))
|
62
|
+
end
|
63
|
+
|
64
|
+
def ensure_parent_id
|
65
|
+
@parent_id ||= hex(ID_LENGTH)
|
66
|
+
end
|
67
|
+
|
68
|
+
def child
|
69
|
+
dup.tap do |tc|
|
70
|
+
tc.parent_id = tc.id
|
71
|
+
tc.id = hex(ID_LENGTH)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_header
|
76
|
+
format('%s-%s-%s-%s', version, trace_id, id, hex_flags)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def hex(len)
|
82
|
+
SecureRandom.hex(len)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Atatus
|
7
|
+
# @api private
|
8
|
+
class Transaction
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegators :@trace_context,
|
12
|
+
:trace_id, :parent_id, :id, :ensure_parent_id
|
13
|
+
|
14
|
+
DEFAULT_TYPE = 'custom'
|
15
|
+
|
16
|
+
# rubocop:disable Metrics/ParameterLists
|
17
|
+
def initialize(
|
18
|
+
name = nil,
|
19
|
+
type = nil,
|
20
|
+
sampled: true,
|
21
|
+
context: nil,
|
22
|
+
labels: nil,
|
23
|
+
trace_context: nil
|
24
|
+
)
|
25
|
+
@name = name
|
26
|
+
@type = type || DEFAULT_TYPE
|
27
|
+
|
28
|
+
@sampled = sampled
|
29
|
+
|
30
|
+
@context = context || Context.new # TODO: Lazy generate this?
|
31
|
+
Util.reverse_merge!(@context.labels, labels) if labels
|
32
|
+
|
33
|
+
@trace_context = trace_context || TraceContext.new(recorded: sampled)
|
34
|
+
|
35
|
+
@started_spans = 0
|
36
|
+
@dropped_spans = 0
|
37
|
+
|
38
|
+
@notifications = [] # for AS::Notifications
|
39
|
+
end
|
40
|
+
# rubocop:enable Metrics/ParameterLists
|
41
|
+
|
42
|
+
attr_accessor :name, :type, :result, :spans
|
43
|
+
|
44
|
+
attr_reader :context, :duration, :started_spans, :dropped_spans,
|
45
|
+
:timestamp, :trace_context, :notifications
|
46
|
+
|
47
|
+
def sampled?
|
48
|
+
@sampled
|
49
|
+
end
|
50
|
+
|
51
|
+
def stopped?
|
52
|
+
!!duration
|
53
|
+
end
|
54
|
+
|
55
|
+
# life cycle
|
56
|
+
|
57
|
+
def start(clock_start = Util.monotonic_micros)
|
58
|
+
@timestamp = Util.micros
|
59
|
+
@clock_start = clock_start
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def stop(clock_end = Util.monotonic_micros)
|
64
|
+
raise 'Transaction not yet start' unless timestamp
|
65
|
+
@duration = clock_end - @clock_start
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def done(result = nil, clock_end: Util.monotonic_micros)
|
70
|
+
stop clock_end
|
71
|
+
self.result = result if result
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# spans
|
76
|
+
|
77
|
+
def inc_started_spans!
|
78
|
+
@started_spans += 1
|
79
|
+
end
|
80
|
+
|
81
|
+
def inc_dropped_spans!
|
82
|
+
@dropped_spans += 1
|
83
|
+
end
|
84
|
+
|
85
|
+
def max_spans_reached?(config)
|
86
|
+
started_spans > config.transaction_max_spans
|
87
|
+
end
|
88
|
+
|
89
|
+
# context
|
90
|
+
|
91
|
+
def add_response(*args)
|
92
|
+
context.response = Context::Response.new(*args)
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect
|
96
|
+
"<Atatus::Transaction id:#{id}" \
|
97
|
+
" name:#{name.inspect} type:#{type.inspect}>"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'atatus/metadata'
|
4
|
+
require 'atatus/transport/connection'
|
5
|
+
require 'atatus/transport/worker'
|
6
|
+
require 'atatus/transport/serializers'
|
7
|
+
require 'atatus/transport/filters'
|
8
|
+
require 'atatus/util/throttle'
|
9
|
+
|
10
|
+
module Atatus
|
11
|
+
module Transport
|
12
|
+
# rubocop:disable Metrics/ClassLength
|
13
|
+
# @api private
|
14
|
+
class Base
|
15
|
+
include Logging
|
16
|
+
|
17
|
+
WATCHER_EXECUTION_INTERVAL = 5
|
18
|
+
WATCHER_TIMEOUT_INTERVAL = 4
|
19
|
+
WORKER_JOIN_TIMEOUT = 5
|
20
|
+
|
21
|
+
def initialize(config)
|
22
|
+
@config = config
|
23
|
+
@queue = SizedQueue.new(config.api_buffer_size)
|
24
|
+
|
25
|
+
@serializers = Serializers.new(config)
|
26
|
+
@filters = Filters.new(config)
|
27
|
+
|
28
|
+
@stopped = Concurrent::AtomicBoolean.new
|
29
|
+
@workers = Array.new(config.pool_size)
|
30
|
+
|
31
|
+
@watcher_mutex = Mutex.new
|
32
|
+
@worker_mutex = Mutex.new
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :config, :queue, :filters, :workers, :watcher, :stopped
|
36
|
+
|
37
|
+
def start
|
38
|
+
debug '%s: Starting Transport', pid_str
|
39
|
+
|
40
|
+
ensure_watcher_running
|
41
|
+
ensure_worker_count
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop
|
45
|
+
debug '%s: Stopping Transport', pid_str
|
46
|
+
|
47
|
+
@stopped.make_true
|
48
|
+
|
49
|
+
stop_watcher
|
50
|
+
stop_workers
|
51
|
+
end
|
52
|
+
|
53
|
+
# rubocop:disable Metrics/MethodLength
|
54
|
+
def submit(resource)
|
55
|
+
if @stopped.true?
|
56
|
+
warn '%s: Transport stopping, no new events accepted', pid_str
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
|
60
|
+
ensure_watcher_running
|
61
|
+
queue.push(resource, true)
|
62
|
+
|
63
|
+
true
|
64
|
+
rescue ThreadError
|
65
|
+
throttled_queue_full_warning
|
66
|
+
nil
|
67
|
+
rescue Exception => e
|
68
|
+
error '%s: Failed adding to the transport queue: %p', pid_str, e.inspect
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
# rubocop:enable Metrics/MethodLength
|
72
|
+
|
73
|
+
def add_filter(key, callback)
|
74
|
+
@filters.add(key, callback)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def pid_str
|
80
|
+
format('[PID:%s]', Process.pid)
|
81
|
+
end
|
82
|
+
|
83
|
+
def ensure_watcher_running
|
84
|
+
# pid has changed == we've forked
|
85
|
+
return if @pid == Process.pid
|
86
|
+
|
87
|
+
@watcher_mutex.synchronize do
|
88
|
+
return if @pid == Process.pid
|
89
|
+
@pid = Process.pid
|
90
|
+
|
91
|
+
@watcher = Concurrent::TimerTask.execute(
|
92
|
+
execution_interval: WATCHER_EXECUTION_INTERVAL,
|
93
|
+
timeout_interval: WATCHER_TIMEOUT_INTERVAL
|
94
|
+
) { ensure_worker_count }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_worker_count
|
99
|
+
@worker_mutex.synchronize do
|
100
|
+
return if all_workers_alive?
|
101
|
+
return if stopped.true?
|
102
|
+
|
103
|
+
@workers.map! do |thread|
|
104
|
+
next thread if thread&.alive?
|
105
|
+
|
106
|
+
boot_worker
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def all_workers_alive?
|
112
|
+
!!workers.all? { |t| t&.alive? }
|
113
|
+
end
|
114
|
+
|
115
|
+
def boot_worker
|
116
|
+
debug '%s: Booting worker...', pid_str
|
117
|
+
|
118
|
+
Thread.new do
|
119
|
+
Worker.new(
|
120
|
+
config, queue,
|
121
|
+
serializers: @serializers,
|
122
|
+
filters: @filters
|
123
|
+
).work_forever
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# rubocop:disable Metrics/MethodLength
|
128
|
+
def stop_workers
|
129
|
+
debug '%s: Stopping workers', pid_str
|
130
|
+
|
131
|
+
send_stop_messages
|
132
|
+
|
133
|
+
@worker_mutex.synchronize do
|
134
|
+
workers.each do |thread|
|
135
|
+
next if thread.nil?
|
136
|
+
next if thread.join(WORKER_JOIN_TIMEOUT)
|
137
|
+
|
138
|
+
debug(
|
139
|
+
'%s: Worker did not stop in %ds, killing...',
|
140
|
+
pid_str, WORKER_JOIN_TIMEOUT
|
141
|
+
)
|
142
|
+
thread.kill
|
143
|
+
end
|
144
|
+
|
145
|
+
@workers.clear
|
146
|
+
end
|
147
|
+
end
|
148
|
+
# rubocop:enable Metrics/MethodLength
|
149
|
+
|
150
|
+
def send_stop_messages
|
151
|
+
config.pool_size.times { queue.push(Worker::StopMessage.new, true) }
|
152
|
+
rescue ThreadError
|
153
|
+
warn 'Cannot push stop messages to worker queue as it is full'
|
154
|
+
end
|
155
|
+
|
156
|
+
def stop_watcher
|
157
|
+
@watcher_mutex.synchronize do
|
158
|
+
return if watcher.nil? || @pid != Process.pid
|
159
|
+
watcher.shutdown
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def throttled_queue_full_warning
|
164
|
+
(@queue_full_log ||= Util::Throttle.new(5) do
|
165
|
+
warn(
|
166
|
+
'%s: Queue is full (%i items), skipping…',
|
167
|
+
pid_str, config.api_buffer_size
|
168
|
+
)
|
169
|
+
end).call
|
170
|
+
end
|
171
|
+
end
|
172
|
+
# rubocop:enable Metrics/ClassLength
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent'
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
require 'atatus/transport/connection/http'
|
7
|
+
|
8
|
+
module Atatus
|
9
|
+
module Transport
|
10
|
+
# rubocop:disable Metrics/ClassLength
|
11
|
+
# @api private
|
12
|
+
class Connection
|
13
|
+
include Logging
|
14
|
+
|
15
|
+
# A connection holds an instance `http` of an Http::Connection.
|
16
|
+
#
|
17
|
+
# The HTTP::Connection itself is not thread safe.
|
18
|
+
#
|
19
|
+
# The connection sends write requests and close requests to `http`, and
|
20
|
+
# has to ensure no write requests are sent after closing `http`.
|
21
|
+
#
|
22
|
+
# The connection schedules a separate thread to close an `http`
|
23
|
+
# connection some time in the future. To avoid the thread interfering
|
24
|
+
# with ongoing write requests to `http`, write and close
|
25
|
+
# requests have to be synchronized.
|
26
|
+
|
27
|
+
HEADERS = {
|
28
|
+
'Content-Type' => 'application/x-ndjson',
|
29
|
+
'Transfer-Encoding' => 'chunked'
|
30
|
+
}.freeze
|
31
|
+
GZIP_HEADERS = HEADERS.merge(
|
32
|
+
'Content-Encoding' => 'gzip'
|
33
|
+
).freeze
|
34
|
+
|
35
|
+
def initialize(config, metadata)
|
36
|
+
@config = config
|
37
|
+
@headers = build_headers(metadata)
|
38
|
+
@metadata = JSON.fast_generate(metadata)
|
39
|
+
@url = config.server_url + '/intake/v2/events'
|
40
|
+
@ssl_context = build_ssl_context
|
41
|
+
@mutex = Mutex.new
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :http
|
45
|
+
|
46
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
47
|
+
def write(str)
|
48
|
+
return false if @config.disable_send
|
49
|
+
|
50
|
+
begin
|
51
|
+
bytes_written = 0
|
52
|
+
|
53
|
+
# The request might get closed from timertask so let's make sure we
|
54
|
+
# hold it open until we've written.
|
55
|
+
@mutex.synchronize do
|
56
|
+
connect if http.nil? || http.closed?
|
57
|
+
bytes_written = http.write(str)
|
58
|
+
end
|
59
|
+
|
60
|
+
flush(:api_request_size) if bytes_written >= @config.api_request_size
|
61
|
+
rescue IOError => e
|
62
|
+
error('Connection error: %s', e.inspect)
|
63
|
+
flush(:ioerror)
|
64
|
+
rescue Errno::EPIPE => e
|
65
|
+
error('Connection error: %s', e.inspect)
|
66
|
+
flush(:broken_pipe)
|
67
|
+
rescue Exception => e
|
68
|
+
error('Connection error: %s', e.inspect)
|
69
|
+
flush(:connection_error)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
73
|
+
|
74
|
+
def flush(reason = :force)
|
75
|
+
# Could happen from the timertask so we need to sync
|
76
|
+
@mutex.synchronize do
|
77
|
+
return if http.nil?
|
78
|
+
http.close(reason)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
format(
|
84
|
+
'@%s http connection closed? :%s>',
|
85
|
+
super.split.first,
|
86
|
+
http.closed?
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def connect
|
93
|
+
schedule_closing if @config.api_request_time
|
94
|
+
|
95
|
+
@http =
|
96
|
+
Http.open(
|
97
|
+
@config, @url,
|
98
|
+
headers: @headers,
|
99
|
+
ssl_context: @ssl_context
|
100
|
+
).tap { |http| http.write(@metadata) }
|
101
|
+
end
|
102
|
+
# rubocop:enable
|
103
|
+
|
104
|
+
def schedule_closing
|
105
|
+
@close_task&.cancel
|
106
|
+
@close_task =
|
107
|
+
Concurrent::ScheduledTask.execute(@config.api_request_time) do
|
108
|
+
flush(:timeout)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_headers(metadata)
|
113
|
+
(
|
114
|
+
@config.http_compression? ? GZIP_HEADERS : HEADERS
|
115
|
+
).dup.tap do |headers|
|
116
|
+
headers['User-Agent'] = build_user_agent(metadata)
|
117
|
+
|
118
|
+
if (token = @config.secret_token)
|
119
|
+
headers['Authorization'] = "Bearer #{token}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def build_user_agent(metadata)
|
125
|
+
runtime = metadata.dig(:metadata, :service, :runtime)
|
126
|
+
|
127
|
+
[
|
128
|
+
"atatus-ruby/#{VERSION}",
|
129
|
+
HTTP::Request::USER_AGENT,
|
130
|
+
[runtime[:name], runtime[:version]].join('/')
|
131
|
+
].join(' ')
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_ssl_context # rubocop:disable Metrics/MethodLength
|
135
|
+
return unless @config.use_ssl?
|
136
|
+
|
137
|
+
OpenSSL::SSL::SSLContext.new.tap do |context|
|
138
|
+
if @config.server_ca_cert
|
139
|
+
context.ca_file = @config.server_ca_cert
|
140
|
+
else
|
141
|
+
context.cert_store =
|
142
|
+
OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
143
|
+
end
|
144
|
+
|
145
|
+
context.verify_mode =
|
146
|
+
if @config.verify_server_cert
|
147
|
+
OpenSSL::SSL::VERIFY_PEER
|
148
|
+
else
|
149
|
+
OpenSSL::SSL::VERIFY_NONE
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# rubocop:enable Metrics/ClassLength
|
155
|
+
end
|
156
|
+
end
|