app_perf_rpm 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/lib/app_perf_rpm/aggregator.rb +77 -0
  3. data/lib/app_perf_rpm/backtrace.rb +92 -0
  4. data/lib/app_perf_rpm/configuration.rb +56 -0
  5. data/lib/app_perf_rpm/dispatcher.rb +85 -0
  6. data/lib/app_perf_rpm/instrumentation.rb +21 -0
  7. data/lib/app_perf_rpm/instruments/action_controller.rb +51 -0
  8. data/lib/app_perf_rpm/instruments/action_view.rb +126 -0
  9. data/lib/app_perf_rpm/instruments/active_record/adapters/mysql2.rb +45 -0
  10. data/lib/app_perf_rpm/instruments/active_record/adapters/postgresql.rb +102 -0
  11. data/lib/app_perf_rpm/instruments/active_record/adapters/sqlite3.rb +103 -0
  12. data/lib/app_perf_rpm/instruments/active_record.rb +57 -0
  13. data/lib/app_perf_rpm/instruments/activerecord_import.rb +47 -0
  14. data/lib/app_perf_rpm/instruments/emque_consuming.rb +31 -0
  15. data/lib/app_perf_rpm/instruments/faraday.rb +37 -0
  16. data/lib/app_perf_rpm/instruments/net_http.rb +36 -0
  17. data/lib/app_perf_rpm/instruments/rack.rb +41 -0
  18. data/lib/app_perf_rpm/instruments/rack_middleware.rb +69 -0
  19. data/lib/app_perf_rpm/instruments/redis.rb +39 -0
  20. data/lib/app_perf_rpm/instruments/sequel.rb +92 -0
  21. data/lib/app_perf_rpm/instruments/sidekiq.rb +55 -0
  22. data/lib/app_perf_rpm/instruments/sinatra.rb +68 -0
  23. data/lib/app_perf_rpm/instruments/typhoeus.rb +55 -0
  24. data/lib/app_perf_rpm/introspector.rb +51 -0
  25. data/lib/app_perf_rpm/logger.rb +32 -0
  26. data/lib/app_perf_rpm/middleware.rb +30 -0
  27. data/lib/app_perf_rpm/rails.rb +14 -0
  28. data/lib/app_perf_rpm/railtie.rb +29 -0
  29. data/lib/app_perf_rpm/span.rb +103 -0
  30. data/lib/app_perf_rpm/tracer.rb +139 -0
  31. data/lib/app_perf_rpm/utils.rb +9 -0
  32. data/lib/app_perf_rpm/worker.rb +46 -0
  33. data/lib/app_perf_rpm.rb +124 -0
  34. data/lib/tasks/install.rake +6 -0
  35. metadata +146 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b34ed99c3e8e44848ad0973d852d87017529d97e
4
+ data.tar.gz: 21b6044514766bc7fc0df5ab6fe191e22d896cd9
5
+ SHA512:
6
+ metadata.gz: 31f24ad79ef22b4a7835daec2a2abf9bdb8d5c8d3b02b48d223eba656eda148841bb12724dc95ddd479f01241e951f42a5862378444c283fa1811bec2adeca48
7
+ data.tar.gz: d1f1aaf3e684d319ff06378ccac8c8e0ccf9f482dd3cc309493dca89a2c7ed79479b3a40f06117e8cc9b0589cf10aebc0781f7f0fc73bba9c461f005bf9145af
@@ -0,0 +1,77 @@
1
+ require 'digest/md5'
2
+
3
+ module AppPerfRpm
4
+ class Aggregator
5
+ def initialize
6
+ end
7
+
8
+ def aggregate(traces)
9
+ metrics = []
10
+ traces = arrange_traces(traces)
11
+ spans = traces_to_spans(traces)
12
+ spans_by_time(spans).each_pair do |time, spans|
13
+ group_spans(spans).each_pair do |(type, layer, domain, url, controller, action), grouped_spans|
14
+ opts = {}
15
+ opts["type"] = type if type
16
+ opts["layer"] = layer if layer
17
+ opts["domain"] = domain if domain
18
+ opts["url"] = url if url
19
+ opts["controller"] = controller if controller
20
+ opts["action"] = action if action
21
+ metrics << build_metric("trace.web.request.duration", time, grouped_spans, opts)
22
+ end
23
+ end
24
+
25
+ return metrics
26
+ end
27
+
28
+ private
29
+
30
+ def build_metric(metric_name, time, spans, opts)
31
+ num_spans = spans.uniq(&:trace_id).size
32
+ durations = spans.inject(0.0) {|s, x| s + x.exclusive_duration }.to_f
33
+ hits = spans.size
34
+
35
+ tags = {
36
+ "traces" => num_spans,
37
+ "hits" => hits
38
+ }.merge(opts)
39
+
40
+ ["metric", time.to_f, metric_name, durations, tags]
41
+ end
42
+
43
+ def arrange_traces(traces)
44
+ traces
45
+ .group_by(&:trace_id)
46
+ .map {|span| Span.arrange(span.last.dup) }
47
+ end
48
+
49
+ def traces_to_spans(traces)
50
+ traces
51
+ .map {|trace| trace.to_spans}
52
+ .flatten
53
+ end
54
+
55
+ def spans_by_time(spans)
56
+ spans.group_by {|span|
57
+ AppPerfRpm.floor_time(Time.at(span.started_at), dispatch_interval)
58
+ }
59
+ end
60
+
61
+ def group_spans(spans)
62
+ spans
63
+ .group_by {|span| [
64
+ span.type,
65
+ span.layer,
66
+ span.domain,
67
+ span.url,
68
+ span.controller,
69
+ span.action
70
+ ]}
71
+ end
72
+
73
+ def dispatch_interval
74
+ 30
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,92 @@
1
+ module AppPerfRpm
2
+ class Backtrace
3
+ class << self
4
+ def backtrace
5
+ bt = Kernel.caller
6
+ bt = clean(bt)
7
+ trim_backtrace(bt)
8
+ end
9
+
10
+ def clean(backtrace)
11
+ backtrace
12
+ .map {|b| clean_line(b) }
13
+ .select {|b| b !~ %r{lib/app_perf_rpm} }
14
+ end
15
+
16
+ #def source_extract(_backtrace = Kernel.caller(2))
17
+ # if(trace = _backtrace.first)
18
+ # file, line_number = extract_file_and_line_number(trace)
19
+
20
+ # {
21
+ # code: source_fragment(file, line_number),
22
+ # line_number: line_number
23
+ # }
24
+ # else
25
+ # nil
26
+ # end
27
+ #end
28
+
29
+ def source_extract(_backtrace = Kernel.caller(0))
30
+ Array(_backtrace).select {|bt| bt[/^#{::AppPerfRpm.configuration.app_root.to_s}\//] }.map do |trace|
31
+ file, line_number = extract_file_and_line_number(trace)
32
+ source_to_hash(file, line_number)
33
+ end
34
+ end
35
+
36
+ def source_to_hash(file, line_number)
37
+ {
38
+ "file" => clean_line(file),
39
+ "code" => source_fragment(file, line_number),
40
+ "line_number" => line_number
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def clean_line(line)
47
+ line
48
+ .sub(/#{::AppPerfRpm.configuration.app_root.to_s}\//, "[APP_PATH]/")
49
+ .sub(gems_regexp, '\2 (\3) [GEM_PATH]/\4')
50
+ end
51
+
52
+ def gems_regexp
53
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
54
+ if gems_paths
55
+ %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ def source_fragment(path, line)
62
+ return unless AppPerfRpm.configuration.app_root
63
+ full_path = AppPerfRpm.configuration.app_root.join(path)
64
+ if File.exist?(full_path)
65
+ File.open(full_path, "r") do |file|
66
+ start = [line - 3, 0].max
67
+ lines = file.each_line.drop(start).take(6)
68
+ Hash[*(start + 1..(lines.count + start)).zip(lines).flatten]
69
+ end
70
+ end
71
+ end
72
+
73
+ def extract_file_and_line_number(trace)
74
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
75
+ [file, line.to_i]
76
+ end
77
+
78
+ def trim_backtrace(_backtrace)
79
+ return _backtrace unless _backtrace.is_a?(Array)
80
+
81
+ length = _backtrace.size
82
+ if length > 100
83
+ # Trim backtraces by getting the first 180 and last 20 lines
84
+ trimmed = _backtrace[0, 80] + ['...[snip]...'] + _backtrace[length - 20, 20]
85
+ else
86
+ trimmed = _backtrace
87
+ end
88
+ trimmed
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,56 @@
1
+ require 'yaml'
2
+
3
+ module AppPerfRpm
4
+ class Configuration
5
+ attr_accessor :app_root,
6
+ :host,
7
+ :port,
8
+ :license_key,
9
+ :ssl,
10
+ :sample_rate,
11
+ :sample_threshold,
12
+ :dispatch_interval,
13
+ :application_name,
14
+ :instrumentation,
15
+ :agent_disabled
16
+
17
+ def initialize
18
+ reload
19
+ end
20
+
21
+ def reload
22
+ ::AppPerfRpm.mutex.synchronize do
23
+ self.app_root = app_root ? Pathname.new(app_root.to_s) : nil
24
+ self.host ||= default_if_blank(ENV["APP_PERF_HOST"], "http://localhost:5000")
25
+ self.ssl ||= false
26
+ self.license_key ||= default_if_blank(ENV["APP_PERF_LICENSE_KEY"], nil)
27
+ self.application_name ||= "Default"
28
+ self.sample_rate ||= 10 # Percentage of request to sample
29
+ self.sample_threshold ||= 0 # Minimum amount of duration to sample
30
+ self.dispatch_interval ||= 60 # In seconds
31
+ self.agent_disabled ||= default_if_blank(ENV["APP_PERF_AGENT_DISABLED"], false)
32
+ self.instrumentation = {
33
+ :rack => { :enabled => true, :backtrace => false, :trace_middleware => true },
34
+ :active_record => { :enabled => true, :backtrace => false },
35
+ :active_record_import => { :enabled => true, :backtrace => false },
36
+ :action_view => { :enabled => true, :backtrace => false },
37
+ :action_controller => { :enabled => true, :backtrace => false },
38
+ :emque_consuming => { :enabled => true, :backtrace => false },
39
+ :redis => { :enabled => true, :backtrace => false },
40
+ :sequel => { :enabled => true, :backtrace => false },
41
+ :sidekiq => { :enabled => true, :backtrace => false },
42
+ :sinatra => { :enabled => true, :backtrace => false },
43
+ :net_http => { :enabled => true, :backtrace => false },
44
+ :typhoeus => { :enabled => true, :backtrace => false },
45
+ :faraday => { :enabled => true, :backtrace => false }
46
+ }
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def default_if_blank(value, default)
53
+ value.nil? || value.blank? ? default : value
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,85 @@
1
+ require 'net/http'
2
+
3
+ module AppPerfRpm
4
+ class Dispatcher
5
+ def initialize
6
+ @start_time = Time.now
7
+ @queue = Queue.new
8
+ @aggregator = Aggregator.new
9
+ end
10
+
11
+ def add_event(event)
12
+ @queue << event
13
+ end
14
+
15
+ def configuration
16
+ ::AppPerfRpm.configuration
17
+ end
18
+
19
+ def ready?
20
+ Time.now > @start_time + configuration.dispatch_interval.to_f &&
21
+ @queue.size.to_i > 0
22
+ end
23
+
24
+ def reset
25
+ @queue.clear
26
+ @start_time = Time.now
27
+ end
28
+
29
+ def dispatch
30
+ begin
31
+ spans = drain(@queue)
32
+ metrics = []#@aggregator.aggregate(spans)
33
+
34
+ dispatch_events(spans.map(&:to_a) + metrics)
35
+ rescue => ex
36
+ ::AppPerfRpm.logger.error "#{ex.inspect}"
37
+ ::AppPerfRpm.logger.error "#{ex.backtrace.inspect}"
38
+ ensure
39
+ reset
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def dispatch_events(data)
46
+ if data && data.length > 0
47
+ uri = URI(url)
48
+
49
+ sock = Net::HTTP.new(uri.host, uri.port)
50
+ sock.use_ssl = configuration.ssl
51
+
52
+ req = Net::HTTP::Post.new(uri.path, { "Content-Type" => "application/json", "Accept-Encoding" => "gzip", "User-Agent" => "gzip" })
53
+ req.body = compress_body(data)
54
+ req.content_type = "application/octet-stream"
55
+
56
+ res = sock.start do |http|
57
+ http.read_timeout = 30
58
+ http.request(req)
59
+ end
60
+ data.clear
61
+ end
62
+ end
63
+
64
+ def compress_body(data)
65
+ body = Oj.dump({
66
+ "name" => configuration.application_name,
67
+ "host" => AppPerfRpm.host,
68
+ "data" => data
69
+ })
70
+
71
+ compressed_body = Zlib::Deflate.deflate(body, Zlib::DEFAULT_COMPRESSION)
72
+ Base64.encode64(compressed_body)
73
+ end
74
+
75
+ def drain(queue)
76
+ Array.new(queue.size) { queue.pop }
77
+ end
78
+
79
+ def url
80
+ host = configuration.host
81
+ license_key = configuration.license_key
82
+ @url ||= "#{host}/api/listener/2/#{license_key}"
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,21 @@
1
+ module AppPerfRpm
2
+ class Instrumentation
3
+ class << self
4
+ def load
5
+ pattern = File.join(File.dirname(__FILE__), 'instruments', '**', '*.rb')
6
+ Dir.glob(pattern) do |f|
7
+ begin
8
+ require f
9
+ rescue => e
10
+ AppPerfRpm.logger.error "Error loading instrumentation file '#{f}' : #{e}"
11
+ AppPerfRpm.logger.error "#{e.backtrace[0..10]}"
12
+ end
13
+ end
14
+
15
+ if defined? Rails::Railtie
16
+ require "app_perf_rpm/railtie"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ module AppPerfRpm
2
+ module Instruments
3
+ module ActionController
4
+ def process_action_with_trace(method_name, *args)
5
+ if ::AppPerfRpm::Tracer.tracing?
6
+ AppPerfRpm::Tracer.trace('actioncontroller') do |span|
7
+ span.controller = self.class.name
8
+ span.action = self.action_name
9
+
10
+ process_action_without_trace(method_name, *args)
11
+ end
12
+ else
13
+ process_action_without_trace(method_name, *args)
14
+ end
15
+ end
16
+
17
+ def perform_action_with_trace(*arguments)
18
+ if ::AppPerfRpm::Tracer.tracing?
19
+ AppPerfRpm::Tracer.trace('actioncontroller') do |span|
20
+ span.controller = @_request.path_parameters['controller']
21
+ span.action = @_request.path_parameters['action']
22
+
23
+ perform_action_without_trace(*arguments)
24
+ end
25
+ else
26
+ perform_action_without_trace(*arguments)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ if ::AppPerfRpm.configuration.instrumentation[:action_controller][:enabled] &&
34
+ defined?(::ActionController)
35
+ AppPerfRpm.logger.info "Initializing actioncontroller tracer."
36
+
37
+ ::ActionController::Base.send(
38
+ :include,
39
+ AppPerfRpm::Instruments::ActionController
40
+ )
41
+
42
+ ::ActionController::Base.class_eval do
43
+ if ::Rails::VERSION::MAJOR > 2
44
+ alias_method :process_action_without_trace, :process_action
45
+ alias_method :process_action, :process_action_with_trace
46
+ else
47
+ alias_method :perform_action_without_trace, :perform_action
48
+ alias_method :perform_action, :perform_action_with_trace
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,126 @@
1
+ if ::AppPerfRpm.configuration.instrumentation[:action_view][:enabled] && defined?(::ActionView)
2
+ if defined?(Rails) && Rails::VERSION::MAJOR == 2
3
+ ActionView::Partials.module_eval do
4
+ alias :render_partial_without_trace :render_partial
5
+ def render_partial(options = {})
6
+ if ::AppPerfRpm::Tracer.tracing? && options.key?(:partial) && options[:partial].is_a?(String)
7
+ opts = {
8
+ "method" => "render_partial",
9
+ "name" => options[:partial]
10
+ }
11
+
12
+ opts["backtrace"] = ::AppPerfRpm::Backtrace.backtrace
13
+ opts["source"] = ::AppPerfRpm::Backtrace.source_extract
14
+
15
+ AppPerfRpm::Tracer.trace("actionview", opts) do |span|
16
+ span.controller = @_request.path_parameters['controller']
17
+ span.action = @_request.path_parameters['action']
18
+ span.backtrace = ::AppPerfRpm::Backtrace.backtrace
19
+ span.source = ::AppPerfRpm::Backtrace.source_extract
20
+
21
+ render_partial_without_trace(options)
22
+ end
23
+ else
24
+ render_partial_without_trace(options)
25
+ end
26
+ end
27
+
28
+ alias :render_partial_collection_without_trace :render_partial_collection
29
+ def render_partial_collection(options = {})
30
+ if ::AppPerfRpm::Tracer.tracing?
31
+ AppPerfRpm::Tracer.trace("actionview") do |span|
32
+ span.backtrace = ::AppPerfRpm::Backtrace.backtrace
33
+ span.source = ::AppPerfRpm::Backtrace.source_extract
34
+ span.options = {
35
+ "method" => "render_partial_collection",
36
+ "name" => @path
37
+ }
38
+
39
+ render_partial_collection_without_trace(options)
40
+ end
41
+ else
42
+ render_partial_collection_without_trace(options)
43
+ end
44
+ end
45
+ end
46
+ else
47
+ ActionView::PartialRenderer.class_eval do
48
+ alias :render_partial_without_trace :render_partial
49
+ def render_partial
50
+ if ::AppPerfRpm::Tracer.tracing?
51
+ AppPerfRpm::Tracer.trace("actionview") do |span|
52
+ span.backtrace = ::AppPerfRpm::Backtrace.backtrace
53
+ span.source = ::AppPerfRpm::Backtrace.source_extract
54
+ span.options = {
55
+ "method" => "render_partial",
56
+ "name" => @options[:partial]
57
+ }
58
+
59
+ render_partial_without_trace
60
+ end
61
+ else
62
+ render_partial_without_trace
63
+ end
64
+ end
65
+
66
+ alias :render_collection_without_trace :render_collection
67
+ def render_collection
68
+ if ::AppPerfRpm::Tracer.tracing?
69
+ AppPerfRpm::Tracer.trace("actionview") do |span|
70
+ span.options = {
71
+ "method" => "render_collection",
72
+ "name" => @path
73
+ }
74
+
75
+ render_collection_without_trace
76
+ end
77
+ else
78
+ render_collection_without_trace
79
+ end
80
+ end
81
+ end
82
+
83
+ ::ActionView::TemplateRenderer.class_eval do
84
+ alias render_with_layout_without_trace render_with_layout
85
+
86
+ def render_with_layout(path, locals, *args, &block)
87
+ if ::AppPerfRpm::Tracer.tracing?
88
+ layout = nil
89
+
90
+ if path
91
+ if method(:find_layout).arity == 3
92
+ # Rails 5
93
+ layout = find_layout(path, locals.keys, [formats.first])
94
+ else
95
+ # Rails 3, 4
96
+ layout = find_layout(path, locals.keys)
97
+ end
98
+
99
+ @path = path
100
+ end
101
+
102
+ AppPerfRpm::Tracer.trace("actionview") do |span|
103
+ if layout
104
+ span.options = {
105
+ "method" => "render_with_layout",
106
+ "name" => layout.identifier,
107
+ "path" => @path,
108
+ "layout" => layout
109
+ }
110
+ else
111
+ span.options = {
112
+ "method" => "render_without_layout",
113
+ "path" => @path
114
+ }
115
+ end
116
+ render_with_layout_without_trace(path, locals, *args, &block)
117
+ end
118
+ else
119
+ render_with_layout_without_trace(path, locals, *args, &block)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ AppPerfRpm.logger.info "Initializing actionview tracer."
126
+ end
@@ -0,0 +1,45 @@
1
+ module AppPerfRpm
2
+ module Instruments
3
+ module ActiveRecord
4
+ module Adapters
5
+ module Mysql2
6
+ include AppPerfRpm::Utils
7
+
8
+ IGNORE_STATEMENTS = {
9
+ "SCHEMA" => true,
10
+ "EXPLAIN" => true,
11
+ "CACHE" => true
12
+ }
13
+
14
+ def ignore_trace?(name)
15
+ IGNORE_STATEMENTS[name.to_s] ||
16
+ (name && name.to_sym == :skip_logging) ||
17
+ name == 'ActiveRecord::SchemaMigration Load'
18
+ end
19
+
20
+ def execute_with_trace(sql, name = nil)
21
+ if ::AppPerfRpm::Tracer.tracing?
22
+ if ignore_trace?(name)
23
+ execute_without_trace(sql, name)
24
+ else
25
+ sanitized_sql = sanitize_sql(sql, :mysql2)
26
+
27
+ AppPerfRpm::Tracer.trace('activerecord') do |span|
28
+ span.options ={
29
+ "adapter" => "mysql2",
30
+ "query" => sanitized_sql,
31
+ "name" => name
32
+ }
33
+
34
+ execute_without_trace(sql, name)
35
+ end
36
+ end
37
+ else
38
+ execute_without_trace(sql, name)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,102 @@
1
+ module AppPerfRpm
2
+ module Instruments
3
+ module ActiveRecord
4
+ module Adapters
5
+ module Postgresql
6
+ include AppPerfRpm::Utils
7
+
8
+ IGNORE_STATEMENTS = {
9
+ "SCHEMA" => true,
10
+ "EXPLAIN" => true,
11
+ "CACHE" => true
12
+ }
13
+
14
+ def ignore_trace?(name)
15
+ IGNORE_STATEMENTS[name.to_s] ||
16
+ (name && name.to_sym == :skip_logging) ||
17
+ name == 'ActiveRecord::SchemaMigration Load'
18
+ end
19
+
20
+ def exec_query_with_trace(sql, name = nil, binds = [])
21
+ if ::AppPerfRpm::Tracer.tracing?
22
+ if ignore_trace?(name)
23
+ exec_query_without_trace(sql, name, binds)
24
+ else
25
+ sanitized_sql = sanitize_sql(sql, :postgres)
26
+
27
+ AppPerfRpm::Tracer.trace('activerecord') do |span|
28
+ span.options = {
29
+ "adapter" => "postgresql",
30
+ "query" => sanitized_sql,
31
+ "name" => name
32
+ }
33
+ exec_query_without_trace(sql, name, binds)
34
+ end
35
+ end
36
+ else
37
+ exec_query_without_trace(sql, name, binds)
38
+ end
39
+ end
40
+
41
+ def exec_delete_with_trace(sql, name = nil, binds = [])
42
+ if ::AppPerfRpm::Tracer.tracing?
43
+ if ignore_trace?(name)
44
+ exec_delete_without_trace(sql, name, binds)
45
+ else
46
+ sanitized_sql = sanitize_sql(sql)
47
+
48
+ AppPerfRpm::Tracer.trace('activerecord') do |span|
49
+ span.options = {
50
+ "adapter" => "postgresql",
51
+ "query" => sanitized_sql,
52
+ "name" => name
53
+ }
54
+ exec_delete_without_trace(sql, name, binds)
55
+ end
56
+ end
57
+ else
58
+ exec_delete_without_trace(sql, name, binds)
59
+ end
60
+ end
61
+
62
+ def exec_insert_with_trace(sql, name = nil, binds = [], *args)
63
+ if ::AppPerfRpm::Tracer.tracing?
64
+ if ignore_trace?(name)
65
+ exec_insert_without_trace(sql, name, binds, *args)
66
+ else
67
+ sanitized_sql = sanitize_sql(sql, :postgres)
68
+
69
+ AppPerfRpm::Tracer.trace('activerecord') do |span|
70
+ span.options = {
71
+ "adapter" => "postgresql",
72
+ "query" => sanitized_sql,
73
+ "name" => name
74
+ }
75
+
76
+ exec_insert_without_trace(sql, name, binds, *args)
77
+ end
78
+ end
79
+ else
80
+ exec_insert_without_trace(sql, name, binds, *args)
81
+ end
82
+ end
83
+
84
+ def begin_db_transaction_with_trace
85
+ if ::AppPerfRpm::Tracer.tracing?
86
+ AppPerfRpm::Tracer.trace('activerecord') do |span|
87
+ span.options = {
88
+ "adapter" => "postgresql",
89
+ "query" => "BEGIN"
90
+ }
91
+
92
+ begin_db_transaction_without_trace
93
+ end
94
+ else
95
+ begin_db_transaction_without_trace
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end