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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/lib/baseline_red_rpm.rb +164 -0
  3. data/lib/baseline_red_rpm/backtrace.rb +117 -0
  4. data/lib/baseline_red_rpm/configuration.rb +63 -0
  5. data/lib/baseline_red_rpm/instrumentation.rb +23 -0
  6. data/lib/baseline_red_rpm/instruments/action_controller.rb +70 -0
  7. data/lib/baseline_red_rpm/instruments/action_view.rb +222 -0
  8. data/lib/baseline_red_rpm/instruments/active_model_serializer.rb +37 -0
  9. data/lib/baseline_red_rpm/instruments/active_record.rb +66 -0
  10. data/lib/baseline_red_rpm/instruments/active_record/adapters/mysql2.rb +55 -0
  11. data/lib/baseline_red_rpm/instruments/active_record/adapters/postgresql.rb +143 -0
  12. data/lib/baseline_red_rpm/instruments/active_record/adapters/sqlite3.rb +142 -0
  13. data/lib/baseline_red_rpm/instruments/activerecord_import.rb +57 -0
  14. data/lib/baseline_red_rpm/instruments/emque_consuming.rb +41 -0
  15. data/lib/baseline_red_rpm/instruments/faraday.rb +48 -0
  16. data/lib/baseline_red_rpm/instruments/grape.rb +63 -0
  17. data/lib/baseline_red_rpm/instruments/net_http.rb +43 -0
  18. data/lib/baseline_red_rpm/instruments/rack.rb +129 -0
  19. data/lib/baseline_red_rpm/instruments/redis.rb +75 -0
  20. data/lib/baseline_red_rpm/instruments/roda.rb +48 -0
  21. data/lib/baseline_red_rpm/instruments/sequel.rb +100 -0
  22. data/lib/baseline_red_rpm/instruments/sidekiq.rb +100 -0
  23. data/lib/baseline_red_rpm/instruments/sinatra.rb +82 -0
  24. data/lib/baseline_red_rpm/instruments/typhoeus.rb +74 -0
  25. data/lib/baseline_red_rpm/introspector.rb +53 -0
  26. data/lib/baseline_red_rpm/logger.rb +34 -0
  27. data/lib/baseline_red_rpm/rails.rb +15 -0
  28. data/lib/baseline_red_rpm/railtie.rb +19 -0
  29. data/lib/baseline_red_rpm/reporters/json_client.rb +69 -0
  30. data/lib/baseline_red_rpm/reporters/null_client.rb +16 -0
  31. data/lib/baseline_red_rpm/tracer.rb +75 -0
  32. data/lib/baseline_red_rpm/tracing/buffer.rb +27 -0
  33. data/lib/baseline_red_rpm/tracing/carrier.rb +25 -0
  34. data/lib/baseline_red_rpm/tracing/collector.rb +33 -0
  35. data/lib/baseline_red_rpm/tracing/endpoint.rb +21 -0
  36. data/lib/baseline_red_rpm/tracing/managed_span.rb +40 -0
  37. data/lib/baseline_red_rpm/tracing/managed_tracer.rb +36 -0
  38. data/lib/baseline_red_rpm/tracing/span.rb +72 -0
  39. data/lib/baseline_red_rpm/tracing/span_context.rb +43 -0
  40. data/lib/baseline_red_rpm/tracing/thread_span_stack.rb +34 -0
  41. data/lib/baseline_red_rpm/tracing/trace_id.rb +13 -0
  42. data/lib/baseline_red_rpm/tracing/tracer.rb +100 -0
  43. data/lib/baseline_red_rpm/utils.rb +45 -0
  44. data/lib/tasks/install.rake +6 -0
  45. metadata +212 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f48e985c64b6fe5ef0768cd698bdff34087adaf
4
+ data.tar.gz: 616121b88979893ded3bdc189d275621aee00f34
5
+ SHA512:
6
+ metadata.gz: 472252bfc20315849876f30e1c9cff7a7916f53ffa0ffa300812344215168733ba4044d02127870ae0730f0568ef2a69f5eae0baa1c290c46ee71777ac1c9fc5
7
+ data.tar.gz: f1460dd9d695924e8ffcc177ba4ac96962dac1f73f2ea77e5a5378a551d7947be8bb6672c22053e80fbb0c5d921868a732ed29580c48fcc14128a57843a7fdf1
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaselineRedRpm
4
+ require "opentracing"
5
+ require 'msgpack'
6
+
7
+ require 'baseline_red_rpm/logger'
8
+ require 'baseline_red_rpm/configuration'
9
+ require 'baseline_red_rpm/backtrace'
10
+
11
+ require 'baseline_red_rpm/reporters/json_client'
12
+ require 'baseline_red_rpm/reporters/null_client'
13
+
14
+ require 'baseline_red_rpm/tracing/buffer'
15
+ require 'baseline_red_rpm/tracing/carrier'
16
+ require 'baseline_red_rpm/tracing/collector'
17
+ require 'baseline_red_rpm/tracing/endpoint'
18
+ require 'baseline_red_rpm/tracing/trace_id'
19
+ require 'baseline_red_rpm/tracing/span_context'
20
+ require 'baseline_red_rpm/tracing/span'
21
+ require 'baseline_red_rpm/tracing/managed_span'
22
+ require 'baseline_red_rpm/tracing/tracer'
23
+ require 'baseline_red_rpm/tracing/managed_tracer'
24
+ require 'baseline_red_rpm/tracing/thread_span_stack'
25
+
26
+ require 'baseline_red_rpm/tracer'
27
+ require 'baseline_red_rpm/utils'
28
+ require 'baseline_red_rpm/instrumentation'
29
+ require 'baseline_red_rpm/rails'
30
+ require 'baseline_red_rpm/introspector'
31
+
32
+ TRACE_CONTEXT_KEY = 'BaselineRed-Trace-Context'
33
+
34
+ class << self
35
+
36
+ attr_writer :config
37
+
38
+ def config
39
+ @config ||= Configuration.new
40
+ end
41
+
42
+ def configure
43
+ yield(config)
44
+ end
45
+
46
+ def load
47
+ #Oj.mimic_JSON
48
+ unless disable_agent?
49
+ BaselineRedRpm::Instrumentation.load
50
+ BaselineRedRpm.tracing_on
51
+ end
52
+ end
53
+
54
+ def mutex
55
+ @mutex ||= Mutex.new
56
+ end
57
+
58
+ def endpoint
59
+ @endpoint ||= BaselineRedRpm::Tracing::Endpoint.local_endpoint(config.application_name)
60
+ end
61
+
62
+ def collector
63
+ @collector ||= BaselineRedRpm::Tracing::Collector.new(endpoint)
64
+ end
65
+
66
+ def url
67
+ @url ||= "#{config.host}/api/listener/3/#{config.license_key}"
68
+ end
69
+
70
+ def sender
71
+ @sender ||= BaselineRedRpm::Reporters::JsonClient.new(
72
+ url: url,
73
+ collector: collector,
74
+ flush_interval: config.flush_interval
75
+ )
76
+ end
77
+
78
+ def tracer
79
+ @tracer ||= BaselineRedRpm::Tracing::ManagedTracer.new(
80
+ BaselineRedRpm::Tracing::Tracer.build(
81
+ :service_name => config.application_name,
82
+ :sender => sender,
83
+ :collector => collector
84
+ ),
85
+ BaselineRedRpm::Tracing::ThreadSpanStack.new
86
+ )
87
+ end
88
+
89
+ def tracing_on
90
+ if @without_tracing_enabled
91
+ BaselineRedRpm.logger.debug "Not turning tracing on due to without tracing mode."
92
+ return
93
+ end
94
+ mutex.synchronize do
95
+ BaselineRedRpm.logger.debug "Enabling tracing."
96
+ @tracing = true
97
+ end
98
+ end
99
+
100
+ def tracing_off
101
+ mutex.synchronize do
102
+ BaselineRedRpm.logger.debug "Disabling tracing."
103
+ @tracing = false
104
+ end
105
+ end
106
+
107
+ def tracing?
108
+ !!@tracing
109
+ end
110
+
111
+ def without_tracing
112
+ @previously_tracing = BaselineRedRpm.tracing?
113
+ @without_tracing_enabled = true
114
+ BaselineRedRpm.tracing_off
115
+ yield if block_given?
116
+ @without_tracing_enabled = false
117
+ ensure
118
+ BaselineRedRpm.tracing_on if @previously_tracing
119
+ end
120
+
121
+ def host
122
+ @host ||= Socket.gethostname
123
+ end
124
+
125
+ def round_time(t, sec = 1)
126
+ t = Time.parse(t.to_s)
127
+
128
+ down = t - (t.to_i % sec)
129
+ up = down + sec
130
+
131
+ difference_down = t - down
132
+ difference_up = up - t
133
+
134
+ if (difference_down < difference_up)
135
+ return down
136
+ else
137
+ return up
138
+ end
139
+ end
140
+
141
+ def floor_time(t, sec = 1)
142
+ Time.at((t.to_f / sec).floor * sec)
143
+ end
144
+
145
+ def disable_agent?
146
+ if config.agent_disabled
147
+ true
148
+ elsif Introspector.agentable?
149
+ false
150
+ else
151
+ true
152
+ end
153
+ end
154
+
155
+ def now
156
+ if defined?(Process::CLOCK_REALTIME)
157
+ Process.clock_gettime(Process::CLOCK_REALTIME)
158
+ else
159
+ Time.now
160
+ end
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaselineRedRpm
4
+ class Backtrace
5
+ class << self
6
+ def backtrace(opts = {})
7
+ kind = opts[:kind]
8
+
9
+ if kind
10
+ bt = Kernel.caller
11
+ bt = clean(bt)
12
+ bt = filter(bt, kind)
13
+ trim_backtrace(bt)
14
+ end
15
+ end
16
+
17
+ def clean(backtrace)
18
+ Array(backtrace)
19
+ .map {|b| clean_line(b) }
20
+ .select {|b| b !~ %r{lib/baseline_red_rpm} }
21
+ end
22
+
23
+ def filter(backtrace, kind)
24
+ case kind
25
+ when :all
26
+ backtrace
27
+ when :app
28
+ backtrace.select {|b| b =~ /\[APP_PATH\]/ }
29
+ when :gem
30
+ backtrace.select {|b| b =~ /\[GEM_PATH\]/ }
31
+ else
32
+ []
33
+ end
34
+ end
35
+
36
+ #def source_extract(_backtrace = Kernel.caller(2))
37
+ # if(trace = _backtrace.first)
38
+ # file, line_number = extract_file_and_line_number(trace)
39
+
40
+ # {
41
+ # code: source_fragment(file, line_number),
42
+ # line_number: line_number
43
+ # }
44
+ # else
45
+ # nil
46
+ # end
47
+ #end
48
+
49
+ def source_extract(opts = {})
50
+ backtrace = opts[:backtrace] || Kernel.caller(0)
51
+
52
+ Array(backtrace).select {|bt| bt[/^#{::BaselineRedRpm.config.app_root.to_s}\//] }.map do |trace|
53
+ file, line_number = extract_file_and_line_number(trace)
54
+ source_to_hash(file, line_number)
55
+ end
56
+ end
57
+
58
+ def source_to_hash(file, line_number)
59
+ {
60
+ "file" => clean_line(file),
61
+ "code" => source_fragment(file, line_number),
62
+ "line_number" => line_number
63
+ }
64
+ end
65
+
66
+ def clean_line(line)
67
+ line
68
+ .sub(/#{::BaselineRedRpm.config.app_root.to_s}\//, "[APP_PATH]/")
69
+ .sub(gems_regexp, '\2 (\3) [GEM_PATH]/\4')
70
+ end
71
+
72
+ private
73
+
74
+ def gems_regexp
75
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
76
+ if gems_paths
77
+ %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
78
+ else
79
+ nil
80
+ end
81
+ end
82
+
83
+ def source_fragment(path, line)
84
+ return unless BaselineRedRpm.config.app_root
85
+ full_path = BaselineRedRpm.config.app_root.join(path)
86
+ if File.exist?(full_path)
87
+ File.open(full_path, "r") do |file|
88
+ start = [line - 3, 0].max
89
+ lines = file.each_line.drop(start).take(6)
90
+ Hash[*(start + 1..(lines.count + start)).zip(lines).flatten]
91
+ end
92
+ end
93
+ end
94
+
95
+ def extract_file_and_line_number(trace)
96
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
97
+ [file, line.to_i]
98
+ end
99
+
100
+ def trim_backtrace(_backtrace, opts = {})
101
+ kind = opts[:kind]
102
+
103
+ return _backtrace unless _backtrace.is_a?(Array)
104
+
105
+ length = _backtrace.size
106
+ if length > 80
107
+ trimmed = _backtrace[0, 80]
108
+ trimmed += ['...[snip]...']
109
+ trimmed += _backtrace[length - 20, 20]
110
+ else
111
+ trimmed = _backtrace
112
+ end
113
+ trimmed
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module BaselineRedRpm
6
+ class Configuration
7
+ attr_accessor :app_root,
8
+ :host,
9
+ :port,
10
+ :license_key,
11
+ :ssl,
12
+ :sample_rate,
13
+ :sample_threshold,
14
+ :flush_interval,
15
+ :application_name,
16
+ :instrumentation,
17
+ :agent_disabled,
18
+ :ignore_paths
19
+
20
+ def initialize
21
+ reload
22
+ end
23
+
24
+ def reload
25
+ ::BaselineRedRpm.mutex.synchronize do
26
+ self.app_root = app_root ? Pathname.new(app_root.to_s) : nil
27
+ self.host ||= default_if_blank(ENV["BASELINE_RED_HOST"], "http://localhost:5000")
28
+ self.ssl ||= default_if_blank(ENV["BASELINE_RED_SSL"], false)
29
+ self.license_key ||= default_if_blank(ENV["BASELINE_RED_LICENSE_KEY"], nil)
30
+ self.application_name ||= "Default"
31
+ self.sample_rate ||= 10 # Percentage of request to sample
32
+ self.sample_threshold ||= 0 # Minimum amount of duration to sample
33
+ self.flush_interval ||= 60 # In seconds
34
+ self.agent_disabled ||= default_if_blank(ENV["BASELINE_RED_AGENT_DISABLED"], false)
35
+ self.ignore_paths ||= /\/assets/
36
+ self.instrumentation = {
37
+ :rack => { :enabled => true, :backtrace => :app, :source => true, :trace_middleware => false },
38
+ :roda => { :enabled => true, :backtrace => :app, :source => true },
39
+ :grape => { :enabled => true, :backtrace => :app, :source => true },
40
+ :active_record => { :enabled => true, :backtrace => :app, :source => true },
41
+ :active_record_import => { :enabled => true, :backtrace => :app, :source => true },
42
+ :active_model_serializer => { :enabled => true, :backtrace => :app, :source => true },
43
+ :action_view => { :enabled => true, :backtrace => :app, :source => true },
44
+ :action_controller => { :enabled => true, :backtrace => :app, :source => true },
45
+ :emque_consuming => { :enabled => true, :backtrace => :app, :source => true },
46
+ :redis => { :enabled => true, :backtrace => :app, :source => true },
47
+ :sequel => { :enabled => true, :backtrace => :app, :source => true },
48
+ :sidekiq => { :enabled => true, :backtrace => :app, :source => true },
49
+ :sinatra => { :enabled => true, :backtrace => :app, :source => true },
50
+ :net_http => { :enabled => true, :backtrace => :app, :source => true },
51
+ :typhoeus => { :enabled => true, :backtrace => :app, :source => true },
52
+ :faraday => { :enabled => true, :backtrace => :app, :source => true }
53
+ }
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def default_if_blank(value, default)
60
+ value.nil? || value.blank? ? default : value
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaselineRedRpm
4
+ class Instrumentation
5
+ class << self
6
+ def load
7
+ pattern = File.join(File.dirname(__FILE__), 'instruments', '**', '*.rb')
8
+ Dir.glob(pattern) do |f|
9
+ begin
10
+ require f
11
+ rescue => e
12
+ BaselineRedRpm.logger.error "Error loading instrumentation file '#{f}' : #{e}"
13
+ BaselineRedRpm.logger.error "#{e.backtrace[0..10]}"
14
+ end
15
+ end
16
+
17
+ if defined? Rails::Railtie
18
+ require "baseline_red_rpm/railtie"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaselineRedRpm
4
+ module Instruments
5
+ module ActionController
6
+ def process_action_with_trace(method_name, *args)
7
+ if ::BaselineRedRpm::Tracer.tracing?
8
+ operation = "#{self.class.name}##{self.action_name}"
9
+ span = BaselineRedRpm.tracer.start_span(operation, tags: {
10
+ "component" => "ActionController",
11
+ "span.kind" => "client"
12
+ })
13
+ BaselineRedRpm::Utils.log_source_and_backtrace(span, :action_controller)
14
+ end
15
+
16
+ process_action_without_trace(method_name, *args)
17
+ rescue Exception => e
18
+ puts e.message.inspect
19
+ puts e.backtrace.join("\n")
20
+ if span
21
+ span.set_tag('error', true)
22
+ span.log_error(e)
23
+ end
24
+ raise
25
+ ensure
26
+ span.finish if span
27
+ end
28
+
29
+ def perform_action_with_trace(*arguments)
30
+ if ::BaselineRedRpm::Tracer.tracing?
31
+ operation = "#{@_request.path_parameters['controller']}##{@_request.path_parameters['action']}"
32
+ span = BaselineRedRpm.tracer.start_span(operation, tags: {
33
+ "component" => "ActionController",
34
+ "span.kind" => "client"
35
+ })
36
+ BaselineRedRpm::Utils.log_source_and_backtrace(span, :action_controller)
37
+ end
38
+ perform_action_without_trace(*arguments)
39
+ rescue Exception => e
40
+ if span
41
+ span.set_tag('error', true)
42
+ span.log_error(e)
43
+ end
44
+ raise
45
+ ensure
46
+ span.finish if span
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ if ::BaselineRedRpm.config.instrumentation[:action_controller][:enabled] &&
53
+ defined?(::ActionController)
54
+ BaselineRedRpm.logger.info "Initializing actioncontroller tracer."
55
+
56
+ ::ActionController::Base.send(
57
+ :include,
58
+ BaselineRedRpm::Instruments::ActionController
59
+ )
60
+
61
+ ::ActionController::Base.class_eval do
62
+ if ::Rails::VERSION::MAJOR > 2
63
+ alias_method :process_action_without_trace, :process_action
64
+ alias_method :process_action, :process_action_with_trace
65
+ else
66
+ alias_method :perform_action_without_trace, :perform_action
67
+ alias_method :perform_action, :perform_action_with_trace
68
+ end
69
+ end
70
+ end