appoptics_apm_mnfst 4.5.2

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 (104) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.gitignore +29 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +121 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +769 -0
  9. data/CONFIG.md +33 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +193 -0
  12. data/README.md +393 -0
  13. data/Rakefile +230 -0
  14. data/appoptics_apm.gemspec +61 -0
  15. data/bin/appoptics_apm_config +15 -0
  16. data/build_gem.sh +15 -0
  17. data/build_gem_upload_to_packagecloud.sh +20 -0
  18. data/examples/SDK/01_basic_tracing.rb +67 -0
  19. data/examples/carrying_context.rb +220 -0
  20. data/ext/oboe_metal/extconf.rb +114 -0
  21. data/ext/oboe_metal/lib/.keep +0 -0
  22. data/ext/oboe_metal/noop/noop.c +7 -0
  23. data/ext/oboe_metal/src/VERSION +1 -0
  24. data/init.rb +4 -0
  25. data/lib/appoptics_apm.rb +76 -0
  26. data/lib/appoptics_apm/api.rb +20 -0
  27. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  28. data/lib/appoptics_apm/api/logging.rb +375 -0
  29. data/lib/appoptics_apm/api/memcache.rb +37 -0
  30. data/lib/appoptics_apm/api/metrics.rb +55 -0
  31. data/lib/appoptics_apm/api/profiling.rb +203 -0
  32. data/lib/appoptics_apm/api/tracing.rb +53 -0
  33. data/lib/appoptics_apm/api/util.rb +122 -0
  34. data/lib/appoptics_apm/base.rb +230 -0
  35. data/lib/appoptics_apm/config.rb +254 -0
  36. data/lib/appoptics_apm/frameworks/grape.rb +97 -0
  37. data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
  38. data/lib/appoptics_apm/frameworks/rails.rb +94 -0
  39. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  40. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -0
  41. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  42. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  43. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  44. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  45. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  46. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  47. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  48. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  49. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  51. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +108 -0
  52. data/lib/appoptics_apm/frameworks/sinatra.rb +125 -0
  53. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  54. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  55. data/lib/appoptics_apm/inst/curb.rb +330 -0
  56. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  57. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  58. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  59. data/lib/appoptics_apm/inst/excon.rb +125 -0
  60. data/lib/appoptics_apm/inst/faraday.rb +94 -0
  61. data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
  62. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  63. data/lib/appoptics_apm/inst/http.rb +73 -0
  64. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  65. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  66. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  67. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  68. data/lib/appoptics_apm/inst/moped.rb +466 -0
  69. data/lib/appoptics_apm/inst/rack.rb +199 -0
  70. data/lib/appoptics_apm/inst/redis.rb +275 -0
  71. data/lib/appoptics_apm/inst/resque.rb +151 -0
  72. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  73. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  74. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  75. data/lib/appoptics_apm/inst/sidekiq-worker.rb +65 -0
  76. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  77. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  78. data/lib/appoptics_apm/instrumentation.rb +22 -0
  79. data/lib/appoptics_apm/legacy_method_profiling.rb +90 -0
  80. data/lib/appoptics_apm/loading.rb +65 -0
  81. data/lib/appoptics_apm/logger.rb +42 -0
  82. data/lib/appoptics_apm/method_profiling.rb +33 -0
  83. data/lib/appoptics_apm/noop/README.md +9 -0
  84. data/lib/appoptics_apm/noop/context.rb +26 -0
  85. data/lib/appoptics_apm/noop/metadata.rb +22 -0
  86. data/lib/appoptics_apm/ruby.rb +35 -0
  87. data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
  88. data/lib/appoptics_apm/sdk/tracing.rb +315 -0
  89. data/lib/appoptics_apm/support.rb +119 -0
  90. data/lib/appoptics_apm/test.rb +94 -0
  91. data/lib/appoptics_apm/thread_local.rb +26 -0
  92. data/lib/appoptics_apm/util.rb +319 -0
  93. data/lib/appoptics_apm/version.rb +15 -0
  94. data/lib/appoptics_apm/xtrace.rb +103 -0
  95. data/lib/joboe_metal.rb +212 -0
  96. data/lib/oboe.rb +7 -0
  97. data/lib/oboe/README +2 -0
  98. data/lib/oboe/backward_compatibility.rb +80 -0
  99. data/lib/oboe/inst/rack.rb +11 -0
  100. data/lib/oboe_metal.rb +198 -0
  101. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  102. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
  103. data/yardoc_frontpage.md +26 -0
  104. metadata +266 -0
@@ -0,0 +1,108 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module ConnectionAdapters
7
+ module Utils
8
+
9
+ def extract_trace_details(sql, name = nil, binds = [])
10
+ opts = {}
11
+
12
+ begin
13
+ if AppOpticsAPM::Config[:sanitize_sql]
14
+ # Sanitize SQL and don't report binds
15
+ opts[:Query] = AppOpticsAPM::Util.sanitize_sql(sql)
16
+ else
17
+ # Report raw SQL and any binds if they exist
18
+ opts[:Query] = sql.to_s
19
+ if binds && !binds.empty?
20
+ opts[:QueryArgs] = binds.map(&:value)
21
+ end
22
+ end
23
+
24
+ opts[:Name] = name.to_s if name
25
+ if AppOpticsAPM::Config[:active_record] && AppOpticsAPM::Config[:active_record][:collect_backtraces]
26
+ opts[:Backtrace] = AppOpticsAPM::API.backtrace
27
+ end
28
+
29
+ config = ActiveRecord::Base.connection_config
30
+ if config
31
+ opts[:Database] = config[:database] if config.key?(:database)
32
+ opts[:RemoteHost] = config[:host] if config.key?(:host)
33
+ adapter_name = config[:adapter]
34
+
35
+ case adapter_name
36
+ when /mysql/i
37
+ opts[:Flavor] = 'mysql'
38
+ when /postgres/i
39
+ opts[:Flavor] = 'postgresql'
40
+ end
41
+ end
42
+ rescue StandardError => e
43
+ AppOpticsAPM.logger.debug "[appoptics_apm/rails] Exception raised capturing ActiveRecord KVs: #{e.inspect}"
44
+ AppOpticsAPM.logger.debug e.backtrace.join('\n')
45
+ end
46
+
47
+ opts
48
+ end
49
+
50
+ # We don't want to trace framework caches. Only instrument SQL that
51
+ # directly hits the database.
52
+ def ignore_payload?(name)
53
+ %w(SCHEMA EXPLAIN CACHE).include?(name.to_s) ||
54
+ (name && name.to_sym == :skip_logging) ||
55
+ name == 'ActiveRecord::SchemaMigration Load'
56
+ end
57
+
58
+ def exec_query_with_appoptics(sql, name = nil, binds = [], prepare: false)
59
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:ar_started) && !ignore_payload?(name)
60
+
61
+ opts = extract_trace_details(sql, name, binds)
62
+ AppOpticsAPM::API.trace('activerecord', opts) do
63
+ exec_query_without_appoptics(sql, name, binds)
64
+ end
65
+ else
66
+ exec_query_without_appoptics(sql, name, binds)
67
+ end
68
+ end
69
+
70
+ def exec_insert_with_appoptics(sql, name = nil, binds = [], *args)
71
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
72
+
73
+ opts = extract_trace_details(sql, name, binds)
74
+ AppOpticsAPM::API.trace('activerecord', opts, :ar_started) do
75
+ exec_insert_without_appoptics(sql, name, binds, *args)
76
+ end
77
+ else
78
+ exec_insert_without_appoptics(sql, name, binds, *args)
79
+ end
80
+ end
81
+
82
+ def exec_delete_with_appoptics(sql, name = nil, binds = [])
83
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
84
+
85
+ opts = extract_trace_details(sql, name, binds)
86
+ AppOpticsAPM::API.trace('activerecord', opts, :ar_started) do
87
+ exec_delete_without_appoptics(sql, name, binds)
88
+ end
89
+ else
90
+ exec_delete_without_appoptics(sql, name, binds)
91
+ end
92
+ end
93
+
94
+ def exec_update_with_appoptics(sql, name = nil, binds = [])
95
+ if AppOpticsAPM.tracing? && !ignore_payload?(name)
96
+
97
+ opts = extract_trace_details(sql, name, binds)
98
+ AppOpticsAPM::API.trace('activerecord', opts, :ar_started) do
99
+ exec_update_without_appoptics(sql, name, binds)
100
+ end
101
+ else
102
+ exec_update_without_appoptics(sql, name, binds)
103
+ end
104
+ end
105
+ end # Utils
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,125 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Sinatra
6
+ module Base
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :dispatch!, ::Sinatra::Base)
9
+ AppOpticsAPM::Util.method_alias(klass, :handle_exception!, ::Sinatra::Base)
10
+ end
11
+
12
+ def dispatch_with_appoptics
13
+
14
+ AppOpticsAPM::API.log_entry('sinatra', {})
15
+
16
+ response = dispatch_without_appoptics
17
+
18
+ # Report Controller/Action and transaction as best possible
19
+ report_kvs = {}
20
+ report_kvs[:Controller] = self.class
21
+ report_kvs[:Action] = env['sinatra.route']
22
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
23
+ env['appoptics_apm.action'] = report_kvs[:Action]
24
+
25
+ response
26
+ rescue => e
27
+ AppOpticsAPM::API.log_exception('sinatra', e)
28
+ raise e
29
+ ensure
30
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sinatra][:collect_backtraces]
31
+ AppOpticsAPM::API.log_exit('sinatra', report_kvs)
32
+ end
33
+
34
+ def handle_exception_with_appoptics(boom)
35
+ AppOpticsAPM::API.log_exception(:sinatra, boom)
36
+ handle_exception_without_appoptics(boom)
37
+ end
38
+
39
+ def appoptics_rum_header
40
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_header is deprecated. It is now a no-op and should be removed from your application code.'
41
+ return ''
42
+ end
43
+ alias_method :oboe_rum_header, :appoptics_rum_header
44
+
45
+ def appoptics_rum_footer
46
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Note that appoptics_rum_footer is deprecated. It is now a no-op and should be removed from your application code.'
47
+ return ''
48
+ end
49
+ alias_method :oboe_rum_footer, :appoptics_rum_footer
50
+ end
51
+
52
+ module Templates
53
+ def self.included(klass)
54
+ AppOpticsAPM::Util.method_alias(klass, :render, ::Sinatra::Templates)
55
+ end
56
+
57
+ def render_with_appoptics(engine, data, options = {}, locals = {}, &block)
58
+ if AppOpticsAPM.tracing?
59
+ report_kvs = {}
60
+
61
+ report_kvs[:engine] = engine
62
+ report_kvs[:template] = data
63
+
64
+ if AppOpticsAPM.tracing_layer_op?(:render)
65
+ # For recursive calls to :render (for sub-partials and layouts),
66
+ # use method profiling.
67
+ begin
68
+ name = data
69
+ report_kvs[:FunctionName] = :render
70
+ report_kvs[:Class] = :Templates
71
+ report_kvs[:Module] = :'Sinatra::Templates'
72
+ report_kvs[:File] = __FILE__
73
+ report_kvs[:LineNumber] = __LINE__
74
+ rescue StandardError => e
75
+ AppOpticsAPM.logger.debug e.message
76
+ AppOpticsAPM.logger.debug e.backtrace.join(', ')
77
+ end
78
+
79
+ AppOpticsAPM::API.profile(name, report_kvs, false) do
80
+ render_without_appoptics(engine, data, options, locals, &block)
81
+ end
82
+
83
+ else
84
+ # Fall back to the raw tracing API so we can pass KVs
85
+ # back on exit (a limitation of the AppOpticsAPM::API.trace
86
+ # block method) This removes the need for an info
87
+ # event to send additonal KVs
88
+ AppOpticsAPM::API.log_entry(:render, {}, :render)
89
+
90
+ begin
91
+ render_without_appoptics(engine, data, options, locals, &block)
92
+ ensure
93
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sinatra][:collect_backtraces]
94
+ AppOpticsAPM::API.log_exit(:render, report_kvs, :render)
95
+ end
96
+ end
97
+ else
98
+ render_without_appoptics(engine, data, options, locals, &block)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ if defined?(Sinatra) && AppopticsAPM::Config[:sinatra][:enabled]
106
+ require 'appoptics_apm/inst/rack'
107
+
108
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Sinatra' if AppOpticsAPM::Config[:verbose]
109
+
110
+ AppOpticsAPM::Inst.load_instrumentation
111
+
112
+ Sinatra::Base.use AppOpticsAPM::Rack
113
+
114
+ # When in the gem TEST environment, we load this instrumentation regardless.
115
+ # Otherwise, only when Padrino isn't around.
116
+ unless defined?(Padrino) && !ENV.key?('APPOPTICS_GEM_TEST')
117
+ # Padrino has 'enhanced' routes and rendering so the Sinatra
118
+ # instrumentation won't work anyways. Only load for pure Sinatra apps.
119
+ AppOpticsAPM::Util.send_include(Sinatra::Base, AppOpticsAPM::Sinatra::Base)
120
+ AppOpticsAPM::Util.send_include(Sinatra::Templates, AppOpticsAPM::Sinatra::Templates)
121
+
122
+ # Report __Init after fork when in Heroku
123
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
124
+ end
125
+ end
@@ -0,0 +1,148 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module BunnyExchange
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :delete, ::Bunny::Exchange)
9
+ end
10
+
11
+ def delete_with_appoptics(opts = {})
12
+ # If we're not tracing, just do a fast return.
13
+ return delete_without_appoptics(opts) if !AppOpticsAPM.tracing?
14
+
15
+ begin
16
+ kvs = {}
17
+ kvs[:Spec] = :pushq
18
+ kvs[:Flavor] = :rabbitmq
19
+ kvs[:Op] = :delete
20
+ kvs[:ExchangeType] = @type
21
+ kvs[:RemoteHost] = channel.connection.host
22
+ kvs[:RemotePort] = channel.connection.port.to_i
23
+ kvs[:VirtualHost] = channel.connection.vhost
24
+
25
+ if @name.is_a?(String) && !@name.empty?
26
+ kvs[:ExchangeName] = @name
27
+ else
28
+ kvs[:ExchangeName] = :default
29
+ end
30
+
31
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
32
+ delete_without_appoptics(opts)
33
+ rescue => e
34
+ AppOpticsAPM::API.log_exception(:'rabbitmq-client', e)
35
+ raise e
36
+ ensure
37
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyclient][:collect_backtraces]
38
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
39
+ end
40
+ end
41
+ end
42
+
43
+ module BunnyChannel
44
+ def self.included(klass)
45
+ AppOpticsAPM::Util.method_alias(klass, :basic_publish, ::Bunny::Channel)
46
+ AppOpticsAPM::Util.method_alias(klass, :queue, ::Bunny::Channel)
47
+ AppOpticsAPM::Util.method_alias(klass, :wait_for_confirms, ::Bunny::Channel)
48
+ end
49
+
50
+ def collect_channel_kvs
51
+ kvs = {}
52
+ kvs[:Spec] = :pushq
53
+ kvs[:Flavor] = :rabbitmq
54
+ kvs[:RemoteHost] = @connection.host
55
+ kvs[:RemotePort] = @connection.port.to_i
56
+ kvs[:VirtualHost] = @connection.vhost
57
+ kvs
58
+ rescue => e
59
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
60
+ ensure
61
+ return kvs
62
+ end
63
+
64
+ def basic_publish_with_appoptics(payload, exchange, routing_key, opts = {})
65
+ # If we're not tracing, just do a fast return.
66
+ return basic_publish_without_appoptics(payload, exchange, routing_key, opts) if !AppOpticsAPM.tracing?
67
+
68
+ begin
69
+ kvs = collect_channel_kvs
70
+
71
+ if exchange.respond_to?(:name)
72
+ kvs[:ExchangeName] = exchange.name
73
+ elsif exchange.respond_to?(:empty?) && !exchange.empty?
74
+ kvs[:ExchangeName] = exchange
75
+ else
76
+ kvs[:ExchangeName] = :default
77
+ end
78
+
79
+ kvs[:Queue] = opts[:queue] if opts.key?(:queue)
80
+ kvs[:RoutingKey] = routing_key if routing_key
81
+ kvs[:Op] = :publish
82
+
83
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
84
+
85
+ # Pass the tracing context as a header
86
+ opts[:headers] ||= {}
87
+ opts[:headers][:SourceTrace] = AppOpticsAPM::Context.toString if AppOpticsAPM.tracing?
88
+
89
+ basic_publish_without_appoptics(payload, exchange, routing_key, opts)
90
+ rescue => e
91
+ AppOpticsAPM::API.log_exception(:'rabbitmq-client', e)
92
+ raise e
93
+ ensure
94
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyclient][:collect_backtraces]
95
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
96
+ end
97
+ end
98
+
99
+ def queue_with_appoptics(name = AMQ::Protocol::EMPTY_STRING, opts = {})
100
+ # If we're not tracing, just do a fast return.
101
+ return queue_without_appoptics(name, opts) if !AppOpticsAPM.tracing?
102
+
103
+ begin
104
+ kvs = collect_channel_kvs
105
+ kvs[:Op] = :queue
106
+
107
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
108
+
109
+ result = queue_without_appoptics(name, opts)
110
+ kvs[:Queue] = result.name
111
+ result
112
+ rescue => e
113
+ AppOpticsAPM::API.log_exception(:'rabbitmq-client', e)
114
+ raise e
115
+ ensure
116
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyclient][:collect_backtraces]
117
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
118
+ end
119
+ end
120
+
121
+ def wait_for_confirms_with_appoptics
122
+ # If we're not tracing, just do a fast return.
123
+ return wait_for_confirms_without_appoptics if !AppOpticsAPM.tracing?
124
+
125
+ begin
126
+ kvs = collect_channel_kvs
127
+ kvs[:Op] = :wait_for_confirms
128
+
129
+ AppOpticsAPM::API.log_entry(:'rabbitmq-client')
130
+
131
+ wait_for_confirms_without_appoptics
132
+ rescue => e
133
+ AppOpticsAPM::API.log_exception(:'rabbitmq-client', e)
134
+ raise e
135
+ ensure
136
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyclient][:collect_backtraces]
137
+ AppOpticsAPM::API.log_exit(:'rabbitmq-client', kvs)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ if defined?(Bunny) && AppOpticsAPM::Config[:bunnyclient][:enabled]
145
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting bunny client' if AppOpticsAPM::Config[:verbose]
146
+ AppOpticsAPM::Util.send_include(Bunny::Exchange, AppOpticsAPM::Inst::BunnyExchange)
147
+ AppOpticsAPM::Util.send_include(Bunny::Channel, AppOpticsAPM::Inst::BunnyChannel)
148
+ end
@@ -0,0 +1,89 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module BunnyConsumer
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :call, ::Bunny::Consumer)
9
+ end
10
+
11
+ def collect_consumer_kvs(args)
12
+ kvs = {}
13
+ kvs[:Spec] = :job
14
+ kvs[:Flavor] = :rabbitmq
15
+ kvs[:RemoteHost] = @channel.connection.host
16
+ kvs[:RemotePort] = @channel.connection.port.to_i
17
+ kvs[:VirtualHost] = @channel.connection.vhost
18
+
19
+ mp = args[1]
20
+ kvs[:RoutingKey] = args[0].routing_key if args[0].routing_key
21
+ kvs[:MsgID] = args[1].message_id if mp.message_id
22
+ kvs[:AppID] = args[1].app_id if mp.app_id
23
+ kvs[:Priority] = args[1].priority if mp.priority
24
+
25
+ if @queue.respond_to?(:name)
26
+ kvs[:Queue] = @queue.name
27
+ else
28
+ kvs[:Queue] = @queue
29
+ end
30
+
31
+ # Report configurable Controller/Action KVs
32
+ # See AppOpticsAPM::Config[:bunnyconsumer] in lib/appoptics_apm/config.rb
33
+ # Used for dashboard trace filtering
34
+ controller_key = AppOpticsAPM::Config[:bunnyconsumer][:controller]
35
+ if mp.respond_to?(controller_key)
36
+ value = mp.method(controller_key).call
37
+ kvs[:Controller] = value if value
38
+ end
39
+
40
+ action_key = AppOpticsAPM::Config[:bunnyconsumer][:action]
41
+ if mp.respond_to?(action_key)
42
+ value = mp.method(action_key).call
43
+ kvs[:Action] = value if value
44
+ end
45
+
46
+ if kvs[:Queue]
47
+ kvs[:URL] = "/bunny/#{kvs[:Queue]}"
48
+ else
49
+ kvs[:URL] = "/bunny/consumer"
50
+ end
51
+
52
+ if AppOpticsAPM::Config[:bunnyconsumer][:log_args] && @arguments
53
+ kvs[:Args] = @arguments.to_s
54
+ end
55
+
56
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:bunnyconsumer][:collect_backtraces]
57
+
58
+ kvs
59
+ rescue => e
60
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
61
+ ensure
62
+ return kvs
63
+ end
64
+
65
+ def call_with_appoptics(*args)
66
+ report_kvs = collect_consumer_kvs(args)
67
+
68
+ # If SourceTrace was passed, capture and report it
69
+ headers = args[1][:headers]
70
+
71
+ if headers && headers['SourceTrace']
72
+ report_kvs[:SourceTrace] = headers['SourceTrace']
73
+
74
+ # Remove SourceTrace
75
+ headers.delete('SourceTrace')
76
+ end
77
+
78
+ AppOpticsAPM::SDK.start_trace(:'rabbitmq-consumer', nil, report_kvs) do
79
+ call_without_appoptics(*args)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ if AppOpticsAPM::Config[:bunnyconsumer][:enabled] && defined?(Bunny)
87
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting bunny consumer' if AppOpticsAPM::Config[:verbose]
88
+ AppOpticsAPM::Util.send_include(Bunny::Consumer, AppOpticsAPM::Inst::BunnyConsumer)
89
+ end