baseline_red_rpm 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/lib/baseline_red_rpm.rb +164 -0
- data/lib/baseline_red_rpm/backtrace.rb +117 -0
- data/lib/baseline_red_rpm/configuration.rb +63 -0
- data/lib/baseline_red_rpm/instrumentation.rb +23 -0
- data/lib/baseline_red_rpm/instruments/action_controller.rb +70 -0
- data/lib/baseline_red_rpm/instruments/action_view.rb +222 -0
- data/lib/baseline_red_rpm/instruments/active_model_serializer.rb +37 -0
- data/lib/baseline_red_rpm/instruments/active_record.rb +66 -0
- data/lib/baseline_red_rpm/instruments/active_record/adapters/mysql2.rb +55 -0
- data/lib/baseline_red_rpm/instruments/active_record/adapters/postgresql.rb +143 -0
- data/lib/baseline_red_rpm/instruments/active_record/adapters/sqlite3.rb +142 -0
- data/lib/baseline_red_rpm/instruments/activerecord_import.rb +57 -0
- data/lib/baseline_red_rpm/instruments/emque_consuming.rb +41 -0
- data/lib/baseline_red_rpm/instruments/faraday.rb +48 -0
- data/lib/baseline_red_rpm/instruments/grape.rb +63 -0
- data/lib/baseline_red_rpm/instruments/net_http.rb +43 -0
- data/lib/baseline_red_rpm/instruments/rack.rb +129 -0
- data/lib/baseline_red_rpm/instruments/redis.rb +75 -0
- data/lib/baseline_red_rpm/instruments/roda.rb +48 -0
- data/lib/baseline_red_rpm/instruments/sequel.rb +100 -0
- data/lib/baseline_red_rpm/instruments/sidekiq.rb +100 -0
- data/lib/baseline_red_rpm/instruments/sinatra.rb +82 -0
- data/lib/baseline_red_rpm/instruments/typhoeus.rb +74 -0
- data/lib/baseline_red_rpm/introspector.rb +53 -0
- data/lib/baseline_red_rpm/logger.rb +34 -0
- data/lib/baseline_red_rpm/rails.rb +15 -0
- data/lib/baseline_red_rpm/railtie.rb +19 -0
- data/lib/baseline_red_rpm/reporters/json_client.rb +69 -0
- data/lib/baseline_red_rpm/reporters/null_client.rb +16 -0
- data/lib/baseline_red_rpm/tracer.rb +75 -0
- data/lib/baseline_red_rpm/tracing/buffer.rb +27 -0
- data/lib/baseline_red_rpm/tracing/carrier.rb +25 -0
- data/lib/baseline_red_rpm/tracing/collector.rb +33 -0
- data/lib/baseline_red_rpm/tracing/endpoint.rb +21 -0
- data/lib/baseline_red_rpm/tracing/managed_span.rb +40 -0
- data/lib/baseline_red_rpm/tracing/managed_tracer.rb +36 -0
- data/lib/baseline_red_rpm/tracing/span.rb +72 -0
- data/lib/baseline_red_rpm/tracing/span_context.rb +43 -0
- data/lib/baseline_red_rpm/tracing/thread_span_stack.rb +34 -0
- data/lib/baseline_red_rpm/tracing/trace_id.rb +13 -0
- data/lib/baseline_red_rpm/tracing/tracer.rb +100 -0
- data/lib/baseline_red_rpm/utils.rb +45 -0
- data/lib/tasks/install.rake +6 -0
- metadata +212 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
class Introspector
|
5
|
+
|
6
|
+
VALID_RUNNERS = [
|
7
|
+
:PhusionPassenger,
|
8
|
+
:Puma,
|
9
|
+
:Rainbows,
|
10
|
+
:Resque,
|
11
|
+
:Sidekiq,
|
12
|
+
:Sinatra,
|
13
|
+
:Unicorn,
|
14
|
+
:Webrick
|
15
|
+
]
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def agentable?
|
19
|
+
if raking? || rspecing?
|
20
|
+
BaselineRedRpm.logger.info("Detected rake, not initializing agent")
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
BaselineRedRpm.logger.info("Detecting runner...")
|
24
|
+
VALID_RUNNERS.each do |runner|
|
25
|
+
if const_defined?(runner.to_s)
|
26
|
+
BaselineRedRpm.logger.info("#{runner} detected. You're valid")
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
BaselineRedRpm.logger.info("No valid runner detected!")
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def rspecing?
|
35
|
+
(File.basename($0) =~ /\Arspec/) == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def raking?
|
39
|
+
(File.basename($0) =~ /\Arake/) == 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def const_defined?(string_const)
|
43
|
+
begin
|
44
|
+
Object.const_get(string_const)
|
45
|
+
true
|
46
|
+
rescue NameError
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module BaselineRedRpm
|
6
|
+
class << self
|
7
|
+
attr_accessor :logger
|
8
|
+
end
|
9
|
+
|
10
|
+
class Logger
|
11
|
+
def info(msg)
|
12
|
+
BaselineRedRpm.info(msg)
|
13
|
+
end
|
14
|
+
|
15
|
+
def debug(msg)
|
16
|
+
BaselineRedRpm.info(msg)
|
17
|
+
end
|
18
|
+
|
19
|
+
def warn(msg)
|
20
|
+
BaselineRedRpm.info(msg)
|
21
|
+
end
|
22
|
+
|
23
|
+
def error(msg)
|
24
|
+
BaselineRedRpm.info(msg)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fatal(msg)
|
28
|
+
BaselineRedRpm.info(msg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
BaselineRedRpm.logger = Logger.new(STDERR)
|
34
|
+
BaselineRedRpm.logger.level = Logger::INFO
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(::Rails)
|
4
|
+
if ::Rails::VERSION::MAJOR > 2
|
5
|
+
require 'baseline_red_rpm/railtie'
|
6
|
+
else
|
7
|
+
Rails.configuration.after_initialize do
|
8
|
+
unless BaselineRedRpm.disable_agent?
|
9
|
+
BaselineRedRpm.load
|
10
|
+
BaselineRedRpm.logger.info "Initializing rack middleware tracer."
|
11
|
+
Rails.configuration.middleware.insert 0, BaselineRedRpm::Instruments::Rack
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
initializer "baseline_red.initialize" do |app|
|
6
|
+
unless BaselineRedRpm.disable_agent?
|
7
|
+
require 'baseline_red_rpm/instruments/rack'
|
8
|
+
BaselineRedRpm.logger.info "Initializing rack middleware tracer."
|
9
|
+
app.middleware.insert 0, BaselineRedRpm::Instruments::Rack
|
10
|
+
end
|
11
|
+
|
12
|
+
config.after_initialize do
|
13
|
+
BaselineRedRpm.config.app_root = Rails.root
|
14
|
+
BaselineRedRpm.config.reload
|
15
|
+
BaselineRedRpm.load
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
module BaselineRedRpm
|
8
|
+
module Reporters
|
9
|
+
class JsonClient
|
10
|
+
def initialize(opts = { :url => nil, :collector => nil, :flush_interval => nil })
|
11
|
+
@collector = opts[:collector]
|
12
|
+
@flush_interval = opts[:flush_interval]
|
13
|
+
@spans_uri = URI.parse(opts[:url])
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@thread = Thread.new do
|
18
|
+
loop do
|
19
|
+
emit_batch(@collector.retrieve)
|
20
|
+
sleep @flush_interval
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop
|
26
|
+
@thread.terminate if @thread
|
27
|
+
emit_batch(@collector.retrieve)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def compress_body(data)
|
33
|
+
body = MessagePack.pack({
|
34
|
+
"name" => BaselineRedRpm.config.application_name,
|
35
|
+
"host" => BaselineRedRpm.host,
|
36
|
+
"data" => data
|
37
|
+
})
|
38
|
+
|
39
|
+
compressed_body = Zlib::Deflate.deflate(body, Zlib::DEFAULT_COMPRESSION)
|
40
|
+
Base64.encode64(compressed_body)
|
41
|
+
end
|
42
|
+
|
43
|
+
def emit_batch(spans)
|
44
|
+
return if spans.empty?
|
45
|
+
|
46
|
+
sock = Net::HTTP.new(@spans_uri.host, @spans_uri.port)
|
47
|
+
sock.use_ssl = ::BaselineRedRpm.config.ssl
|
48
|
+
|
49
|
+
request = Net::HTTP::Post.new(@spans_uri.request_uri, {
|
50
|
+
"Accept-Encoding" => "gzip",
|
51
|
+
"User-Agent" => "gzip"
|
52
|
+
})
|
53
|
+
request.body = compress_body(spans)
|
54
|
+
request.content_type = "application/octet-stream"
|
55
|
+
|
56
|
+
response = sock.start do |http|
|
57
|
+
http.read_timeout = 30
|
58
|
+
http.request(request)
|
59
|
+
end
|
60
|
+
|
61
|
+
if response.code != 202
|
62
|
+
STDERR.puts(response.body)
|
63
|
+
end
|
64
|
+
rescue => e
|
65
|
+
STDERR.puts("Error emitting spans batch: #{e.message}\n#{e.backtrace.join("\n")}")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
class Tracer
|
5
|
+
class << self
|
6
|
+
# This method should be called by any components that are
|
7
|
+
# capable of starting the tracing process.
|
8
|
+
# ie. rack, sidekiq worker, etc
|
9
|
+
def sample!(incoming_trace = nil, force = false)
|
10
|
+
# Since we keep track of the active span, meaning we have entered into
|
11
|
+
# tracing at some point, and we no longer have an active span,
|
12
|
+
# reset tracing.
|
13
|
+
sample_off! if !BaselineRedRpm.tracer.active_span
|
14
|
+
|
15
|
+
# Now determine if we want to trace, either by an incoming
|
16
|
+
# trace or meeting the sample rate.
|
17
|
+
Thread.current[:sample] = force || !!incoming_trace || should_sample?
|
18
|
+
Thread.current[:sample]
|
19
|
+
end
|
20
|
+
|
21
|
+
def sample_off!
|
22
|
+
Thread.current[:sample] = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def sampled?
|
26
|
+
!!Thread.current[:sample]
|
27
|
+
end
|
28
|
+
|
29
|
+
def tracing?
|
30
|
+
BaselineRedRpm.tracing? && sampled?
|
31
|
+
end
|
32
|
+
|
33
|
+
def random_percentage
|
34
|
+
rand * 100
|
35
|
+
end
|
36
|
+
|
37
|
+
def should_sample?
|
38
|
+
random_percentage <= ::BaselineRedRpm.config.sample_rate.to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def profile(layer, opts = {})
|
42
|
+
if defined?(TracePoint)
|
43
|
+
@times = {}
|
44
|
+
traces = []
|
45
|
+
tracer = TracePoint.new(:call, :return) do |tp|
|
46
|
+
backtrace = caller(0)
|
47
|
+
key = "#{tp.defined_class}_#{tp.method_id}_#{backtrace.size}"
|
48
|
+
if tp.event == :call
|
49
|
+
@times[key] = Time.now.to_f
|
50
|
+
else
|
51
|
+
if @times[key]
|
52
|
+
@times[key] = Time.now.to_f - @times[key].to_f
|
53
|
+
traces << {
|
54
|
+
"duration "=> @times[key].to_f,
|
55
|
+
"class" => tp.defined_class,
|
56
|
+
"method" => tp.method_id,
|
57
|
+
"backtrace" => backtrace,
|
58
|
+
"line" => ::BaselineRedRpm::Backtrace.send(:clean_line, tp.path),
|
59
|
+
"line_number" => tp.lineno
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
result = tracer.enable { yield }
|
66
|
+
@times = {}
|
67
|
+
|
68
|
+
return traces, result
|
69
|
+
else
|
70
|
+
return [], yield
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
module Tracing
|
5
|
+
class Buffer
|
6
|
+
def initialize
|
7
|
+
@buffer = []
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(element)
|
12
|
+
@mutex.synchronize do
|
13
|
+
@buffer << element
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def retrieve
|
19
|
+
@mutex.synchronize do
|
20
|
+
elements = @buffer.dup
|
21
|
+
@buffer.clear
|
22
|
+
elements
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
module Tracing
|
5
|
+
class Carrier
|
6
|
+
def initialize
|
7
|
+
@data = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
@data[key]
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(key, value)
|
15
|
+
@data[key] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
@data.each do |datum|
|
20
|
+
yield(datum)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
module Tracing
|
5
|
+
class Collector
|
6
|
+
attr_reader :buffer
|
7
|
+
|
8
|
+
def initialize(local_endpoint)
|
9
|
+
@buffer = Buffer.new
|
10
|
+
@local_endpoint = local_endpoint
|
11
|
+
end
|
12
|
+
|
13
|
+
def retrieve
|
14
|
+
@buffer.retrieve
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_span(span, end_time)
|
18
|
+
duration = end_time - span.start_time
|
19
|
+
|
20
|
+
@buffer << {
|
21
|
+
"traceId" => span.context.trace_id,
|
22
|
+
"id" => span.context.span_id,
|
23
|
+
"parentId" => span.context.parent_id,
|
24
|
+
"name" => span.operation_name,
|
25
|
+
"timestamp" => span.start_time,
|
26
|
+
"duration" => duration * 1_000,
|
27
|
+
"logEntries" => span.log_entries,
|
28
|
+
"tags" => span.tags
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module BaselineRedRpm
|
6
|
+
module Tracing
|
7
|
+
class Endpoint
|
8
|
+
LOCAL_IP = (
|
9
|
+
Socket.ip_address_list.detect(&:ipv4_private?) ||
|
10
|
+
Socket.ip_address_list.reverse.detect(&:ipv4?)
|
11
|
+
).ip_address
|
12
|
+
|
13
|
+
def self.local_endpoint(service_name)
|
14
|
+
{
|
15
|
+
"serviceName" => service_name,
|
16
|
+
"ipv4" => LOCAL_IP
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
module Tracing
|
5
|
+
class ManagedSpan < Span
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@span, :context, :operation_name=, :set_tag, :set_baggage_item, :get_baggage_item, :log, :finish
|
9
|
+
|
10
|
+
def initialize(span, deactivate)
|
11
|
+
@span = span
|
12
|
+
@deactivate = deactivate.respond_to?(:call) ? deactivate : nil
|
13
|
+
@active = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def wrapped
|
17
|
+
@span
|
18
|
+
end
|
19
|
+
|
20
|
+
def active?
|
21
|
+
@active
|
22
|
+
end
|
23
|
+
|
24
|
+
def deactivate
|
25
|
+
if @active && @deactivate
|
26
|
+
deactivated_span = @deactivate.call
|
27
|
+
warn "ActiveSpan::SpanSource inconsistency found during deactivation" unless deactivated_span == self
|
28
|
+
@active = false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def finish(opts = {})
|
33
|
+
opts[:end_time] ||= BaselineRedRpm.now
|
34
|
+
|
35
|
+
deactivate
|
36
|
+
@span.finish(end_time: opts[:end_time])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaselineRedRpm
|
4
|
+
module Tracing
|
5
|
+
class ManagedTracer
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@tracer, :inject, :extract
|
8
|
+
|
9
|
+
attr_reader :thread_span_stack
|
10
|
+
|
11
|
+
def initialize(tracer, thread_span_stack = ThreadSpanStack.new)
|
12
|
+
@tracer = tracer
|
13
|
+
@thread_span_stack = thread_span_stack
|
14
|
+
end
|
15
|
+
|
16
|
+
def wrapped
|
17
|
+
@tracer
|
18
|
+
end
|
19
|
+
|
20
|
+
def collector
|
21
|
+
@tracer.collector
|
22
|
+
end
|
23
|
+
|
24
|
+
def active_span
|
25
|
+
thread_span_stack.active_span
|
26
|
+
end
|
27
|
+
|
28
|
+
def start_span(operation_name, opts = {}, *args)
|
29
|
+
opts[:child_of] ||= active_span
|
30
|
+
|
31
|
+
span = @tracer.start_span(operation_name, opts, *args)
|
32
|
+
@thread_span_stack.set_active_span(span)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|