appoptics_apm_mnfst 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
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,151 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'socket'
5
+ require 'json'
6
+
7
+ module AppOpticsAPM
8
+ module Inst
9
+ module ResqueClient
10
+ def self.included(klass)
11
+ klass.send :extend, ::Resque
12
+ AppOpticsAPM::Util.method_alias(klass, :enqueue, ::Resque)
13
+ AppOpticsAPM::Util.method_alias(klass, :enqueue_to, ::Resque)
14
+ AppOpticsAPM::Util.method_alias(klass, :dequeue, ::Resque)
15
+ end
16
+
17
+ def extract_trace_details(op, klass, args)
18
+ report_kvs = {}
19
+
20
+ begin
21
+ report_kvs[:Spec] = :pushq
22
+ report_kvs[:Flavor] = :resque
23
+ report_kvs[:JobName] = klass.to_s
24
+
25
+ if AppOpticsAPM::Config[:resqueclient][:log_args]
26
+ kv_args = args.to_json
27
+
28
+ # Limit the argument json string to 1024 bytes
29
+ if kv_args.length > 1024
30
+ report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
31
+ else
32
+ report_kvs[:Args] = kv_args
33
+ end
34
+ end
35
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:resqueclient][:collect_backtraces]
36
+ report_kvs[:Queue] = klass.instance_variable_get(:@queue)
37
+ rescue => e
38
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
39
+ end
40
+
41
+ report_kvs
42
+ end
43
+
44
+ def enqueue_with_appoptics(klass, *args)
45
+ if AppOpticsAPM.tracing?
46
+ report_kvs = extract_trace_details(:enqueue, klass, args)
47
+
48
+ AppOpticsAPM::API.trace(:'resque-client', report_kvs, :enqueue) do
49
+ enqueue_without_appoptics(klass, *args)
50
+ end
51
+ else
52
+ enqueue_without_appoptics(klass, *args)
53
+ end
54
+ end
55
+
56
+ def enqueue_to_with_appoptics(queue, klass, *args)
57
+ if AppOpticsAPM.tracing? && !AppOpticsAPM.tracing_layer_op?(:enqueue)
58
+ report_kvs = extract_trace_details(:enqueue_to, klass, args)
59
+ report_kvs[:Queue] = queue.to_s if queue
60
+
61
+ AppOpticsAPM::API.trace(:'resque-client', report_kvs) do
62
+ enqueue_to_without_appoptics(queue, klass, *args)
63
+ end
64
+ else
65
+ enqueue_to_without_appoptics(queue, klass, *args)
66
+ end
67
+ end
68
+
69
+ def dequeue_with_appoptics(klass, *args)
70
+ if AppOpticsAPM.tracing?
71
+ report_kvs = extract_trace_details(:dequeue, klass, args)
72
+
73
+ AppOpticsAPM::API.trace(:'resque-client', report_kvs) do
74
+ dequeue_without_appoptics(klass, *args)
75
+ end
76
+ else
77
+ dequeue_without_appoptics(klass, *args)
78
+ end
79
+ end
80
+ end
81
+
82
+ module ResqueWorker
83
+ def self.included(klass)
84
+ AppOpticsAPM::Util.method_alias(klass, :perform, ::Resque::Worker)
85
+ end
86
+
87
+ def perform_with_appoptics(job)
88
+ report_kvs = {}
89
+
90
+ begin
91
+ report_kvs[:Spec] = :job
92
+ report_kvs[:Flavor] = :resque
93
+ report_kvs[:JobName] = job.payload['class'].to_s
94
+ report_kvs[:Queue] = job.queue
95
+
96
+ # Set these keys for the ability to separate out
97
+ # background tasks into a separate app on the server-side UI
98
+
99
+ report_kvs[:'HTTP-Host'] = Socket.gethostname
100
+ report_kvs[:Controller] = "Resque_#{job.queue}"
101
+ report_kvs[:Action] = job.payload['class'].to_s
102
+ report_kvs[:URL] = "/resque/#{job.queue}/#{job.payload['class']}"
103
+
104
+ if AppOpticsAPM::Config[:resqueworker][:log_args]
105
+ kv_args = job.payload['args'].to_json
106
+
107
+ # Limit the argument json string to 1024 bytes
108
+ if kv_args.length > 1024
109
+ report_kvs[:Args] = kv_args[0..1023] + '...[snipped]'
110
+ else
111
+ report_kvs[:Args] = kv_args
112
+ end
113
+ end
114
+
115
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:resqueworker][:collect_backtraces]
116
+ rescue => e
117
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" if AppOpticsAPM::Config[:verbose]
118
+ end
119
+
120
+ AppOpticsAPM::SDK.start_trace(:'resque-worker', nil, report_kvs) do
121
+ perform_without_appoptics(job)
122
+ end
123
+ end
124
+ end
125
+
126
+ module ResqueJob
127
+ def self.included(klass)
128
+ AppOpticsAPM::Util.method_alias(klass, :fail, ::Resque::Job)
129
+ end
130
+
131
+ def fail_with_appoptics(exception)
132
+ if AppOpticsAPM.tracing?
133
+ AppOpticsAPM::API.log_exception(:resque, exception)
134
+ end
135
+ fail_without_appoptics(exception)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ if defined?(Resque)
142
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting resque' if AppOpticsAPM::Config[:verbose]
143
+
144
+ AppOpticsAPM::Util.send_include(Resque, AppOpticsAPM::Inst::ResqueClient) if AppOpticsAPM::Config[:resqueclient][:enabled]
145
+ AppOpticsAPM::Util.send_include(Resque::Worker, AppOpticsAPM::Inst::ResqueWorker) if AppOpticsAPM::Config[:resqueworker][:enabled]
146
+ if AppOpticsAPM::Config[:resqueclient][:enabled] || AppOpticsAPM::Config[:resqueworker][:enabled]
147
+ AppOpticsAPM::Util.send_include(Resque::Job, AppOpticsAPM::Inst::ResqueJob)
148
+ end
149
+ end
150
+
151
+
@@ -0,0 +1,48 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module RestClientRequest
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :execute, ::RestClient::Request)
9
+ end
10
+
11
+ ##
12
+ # execute_with_appoptics
13
+ #
14
+ # The wrapper method for RestClient::Request.execute
15
+ #
16
+ def execute_with_appoptics(&block)
17
+ blacklisted = AppOpticsAPM::API.blacklisted?(url)
18
+
19
+ unless AppOpticsAPM.tracing?
20
+ xtrace = AppOpticsAPM::Context.toString
21
+ @processed_headers['X-Trace'] = AppOpticsAPM::Context.toString if AppOpticsAPM::XTrace.valid?(xtrace) && !blacklisted
22
+ return execute_without_appoptics(&block)
23
+ end
24
+
25
+ begin
26
+ kvs = {}
27
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:rest_client][:collect_backtraces]
28
+ AppOpticsAPM::API.log_entry('rest-client', kvs)
29
+
30
+ @processed_headers['X-Trace'] = AppOpticsAPM::Context.toString unless blacklisted
31
+
32
+ # The core rest-client call
33
+ execute_without_appoptics(&block)
34
+ rescue => e
35
+ AppOpticsAPM::API.log_exception('rest-client', e)
36
+ raise e
37
+ ensure
38
+ AppOpticsAPM::API.log_exit('rest-client')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ if defined?(RestClient) && AppOpticsAPM::Config[:rest_client][:enabled]
46
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting rest-client' if AppOpticsAPM::Config[:verbose]
47
+ AppOpticsAPM::Util.send_include(RestClient::Request, AppOpticsAPM::Inst::RestClientRequest)
48
+ end
@@ -0,0 +1,178 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ ##
7
+ # AppOpticsAPM::Inst::Sequel
8
+ #
9
+ # The common (shared) methods used by the AppOpticsAPM Sequel instrumentation
10
+ # across multiple modules/classes.
11
+ #
12
+ module Sequel
13
+ ##
14
+ # extract_trace_details
15
+ #
16
+ # Given SQL and the options hash, this method extracts the interesting
17
+ # bits for reporting to the AppOptics dashboard.
18
+ #
19
+ def extract_trace_details(sql, opts)
20
+ kvs = {}
21
+
22
+ if !sql.is_a?(String)
23
+ kvs[:IsPreparedStatement] = true
24
+ end
25
+
26
+ if ::Sequel::VERSION > '4.36.0' && !sql.is_a?(String)
27
+ # In 4.37.0, sql was converted to a prepared statement object
28
+ sql = sql.prepared_sql unless sql.is_a?(Symbol)
29
+ end
30
+
31
+ if AppOpticsAPM::Config[:sanitize_sql]
32
+ # Sanitize SQL and don't report binds
33
+ if sql.is_a?(Symbol)
34
+ kvs[:Query] = sql
35
+ else
36
+ kvs[:Query] = AppOpticsAPM::Util.sanitize_sql(sql)
37
+ end
38
+ else
39
+ # Report raw SQL and any binds if they exist
40
+ kvs[:Query] = sql.to_s
41
+ kvs[:QueryArgs] = opts[:arguments] if opts.is_a?(Hash) && opts.key?(:arguments)
42
+ end
43
+
44
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sequel][:collect_backtraces]
45
+
46
+ if ::Sequel::VERSION < '3.41.0' && !(self.class.to_s =~ /Dataset$/)
47
+ db_opts = @opts
48
+ elsif @pool
49
+ db_opts = @pool.db.opts
50
+ else
51
+ db_opts = @db.opts
52
+ end
53
+
54
+ kvs[:Database] = db_opts[:database]
55
+ kvs[:RemoteHost] = db_opts[:host]
56
+ kvs[:RemotePort] = db_opts[:port] if db_opts.key?(:port)
57
+ kvs[:Flavor] = db_opts[:adapter]
58
+ rescue => e
59
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug Error capturing Sequel KVs: #{e.message}" if AppOpticsAPM::Config[:verbose]
60
+ ensure
61
+ return kvs
62
+ end
63
+
64
+ ##
65
+ # exec_with_appoptics
66
+ #
67
+ # This method wraps and routes the call to the specified
68
+ # original method call
69
+ #
70
+ def exec_with_appoptics(method, sql, opts = ::Sequel::OPTS, &block)
71
+ if AppOpticsAPM.tracing?
72
+ kvs = extract_trace_details(sql, opts)
73
+ AppOpticsAPM::API.log_entry(:sequel, kvs)
74
+ end
75
+
76
+ send(method, sql, opts, &block)
77
+ rescue => e
78
+ AppOpticsAPM::API.log_exception(:sequel, e)
79
+ raise e
80
+ ensure
81
+ AppOpticsAPM::API.log_exit(:sequel)
82
+ end
83
+ end
84
+
85
+ module SequelDatabase
86
+ include AppOpticsAPM::Inst::Sequel
87
+
88
+ def self.included(klass)
89
+ AppOpticsAPM::Util.method_alias(klass, :run, ::Sequel::Database)
90
+ AppOpticsAPM::Util.method_alias(klass, :execute_ddl, ::Sequel::Database)
91
+ AppOpticsAPM::Util.method_alias(klass, :execute_dui, ::Sequel::Database)
92
+ AppOpticsAPM::Util.method_alias(klass, :execute_insert, ::Sequel::Database)
93
+ end
94
+
95
+ def run_with_appoptics(sql, opts = ::Sequel::OPTS)
96
+ if AppOpticsAPM.tracing?
97
+ kvs = extract_trace_details(sql, opts)
98
+ AppOpticsAPM::API.log_entry(:sequel, kvs)
99
+ end
100
+
101
+ run_without_appoptics(sql, opts)
102
+ rescue => e
103
+ AppOpticsAPM::API.log_exception(:sequel, e)
104
+ raise e
105
+ ensure
106
+ AppOpticsAPM::API.log_exit(:sequel)
107
+ end
108
+
109
+ def execute_ddl_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
110
+ # If we're already tracing a sequel operation, then this call likely came
111
+ # from Sequel::Dataset. In this case, just pass it on.
112
+ return execute_ddl_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
113
+
114
+ exec_with_appoptics(:execute_ddl_without_appoptics, sql, opts, &block)
115
+ end
116
+
117
+ def execute_dui_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
118
+ # If we're already tracing a sequel operation, then this call likely came
119
+ # from Sequel::Dataset. In this case, just pass it on.
120
+ return execute_dui_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
121
+
122
+ exec_with_appoptics(:execute_dui_without_appoptics, sql, opts, &block)
123
+ end
124
+
125
+ def execute_insert_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
126
+ # If we're already tracing a sequel operation, then this call likely came
127
+ # from Sequel::Dataset. In this case, just pass it on.
128
+ return execute_insert_without_appoptics(sql, opts, &block) if AppOpticsAPM.tracing_layer?(:sequel)
129
+
130
+ exec_with_appoptics(:execute_insert_without_appoptics, sql, opts, &block)
131
+ end
132
+ end # module SequelDatabase
133
+
134
+ module SequelDataset
135
+ include AppOpticsAPM::Inst::Sequel
136
+
137
+ def self.included(klass)
138
+ AppOpticsAPM::Util.method_alias(klass, :execute, ::Sequel::Dataset)
139
+ AppOpticsAPM::Util.method_alias(klass, :execute_ddl, ::Sequel::Dataset)
140
+ AppOpticsAPM::Util.method_alias(klass, :execute_dui, ::Sequel::Dataset)
141
+ AppOpticsAPM::Util.method_alias(klass, :execute_insert, ::Sequel::Dataset)
142
+ end
143
+
144
+ def execute_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
145
+ exec_with_appoptics(:execute_without_appoptics, sql, opts, &block)
146
+ end
147
+
148
+ def execute_ddl_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
149
+ exec_with_appoptics(:execute_ddl_without_appoptics, sql, opts, &block)
150
+ end
151
+
152
+ def execute_dui_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
153
+ exec_with_appoptics(:execute_dui_without_appoptics, sql, opts, &block)
154
+ end
155
+
156
+ def execute_insert_with_appoptics(sql, opts = ::Sequel::OPTS, &block)
157
+ exec_with_appoptics(:execute_insert_without_appoptics, sql, opts, &block)
158
+ end
159
+
160
+ end # module SequelDataset
161
+ end # module Inst
162
+ end # module AppOpticsAPM
163
+
164
+ if AppOpticsAPM::Config[:sequel][:enabled]
165
+ if defined?(::Sequel) && ::Sequel::VERSION < '4.0.0'
166
+ # For versions before 4.0.0, Sequel::OPTS wasn't defined.
167
+ # Define it as an empty hash for backwards compatibility.
168
+ module ::Sequel
169
+ OPTS = {}
170
+ end
171
+ end
172
+
173
+ if defined?(::Sequel)
174
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting sequel' if AppOpticsAPM::Config[:verbose]
175
+ AppOpticsAPM::Util.send_include(::Sequel::Database, AppOpticsAPM::Inst::SequelDatabase)
176
+ AppOpticsAPM::Util.send_include(::Sequel::Dataset, AppOpticsAPM::Inst::SequelDataset)
177
+ end
178
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ class SidekiqClient
6
+ def collect_kvs(args)
7
+ begin
8
+ # Attempt to collect up pertinent info. If we hit something unexpected,
9
+ # keep calm and instrument on.
10
+
11
+ report_kvs = {}
12
+ worker_class, msg, queue, _ = args
13
+
14
+ report_kvs[:Spec] = :pushq
15
+ report_kvs[:Flavor] = :sidekiq
16
+ report_kvs[:Queue] = queue
17
+ report_kvs[:Retry] = msg['retry']
18
+ report_kvs[:JobName] = msg['wrapped'] || worker_class
19
+ report_kvs[:MsgID] = msg['jid']
20
+ report_kvs[:Args] = msg['args'].to_s[0..1024] if AppOpticsAPM::Config[:sidekiqclient][:log_args]
21
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sidekiqclient][:collect_backtraces]
22
+ rescue => e
23
+ AppOpticsAPM.logger.warn "[appoptics_apm/sidekiq] Non-fatal error capturing KVs: #{e.message}"
24
+ end
25
+ report_kvs
26
+ end
27
+
28
+ def call(*args)
29
+ # args: 0: worker_class, 1: msg, 2: queue, 3: redis_pool
30
+ if AppOpticsAPM.tracing?
31
+ report_kvs = collect_kvs(args)
32
+ AppOpticsAPM::API.log_entry(:'sidekiq-client', report_kvs)
33
+ args[1]['SourceTrace'] = AppOpticsAPM::Context.toString
34
+ end
35
+
36
+ result = yield
37
+ rescue => e
38
+ AppOpticsAPM::API.log_exception(:'sidekiq-client', e, { :JobID => result['jid'] })
39
+ raise
40
+ ensure
41
+ AppOpticsAPM::API.log_exit(:'sidekiq-client', { :JobID => result['jid'] })
42
+ end
43
+ end
44
+ end
45
+
46
+ if defined?(Sidekiq) && AppOpticsAPM::Config[:sidekiqclient][:enabled]
47
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting sidekiq client' if AppOpticsAPM::Config[:verbose]
48
+
49
+ Sidekiq.configure_client do |config|
50
+ config.client_middleware do |chain|
51
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Adding Sidekiq client middleware' if AppOpticsAPM::Config[:verbose]
52
+ chain.add AppOpticsAPM::SidekiqClient
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ class SidekiqWorker
6
+ def collect_kvs(args)
7
+ begin
8
+ # Attempt to collect up pertinent info. If we hit something unexpected,
9
+ # keep calm and instrument on.
10
+ report_kvs = {}
11
+ _worker, msg, queue = args
12
+
13
+ # Background Job Spec KVs
14
+ report_kvs[:Spec] = :job
15
+ report_kvs[:Flavor] = :sidekiq
16
+ report_kvs[:Queue] = queue
17
+ report_kvs[:Retry] = msg['retry']
18
+ report_kvs[:JobName] = msg['wrapped'] || msg['class']
19
+ report_kvs[:MsgID] = msg['jid']
20
+ report_kvs[:Args] = msg['args'].to_s[0..1024] if AppOpticsAPM::Config[:sidekiqworker][:log_args]
21
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:sidekiqworker][:collect_backtraces]
22
+
23
+ # Webserver Spec KVs
24
+ report_kvs[:'HTTP-Host'] = Socket.gethostname
25
+ report_kvs[:Controller] = "Sidekiq_#{queue}"
26
+ report_kvs[:Action] = msg['wrapped'] || msg['class']
27
+ report_kvs[:URL] = "/sidekiq/#{queue}/#{msg['wrapped'] || msg['class']}"
28
+ rescue => e
29
+ AppOpticsAPM.logger.warn "[appoptics_apm/sidekiq] Non-fatal error capturing KVs: #{e.message}"
30
+ end
31
+ report_kvs
32
+ end
33
+
34
+ def call(*args)
35
+ # args: 0: worker, 1: msg, 2: queue
36
+ report_kvs = collect_kvs(args)
37
+
38
+ # Something is happening across Celluloid threads where liboboe settings
39
+ # are being lost. So we re-set the tracing mode to assure
40
+ # we sample as desired. Setting the tracing mode will re-update
41
+ # the liboboe settings.
42
+ AppOpticsAPM.set_tracing_mode(AppOpticsAPM::Config[:tracing_mode].to_sym)
43
+
44
+ # Continue the trace from the enqueue side?
45
+ if args[1].is_a?(Hash) && AppOpticsAPM::XTrace.valid?(args[1]['SourceTrace'])
46
+ report_kvs[:SourceTrace] = args[1]['SourceTrace']
47
+ end
48
+
49
+ AppOpticsAPM::SDK.start_trace(:'sidekiq-worker', nil, report_kvs) do
50
+ yield
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ if defined?(Sidekiq) && AppOpticsAPM::Config[:sidekiqworker][:enabled]
57
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting sidekiq worker' if AppOpticsAPM::Config[:verbose]
58
+
59
+ Sidekiq.configure_server do |config|
60
+ config.server_middleware do |chain|
61
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Adding Sidekiq worker middleware' if AppOpticsAPM::Config[:verbose]
62
+ chain.add AppOpticsAPM::SidekiqWorker
63
+ end
64
+ end
65
+ end