appoptics_apm-zearn 4.13.1

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 (145) 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/.github/workflows/build_and_release_gem.yml +103 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +168 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +159 -0
  12. data/.gitignore +36 -0
  13. data/.rubocop.yml +29 -0
  14. data/.travis.yml +130 -0
  15. data/.yardopts +6 -0
  16. data/CHANGELOG.md +769 -0
  17. data/CONFIG.md +33 -0
  18. data/Gemfile +14 -0
  19. data/LICENSE +202 -0
  20. data/README.md +393 -0
  21. data/appoptics_apm.gemspec +70 -0
  22. data/bin/appoptics_apm_config +15 -0
  23. data/examples/prepend.rb +13 -0
  24. data/examples/sdk_examples.rb +158 -0
  25. data/ext/oboe_metal/README.md +69 -0
  26. data/ext/oboe_metal/extconf.rb +151 -0
  27. data/ext/oboe_metal/lib/.keep +0 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  30. data/ext/oboe_metal/noop/noop.c +8 -0
  31. data/ext/oboe_metal/src/README.md +6 -0
  32. data/ext/oboe_metal/src/VERSION +2 -0
  33. data/ext/oboe_metal/src/bson/bson.h +220 -0
  34. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  35. data/ext/oboe_metal/src/frames.cc +246 -0
  36. data/ext/oboe_metal/src/frames.h +40 -0
  37. data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
  38. data/ext/oboe_metal/src/logging.cc +95 -0
  39. data/ext/oboe_metal/src/logging.h +35 -0
  40. data/ext/oboe_metal/src/oboe.h +1156 -0
  41. data/ext/oboe_metal/src/oboe_api.cpp +652 -0
  42. data/ext/oboe_metal/src/oboe_api.hpp +431 -0
  43. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  44. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7329 -0
  45. data/ext/oboe_metal/src/profiling.cc +435 -0
  46. data/ext/oboe_metal/src/profiling.h +78 -0
  47. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  48. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  49. data/ext/oboe_metal/test/README.md +56 -0
  50. data/ext/oboe_metal/test/frames_test.cc +164 -0
  51. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  52. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  54. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  55. data/ext/oboe_metal/test/test.h +11 -0
  56. data/ext/oboe_metal/test/test_main.cc +32 -0
  57. data/init.rb +4 -0
  58. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  59. data/lib/appoptics_apm/api/logging.rb +381 -0
  60. data/lib/appoptics_apm/api/memcache.rb +37 -0
  61. data/lib/appoptics_apm/api/metrics.rb +63 -0
  62. data/lib/appoptics_apm/api/tracing.rb +57 -0
  63. data/lib/appoptics_apm/api/util.rb +120 -0
  64. data/lib/appoptics_apm/api.rb +21 -0
  65. data/lib/appoptics_apm/base.rb +231 -0
  66. data/lib/appoptics_apm/config.rb +299 -0
  67. data/lib/appoptics_apm/frameworks/grape.rb +98 -0
  68. data/lib/appoptics_apm/frameworks/padrino.rb +78 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +114 -0
  81. data/lib/appoptics_apm/frameworks/rails/inst/logger_formatters.rb +27 -0
  82. data/lib/appoptics_apm/frameworks/rails.rb +100 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +96 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  86. data/lib/appoptics_apm/inst/curb.rb +332 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  90. data/lib/appoptics_apm/inst/excon.rb +125 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +106 -0
  92. data/lib/appoptics_apm/inst/graphql.rb +240 -0
  93. data/lib/appoptics_apm/inst/grpc_client.rb +159 -0
  94. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  95. data/lib/appoptics_apm/inst/http.rb +81 -0
  96. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  97. data/lib/appoptics_apm/inst/logger_formatter.rb +50 -0
  98. data/lib/appoptics_apm/inst/logging_log_event.rb +28 -0
  99. data/lib/appoptics_apm/inst/lumberjack_formatter.rb +13 -0
  100. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  101. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  102. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  103. data/lib/appoptics_apm/inst/moped.rb +466 -0
  104. data/lib/appoptics_apm/inst/rack.rb +182 -0
  105. data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
  106. data/lib/appoptics_apm/inst/redis.rb +274 -0
  107. data/lib/appoptics_apm/inst/resque.rb +151 -0
  108. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  109. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  110. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  111. data/lib/appoptics_apm/inst/sidekiq-worker.rb +66 -0
  112. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  113. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  114. data/lib/appoptics_apm/instrumentation.rb +22 -0
  115. data/lib/appoptics_apm/loading.rb +65 -0
  116. data/lib/appoptics_apm/logger.rb +14 -0
  117. data/lib/appoptics_apm/noop/README.md +9 -0
  118. data/lib/appoptics_apm/noop/context.rb +27 -0
  119. data/lib/appoptics_apm/noop/metadata.rb +25 -0
  120. data/lib/appoptics_apm/noop/profiling.rb +21 -0
  121. data/lib/appoptics_apm/oboe_init_options.rb +211 -0
  122. data/lib/appoptics_apm/ruby.rb +35 -0
  123. data/lib/appoptics_apm/sdk/current_trace.rb +77 -0
  124. data/lib/appoptics_apm/sdk/custom_metrics.rb +94 -0
  125. data/lib/appoptics_apm/sdk/logging.rb +37 -0
  126. data/lib/appoptics_apm/sdk/tracing.rb +434 -0
  127. data/lib/appoptics_apm/support/profiling.rb +18 -0
  128. data/lib/appoptics_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/appoptics_apm/support/transaction_settings.rb +219 -0
  130. data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
  131. data/lib/appoptics_apm/support_report.rb +119 -0
  132. data/lib/appoptics_apm/test.rb +95 -0
  133. data/lib/appoptics_apm/thread_local.rb +26 -0
  134. data/lib/appoptics_apm/util.rb +326 -0
  135. data/lib/appoptics_apm/version.rb +16 -0
  136. data/lib/appoptics_apm/xtrace.rb +115 -0
  137. data/lib/appoptics_apm.rb +77 -0
  138. data/lib/joboe_metal.rb +212 -0
  139. data/lib/oboe.rb +7 -0
  140. data/lib/oboe_metal.rb +172 -0
  141. data/lib/rails/generators/appoptics_apm/install_generator.rb +47 -0
  142. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +425 -0
  143. data/log/.keep +0 -0
  144. data/yardoc_frontpage.md +26 -0
  145. metadata +231 -0
@@ -0,0 +1,231 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ # Constants from liboboe
5
+ APPOPTICS_TRACE_DISABLED = 0
6
+ APPOPTICS_TRACE_ENABLED = 1
7
+
8
+ # OBOE_SAMPLE_RATE_SOURCE_FILE = 1
9
+ # OBOE_SAMPLE_RATE_SOURCE_DEFAULT = 2
10
+ # OBOE_SAMPLE_RATE_SOURCE_OBOE = 3
11
+ # OBOE_SAMPLE_RATE_SOURCE_LAST_OBOE = 4
12
+ # OBOE_SAMPLE_RATE_SOURCE_DEFAULT_MISCONFIGURED = 5
13
+ # OBOE_SAMPLE_RATE_SOURCE_OBOE_DEFAULT = 6
14
+
15
+ # Masks for bitwise ops
16
+ # ZERO_MASK = 0b0000000000000000000000000000
17
+
18
+ SAMPLE_RATE_MASK = 0b0000111111111111111111111111
19
+ SAMPLE_SOURCE_MASK = 0b1111000000000000000000000000
20
+
21
+ # ZERO_SAMPLE_RATE_MASK = 0b1111000000000000000000000000
22
+ # ZERO_SAMPLE_SOURCE_MASK = 0b0000111111111111111111111111
23
+
24
+ # APPOPTICS_STR_BLANK = ''.freeze
25
+ APPOPTICS_STR_LAYER = 'Layer'.freeze
26
+ APPOPTICS_STR_LABEL = 'Label'.freeze
27
+
28
+ ##
29
+ # This module is the base module for the various implementations of AppOpticsAPM reporting.
30
+ # Current variations as of 2014-09-10 are a c-extension, JRuby (using AppOpticsAPM Java
31
+ # instrumentation) and a Heroku c-extension (with embedded tracelyzer)
32
+ module AppOpticsAPMBase
33
+ extend AppOpticsAPM::ThreadLocal
34
+
35
+ attr_accessor :reporter
36
+ attr_accessor :loaded
37
+ thread_local :sample_source
38
+ thread_local :sample_rate
39
+ thread_local :layer
40
+ thread_local :layer_op
41
+
42
+ # transaction_name is used for custom transaction naming
43
+ # It needs to be globally accessible, but is only set by the request processors of the different frameworks
44
+ # and read by rack
45
+ thread_local :transaction_name
46
+
47
+ # Semaphore used during the test suite to test
48
+ # global config options.
49
+ thread_local :config_lock
50
+
51
+ # The following accessors indicate the incoming tracing state received
52
+ # by the rack layer. These are primarily used to identify state
53
+ # between the Ruby and JAppOpticsAPM instrumentation under JRuby.
54
+ #
55
+ # This is because that even though there may be an incoming
56
+ # X-Trace request header, tracing may have already been started
57
+ # by Joboe. Such a scenario occurs when the application is being
58
+ # hosted by a Java container (such as Tomcat or Glassfish) and
59
+ # AppOpticsAPM has already initiated tracing. In this case, we shouldn't
60
+ # pickup the X-Trace context in the X-Trace header and we shouldn't
61
+ # set the outgoing response X-Trace header or clear context.
62
+ # Yeah I know. Yuck.
63
+
64
+ # Occurs only on Jruby. Indicates that Joboe (the java instrumentation)
65
+ # has already started tracing before it hit the JRuby instrumentation.
66
+ # It is used in Rack#call if there is a context when entering rack
67
+ thread_local :has_incoming_context
68
+
69
+ # Indicates the existence of a valid X-Trace request header
70
+ thread_local :has_xtrace_header
71
+
72
+ # This indicates that this trace was continued from
73
+ # an incoming X-Trace request header or in the case
74
+ # of JRuby, a trace already started by JAppOpticsAPM.
75
+ thread_local :is_continued_trace
76
+
77
+ ##
78
+ # extended
79
+ #
80
+ # Invoked when this module is extended.
81
+ # e.g. extend AppOpticsAPMBase
82
+ #
83
+ def self.extended(cls)
84
+ cls.loaded = true
85
+
86
+ # This gives us pretty accessors with questions marks at the end
87
+ # e.g. is_continued_trace --> is_continued_trace?
88
+ AppOpticsAPM.methods.select { |m| m =~ /^is_|^has_/ }.each do |c|
89
+ unless c =~ /\?$|=$/
90
+ # AppOpticsAPM.logger.debug "aliasing #{c}? to #{c}"
91
+ alias_method "#{c}?", c
92
+ end
93
+ end
94
+ end
95
+
96
+ ##
97
+ # pickup_context
98
+ #
99
+ # for JRUBY
100
+ # Determines whether we should pickup context
101
+ # from an incoming X-Trace request header. The answer
102
+ # is generally yes but there are cases in JRuby under
103
+ # Tomcat (or Glassfish etc.) where tracing may have
104
+ # been already started by the Java instrumentation (Joboe)
105
+ # in which case we don't want to do this.
106
+ #
107
+ def pickup_context?(xtrace)
108
+ return false unless AppOpticsAPM::XTrace.valid?(xtrace)
109
+
110
+ if defined?(JRUBY_VERSION) && AppOpticsAPM.tracing?
111
+ return false
112
+ else
113
+ return true
114
+ end
115
+ end
116
+
117
+ ##
118
+ # tracing_layer?
119
+ #
120
+ # Queries the thread local variable about the current
121
+ # layer being traced. This is used in cases of recursive
122
+ # operation tracing or one instrumented operation calling another.
123
+ #
124
+ def tracing_layer?(layer)
125
+ AppOpticsAPM.layer == layer.to_sym
126
+ end
127
+
128
+ ##
129
+ # tracing_layer_op?
130
+ #
131
+ # Queries the thread local variable about the current
132
+ # operation being traced. This is used in cases of recursive
133
+ # operation tracing or one instrumented operation calling another.
134
+ #
135
+ # In such cases, we only want to trace the outermost operation.
136
+ #
137
+ def tracing_layer_op?(operation)
138
+ unless AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.is_a?(Array)
139
+ AppOpticsAPM.logger.error('[appopticsapm/logging] INTERNAL: layer_op should be nil or an array, please report to technicalsupport@solarwinds.com')
140
+ return false
141
+ end
142
+
143
+ return false if AppOpticsAPM.layer_op.nil? || AppOpticsAPM.layer_op.empty? || !operation.respond_to?(:to_sym)
144
+ AppOpticsAPM.layer_op.last == operation.to_sym
145
+ end
146
+
147
+ # TODO ME review use of these boolean statements
148
+ # ____ they should now be handled by TransactionSettings,
149
+ # ____ because there can be exceptions to :enabled and :disabled
150
+
151
+ ##
152
+ # Returns true if the tracing_mode is set to :enabled.
153
+ # False otherwise
154
+ #
155
+ def tracing_enabled?
156
+ AppOpticsAPM::Config[:tracing_mode] &&
157
+ [:enabled, :always].include?(AppOpticsAPM::Config[:tracing_mode].to_sym)
158
+ end
159
+
160
+ ##
161
+ # Returns true if the tracing_mode is set to :disabled.
162
+ # False otherwise
163
+ #
164
+ def tracing_disabled?
165
+ AppOpticsAPM::Config[:tracing_mode] &&
166
+ [:disabled, :never].include?(AppOpticsAPM::Config[:tracing_mode].to_sym)
167
+ end
168
+
169
+ ##
170
+ # Returns true if we are currently tracing a request
171
+ # False otherwise
172
+ #
173
+ def tracing?
174
+ return false if !AppOpticsAPM.loaded # || AppOpticsAPM.tracing_disabled?
175
+ AppOpticsAPM::Context.isSampled
176
+ end
177
+
178
+ def heroku?
179
+ ENV.key?('APPOPTICS_URL')
180
+ end
181
+
182
+ ##
183
+ # Determines if we are running under a forking webserver
184
+ #
185
+ def forking_webserver?
186
+ if (defined?(::Unicorn) && ($PROGRAM_NAME =~ /unicorn/i)) ||
187
+ (defined?(::Puma) && ($PROGRAM_NAME =~ /puma/i))
188
+ true
189
+ else
190
+ false
191
+ end
192
+ end
193
+
194
+ ##
195
+ # Indicates whether a supported framework is in use
196
+ # or not
197
+ #
198
+ def framework?
199
+ defined?(::Rails) || defined?(::Sinatra) || defined?(::Padrino) || defined?(::Grape)
200
+ end
201
+
202
+ ##
203
+ # These methods should be implemented by the descendants
204
+ # (Oboe_metal, JOboe_metal (JRuby), Heroku_metal)
205
+ #
206
+ def sample?(_opts = {})
207
+ fail 'sample? should be implemented by metal layer.'
208
+ end
209
+
210
+ def log(_layer, _label, _options = {})
211
+ fail 'log should be implemented by metal layer.'
212
+ end
213
+
214
+ def set_tracing_mode(_mode)
215
+ fail 'set_tracing_mode should be implemented by metal layer.'
216
+ end
217
+
218
+ def set_sample_rate(_rate)
219
+ fail 'set_sample_rate should be implemented by metal layer.'
220
+ end
221
+ end
222
+
223
+ module AppOpticsAPM
224
+ extend AppOpticsAPMBase
225
+ end
226
+
227
+ # Setup an alias so we don't bug users
228
+ # about single letter capitalization
229
+ AppopticsAPM = AppOpticsAPM
230
+ AppOpticsApm = AppOpticsAPM
231
+ AppopticsApm = AppOpticsAPM
@@ -0,0 +1,299 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative 'support/transaction_settings'
5
+
6
+ module AppOpticsAPM
7
+ ##
8
+ # This module exposes a nested configuration hash that can be used to
9
+ # configure and/or modify the functionality of the appoptics_apm gem.
10
+ #
11
+ # Use AppOpticsAPM::Config.show to view the entire nested hash.
12
+ #
13
+ module Config
14
+ @@config = {}
15
+
16
+ @@instrumentation = [:action_controller, :action_controller_api, :action_view,
17
+ :active_record, :bunnyclient, :bunnyconsumer, :cassandra, :curb,
18
+ :dalli, :delayed_jobclient, :delayed_jobworker,
19
+ :excon, :faraday, :graphql, :grpc_client, :grpc_server, :grape,
20
+ :httpclient, :nethttp, :memcached, :mongo, :moped, :padrino, :rack, :redis,
21
+ :resqueclient, :resqueworker, :rest_client,
22
+ :sequel, :sidekiqclient, :sidekiqworker, :sinatra, :typhoeus]
23
+
24
+ # ignore configs for instrumentations we don't have anymore
25
+ # can't remove because the config may still be present in configs created
26
+ # with previous gem versions
27
+ @@ignore = [:em_http_request]
28
+
29
+ # Subgrouping of instrumentation
30
+ @@http_clients = [:curb, :excon,
31
+ # :em_http_request,
32
+ :faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
33
+
34
+ ##
35
+ # load_config_file
36
+ #
37
+ # There are 3 possible locations for the config file:
38
+ # Rails default, ENV['APPOPTICS_APM_CONFIG_RUBY'], or the gem's default
39
+ #
40
+ # Hierarchie:
41
+ # 1 - Rails default: config/initializers/appoptics_apm.rb
42
+ # (also loaded by Rails, but we can't reliably determine if Rails is running)
43
+ # 2 - ENV['APPOPTICS_APM_CONFIG_RUBY']
44
+ # 3 - Gem default: <startup_dir>/appoptics_apm_config.rb
45
+ #
46
+ def self.load_config_file
47
+ config_files = []
48
+
49
+ # Check for the rails config file
50
+ config_file = File.join(Dir.pwd, 'config/initializers/appoptics_apm.rb')
51
+ config_files << config_file if File.exist?(config_file)
52
+
53
+ # Check for file set by env variable
54
+ if ENV.key?('APPOPTICS_APM_CONFIG_RUBY')
55
+ if File.exist?(ENV['APPOPTICS_APM_CONFIG_RUBY']) && !File.directory?(ENV['APPOPTICS_APM_CONFIG_RUBY'])
56
+ config_files << ENV['APPOPTICS_APM_CONFIG_RUBY']
57
+ elsif File.exist?(File.join(ENV['APPOPTICS_APM_CONFIG_RUBY'], 'appoptics_apm_config.rb'))
58
+ config_files << File.join(ENV['APPOPTICS_APM_CONFIG_RUBY'], 'appoptics_apm_config.rb')
59
+ else
60
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] Could not find the configuration file set by the APPOPTICS_APM_CONFIG_RUBY environment variable: #{ENV['APPOPTICS_APM_CONFIG_RUBY']}"
61
+ end
62
+ end
63
+
64
+ # Check for default config file
65
+ config_file = File.join(Dir.pwd, 'appoptics_apm_config.rb')
66
+ config_files << config_file if File.exist?(config_file)
67
+
68
+ unless config_files.empty? # we use the defaults from the template if there are no config files
69
+ if config_files.size > 1
70
+ AppOpticsAPM.logger.warn [
71
+ '[appoptics_apm/config] Multiple configuration files configured, using the first one listed: ',
72
+ config_files.join(', ')
73
+ ].join(' ')
74
+ end
75
+ load(config_files[0])
76
+ end
77
+
78
+ # sets AppOpticsAPM::Config[:debug_level], AppOpticsAPM.logger.level
79
+ set_log_level
80
+
81
+ # the verbose setting is only relevant for ruby, ENV['APPOPTICS_GEM_VERBOSE'] overrides
82
+ if ENV.key?('APPOPTICS_GEM_VERBOSE')
83
+ AppOpticsAPM::Config[:verbose] = ENV['APPOPTICS_GEM_VERBOSE'].downcase == 'true'
84
+ end
85
+ end
86
+
87
+ def self.set_log_level
88
+ unless (-1..6).include?(AppOpticsAPM::Config[:debug_level])
89
+ AppOpticsAPM::Config[:debug_level] = 3
90
+ end
91
+
92
+ # let's find and use the equivalent debug level for ruby
93
+ debug_level = (ENV['APPOPTICS_DEBUG_LEVEL'] || AppOpticsAPM::Config[:debug_level] || 3).to_i
94
+ if debug_level < 0
95
+ # there should be no logging if APPOPTICS_DEBUG_LEVEL == -1
96
+ # In Ruby level 5 is UNKNOWN and it can log, but level 6 is quiet
97
+ AppOpticsAPM.logger.level = 6
98
+ else
99
+ AppOpticsAPM.logger.level = [4 - debug_level, 0].max
100
+ end
101
+ AppOpticsAPM::Config[:debug_level] = debug_level
102
+ end
103
+
104
+ ##
105
+ # print_config
106
+ #
107
+ # print configurations one per line
108
+ # to create an output similar to the content of the config file
109
+ #
110
+ def self.print_config
111
+ AppOpticsAPM.logger.warn "# General configurations"
112
+ non_instrumentation = @@config.keys - @@instrumentation
113
+ non_instrumentation.each do |config|
114
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}] = #{@@config[config]}"
115
+ end
116
+
117
+ AppOpticsAPM.logger.warn "\n# Instrumentation specific configurations"
118
+ AppOpticsAPM.logger.warn "# Enabled/Disabled Instrumentation"
119
+ @@instrumentation.each do |config|
120
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:enabled] = #{@@config[config][:enabled]}"
121
+ end
122
+
123
+ AppOpticsAPM.logger.warn "\n# Enabled/Disabled Backtrace Collection"
124
+ @@instrumentation.each do |config|
125
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:collect_backtraces] = #{@@config[config][:collect_backtraces]}"
126
+ end
127
+
128
+ AppOpticsAPM.logger.warn "\n# Logging of outgoing HTTP query args"
129
+ @@instrumentation.each do |config|
130
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:#{config}][:log_args] = #{@@config[config][:log_args] || false}"
131
+ end
132
+
133
+ AppOpticsAPM.logger.warn "\n# Bunny Controller and Action"
134
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:bunnyconsumer][:controller] = #{@@config[:bunnyconsumer][:controller].inspect}"
135
+ AppOpticsAPM.logger.warn "AppOpticsAPM::Config[:bunnyconsumer][:action] = #{@@config[:bunnyconsumer][:action].inspect}"
136
+ nil
137
+ end
138
+
139
+ ##
140
+ # initialize
141
+ #
142
+ # Initializer method to set everything up with a default configuration.
143
+ # The defaults are read from the template configuration file.
144
+ #
145
+ # rubocop:disable Metrics/AbcSize
146
+ def self.initialize(_data = {})
147
+ (@@instrumentation+@@ignore).each { |k| @@config[k] = {} }
148
+ @@config[:transaction_name] = {}
149
+
150
+ # Always load the template, it has all the keys and defaults defined,
151
+ # no guarantee of completeness in the user's config file
152
+ load(File.join(File.dirname(File.dirname(__FILE__)),
153
+ 'rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb'))
154
+ end
155
+ # rubocop:enable Metrics/AbcSize
156
+
157
+ def self.update!(data)
158
+ data.each do |key, value|
159
+ self[key] = value
160
+ end
161
+ end
162
+
163
+ def self.merge!(data)
164
+ update!(data)
165
+ end
166
+
167
+ def self.[](key)
168
+ if key == :resque
169
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] :resque config is deprecated. It is now split into :resqueclient and :resqueworker.'
170
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Called from #{Kernel.caller[0]}"
171
+ end
172
+
173
+ @@config[key.to_sym]
174
+ end
175
+
176
+ ##
177
+ # []=
178
+ #
179
+ # Config variable assignment method. Here we validate and store the
180
+ # assigned value(s) and trigger any secondary action needed.
181
+ #
182
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
183
+ def self.[]=(key, value)
184
+ key = key.to_sym
185
+ @@config[key] = value
186
+
187
+ if key == :sampling_rate
188
+ AppOpticsAPM.logger.warn '[appoptics_apm/config] sampling_rate is not a supported setting for AppOpticsAPM::Config. ' \
189
+ 'Please use :sample_rate.'
190
+
191
+ elsif key == :sample_rate
192
+ unless value.is_a?(Integer) || value.is_a?(Float)
193
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] :sample_rate must be a number between 0 and 1000000 (1m) " \
194
+ "(provided: #{value}), corrected to 0"
195
+ value = 0
196
+ end
197
+
198
+ # Validate :sample_rate value
199
+ unless value.between?(0, 1e6)
200
+ value_1 = value
201
+ value = value_1 < 0 ? 0 : 1_000_000
202
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] :sample_rate must be between 0 and 1000000 (1m) " \
203
+ "(provided: #{value_1}), corrected to #{value}"
204
+ end
205
+
206
+ # Assure value is an integer
207
+ @@config[key.to_sym] = value.to_i
208
+ AppOpticsAPM.set_sample_rate(value) if AppOpticsAPM.loaded
209
+
210
+ elsif key == :action_blacklist
211
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] :action_blacklist has been deprecated and no longer functions."
212
+
213
+ elsif key == :dnt_regexp
214
+ if value.nil? || value == ''
215
+ @@config[:dnt_compiled] = nil
216
+ else
217
+ @@config[:dnt_compiled] =
218
+ Regexp.new(AppOpticsAPM::Config[:dnt_regexp], AppOpticsAPM::Config[:dnt_opts] || nil)
219
+ end
220
+
221
+ elsif key == :dnt_opts
222
+ if AppOpticsAPM::Config[:dnt_regexp] && AppOpticsAPM::Config[:dnt_regexp] != ''
223
+ @@config[:dnt_compiled] =
224
+ Regexp.new(AppOpticsAPM::Config[:dnt_regexp], AppOpticsAPM::Config[:dnt_opts] || nil)
225
+ end
226
+
227
+ elsif key == :profiling_interval
228
+ if value.is_a?(Integer) && value > 0
229
+ value = [100, value].min
230
+ else
231
+ value = 10
232
+ end
233
+ @@config[:profiling_interval] = value
234
+ # CProfiler may not be loaded yet, the profiler will send the value
235
+ # after it is loaded
236
+ AppOpticsAPM::CProfiler.set_interval(value) if defined? AppOpticsAPM::CProfiler
237
+
238
+ elsif key == :transaction_settings
239
+ if value.is_a?(Hash)
240
+ AppOpticsAPM::TransactionSettings.compile_url_settings(value[:url])
241
+ else
242
+ AppOpticsAPM::TransactionSettings.reset_url_regexps
243
+ end
244
+
245
+ elsif key == :resque
246
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] :resque config is deprecated. It is now split into :resqueclient and :resqueworker."
247
+ AppOpticsAPM.logger.warn "[appoptics_apm/config] Called from #{Kernel.caller[0]}"
248
+
249
+ elsif key == :include_url_query_params # DEPRECATED
250
+ # Obey the global flag and update all of the per instrumentation
251
+ # <tt>:log_args</tt> values.
252
+ @@config[:rack][:log_args] = value
253
+
254
+ elsif key == :include_remote_url_params # DEPRECATED
255
+ # Obey the global flag and update all of the per instrumentation
256
+ # <tt>:log_args</tt> values.
257
+ @@http_clients.each do |i|
258
+ @@config[i][:log_args] = value
259
+ end
260
+
261
+ elsif key == :tracing_mode
262
+ # CAN'T DO `set_tracing_mode` ANYMORE, ALL TRACING COMMUNICATION TO OBOE
263
+ # IS NOW HANDLED BY TransactionSettings
264
+ # AppOpticsAPM.set_tracing_mode(value.to_sym) if AppOpticsAPM.loaded
265
+
266
+ # Make sure that the mode is stored as a symbol
267
+ @@config[key.to_sym] = value.to_sym
268
+
269
+ elsif key == :trigger_tracing_mode
270
+ # Make sure that the mode is stored as a symbol
271
+ @@config[key.to_sym] = value.to_sym
272
+ end
273
+ end
274
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
275
+
276
+ def self.method_missing(sym, *args)
277
+ class_var_name = "@@#{sym}"
278
+
279
+ if sym.to_s =~ /(.+)=$/
280
+ self[$1] = args.first
281
+ else
282
+ # Try part of the @@config hash first
283
+ if @@config.key?(sym)
284
+ self[sym]
285
+
286
+ # Then try as a class variable
287
+ elsif self.class_variable_defined?(class_var_name.to_sym)
288
+ self.class_eval(class_var_name)
289
+
290
+ # Congrats - You've won a brand new nil...
291
+ else
292
+ nil
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ AppOpticsAPM::Config.initialize
@@ -0,0 +1,98 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+ #
4
+ class GrapeError < StandardError; end
5
+
6
+ module AppOpticsAPM
7
+ module Grape
8
+ module API
9
+ def self.extended(klass)
10
+ AppOpticsAPM::Util.class_method_alias(klass, :inherited, ::Grape::API)
11
+ end
12
+
13
+ def inherited_with_appoptics(subclass)
14
+ inherited_without_appoptics(subclass)
15
+
16
+ subclass.use AppOpticsAPM::Rack
17
+ end
18
+ end
19
+
20
+ module Endpoint
21
+ def self.included(klass)
22
+ AppOpticsAPM::Util.method_alias(klass, :run, ::Grape::Endpoint)
23
+ end
24
+
25
+ def run_with_appoptics(*args)
26
+ # Report Controller/Action and Transaction as best possible
27
+ report_kvs = {}
28
+
29
+ report_kvs[:Controller] = options[:for].to_s
30
+ report_kvs[:Action] =
31
+ if route&.pattern
32
+ route.options ? "#{route.options[:method]}#{route.pattern.origin}" : route.pattern.origin
33
+ else
34
+ args.empty? ? env['PATH_INFO'] : args[0]['PATH_INFO']
35
+ end
36
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:grape][:collect_backtraces]
37
+
38
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
39
+ env['appoptics_apm.action'] = report_kvs[:Action]
40
+
41
+ AppOpticsAPM::API.log_entry('grape', report_kvs)
42
+
43
+ run_without_appoptics(*args)
44
+ ensure
45
+ AppOpticsAPM::API.log_exit('grape')
46
+ end
47
+ end
48
+
49
+ module Middleware
50
+ module Error
51
+ def self.included(klass)
52
+ AppOpticsAPM::Util.method_alias(klass, :error_response, ::Grape::Middleware::Error)
53
+ end
54
+
55
+ def error_response_with_appoptics(error = {})
56
+ response = error_response_without_appoptics(error)
57
+ status, headers, _body = response.finish
58
+
59
+ xtrace = AppOpticsAPM::Context.toString
60
+
61
+ if AppOpticsAPM.tracing?
62
+
63
+ # Since Grape uses throw/catch and not Exceptions, we have to create an exception here
64
+ exception = GrapeError.new(error[:message] ? error[:message] : "No message given.")
65
+ exception.set_backtrace(AppOpticsAPM::API.backtrace)
66
+
67
+ AppOpticsAPM::API.log_exception('rack', exception)
68
+
69
+ # Since calls to error() are handled similar to abort in Grape. We
70
+ # manually log the rack exit here since the original code won't
71
+ # be returned to
72
+ xtrace = AppOpticsAPM::API.log_end('rack', :Status => status)
73
+ end
74
+
75
+ if headers && AppOpticsAPM::XTrace.valid?(xtrace)
76
+ unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
77
+ headers['X-Trace'] = xtrace if headers.is_a?(Hash)
78
+ end
79
+ end
80
+
81
+ response
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ if AppOpticsAPM::Config[:grape][:enabled] && defined?(Grape)
89
+ require 'appoptics_apm/inst/rack'
90
+
91
+ AppOpticsAPM.logger.info "[appoptics_apm/loading] Instrumenting Grape" if AppOpticsAPM::Config[:verbose]
92
+
93
+ AppOpticsAPM::Inst.load_instrumentation
94
+
95
+ AppOpticsAPM::Util.send_extend(Grape::API, AppOpticsAPM::Grape::API)
96
+ AppOpticsAPM::Util.send_include(Grape::Endpoint, AppOpticsAPM::Grape::Endpoint)
97
+ AppOpticsAPM::Util.send_include(Grape::Middleware::Error, AppOpticsAPM::Grape::Middleware::Error)
98
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module PadrinoInst
6
+ module Routing
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :dispatch!, ::Padrino::Routing)
9
+ end
10
+
11
+ def dispatch_with_appoptics
12
+
13
+ AppOpticsAPM::API.log_entry('padrino', {})
14
+ report_kvs = {}
15
+
16
+ result = dispatch_without_appoptics
17
+
18
+ # Report Controller/Action and Transaction as best possible
19
+ controller = (request.controller && !request.controller.empty?) ? request.controller : nil
20
+ report_kvs[:Controller] = controller || self.class
21
+ report_kvs[:Action] = request.route_obj ? request.route_obj.path : request.action
22
+ env['appoptics_apm.controller'] = report_kvs[:Controller]
23
+ env['appoptics_apm.action'] = report_kvs[:Action]
24
+
25
+ result
26
+ rescue => e
27
+ AppOpticsAPM::API.log_exception('padrino', e)
28
+ raise e
29
+ ensure
30
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:padrino][:collect_backtraces]
31
+ AppOpticsAPM::API.log_exit('padrino', report_kvs)
32
+ end
33
+ end
34
+
35
+ module Rendering
36
+ def self.included(klass)
37
+ AppOpticsAPM::Util.method_alias(klass, :render, ::Padrino::Rendering)
38
+ end
39
+
40
+ # TODO add test coverage, currently there are no tests for this
41
+ # ____ I'm not sure this gets ever called, Padrino uses Sinatra's render method
42
+ def render_with_appoptics(engine, data = nil, options = {}, locals = {}, &block)
43
+ if AppOpticsAPM.tracing?
44
+ report_kvs = {}
45
+
46
+ report_kvs[:engine] = engine
47
+ report_kvs[:template] = data
48
+
49
+ AppOpticsAPM::SDK.trace(:padrino_render, report_kvs, :padrino_render) do
50
+ report_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:padrino][:collect_backtraces]
51
+ render_without_appoptics(engine, data, options, locals, &block)
52
+ end
53
+ else
54
+ render_without_appoptics(engine, data, options, locals, &block)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ if defined?(Padrino) && AppOpticsAPM::Config[:padrino][:enabled]
62
+ # This instrumentation is a superset of the Sinatra instrumentation similar
63
+ # to how Padrino is a superset of Sinatra itself.
64
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting Padrino' if AppOpticsAPM::Config[:verbose]
65
+
66
+ Padrino.after_load do
67
+ AppOpticsAPM.logger = Padrino.logger if Padrino.respond_to?(:logger)
68
+ AppOpticsAPM::Inst.load_instrumentation
69
+
70
+ AppOpticsAPM::Util.send_include(Padrino::Routing::InstanceMethods, AppOpticsAPM::PadrinoInst::Routing)
71
+ if defined?(Padrino::Rendering)
72
+ AppOpticsAPM::Util.send_include(Padrino::Rendering::InstanceMethods, AppOpticsAPM::PadrinoInst::Rendering)
73
+ end
74
+
75
+ # Report __Init after fork when in Heroku
76
+ AppOpticsAPM::API.report_init unless AppOpticsAPM.heroku?
77
+ end
78
+ end