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.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.github/workflows/build_and_release_gem.yml +103 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +168 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +159 -0
- data/.gitignore +36 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +130 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +33 -0
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/README.md +393 -0
- data/appoptics_apm.gemspec +70 -0
- data/bin/appoptics_apm_config +15 -0
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +158 -0
- data/ext/oboe_metal/README.md +69 -0
- data/ext/oboe_metal/extconf.rb +151 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/noop/noop.c +8 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -0
- data/ext/oboe_metal/src/bson/bson.h +220 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/frames.cc +246 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +1156 -0
- data/ext/oboe_metal/src/oboe_api.cpp +652 -0
- data/ext/oboe_metal/src/oboe_api.hpp +431 -0
- data/ext/oboe_metal/src/oboe_debug.h +59 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +7329 -0
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/init.rb +4 -0
- data/lib/appoptics_apm/api/layerinit.rb +41 -0
- data/lib/appoptics_apm/api/logging.rb +381 -0
- data/lib/appoptics_apm/api/memcache.rb +37 -0
- data/lib/appoptics_apm/api/metrics.rb +63 -0
- data/lib/appoptics_apm/api/tracing.rb +57 -0
- data/lib/appoptics_apm/api/util.rb +120 -0
- data/lib/appoptics_apm/api.rb +21 -0
- data/lib/appoptics_apm/base.rb +231 -0
- data/lib/appoptics_apm/config.rb +299 -0
- data/lib/appoptics_apm/frameworks/grape.rb +98 -0
- data/lib/appoptics_apm/frameworks/padrino.rb +78 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +88 -0
- data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +114 -0
- data/lib/appoptics_apm/frameworks/rails/inst/logger_formatters.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails.rb +100 -0
- data/lib/appoptics_apm/frameworks/sinatra.rb +96 -0
- data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
- data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
- data/lib/appoptics_apm/inst/curb.rb +332 -0
- data/lib/appoptics_apm/inst/dalli.rb +85 -0
- data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
- data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
- data/lib/appoptics_apm/inst/excon.rb +125 -0
- data/lib/appoptics_apm/inst/faraday.rb +106 -0
- data/lib/appoptics_apm/inst/graphql.rb +240 -0
- data/lib/appoptics_apm/inst/grpc_client.rb +159 -0
- data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
- data/lib/appoptics_apm/inst/http.rb +81 -0
- data/lib/appoptics_apm/inst/httpclient.rb +174 -0
- data/lib/appoptics_apm/inst/logger_formatter.rb +50 -0
- data/lib/appoptics_apm/inst/logging_log_event.rb +28 -0
- data/lib/appoptics_apm/inst/lumberjack_formatter.rb +13 -0
- data/lib/appoptics_apm/inst/memcached.rb +86 -0
- data/lib/appoptics_apm/inst/mongo.rb +246 -0
- data/lib/appoptics_apm/inst/mongo2.rb +225 -0
- data/lib/appoptics_apm/inst/moped.rb +466 -0
- data/lib/appoptics_apm/inst/rack.rb +182 -0
- data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
- data/lib/appoptics_apm/inst/redis.rb +274 -0
- data/lib/appoptics_apm/inst/resque.rb +151 -0
- data/lib/appoptics_apm/inst/rest-client.rb +48 -0
- data/lib/appoptics_apm/inst/sequel.rb +178 -0
- data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
- data/lib/appoptics_apm/inst/sidekiq-worker.rb +66 -0
- data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
- data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
- data/lib/appoptics_apm/instrumentation.rb +22 -0
- data/lib/appoptics_apm/loading.rb +65 -0
- data/lib/appoptics_apm/logger.rb +14 -0
- data/lib/appoptics_apm/noop/README.md +9 -0
- data/lib/appoptics_apm/noop/context.rb +27 -0
- data/lib/appoptics_apm/noop/metadata.rb +25 -0
- data/lib/appoptics_apm/noop/profiling.rb +21 -0
- data/lib/appoptics_apm/oboe_init_options.rb +211 -0
- data/lib/appoptics_apm/ruby.rb +35 -0
- data/lib/appoptics_apm/sdk/current_trace.rb +77 -0
- data/lib/appoptics_apm/sdk/custom_metrics.rb +94 -0
- data/lib/appoptics_apm/sdk/logging.rb +37 -0
- data/lib/appoptics_apm/sdk/tracing.rb +434 -0
- data/lib/appoptics_apm/support/profiling.rb +18 -0
- data/lib/appoptics_apm/support/transaction_metrics.rb +67 -0
- data/lib/appoptics_apm/support/transaction_settings.rb +219 -0
- data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
- data/lib/appoptics_apm/support_report.rb +119 -0
- data/lib/appoptics_apm/test.rb +95 -0
- data/lib/appoptics_apm/thread_local.rb +26 -0
- data/lib/appoptics_apm/util.rb +326 -0
- data/lib/appoptics_apm/version.rb +16 -0
- data/lib/appoptics_apm/xtrace.rb +115 -0
- data/lib/appoptics_apm.rb +77 -0
- data/lib/joboe_metal.rb +212 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +172 -0
- data/lib/rails/generators/appoptics_apm/install_generator.rb +47 -0
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +425 -0
- data/log/.keep +0 -0
- data/yardoc_frontpage.md +26 -0
- metadata +231 -0
@@ -0,0 +1,326 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
##
|
6
|
+
# Provides utility methods for use while in the business
|
7
|
+
# of instrumenting code
|
8
|
+
module Util
|
9
|
+
class << self
|
10
|
+
def contextual_name(cls)
|
11
|
+
# Attempt to infer a contextual name if not indicated
|
12
|
+
#
|
13
|
+
# For example:
|
14
|
+
# ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.to_s.split(/::/).last
|
15
|
+
# => "AbstractMysqlAdapter"
|
16
|
+
#
|
17
|
+
cls.to_s.split(/::/).last
|
18
|
+
rescue
|
19
|
+
cls
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# method_alias
|
24
|
+
#
|
25
|
+
# Centralized utility method to alias a method on an arbitrary
|
26
|
+
# class or module.
|
27
|
+
#
|
28
|
+
def method_alias(cls, method, name = nil)
|
29
|
+
name ||= contextual_name(cls)
|
30
|
+
|
31
|
+
if cls.method_defined?(method.to_sym) || cls.private_method_defined?(method.to_sym)
|
32
|
+
|
33
|
+
# Strip '!' or '?' from method if present
|
34
|
+
safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
|
35
|
+
safe_method_name ||= method
|
36
|
+
|
37
|
+
without_appoptics = "#{safe_method_name}_without_appoptics"
|
38
|
+
with_appoptics = "#{safe_method_name}_with_appoptics"
|
39
|
+
|
40
|
+
# Only alias if we haven't done so already
|
41
|
+
unless cls.method_defined?(without_appoptics.to_sym) ||
|
42
|
+
cls.private_method_defined?(without_appoptics.to_sym)
|
43
|
+
|
44
|
+
cls.class_eval do
|
45
|
+
alias_method without_appoptics, method.to_s
|
46
|
+
alias_method method.to_s, with_appoptics
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument #{name}.#{method}. Partial traces may occur."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# class_method_alias
|
56
|
+
#
|
57
|
+
# Centralized utility method to alias a class method on an arbitrary
|
58
|
+
# class or module
|
59
|
+
#
|
60
|
+
def class_method_alias(cls, method, name = nil)
|
61
|
+
name ||= contextual_name(cls)
|
62
|
+
|
63
|
+
if cls.singleton_methods.include? method.to_sym
|
64
|
+
|
65
|
+
# Strip '!' or '?' from method if present
|
66
|
+
safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
|
67
|
+
safe_method_name ||= method
|
68
|
+
|
69
|
+
without_appoptics = "#{safe_method_name}_without_appoptics"
|
70
|
+
with_appoptics = "#{safe_method_name}_with_appoptics"
|
71
|
+
|
72
|
+
# Only alias if we haven't done so already
|
73
|
+
unless cls.singleton_methods.include? without_appoptics.to_sym
|
74
|
+
cls.singleton_class.send(:alias_method, without_appoptics, method.to_s)
|
75
|
+
cls.singleton_class.send(:alias_method, method.to_s, with_appoptics)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/loading] Couldn't properly instrument #{name}. Partial traces may occur."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# send_extend
|
84
|
+
#
|
85
|
+
# Centralized utility method to send an extend call for an
|
86
|
+
# arbitrary class
|
87
|
+
def send_extend(target_cls, cls)
|
88
|
+
target_cls.send(:extend, cls) if defined?(target_cls)
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# send_include
|
93
|
+
#
|
94
|
+
# Centralized utility method to send a include call for an
|
95
|
+
# arbitrary class
|
96
|
+
def send_include(target_cls, cls)
|
97
|
+
target_cls.send(:include, cls) if defined?(target_cls)
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# prettify
|
102
|
+
#
|
103
|
+
# Even to my surprise, 'prettify' is a real word:
|
104
|
+
# transitive v. To make pretty or prettier, especially in a superficial or insubstantial way.
|
105
|
+
# from The American Heritage Dictionary of the English Language, 4th Edition
|
106
|
+
#
|
107
|
+
# This method makes things 'purty' for reporting.
|
108
|
+
def prettify(x)
|
109
|
+
if (x.to_s =~ /^#</) == 0
|
110
|
+
x.class.to_s
|
111
|
+
else
|
112
|
+
x.to_s
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# upcase
|
118
|
+
#
|
119
|
+
# Occasionally, we want to send some values in all caps. This is true
|
120
|
+
# for things like HTTP scheme or method. This takes anything and does
|
121
|
+
# it's best to safely convert it to a string (if needed) and convert it
|
122
|
+
# to all uppercase.
|
123
|
+
def upcase(o)
|
124
|
+
if o.is_a?(String) || o.respond_to?(:to_s)
|
125
|
+
o.to_s.upcase
|
126
|
+
else
|
127
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/debug] AppOpticsAPM::Util.upcase: could not convert #{o.class}"
|
128
|
+
'UNKNOWN'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# to_query
|
134
|
+
#
|
135
|
+
# Used to convert a hash into a URL # query.
|
136
|
+
#
|
137
|
+
def to_query(h)
|
138
|
+
return '' unless h.is_a?(Hash)
|
139
|
+
|
140
|
+
result = []
|
141
|
+
|
142
|
+
h.each { |k, v| result.push(k.to_s + '=' + v.to_s) }
|
143
|
+
result.sort.join('&')
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# sanitize_sql
|
148
|
+
#
|
149
|
+
# Used to remove query literals from SQL. Used by all
|
150
|
+
# DB adapter instrumentation.
|
151
|
+
#
|
152
|
+
# The regular expression passed to String.gsub is configurable
|
153
|
+
# via AppOpticsAPM::Config[:sanitize_sql_regexp] and
|
154
|
+
# AppOpticsAPM::Config[:sanitize_sql_opts].
|
155
|
+
#
|
156
|
+
def sanitize_sql(sql)
|
157
|
+
return sql unless AppOpticsAPM::Config[:sanitize_sql]
|
158
|
+
|
159
|
+
regexp = Regexp.new(AppOpticsAPM::Config[:sanitize_sql_regexp], AppOpticsAPM::Config[:sanitize_sql_opts])
|
160
|
+
sql.gsub(/\\\'/,'').gsub(regexp, '?')
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# deep_dup
|
165
|
+
#
|
166
|
+
# deep duplicate of array or hash
|
167
|
+
#
|
168
|
+
def deep_dup(obj)
|
169
|
+
if obj.is_a? Array
|
170
|
+
new_obj = []
|
171
|
+
obj.each do |v|
|
172
|
+
new_obj << deep_dup(v)
|
173
|
+
end
|
174
|
+
elsif obj.is_a? Hash
|
175
|
+
new_obj = {}
|
176
|
+
obj.each_pair do |key, value|
|
177
|
+
new_obj[key] = deep_dup(value)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# legacy_build_init_report
|
184
|
+
#
|
185
|
+
# Internal: Build a hash of KVs that reports on the status of the
|
186
|
+
# running environment. This is used on stack boot in __Init reporting
|
187
|
+
# and for AppOpticsAPM.support_report.
|
188
|
+
#
|
189
|
+
# This legacy version of build_init_report is used for apps without Bundler.
|
190
|
+
#
|
191
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
192
|
+
#
|
193
|
+
# @deprecated Please use {#build_init_report} instead
|
194
|
+
def legacy_build_init_report
|
195
|
+
AppOpticsAPM.logger.warn '[appoptics_apm/deprecated] Oboe::API will be deprecated in a future version.'
|
196
|
+
platform_info = {}
|
197
|
+
|
198
|
+
begin
|
199
|
+
# Report the framework in use
|
200
|
+
if defined?(::RailsLts::VERSION)
|
201
|
+
platform_info['Ruby.RailsLts.Version'] = "RailsLts-#{::RailsLts::VERSION}"
|
202
|
+
elsif defined?(::Rails.version)
|
203
|
+
platform_info['Ruby.Rails.Version'] = "Rails-#{::Rails.version}"
|
204
|
+
end
|
205
|
+
platform_info['Ruby.Grape.Version'] = "Grape-#{::Grape::VERSION}" if defined?(::Grape::VERSION)
|
206
|
+
platform_info['Ruby.Cramp.Version'] = "Cramp-#{::Cramp::VERSION}" if defined?(::Cramp::VERSION)
|
207
|
+
|
208
|
+
if defined?(::Padrino::VERSION)
|
209
|
+
platform_info['Ruby.Padrino.Version'] = "Padrino-#{::Padrino::VERSION}"
|
210
|
+
elsif defined?(::Sinatra::VERSION)
|
211
|
+
platform_info['Ruby.Sinatra.Version'] = "Sinatra-#{::Sinatra::VERSION}"
|
212
|
+
end
|
213
|
+
|
214
|
+
# Report the instrumented libraries
|
215
|
+
platform_info['Ruby.Cassandra.Version'] = "Cassandra-#{::Cassandra.VERSION}" if defined?(::Cassandra.VERSION)
|
216
|
+
platform_info['Ruby.Curb.Version'] = "Curb-#{::Curl::VERSION}" if defined?(::Curl::VERSION)
|
217
|
+
platform_info['Ruby.Dalli.Version'] = "Dalli-#{::Dalli::VERSION}" if defined?(::Dalli::VERSION)
|
218
|
+
platform_info['Ruby.Excon.Version'] = "Excon-#{::Excon::VERSION}" if defined?(::Excon::VERSION)
|
219
|
+
platform_info['Ruby.Faraday.Version'] = "Faraday-#{::Faraday::VERSION}" if defined?(::Faraday::VERSION)
|
220
|
+
platform_info['Ruby.HTTPClient.Version'] = "HTTPClient-#{::HTTPClient::VERSION}" if defined?(::HTTPClient::VERSION)
|
221
|
+
platform_info['Ruby.Memcached.Version'] = "Memcached-#{::Memcached::VERSION}" if defined?(::Memcached::VERSION)
|
222
|
+
platform_info['Ruby.Moped.Version'] = "Moped-#{::Moped::VERSION}" if defined?(::Moped::VERSION)
|
223
|
+
platform_info['Ruby.Redis.Version'] = "Redis-#{::Redis::VERSION}" if defined?(::Redis::VERSION)
|
224
|
+
platform_info['Ruby.Resque.Version'] = "Resque-#{::Resque::VERSION}" if defined?(::Resque::VERSION)
|
225
|
+
platform_info['Ruby.RestClient.Version'] = "RestClient-#{::RestClient::VERSION}" if defined?(::RestClient::VERSION)
|
226
|
+
platform_info['Ruby.Sidekiq.Version'] = "Sidekiq-#{::Sidekiq::VERSION}" if defined?(::Sidekiq::VERSION)
|
227
|
+
platform_info['Ruby.Typhoeus.Version'] = "Typhoeus-#{::Typhoeus::VERSION}" if defined?(::Typhoeus::VERSION)
|
228
|
+
|
229
|
+
if Gem.loaded_specs.key?('delayed_job')
|
230
|
+
# Oddly, DelayedJob doesn't have an embedded version number so we get it from the loaded
|
231
|
+
# gem specs.
|
232
|
+
version = Gem.loaded_specs['delayed_job'].version.to_s
|
233
|
+
platform_info['Ruby.DelayedJob.Version'] = "DelayedJob-#{version}"
|
234
|
+
end
|
235
|
+
|
236
|
+
# Special case since the Mongo 1.x driver doesn't embed the version number in the gem directly
|
237
|
+
if ::Gem.loaded_specs.key?('mongo')
|
238
|
+
platform_info['Ruby.Mongo.Version'] = "Mongo-#{::Gem.loaded_specs['mongo'].version}"
|
239
|
+
end
|
240
|
+
|
241
|
+
# Report the DB adapter in use
|
242
|
+
platform_info['Ruby.Mysql.Version'] = Mysql::GemVersion::VERSION if defined?(Mysql::GemVersion::VERSION)
|
243
|
+
platform_info['Ruby.PG.Version'] = PG::VERSION if defined?(PG::VERSION)
|
244
|
+
platform_info['Ruby.Mysql2.Version'] = Mysql2::VERSION if defined?(Mysql2::VERSION)
|
245
|
+
platform_info['Ruby.Sequel.Version'] = ::Sequel::VERSION if defined?(::Sequel::VERSION)
|
246
|
+
rescue StandardError, ScriptError => e
|
247
|
+
# Also rescue ScriptError (aka SyntaxError) in case one of the expected
|
248
|
+
# version defines don't exist
|
249
|
+
|
250
|
+
platform_info['Error'] = "Error in legacy_build_init_report: #{e.message}"
|
251
|
+
|
252
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/legacy] Error in legacy_build_init_report: #{e.message}"
|
253
|
+
AppOpticsAPM.logger.debug e.backtrace
|
254
|
+
end
|
255
|
+
platform_info
|
256
|
+
end
|
257
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
258
|
+
|
259
|
+
##
|
260
|
+
# build_init_report
|
261
|
+
#
|
262
|
+
# Internal: Build a hash of KVs that reports on the status of the
|
263
|
+
# running environment. This is used on stack boot in __Init reporting
|
264
|
+
# and for AppOpticsAPM.support_report.
|
265
|
+
#
|
266
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
267
|
+
def build_init_report
|
268
|
+
platform_info = { '__Init' => 1 }
|
269
|
+
|
270
|
+
begin
|
271
|
+
platform_info['Force'] = true
|
272
|
+
platform_info['Ruby.Platform.Version'] = RUBY_PLATFORM
|
273
|
+
platform_info['Ruby.Version'] = RUBY_VERSION
|
274
|
+
platform_info['Ruby.AppOptics.Version'] = AppOpticsAPM::Version::STRING
|
275
|
+
|
276
|
+
# oboe not loaded yet, can't use oboe_api function to read oboe VERSION
|
277
|
+
clib_version_file = File.join(Gem::Specification.find_by_name('appoptics_apm').gem_dir, 'ext', 'oboe_metal', 'src', 'VERSION')
|
278
|
+
platform_info['Ruby.AppOpticsExtension.Version'] = File.read(clib_version_file).strip
|
279
|
+
platform_info['RubyHeroku.AppOpticsAPM.Version'] = AppOpticsAPMHeroku::Version::STRING if defined?(AppOpticsAPMHeroku)
|
280
|
+
platform_info['Ruby.TraceMode.Version'] = AppOpticsAPM::Config[:tracing_mode]
|
281
|
+
|
282
|
+
# Collect up the loaded gems
|
283
|
+
if defined?(Gem) && Gem.respond_to?(:loaded_specs)
|
284
|
+
Gem.loaded_specs.each_pair { |k, v|
|
285
|
+
platform_info["Ruby.#{k}.Version"] = v.version.to_s
|
286
|
+
}
|
287
|
+
else
|
288
|
+
platform_info.merge!(legacy_build_init_report)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Report the server in use (if possible)
|
292
|
+
if defined?(::Unicorn::Const::UNICORN_VERSION)
|
293
|
+
platform_info['Ruby.AppContainer.Version'] = "Unicorn-#{::Unicorn::Const::UNICORN_VERSION}"
|
294
|
+
elsif defined?(::Puma::Const::PUMA_VERSION)
|
295
|
+
platform_info['Ruby.AppContainer.Version'] = "Puma-#{::Puma::Const::PUMA_VERSION} (#{::Puma::Const::CODE_NAME})"
|
296
|
+
elsif defined?(::PhusionPassenger::PACKAGE_NAME)
|
297
|
+
platform_info['Ruby.AppContainer.Version'] = "#{::PhusionPassenger::PACKAGE_NAME}-#{::PhusionPassenger::VERSION_STRING}"
|
298
|
+
elsif defined?(::Thin::VERSION::STRING)
|
299
|
+
platform_info['Ruby.AppContainer.Version'] = "Thin-#{::Thin::VERSION::STRING} (#{::Thin::VERSION::CODENAME})"
|
300
|
+
elsif defined?(::Mongrel::Const::MONGREL_VERSION)
|
301
|
+
platform_info['Ruby.AppContainer.Version'] = "Mongrel-#{::Mongrel::Const::MONGREL_VERSION}"
|
302
|
+
elsif defined?(::Mongrel2::VERSION)
|
303
|
+
platform_info['Ruby.AppContainer.Version'] = "Mongrel2-#{::Mongrel2::VERSION}"
|
304
|
+
elsif defined?(::Trinidad::VERSION)
|
305
|
+
platform_info['Ruby.AppContainer.Version'] = "Trinidad-#{::Trinidad::VERSION}"
|
306
|
+
elsif defined?(::WEBrick::VERSION)
|
307
|
+
platform_info['Ruby.AppContainer.Version'] = "WEBrick-#{::WEBrick::VERSION}"
|
308
|
+
else
|
309
|
+
platform_info['Ruby.AppContainer.Version'] = File.basename($PROGRAM_NAME)
|
310
|
+
end
|
311
|
+
|
312
|
+
rescue StandardError, ScriptError => e
|
313
|
+
# Also rescue ScriptError (aka SyntaxError) in case one of the expected
|
314
|
+
# version defines don't exist
|
315
|
+
|
316
|
+
platform_info['Error'] = "Error in build_report: #{e.message}"
|
317
|
+
|
318
|
+
AppOpticsAPM.logger.warn "[appoptics_apm/warn] Error in build_init_report: #{e.message}"
|
319
|
+
AppOpticsAPM.logger.debug e.backtrace
|
320
|
+
end
|
321
|
+
platform_info
|
322
|
+
end
|
323
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
##
|
6
|
+
# The current version of the gem. Used mainly by
|
7
|
+
# appoptics_apm.gemspec during gem build process
|
8
|
+
module Version
|
9
|
+
MAJOR = 4 # breaking,
|
10
|
+
MINOR = 13 # feature,
|
11
|
+
PATCH = 1 # fix => BFF
|
12
|
+
PRE = nil
|
13
|
+
|
14
|
+
STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
module AppOpticsAPM
|
5
|
+
##
|
6
|
+
# Methods to act on, manipulate or investigate an X-Trace
|
7
|
+
# value
|
8
|
+
#
|
9
|
+
# TODO add unit tests
|
10
|
+
class XTrace
|
11
|
+
class << self
|
12
|
+
##
|
13
|
+
# AppOpticsAPM::XTrace.valid?
|
14
|
+
#
|
15
|
+
# Perform basic validation on a potential X-Trace Id
|
16
|
+
# returns true if it is from a valid context
|
17
|
+
#
|
18
|
+
def valid?(xtrace)
|
19
|
+
# Shouldn't be nil
|
20
|
+
return false unless xtrace
|
21
|
+
|
22
|
+
# The X-Trace ID shouldn't be an initialized empty ID
|
23
|
+
return false if (xtrace =~ /^2b0000000/i) == 0
|
24
|
+
|
25
|
+
# Valid X-Trace IDs have a length of 60 bytes and start with '2b'
|
26
|
+
xtrace.length == 60 && (xtrace =~ /^2b/i) == 0
|
27
|
+
rescue StandardError => e
|
28
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
|
29
|
+
AppOpticsAPM.logger.debug e.backtrace
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def sampled?(xtrace)
|
34
|
+
valid?(xtrace) && xtrace[59].to_i & 1 == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def ok?(xtrace)
|
38
|
+
# Valid X-Trace IDs have a length of 60 bytes and start with '2b'
|
39
|
+
xtrace && xtrace.length == 60 && (xtrace =~ /^2b/i) == 0
|
40
|
+
rescue StandardError => e
|
41
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
|
42
|
+
AppOpticsAPM.logger.debug e.backtrace
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_sampled(xtrace)
|
47
|
+
xtrace[59] = (xtrace[59].hex | 1).to_s(16).upcase
|
48
|
+
xtrace
|
49
|
+
end
|
50
|
+
|
51
|
+
def unset_sampled(xtrace)
|
52
|
+
xtrace[59] = (~(~xtrace[59].hex | 1)).to_s(16).upcase
|
53
|
+
xtrace
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# AppOpticsAPM::XTrace.task_id
|
58
|
+
#
|
59
|
+
# Extract and return the task_id portion of an X-Trace ID
|
60
|
+
#
|
61
|
+
def task_id(xtrace)
|
62
|
+
return nil unless ok?(xtrace)
|
63
|
+
|
64
|
+
xtrace[2..41]
|
65
|
+
rescue StandardError => e
|
66
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
|
67
|
+
AppOpticsAPM.logger.debug e.backtrace
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# AppOpticsAPM::XTrace.edge_id
|
73
|
+
#
|
74
|
+
# Extract and return the edge_id portion of an X-Trace ID
|
75
|
+
#
|
76
|
+
def edge_id(xtrace)
|
77
|
+
return nil unless AppOpticsAPM::XTrace.valid?(xtrace)
|
78
|
+
|
79
|
+
xtrace[42..57]
|
80
|
+
rescue StandardError => e
|
81
|
+
AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
|
82
|
+
AppOpticsAPM.logger.debug e.backtrace
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# continue_service_context
|
88
|
+
#
|
89
|
+
# In the case of service calls such as external HTTP requests, we
|
90
|
+
# pass along X-Trace headers so that request context can be maintained
|
91
|
+
# across servers and applications.
|
92
|
+
#
|
93
|
+
# Remote requests can return a X-Trace header in which case we want
|
94
|
+
# to pickup and continue the context in most cases.
|
95
|
+
#
|
96
|
+
# +start+ is the context just before the outgoing request
|
97
|
+
# +finish+ is the context returned to us (as an HTTP response header
|
98
|
+
# if that be the case)
|
99
|
+
#
|
100
|
+
def continue_service_context(start_xtrace, end_xtrace)
|
101
|
+
if AppOpticsAPM::XTrace.valid?(end_xtrace) && AppOpticsAPM.tracing?
|
102
|
+
|
103
|
+
# Make sure that we received back a valid X-Trace with the same task_id
|
104
|
+
# and the sampling bit is set, otherwise it is a response from a non-sampling service
|
105
|
+
if AppOpticsAPM::XTrace.task_id(start_xtrace) == AppOpticsAPM::XTrace.task_id(end_xtrace) &&
|
106
|
+
AppOpticsAPM::XTrace.sampled?(end_xtrace)
|
107
|
+
AppOpticsAPM::Context.fromString(end_xtrace)
|
108
|
+
else
|
109
|
+
AppOpticsAPM.logger.debug "[XTrace] Sampling flag unset or mismatched start and finish ids:\n#{start_xtrace}\n#{end_xtrace}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Copyright (c) 2016 SolarWinds, LLC.
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'openssl'
|
6
|
+
require 'appoptics_apm/version'
|
7
|
+
require 'appoptics_apm/thread_local'
|
8
|
+
require 'appoptics_apm/logger'
|
9
|
+
require 'appoptics_apm/util'
|
10
|
+
require 'appoptics_apm/xtrace'
|
11
|
+
require 'appoptics_apm/support_report'
|
12
|
+
require 'appoptics_apm/base'
|
13
|
+
AppOpticsAPM.loaded = false
|
14
|
+
|
15
|
+
require 'appoptics_apm/config'
|
16
|
+
AppOpticsAPM::Config.load_config_file
|
17
|
+
|
18
|
+
begin
|
19
|
+
if RUBY_PLATFORM == 'java'
|
20
|
+
require '/usr/local/tracelytics/tracelyticsagent.jar'
|
21
|
+
require 'joboe_metal'
|
22
|
+
elsif RUBY_PLATFORM =~ /linux/
|
23
|
+
require_relative './libappoptics_apm.so'
|
24
|
+
require 'appoptics_apm/oboe_init_options'
|
25
|
+
require 'oboe_metal.rb' # sets AppOpticsAPM.loaded = true if successful
|
26
|
+
else
|
27
|
+
AppOpticsAPM.logger.warn '==================================================================='
|
28
|
+
AppOpticsAPM.logger.warn "AppOptics warning: Platform #{RUBY_PLATFORM} not yet supported."
|
29
|
+
AppOpticsAPM.logger.warn 'see: https://docs.appoptics.com/kb/apm_tracing/supported_platforms/'
|
30
|
+
AppOpticsAPM.logger.warn 'Tracing disabled.'
|
31
|
+
AppOpticsAPM.logger.warn 'Contact technicalsupport@solarwinds.com if this is unexpected.'
|
32
|
+
AppOpticsAPM.logger.warn '==================================================================='
|
33
|
+
end
|
34
|
+
rescue LoadError => e
|
35
|
+
unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_APPOPTICS_WARNING']
|
36
|
+
AppOpticsAPM.logger.error '=============================================================='
|
37
|
+
AppOpticsAPM.logger.error 'Missing AppOpticsAPM libraries. Tracing disabled.'
|
38
|
+
AppOpticsAPM.logger.error "Error: #{e.message}"
|
39
|
+
AppOpticsAPM.logger.error 'See: https://docs.appoptics.com/kb/apm_tracing/ruby/'
|
40
|
+
AppOpticsAPM.logger.error '=============================================================='
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# appoptics_apm/loading can set AppOpticsAPM.loaded = false if the service key is not working
|
45
|
+
require 'appoptics_apm/loading'
|
46
|
+
|
47
|
+
if AppOpticsAPM.loaded
|
48
|
+
require 'appoptics_apm/instrumentation'
|
49
|
+
require 'appoptics_apm/support/profiling'
|
50
|
+
require 'appoptics_apm/support/transaction_metrics'
|
51
|
+
require 'appoptics_apm/support/x_trace_options'
|
52
|
+
|
53
|
+
# Frameworks
|
54
|
+
require 'appoptics_apm/frameworks/rails'
|
55
|
+
require 'appoptics_apm/frameworks/sinatra'
|
56
|
+
require 'appoptics_apm/frameworks/padrino'
|
57
|
+
require 'appoptics_apm/frameworks/grape'
|
58
|
+
else
|
59
|
+
AppOpticsAPM.logger.warn '=============================================================='
|
60
|
+
AppOpticsAPM.logger.warn 'AppOpticsAPM not loaded. Tracing disabled.'
|
61
|
+
AppOpticsAPM.logger.warn 'There may be a problem with the service key or other settings.'
|
62
|
+
AppOpticsAPM.logger.warn 'Please check previous log messages.'
|
63
|
+
AppOpticsAPM.logger.warn '=============================================================='
|
64
|
+
require 'appoptics_apm/noop/context'
|
65
|
+
require 'appoptics_apm/noop/metadata'
|
66
|
+
require 'appoptics_apm/noop/profiling'
|
67
|
+
end
|
68
|
+
|
69
|
+
# Load Ruby module last. If there is no framework detected,
|
70
|
+
# it will load all of the Ruby instrumentation
|
71
|
+
require 'appoptics_apm/ruby'
|
72
|
+
|
73
|
+
require 'appoptics_apm/test' if ENV['APPOPTICS_GEM_TEST']
|
74
|
+
rescue => e
|
75
|
+
$stderr.puts "[appoptics_apm/error] Problem loading: #{e.inspect}"
|
76
|
+
$stderr.puts e.backtrace
|
77
|
+
end
|