instana 1.10.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +23 -0
  3. data/.gitignore +16 -0
  4. data/.rubocop.yml +1156 -0
  5. data/.travis.yml +43 -0
  6. data/Configuration.md +149 -0
  7. data/Dockerfile +13 -0
  8. data/Gemfile +41 -0
  9. data/LICENSE +21 -0
  10. data/README.md +102 -0
  11. data/Rakefile +56 -0
  12. data/Tracing.md +145 -0
  13. data/Troubleshooting.md +32 -0
  14. data/benchmarks/Gemfile +7 -0
  15. data/benchmarks/id_generation.rb +12 -0
  16. data/benchmarks/opentracing.rb +26 -0
  17. data/benchmarks/rack_vanilla_vs_traced.rb +80 -0
  18. data/benchmarks/stackprof_rack_tracing.rb +77 -0
  19. data/benchmarks/time_processing.rb +12 -0
  20. data/bin/console +7 -0
  21. data/bin/setup +8 -0
  22. data/examples/opentracing.rb +31 -0
  23. data/examples/tracing.rb +80 -0
  24. data/gemfiles/libraries.gemfile +71 -0
  25. data/gemfiles/rails32.gemfile +51 -0
  26. data/gemfiles/rails42.gemfile +50 -0
  27. data/gemfiles/rails50.gemfile +52 -0
  28. data/instana.gemspec +46 -0
  29. data/lib/instana.rb +12 -0
  30. data/lib/instana/agent.rb +441 -0
  31. data/lib/instana/agent/helpers.rb +61 -0
  32. data/lib/instana/agent/hooks.rb +37 -0
  33. data/lib/instana/agent/tasks.rb +48 -0
  34. data/lib/instana/base.rb +54 -0
  35. data/lib/instana/collector.rb +116 -0
  36. data/lib/instana/collectors/gc.rb +57 -0
  37. data/lib/instana/collectors/memory.rb +34 -0
  38. data/lib/instana/collectors/thread.rb +30 -0
  39. data/lib/instana/config.rb +79 -0
  40. data/lib/instana/eum/eum-test.js.erb +16 -0
  41. data/lib/instana/eum/eum.js.erb +14 -0
  42. data/lib/instana/frameworks/cuba.rb +6 -0
  43. data/lib/instana/frameworks/instrumentation/abstract_mysql_adapter.rb +58 -0
  44. data/lib/instana/frameworks/instrumentation/action_controller.rb +183 -0
  45. data/lib/instana/frameworks/instrumentation/action_view.rb +43 -0
  46. data/lib/instana/frameworks/instrumentation/active_record.rb +27 -0
  47. data/lib/instana/frameworks/instrumentation/mysql2_adapter.rb +81 -0
  48. data/lib/instana/frameworks/instrumentation/mysql_adapter.rb +56 -0
  49. data/lib/instana/frameworks/instrumentation/postgresql_adapter.rb +71 -0
  50. data/lib/instana/frameworks/rails.rb +42 -0
  51. data/lib/instana/frameworks/roda.rb +6 -0
  52. data/lib/instana/frameworks/sinatra.rb +9 -0
  53. data/lib/instana/helpers.rb +40 -0
  54. data/lib/instana/instrumentation.rb +21 -0
  55. data/lib/instana/instrumentation/dalli.rb +78 -0
  56. data/lib/instana/instrumentation/excon.rb +74 -0
  57. data/lib/instana/instrumentation/grpc.rb +84 -0
  58. data/lib/instana/instrumentation/net-http.rb +66 -0
  59. data/lib/instana/instrumentation/rack.rb +77 -0
  60. data/lib/instana/instrumentation/redis.rb +82 -0
  61. data/lib/instana/instrumentation/resque.rb +131 -0
  62. data/lib/instana/instrumentation/rest-client.rb +34 -0
  63. data/lib/instana/instrumentation/sidekiq-client.rb +45 -0
  64. data/lib/instana/instrumentation/sidekiq-worker.rb +54 -0
  65. data/lib/instana/opentracing/carrier.rb +4 -0
  66. data/lib/instana/opentracing/tracer.rb +18 -0
  67. data/lib/instana/rack.rb +10 -0
  68. data/lib/instana/setup.rb +36 -0
  69. data/lib/instana/test.rb +40 -0
  70. data/lib/instana/thread_local.rb +15 -0
  71. data/lib/instana/tracer.rb +392 -0
  72. data/lib/instana/tracing/processor.rb +92 -0
  73. data/lib/instana/tracing/span.rb +401 -0
  74. data/lib/instana/tracing/span_context.rb +33 -0
  75. data/lib/instana/util.rb +261 -0
  76. data/lib/instana/version.rb +4 -0
  77. data/lib/oj_check.rb +16 -0
  78. data/lib/opentracing.rb +6 -0
  79. data/test/agent/agent_test.rb +143 -0
  80. data/test/apps/cuba.rb +15 -0
  81. data/test/apps/grpc_server.rb +81 -0
  82. data/test/apps/roda.rb +10 -0
  83. data/test/apps/sinatra.rb +5 -0
  84. data/test/benchmarks/bench_id_generation.rb +12 -0
  85. data/test/benchmarks/bench_opentracing.rb +13 -0
  86. data/test/config_test.rb +37 -0
  87. data/test/frameworks/cuba_test.rb +44 -0
  88. data/test/frameworks/rack_test.rb +167 -0
  89. data/test/frameworks/rails/actioncontroller_test.rb +93 -0
  90. data/test/frameworks/rails/actionview3_test.rb +255 -0
  91. data/test/frameworks/rails/actionview4_test.rb +254 -0
  92. data/test/frameworks/rails/actionview5_test.rb +221 -0
  93. data/test/frameworks/rails/activerecord3_test.rb +134 -0
  94. data/test/frameworks/rails/activerecord4_test.rb +134 -0
  95. data/test/frameworks/rails/activerecord5_test.rb +87 -0
  96. data/test/frameworks/roda_test.rb +44 -0
  97. data/test/frameworks/sinatra_test.rb +44 -0
  98. data/test/instana_test.rb +27 -0
  99. data/test/instrumentation/dalli_test.rb +253 -0
  100. data/test/instrumentation/excon_test.rb +147 -0
  101. data/test/instrumentation/grpc_test.rb +377 -0
  102. data/test/instrumentation/net-http_test.rb +160 -0
  103. data/test/instrumentation/redis_test.rb +119 -0
  104. data/test/instrumentation/resque_test.rb +128 -0
  105. data/test/instrumentation/rest-client_test.rb +55 -0
  106. data/test/instrumentation/sidekiq-client_test.rb +125 -0
  107. data/test/instrumentation/sidekiq-worker_test.rb +173 -0
  108. data/test/jobs/resque_error_job.rb +22 -0
  109. data/test/jobs/resque_fast_job.rb +20 -0
  110. data/test/jobs/sidekiq_job_1.rb +6 -0
  111. data/test/jobs/sidekiq_job_2.rb +7 -0
  112. data/test/models/block.rb +18 -0
  113. data/test/servers/grpc_50051.rb +20 -0
  114. data/test/servers/helpers/sidekiq_worker_initializer.rb +27 -0
  115. data/test/servers/rackapp_6511.rb +25 -0
  116. data/test/servers/rails_3205.rb +167 -0
  117. data/test/servers/sidekiq/worker.rb +27 -0
  118. data/test/test_helper.rb +145 -0
  119. data/test/tracing/custom_test.rb +158 -0
  120. data/test/tracing/id_management_test.rb +130 -0
  121. data/test/tracing/opentracing_test.rb +335 -0
  122. data/test/tracing/trace_test.rb +67 -0
  123. data/test/tracing/tracer_async_test.rb +198 -0
  124. data/test/tracing/tracer_test.rb +223 -0
  125. metadata +327 -0
@@ -0,0 +1,79 @@
1
+ module Instana
2
+ class Config
3
+
4
+ def initialize
5
+ @config = {}
6
+ if ENV.key?('INSTANA_AGENT_HOST')
7
+ @config[:agent_host] = ENV['INSTANA_AGENT_HOST']
8
+ else
9
+ @config[:agent_host] = '127.0.0.1'
10
+ end
11
+ if ENV.key?('INSTANA_AGENT_PORT')
12
+ @config[:agent_port] = ENV['INSTANA_AGENT_PORT']
13
+ else
14
+ @config[:agent_port] = 42699
15
+ end
16
+
17
+ # Global on/off switch for prebuilt environments
18
+ # Setting this to false will disable this gem
19
+ # from doing anything.
20
+ @config[:enabled] = true
21
+
22
+ # Enable/disable metrics globally or individually (default: all enabled)
23
+ @config[:metrics] = { :enabled => true }
24
+ @config[:metrics][:gc] = { :enabled => true }
25
+ @config[:metrics][:memory] = { :enabled => true }
26
+ @config[:metrics][:thread] = { :enabled => true }
27
+
28
+ # Enable/disable tracing (default: enabled)
29
+ @config[:tracing] = { :enabled => true }
30
+
31
+ if ENV.key?('INSTANA_DEBUG')
32
+ @config[:collector] = { :enabled => true, :interval => 3 }
33
+ else
34
+ @config[:collector] = { :enabled => true, :interval => 1 }
35
+ end
36
+
37
+ # EUM Related
38
+ @config[:eum_api_key] = nil
39
+ @config[:eum_baggage] = {}
40
+
41
+ # In Ruby, backtrace collection is very expensive so it's
42
+ # (unfortunately) disabled by default. If you still want
43
+ # backtraces, it can be enabled with this config option.
44
+ # ::Instana.config[:collect_backtraces] = true
45
+ @config[:collect_backtraces] = false
46
+
47
+ @config[:action_controller] = { :enabled => true }
48
+ @config[:action_view] = { :enabled => true }
49
+ @config[:active_record] = { :enabled => true }
50
+ @config[:dalli] = { :enabled => true }
51
+ @config[:excon] = { :enabled => true }
52
+ @config[:grpc] = { :enabled => true }
53
+ @config[:nethttp] = { :enabled => true }
54
+ @config[:redis] = { :enabled => true }
55
+ @config[:'resque-client'] = { :enabled => true }
56
+ @config[:'resque-worker'] = { :enabled => true }
57
+ @config[:'rest-client'] = { :enabled => true }
58
+ @config[:'sidekiq-client'] = { :enabled => true }
59
+ @config[:'sidekiq-worker'] = { :enabled => true }
60
+ end
61
+
62
+ def [](key)
63
+ @config[key.to_sym]
64
+ end
65
+
66
+ def []=(key, value)
67
+ @config[key.to_sym] = value
68
+
69
+ if key == :enabled
70
+ # Configuring global enable/disable flag, then set the
71
+ # appropriate children flags.
72
+ @config[:metrics][:enabled] = value
73
+ @config[:tracing][:enabled] = value
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ ::Instana.config = ::Instana::Config.new
@@ -0,0 +1,16 @@
1
+ <script nonce="68afd870-ae85-48c6-9689-9a5c359d5a1f">
2
+ (function(i,s,o,g,r,a,m){i['InstanaEumObject']=r;i[r]=i[r]||function(){
3
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
4
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
5
+ })(window,document,'script','//eum-test-fullstack-0-us-west-2.instana.io/eum.min.js','ineum');
6
+
7
+ ineum('reportingUrl', '//eum-test-fullstack-0-us-west-2.instana.io');
8
+ ineum('apiKey', '<%=::Instana.config[:eum_api_key]%>');
9
+ ineum('traceId', '<%=::Instana.tracer.trace_id_header%>');
10
+
11
+ <% if !::Instana.config[:eum_baggage].empty? %>
12
+ <% ::Instana.config[:eum_baggage].each do |k, v| %>
13
+ ineum('meta', '<%=k%>', '<%=v%>');
14
+ <% end %>
15
+ <% end %>
16
+ </script>
@@ -0,0 +1,14 @@
1
+ <script>
2
+ (function(i,s,o,g,r,a,m){i['InstanaEumObject']=r;i[r]=i[r]||function(){
3
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
4
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
5
+ })(window,document,'script','//eum.instana.io/eum.min.js','ineum');
6
+ ineum('apiKey', '<%=::Instana.config[:eum_api_key]%>');
7
+ ineum('traceId', '<%=::Instana.tracer.trace_id_header%>');
8
+
9
+ <% if !::Instana.config[:eum_baggage].empty? %>
10
+ <% ::Instana.config[:eum_baggage].each do |k, v| %>
11
+ ineum('meta', '<%=k%>', '<%=v%>');
12
+ <% end %>
13
+ <% end %>
14
+ </script>
@@ -0,0 +1,6 @@
1
+ require "instana/rack"
2
+
3
+ if defined?(::Cuba)
4
+ ::Instana.logger.info "Instrumenting Cuba"
5
+ Cuba.use ::Instana::Rack
6
+ end
@@ -0,0 +1,58 @@
1
+ module Instana
2
+ module Instrumentation
3
+ module AbstractMysqlAdapter
4
+ IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE).freeze
5
+ EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
6
+
7
+ # This module supports instrumenting ActiveRecord with the mysql2 adapter.
8
+ #
9
+ def self.included(klass)
10
+ if ActiveRecord::VERSION::STRING >= '3.2'
11
+ Instana::Util.method_alias(klass, :execute)
12
+
13
+ @@sanitize_regexp = Regexp.new('(\'[\s\S][^\']*\'|\d*\.\d+|\d+|NULL)', Regexp::IGNORECASE)
14
+ end
15
+ end
16
+
17
+ # Collect up this DB connection info for reporting.
18
+ #
19
+ # @param sql [String]
20
+ # @return [Hash] Hash of collected KVs
21
+ #
22
+ def collect(sql)
23
+ payload = { :activerecord => {} }
24
+ payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
25
+ payload[:activerecord][:adapter] = @config[:adapter]
26
+ payload[:activerecord][:host] = @config[:host]
27
+ payload[:activerecord][:db] = @config[:database]
28
+ payload[:activerecord][:username] = @config[:username]
29
+ payload
30
+ end
31
+
32
+ # In the spirit of ::ActiveRecord::ExplainSubscriber.ignore_payload? There are
33
+ # only certain calls that we're interested in tracing. e.g. No use to instrument
34
+ # framework caches.
35
+ #
36
+ # @param payload [String]
37
+ # @return [Boolean]
38
+ #
39
+ def ignore_payload?(name, sql)
40
+ IGNORED_PAYLOADS.include?(name) || sql !~ EXPLAINED_SQLS
41
+ end
42
+
43
+ def execute_with_instana(sql, name = nil)
44
+ tracing = ::Instana.tracer.tracing?
45
+ if !tracing || ignore_payload?(name, sql)
46
+ return execute_without_instana(sql, name)
47
+ elsif ::Instana.tracer.current_span[:n] == :activerecord
48
+ return execute_without_instana(sql, name)
49
+ end
50
+
51
+ kv_payload = collect(sql)
52
+ ::Instana.tracer.trace(:activerecord, kv_payload) do
53
+ execute_without_instana(sql, name)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,183 @@
1
+ module Instana
2
+ module Instrumentation
3
+
4
+ # Contains the methods common to both ::Instana::Instrumentation::ActionController
5
+ # and ::Instana::Instrumentation::ActionControllerLegacy
6
+ #
7
+ module ActionControllerCommon
8
+
9
+ # Indicates whether a Controller rescue handler is in place. If so, this affects
10
+ # error logging and reporting. (Hence the need for this method).
11
+ #
12
+ # @return [Boolean]
13
+ #
14
+ def has_rails_handler?(exception)
15
+ found = false
16
+ rescue_handlers.detect do |klass_name, _handler|
17
+ # Rescue handlers can be specified as strings or constant names
18
+ klass = self.class.const_get(klass_name) rescue nil
19
+ klass ||= klass_name.constantize rescue nil
20
+ found = exception.is_a?(klass) if klass
21
+ end
22
+ found
23
+ rescue => e
24
+ ::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
25
+ return false
26
+ end
27
+
28
+ # Render can be called with many options across the various supported
29
+ # versions of Rails. This method attempts to make sense and provide
30
+ # insight into what is happening (rendering a layout, file, nothing,
31
+ # plaintext etc.)
32
+ def get_render_topic(opts)
33
+ if opts.key?(:layout)
34
+ case opts[:layout]
35
+ when FalseClass
36
+ name = "Without layout"
37
+ when String
38
+ name = opts[:layout]
39
+ when Proc
40
+ name = "Proc"
41
+ else
42
+ name = "Default"
43
+ end
44
+ end
45
+
46
+ return name if name
47
+
48
+ if opts.key?(:template)
49
+ name ||= opts[:template]
50
+ elsif opts.key?(:file)
51
+ name ||= opts[:file]
52
+ elsif opts.key?(:nothing)
53
+ name = "Nothing"
54
+ elsif opts.key?(:plain)
55
+ name = "Plaintext"
56
+ elsif opts.key?(:json)
57
+ name = "JSON"
58
+ elsif opts.key?(:xml)
59
+ name = "XML"
60
+ elsif opts.key?(:body)
61
+ name = "Raw"
62
+ elsif opts.key?(:js)
63
+ name = "Javascript"
64
+ end
65
+ name
66
+ end
67
+ end
68
+
69
+ # Used in ActionPack versions 5 and beyond, this module provides
70
+ # instrumentation for ActionController (a part of ActionPack)
71
+ #
72
+ module ActionController
73
+ include ::Instana::Instrumentation::ActionControllerCommon
74
+
75
+ # This is the Rails 5 version of the process_action method where we use prepend to
76
+ # instrument the class method instead of using the older alias_method_chain.
77
+ #
78
+ def process_action(*args)
79
+ kv_payload = { :actioncontroller => {} }
80
+ kv_payload[:actioncontroller][:controller] = self.class.name
81
+ kv_payload[:actioncontroller][:action] = action_name
82
+
83
+ ::Instana.tracer.log_entry(:actioncontroller, kv_payload)
84
+
85
+ super(*args)
86
+ rescue Exception => e
87
+ ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
88
+ raise
89
+ ensure
90
+ ::Instana.tracer.log_exit(:actioncontroller)
91
+ end
92
+
93
+ # The Instana wrapper method for ActionController::Base.render
94
+ # for versions 5+.
95
+ #
96
+ def render(*args, &blk)
97
+ # Figure out what's being rendered
98
+ if args.length > 0 && args[0].is_a?(Hash)
99
+ name = get_render_topic(args[0])
100
+ end
101
+ name ||= "Default"
102
+
103
+ ::Instana.tracer.log_entry(:actionview, :actionview => { :name => name })
104
+
105
+ super(*args, &blk)
106
+ rescue Exception => e
107
+ ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
108
+ raise
109
+ ensure
110
+ ::Instana.tracer.log_exit(:actionview)
111
+ end
112
+ end
113
+
114
+ # Used in ActionPack versions 4 and earlier, this module provides
115
+ # instrumentation for ActionController (a part of ActionPack)
116
+ #
117
+ module ActionControllerLegacy
118
+ include ::Instana::Instrumentation::ActionControllerCommon
119
+
120
+ def self.included(klass)
121
+ klass.class_eval do
122
+ alias_method_chain :process_action, :instana
123
+ alias_method_chain :render, :instana
124
+ end
125
+ end
126
+
127
+ # The Instana wrapper method for ActionController::Base.process_action
128
+ # for versions 3 and 4.
129
+ #
130
+ def process_action_with_instana(*args)
131
+ kv_payload = { :actioncontroller => {} }
132
+ kv_payload[:actioncontroller][:controller] = self.class.name
133
+ kv_payload[:actioncontroller][:action] = action_name
134
+
135
+ ::Instana.tracer.log_entry(:actioncontroller, kv_payload)
136
+
137
+ process_action_without_instana(*args)
138
+ rescue Exception => e
139
+ ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
140
+ raise
141
+ ensure
142
+ ::Instana.tracer.log_exit(:actioncontroller)
143
+ end
144
+
145
+ # The Instana wrapper method for ActionController::Base.render
146
+ # for versions 3 and 4.
147
+ #
148
+ def render_with_instana(*args, &blk)
149
+ if args.length > 0 && args[0].is_a?(Hash)
150
+ name = get_render_topic(args[0])
151
+ end
152
+ name ||= "Default"
153
+ ::Instana.tracer.log_entry(:actionview, :actionview => { :name => name })
154
+ render_without_instana(*args, &blk)
155
+ rescue Exception => e
156
+ ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
157
+ raise
158
+ ensure
159
+ ::Instana.tracer.log_exit(:actionview)
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ if defined?(::ActionController) && ::Instana.config[:action_controller][:enabled] && ::ActionPack::VERSION::MAJOR >= 2
166
+ ::Instana.logger.info "Instrumenting ActionController"
167
+ if ActionPack::VERSION::MAJOR >= 5
168
+ ::ActionController::Base.send(:prepend, ::Instana::Instrumentation::ActionController)
169
+ else
170
+ ::ActionController::Base.send(:include, ::Instana::Instrumentation::ActionControllerLegacy)
171
+ end
172
+ end
173
+
174
+ # ActionController::API was introduced in Ruby on Rails 5 but was originally an independent project before being
175
+ # rolled into the Rails ActionPack. In case, someone is using the independent project or potentially backported
176
+ # the rails version to and older Ruby on Rails version, we only limit in a minimal way re: version checking.
177
+ #
178
+ # We allow ActionController::API instrumentation in version of Ruby on Rails 3 and higher.
179
+ #
180
+ if defined?(::ActionController::API) && ::Instana.config[:action_controller][:enabled] && ::ActionPack::VERSION::MAJOR >= 3
181
+ ::Instana.logger.info "Instrumenting ActionController API"
182
+ ::ActionController::API.send(:prepend, ::Instana::Instrumentation::ActionController)
183
+ end
@@ -0,0 +1,43 @@
1
+ module Instana
2
+ module Instrumentation
3
+ module ActionViewRenderer
4
+ def self.included(klass)
5
+ ::Instana::Util.method_alias(klass, :render_partial)
6
+ ::Instana::Util.method_alias(klass, :render_collection)
7
+ end
8
+
9
+ def render_partial_with_instana
10
+ kv_payload = { :render => {} }
11
+ kv_payload[:render][:type] = :partial
12
+ kv_payload[:render][:name] = @options[:partial].to_s if @options.is_a?(Hash)
13
+
14
+ ::Instana.tracer.log_entry(:render, kv_payload)
15
+ render_partial_without_instana
16
+ rescue Exception => e
17
+ ::Instana.tracer.log_error(e)
18
+ raise
19
+ ensure
20
+ ::Instana.tracer.log_exit(:render)
21
+ end
22
+
23
+ def render_collection_with_instana
24
+ kv_payload = { :render => {} }
25
+ kv_payload[:render][:type] = :collection
26
+ kv_payload[:render][:name] = @path.to_s
27
+
28
+ ::Instana.tracer.log_entry(:render, kv_payload)
29
+ render_collection_without_instana
30
+ rescue Exception => e
31
+ ::Instana.tracer.log_error(e)
32
+ raise
33
+ ensure
34
+ ::Instana.tracer.log_exit(:render)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ if defined?(::ActionView) && ::Instana.config[:action_view][:enabled] && ::ActionPack::VERSION::STRING >= '3.1'
41
+ ::Instana.logger.info "Instrumenting ActionView"
42
+ ::ActionView::PartialRenderer.send(:include, ::Instana::Instrumentation::ActionViewRenderer)
43
+ end
@@ -0,0 +1,27 @@
1
+
2
+ require "instana/frameworks/instrumentation/mysql_adapter"
3
+ require "instana/frameworks/instrumentation/abstract_mysql_adapter"
4
+ require "instana/frameworks/instrumentation/mysql2_adapter"
5
+ require "instana/frameworks/instrumentation/postgresql_adapter"
6
+
7
+ if defined?(::ActiveRecord) && ::Instana.config[:active_record][:enabled]
8
+
9
+ # Mysql
10
+ if defined?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
11
+ ::Instana.logger.info "Instrumenting ActiveRecord (mysql)"
12
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:include, ::Instana::Instrumentation::MysqlAdapter)
13
+ ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.send(:include, ::Instana::Instrumentation::AbstractMysqlAdapter)
14
+ end
15
+
16
+ # Mysql2
17
+ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
18
+ ::Instana.logger.info "Instrumenting ActiveRecord (mysql2)"
19
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:include, ::Instana::Instrumentation::Mysql2Adapter)
20
+ end
21
+
22
+ # Postgres
23
+ if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
24
+ ::Instana.logger.info "Instrumenting ActiveRecord (postgresql)"
25
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:include, ::Instana::Instrumentation::PostgreSQLAdapter)
26
+ end
27
+ end
@@ -0,0 +1,81 @@
1
+ module Instana
2
+ module Instrumentation
3
+ module Mysql2Adapter
4
+ IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE).freeze
5
+ EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
6
+
7
+ # This module supports instrumenting ActiveRecord with the mysql2 adapter.
8
+ #
9
+ def self.included(klass)
10
+ # ActiveRecord 3.1 and up only (for now possibly)
11
+ if ActiveRecord::VERSION::STRING > '3.0'
12
+ Instana::Util.method_alias(klass, :exec_delete)
13
+ Instana::Util.method_alias(klass, :exec_insert)
14
+ Instana::Util.method_alias(klass, :exec_query)
15
+
16
+ @@sanitize_regexp = Regexp.new('(\'[\s\S][^\']*\'|\d*\.\d+|\d+|NULL)', Regexp::IGNORECASE)
17
+ end
18
+ end
19
+
20
+ # Collect up this DB connection info for reporting.
21
+ #
22
+ # @param sql [String]
23
+ # @return [Hash] Hash of collected KVs
24
+ #
25
+ def collect(sql)
26
+ payload = { :activerecord => {} }
27
+ payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
28
+ payload[:activerecord][:adapter] = @config[:adapter]
29
+ payload[:activerecord][:host] = @config[:host]
30
+ payload[:activerecord][:db] = @config[:database]
31
+ payload[:activerecord][:username] = @config[:username]
32
+ payload
33
+ end
34
+
35
+ # In the spirit of ::ActiveRecord::ExplainSubscriber.ignore_payload? There are
36
+ # only certain calls that we're interested in tracing. e.g. No use to instrument
37
+ # framework caches.
38
+ #
39
+ # @param payload [String]
40
+ # @return [Boolean]
41
+ #
42
+ def ignore_payload?(name, sql)
43
+ IGNORED_PAYLOADS.include?(name) || sql !~ EXPLAINED_SQLS
44
+ end
45
+
46
+ def exec_delete_with_instana(sql, name = nil, binds = [])
47
+ if !::Instana.tracer.tracing? || ignore_payload?(name, sql)
48
+ return exec_delete_without_instana(sql, name, binds)
49
+ end
50
+
51
+ kv_payload = collect(sql)
52
+ ::Instana.tracer.trace(:activerecord, kv_payload) do
53
+ exec_delete_without_instana(sql, name, binds)
54
+ end
55
+ end
56
+
57
+ def exec_insert_with_instana(sql, name = 'SQL', binds = [], *args)
58
+ if !::Instana.tracer.tracing? || ignore_payload?(name, sql)
59
+ return exec_insert_without_instana(sql, name, binds, *args)
60
+ end
61
+
62
+ kv_payload = collect(sql)
63
+ ::Instana.tracer.trace(:activerecord, kv_payload) do
64
+ exec_insert_without_instana(sql, name, binds, *args)
65
+ end
66
+ end
67
+
68
+ def exec_query_with_instana(sql, name = 'SQL', binds = [], *args)
69
+ if !::Instana.tracer.tracing? || ignore_payload?(name, sql) ||
70
+ ::Instana.tracer.current_span[:n] == :activerecord
71
+ return exec_query_without_instana(sql, name, binds, *args)
72
+ end
73
+
74
+ kv_payload = collect(sql)
75
+ ::Instana.tracer.trace(:activerecord, kv_payload) do
76
+ exec_query_without_instana(sql, name, binds, *args)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end