Skip to content

Commit d84fde0

Browse files
committed
Merge branch 'master' of github.com:appoptics/ruby-appoptics
2 parents db13068 + a8da608 commit d84fde0

File tree

8 files changed

+232
-62
lines changed

8 files changed

+232
-62
lines changed

lib/appoptics_apm.rb

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,46 +13,44 @@
1313
require 'appoptics_apm/util'
1414
require 'appoptics_apm/xtrace'
1515
require 'appoptics_apm/support'
16+
require 'appoptics_apm/base'
17+
AppOpticsAPM.loaded = false
1618

17-
# If OboeHeroku is already defined then we are in a PaaS environment
18-
# with an alternate metal (see the oboe-heroku gem)
19-
unless defined?(OboeHeroku)
20-
require 'appoptics_apm/base'
21-
AppOpticsAPM.loaded = false
19+
require 'appoptics_apm/config'
20+
AppOpticsAPM::Config.load_config_file
2221

23-
begin
24-
if RUBY_PLATFORM == 'java'
25-
require '/usr/local/tracelytics/tracelyticsagent.jar'
26-
require 'joboe_metal'
27-
elsif RUBY_PLATFORM =~ /linux/
28-
require 'oboe_metal.so'
29-
require 'oboe_metal.rb' # sets AppOpticsAPM.loaded = true if successful
30-
else
31-
$stderr.puts '==================================================================='
32-
$stderr.puts "AppOptics warning: Platform #{RUBY_PLATFORM} not yet supported."
33-
$stderr.puts 'see: https://docs.appoptics.com/kb/apm_tracing/supported_platforms/'
34-
$stderr.puts 'Tracing disabled.'
35-
$stderr.puts 'Contact support@appoptics.com if this is unexpected.'
36-
$stderr.puts '==================================================================='
37-
end
38-
rescue LoadError
39-
unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_APPOPTICS_WARNING']
40-
$stderr.puts '=============================================================='
41-
$stderr.puts 'Missing AppOpticsAPM libraries. Tracing disabled.'
42-
$stderr.puts 'See: https://docs.appoptics.com/kb/apm_tracing/ruby/'
43-
$stderr.puts '=============================================================='
44-
end
22+
begin
23+
if RUBY_PLATFORM == 'java'
24+
require '/usr/local/tracelytics/tracelyticsagent.jar'
25+
require 'joboe_metal'
26+
elsif RUBY_PLATFORM =~ /linux/
27+
require_relative './oboe_metal.so'
28+
require 'oboe_metal.rb' # sets AppOpticsAPM.loaded = true if successful
29+
else
30+
$stderr.puts '==================================================================='
31+
$stderr.puts "AppOptics warning: Platform #{RUBY_PLATFORM} not yet supported."
32+
$stderr.puts 'see: https://docs.appoptics.com/kb/apm_tracing/supported_platforms/'
33+
$stderr.puts 'Tracing disabled.'
34+
$stderr.puts 'Contact support@appoptics.com if this is unexpected.'
35+
$stderr.puts '==================================================================='
36+
end
37+
rescue LoadError => e
38+
unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_APPOPTICS_WARNING']
39+
$stderr.puts '=============================================================='
40+
$stderr.puts 'Missing AppOpticsAPM libraries. Tracing disabled.'
41+
$stderr.puts "Error: #{e.message}"
42+
$stderr.puts 'See: https://docs.appoptics.com/kb/apm_tracing/ruby/'
43+
$stderr.puts '=============================================================='
4544
end
4645
end
4746

48-
require 'appoptics_apm/config'
49-
AppOpticsAPM::Config.load_config_file
50-
5147
require 'appoptics_apm/loading'
5248
require 'appoptics_apm/legacy_method_profiling'
5349
require 'appoptics_apm/method_profiling'
5450

5551
if AppOpticsAPM.loaded
52+
# tracing mode is configured via config file but can only be set once we have oboe_metal loaded
53+
AppOpticsAPM.set_tracing_mode(AppOpticsAPM::Config[:tracing_mode].to_sym)
5654
require 'appoptics_apm/instrumentation'
5755

5856
# Frameworks

lib/appoptics_apm/config.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,31 @@ def self.load_config_file
5757
config_file = File.join(Dir.pwd, 'appoptics_apm_config.rb')
5858
config_files << config_file if File.exist?(config_file)
5959

60-
return if config_files.empty?
60+
return if config_files.empty? # we use the defaults from the template in this case
6161

6262
if config_files.size > 1
6363
$stderr.puts 'Found multiple configuration files, using the first one listed:'
6464
config_files.each { |path| $stderr.puts " #{path}" }
6565
end
6666
load(config_files[0])
67+
check_env_vars
68+
end
69+
70+
# There are 4 variables that can be set in the config file or as env vars.
71+
# Oboe will override vars passed in if it finds an environment variable
72+
# :debug_level and :verbose need special consideration, because they are used in Ruby
73+
def self.check_env_vars
74+
unless (0..6).include?(AppOpticsAPM::Config[:debug_level])
75+
AppOpticsAPM::Config[:debug_level] = nil
76+
end
77+
# let's use the same debug level for ruby as well
78+
debug_level = ENV['APPOPTICS_DEBUG_LEVEL'] || AppOpticsAPM::Config[:debug_level] || 3
79+
AppOpticsAPM.logger.level = [4 - debug_level.to_i, 0].max
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
6785
end
6886

6987
##
@@ -109,12 +127,16 @@ def self.print_config
109127
#
110128
# rubocop:disable Metrics/AbcSize
111129
def self.initialize(_data = {})
112-
@@instrumentation.each do |k|
113-
@@config[k] = {}
114-
end
130+
@@instrumentation.each { |k| @@config[k] = {} }
115131
@@config[:transaction_name] = {}
132+
133+
# Always load the template, it has all the keys and defaults defined,
134+
# no guarantee of completeness in the user's config file
116135
load(File.join(File.dirname(File.dirname(__FILE__)),
117136
'rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb'))
137+
138+
# to make sure we include the service_key if it is set as an ENV var
139+
check_env_vars
118140
end
119141
# rubocop:enable Metrics/AbcSize
120142

lib/appoptics_apm/sdk.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,14 @@ def tracing?
299299
# end
300300
#
301301
def appoptics_ready?(wait_milliseconds = 3000)
302-
AppopticsAPM::Context.isReady(wait_milliseconds)
302+
# These codes are returned by isReady:
303+
# OBOE_SERVER_RESPONSE_UNKNOWN 0
304+
# OBOE_SERVER_RESPONSE_OK 1
305+
# OBOE_SERVER_RESPONSE_TRY_LATER 2
306+
# OBOE_SERVER_RESPONSE_LIMIT_EXCEEDED 3
307+
# OBOE_SERVER_RESPONSE_INVALID_API_KEY 4
308+
# OBOE_SERVER_RESPONSE_CONNECT_ERROR 5
309+
AppopticsAPM::Context.isReady(wait_milliseconds) == 1
303310
end
304311
end
305312

lib/oboe_metal.rb

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,27 @@ def start
2121
return unless AppOpticsAPM.loaded
2222

2323
begin
24-
protocol = ENV.key?('APPOPTICS_GEM_TEST') ? 'file' : 'ssl'
24+
options = []
2525

26-
case protocol
26+
ENV['APPOPTICS_REPORTER'] = 'file' if ENV.key?('APPOPTICS_GEM_TEST')
27+
28+
case ENV['APPOPTICS_REPORTER']
2729
when 'file'
28-
options = "file=#{TRACE_FILE}"
30+
ENV['APPOPTICS_REPORTER_FILE'] = TRACE_FILE
2931
when 'udp'
30-
options = "addr=#{AppOpticsAPM::Config[:reporter_host]},port=#{AppOpticsAPM::Config[:reporter_port]}"
31-
else
32-
if ENV['APPOPTICS_SERVICE_KEY'].to_s == ''
32+
ENV['APPOPTICS_REPORTER_UDP'] = "#{AppOpticsAPM::Config[:reporter_host]}:#{AppOpticsAPM::Config[:reporter_port]}"
33+
else # default is ssl, service_key is mandatory
34+
if AppOpticsAPM::Config[:service_key].to_s == '' && ENV['APPOPTICS_SERVICE_KEY'].to_s == ''
3335
AppOpticsAPM.logger.warn "[appoptics_apm/warn] APPOPTICS_SERVICE_KEY not set. Cannot submit data."
3436
AppOpticsAPM.loaded = false
3537
return
3638
end
37-
# ssl reporter requires the service key passed in as arg "cid"
38-
options = "cid=#{ENV['APPOPTICS_SERVICE_KEY']}"
39+
# Oboe will override these settings if there are env settings for them
40+
options << AppOpticsAPM::Config[:service_key].to_s
41+
options << AppOpticsAPM::Config[:hostname_alias].to_s
42+
options << AppOpticsAPM::Config[:debug_level] unless AppOpticsAPM::Config[:debug_level].nil?
3943
end
40-
41-
AppOpticsAPM.reporter = Oboe_metal::Reporter.new(protocol, options)
44+
AppOpticsAPM.reporter = Oboe_metal::Reporter.new(*options)
4245

4346
# Only report __Init from here if we are not instrumenting a framework.
4447
# Otherwise, frameworks will handle reporting __Init after full initialization

lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,47 @@
88

99
if defined?(AppOpticsAPM::Config)
1010

11+
# :service_key, :hostname_alias, and :debug_level are startup settings and can't be changed afterwards.
12+
#
13+
# Set APPOPTICS_SERVICE_KEY
14+
# This Setting will be overridden if APPOPTICS_SERVICE_KEY is set as an environment variable.
15+
# This is a required setting. If the service key is not set here it needs to be set as environment variable.
16+
#
17+
# The service key is a combination of the API token plus a service name.
18+
# E.g.: 0123456789abcde0123456789abcde0123456789abcde0123456789abcde1234:my_service
19+
#
20+
# AppOpticsAPM::Config[:service_key] = '0123456789abcde0123456789abcde0123456789abcde0123456789abcde1234:my_service'
21+
22+
#
23+
# Set APPOPTICS_HOSTNAME_ALIAS
24+
# This Setting will be overridden if APPOPTICS_HOSTNAME_ALIAS is set as an environment variable
25+
#
26+
# AppOpticsAPM::Config[:hostname_alias] = 'alias_name'
27+
28+
#
29+
# Set APPOPTICS_DEBUG_LEVEL
30+
# This Setting will be overridden if APPOPTICS_DEBUG_LEVEL is set as an environment variable
31+
#
32+
# It sets the log level and takes the following values:
33+
## 0 fatal, 1 error, 2 warning, 3 info (the default), 4 debug low, 5 debug medium, 6 debug high.
34+
#
35+
#
36+
AppOpticsAPM::Config[:debug_level] = 3
37+
#
38+
# :debug_level will be used in the c-extension of the gem and also mapped to the
39+
# Ruby logger as FATAL, ERROR, WARN, INFO, or DEBUG
40+
# The Ruby logger can afterwards be changed to a different level as follows:
41+
# AppOpticsAPM.logger.level = Logger::INFO
42+
43+
#
44+
# Set APPOPTICS_GEM_VERBOSE
45+
# This Setting will be overridden if APPOPTICS_GEM_VERBOSE is set as an environment variable
46+
#
47+
# On startup the components that are being instrumented will be reported if this is set to true.
48+
# If true and the log level is 4 or higher this may create extra debug log messages
49+
#
50+
AppOpticsAPM::Config[:verbose] = false
51+
1152
#
1253
# Turn tracing on or off
1354
#
@@ -17,11 +58,6 @@
1758
#
1859
AppOpticsAPM::Config[:tracing_mode] = :always
1960

20-
#
21-
# Verbose output of instrumentation initialization
22-
#
23-
AppOpticsAPM::Config[:verbose] = ENV.key?('APPOPTICS_GEM_VERBOSE') && ENV['APPOPTICS_GEM_VERBOSE'] == 'true' ? true : false
24-
2561
#
2662
# Prepend domain to transaction name
2763
#
@@ -122,7 +158,9 @@
122158
#
123159
# If you're having trouble with one of the instrumentation libraries, they
124160
# can be individually disabled here by setting the :enabled
125-
# value to false:
161+
# value to false.
162+
#
163+
# :enabled settings are read on startup and can't be changed afterwards
126164
#
127165
AppOpticsAPM::Config[:action_controller][:enabled] = true
128166
AppOpticsAPM::Config[:action_controller_api][:enabled] = true

test/support/config_test.rb

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,133 @@ class ConfigTest
1515
FileUtils.mkdir_p(File.join(Dir.pwd, 'config', 'initializers'))
1616

1717
before do
18+
@tracing_mode = AppOpticsAPM::Config[:tracing_mode]
19+
@sample_rate = AppOpticsAPM::Config[:sample_rate]
20+
@gem_verbose = AppOpticsAPM::Config[:verbose]
21+
1822
ENV.delete('APPOPTICS_APM_CONFIG_RUBY')
23+
ENV.delete('APPOPTICS_SERVICE_KEY')
24+
ENV.delete('APPOPTICS_HOSTNAME_ALIAS')
25+
ENV.delete('APPOPTICS_DEBUG_LEVEL')
26+
ENV.delete('APPOPTICS_GEM_VERBOSE')
27+
28+
AppOpticsAPM::Config[:service_key] = nil
29+
AppOpticsAPM::Config[:hostname_alias] = nil
30+
AppOpticsAPM::Config[:debug_level] = nil
31+
AppOpticsAPM::Config[:verbose] = nil
32+
1933
FileUtils.rm(@@default_config_path, :force => true)
2034
FileUtils.rm(@@rails_config_path, :force => true)
2135
FileUtils.rm(@@test_config_path, :force => true)
2236
end
2337

2438
after do
25-
# Set back to always trace mode
26-
AppOpticsAPM::Config[:tracing_mode] = "always"
27-
AppOpticsAPM::Config[:sample_rate] = 1000000
39+
AppOpticsAPM::Config[:tracing_mode] = @tracing_mode
40+
AppOpticsAPM::Config[:sample_rate] = @sample_rate
41+
AppOpticsAPM::Config[:verbose] = @gem_verbose
42+
FileUtils.rm_f(@@default_config_path)
2843
end
2944

3045
after(:all) do
31-
AppOpticsAPM::Config[:tracing_mode] = "always"
32-
AppOpticsAPM::Config[:sample_rate] = 1000000
3346
ENV.delete('APPOPTICS_APM_CONFIG_RUBY')
47+
ENV.delete('APPOPTICS_SERVICE_KEY')
48+
ENV.delete('APPOPTICS_HOSTNAME_ALIAS')
49+
ENV.delete('APPOPTICS_DEBUG_LEVEL')
50+
ENV.delete('APPOPTICS_GEM_VERBOSE')
3451
FileUtils.rm(@@default_config_path, :force => true)
3552
FileUtils.rm(@@rails_config_path, :force => true)
3653
FileUtils.rm(@@test_config_path, :force => true)
3754
end
3855

56+
it 'should read the settings from the config file' do
57+
File.open(@@default_config_path, 'w') do |f|
58+
f.puts "AppOpticsAPM::Config[:service_key] = '11111111-1111-1111-1111-111111111111:the_service_name'"
59+
f.puts "AppOpticsAPM::Config[:hostname_alias] = 'my_service'"
60+
f.puts "AppOpticsAPM::Config[:debug_level] = 6"
61+
f.puts "AppOpticsAPM::Config[:verbose] = true"
62+
end
63+
64+
AppOpticsAPM::Config.load_config_file
65+
66+
ENV['APPOPTICS_SERVICE_KEY'].must_be_nil
67+
AppOpticsAPM::Config[:service_key].must_equal '11111111-1111-1111-1111-111111111111:the_service_name'
68+
69+
ENV['APPOPTICS_HOSTNAME_ALIAS'].must_be_nil
70+
AppOpticsAPM::Config[:hostname_alias].must_equal 'my_service'
71+
72+
# logging happens in 2 places, oboe and ruby, we translate
73+
ENV['APPOPTICS_DEBUG_LEVEL'].must_be_nil
74+
AppOpticsAPM::Config[:debug_level].must_equal 6
75+
AppOpticsAPM.logger.level.must_equal Logger::DEBUG
76+
77+
ENV['APPOPTICS_GEM_VERBOSE'].must_be_nil
78+
AppOpticsAPM::Config[:verbose].must_equal true
79+
end
80+
81+
it 'should NOT override env vars with config file settings' do
82+
ENV['APPOPTICS_SERVICE_KEY'] = '22222222-2222-2222-2222-222222222222:the_service_name'
83+
ENV['APPOPTICS_HOSTNAME_ALIAS'] = 'my_other_service'
84+
ENV['APPOPTICS_DEBUG_LEVEL'] = '2'
85+
ENV['APPOPTICS_GEM_VERBOSE'] = 'TRUE'
86+
87+
File.open(@@default_config_path, 'w') do |f|
88+
f.puts "AppOpticsAPM::Config[:service_key] = '11111111-1111-1111-1111-111111111111:the_service_name'"
89+
f.puts "AppOpticsAPM::Config[:hostname_alias] = 'my_service'"
90+
f.puts "AppOpticsAPM::Config[:debug_level] = 6"
91+
f.puts "AppOpticsAPM::Config[:verbose] = false"
92+
end
93+
94+
AppOpticsAPM::Config.load_config_file
95+
96+
ENV['APPOPTICS_SERVICE_KEY'].must_equal '22222222-2222-2222-2222-222222222222:the_service_name'
97+
ENV['APPOPTICS_HOSTNAME_ALIAS'].must_equal 'my_other_service'
98+
ENV['APPOPTICS_DEBUG_LEVEL'].must_equal '2'
99+
AppOpticsAPM.logger.level.must_equal Logger::WARN
100+
ENV['APPOPTICS_GEM_VERBOSE'].must_equal 'TRUE'
101+
AppOpticsAPM::Config[:verbose].must_equal true
102+
end
103+
104+
it 'should use default when there is a wrong debug level setting' do
105+
File.open(@@default_config_path, 'w') do |f|
106+
f.puts "AppOpticsAPM::Config[:debug_level] = 7"
107+
end
108+
109+
AppOpticsAPM::Config.load_config_file
110+
111+
ENV['APPOPTICS_DEBUG_LEVEL'].must_be_nil
112+
AppOpticsAPM::Config[:debug_level].must_be_nil
113+
AppOpticsAPM.logger.level.must_equal Logger::INFO
114+
end
115+
116+
it "should accept 'true'/'TRUE'/'True'/... as true for VERBOSE" do
117+
File.open(@@default_config_path, 'w') do |f|
118+
f.puts "AppOpticsAPM::Config[:verbose] = false"
119+
end
120+
121+
ENV['APPOPTICS_GEM_VERBOSE'] = 'FALSE'
122+
AppOpticsAPM::Config.load_config_file
123+
AppOpticsAPM::Config[:verbose].wont_equal true
124+
125+
ENV['APPOPTICS_GEM_VERBOSE'] = 'TRUE'
126+
AppOpticsAPM::Config.load_config_file
127+
AppOpticsAPM::Config[:verbose].must_equal true
128+
129+
ENV['APPOPTICS_GEM_VERBOSE'] = 'verbose'
130+
AppOpticsAPM::Config.load_config_file
131+
AppOpticsAPM::Config[:verbose].wont_equal true
132+
133+
ENV['APPOPTICS_GEM_VERBOSE'] = 'True'
134+
AppOpticsAPM::Config.load_config_file
135+
AppOpticsAPM::Config[:verbose].must_equal true
136+
end
137+
39138
it 'should have the correct instrumentation defaults' do
40139
# Reset AppOpticsAPM::Config to defaults
41140
AppOpticsAPM::Config.initialize
42141

142+
AppOpticsAPM::Config[:debug_level] = 3
143+
AppOpticsAPM::Config[:verbose].must_equal false
43144
AppOpticsAPM::Config[:tracing_mode].must_equal :always
44-
AppOpticsAPM::Config[:verbose].must_equal ENV.key?('APPOPTICS_GEM_VERBOSE') && ENV['APPOPTICS_GEM_VERBOSE'] == 'true' ? true : false
45-
46145
AppOpticsAPM::Config[:sanitize_sql].must_equal true
47146
AppOpticsAPM::Config[:sanitize_sql_regexp].must_equal '(\'[\s\S][^\']*\'|\d*\.\d+|\d+|NULL)'
48147
AppOpticsAPM::Config[:sanitize_sql_opts].must_equal Regexp::IGNORECASE

0 commit comments

Comments
 (0)