baseline_red_rpm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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