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,230 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rubygems'
4
+ require 'fileutils'
5
+ require 'open-uri'
6
+ require 'bundler/setup'
7
+ require 'rake/testtask'
8
+ require 'appoptics_apm/test'
9
+
10
+ Rake::TestTask.new do |t|
11
+ t.verbose = false
12
+ t.warning = false
13
+ t.ruby_opts = []
14
+ t.libs << 'test'
15
+
16
+ # Since we support so many libraries and frameworks, tests
17
+ # runs are segmented into gemfiles that have different
18
+ # sets and versions of gems (libraries and frameworks).
19
+ #
20
+ # Here we detect the Gemfile the tests are being run against
21
+ # and load the appropriate tests.
22
+ #
23
+ case AppOpticsAPM::Test.gemfile
24
+ when /delayed_job/
25
+ require 'delayed/tasks'
26
+ t.test_files = FileList['test/queues/delayed_job*_test.rb']
27
+ when /rails/
28
+ # Pre-load rails to get the major version number
29
+ require 'rails'
30
+
31
+ if Rails::VERSION::MAJOR == 5
32
+ t.test_files = FileList["test/frameworks/rails#{Rails::VERSION::MAJOR}x_test.rb"] +
33
+ FileList["test/frameworks/rails#{Rails::VERSION::MAJOR}x_api_test.rb"]
34
+ else
35
+ t.test_files = FileList["test/frameworks/rails#{Rails::VERSION::MAJOR}x_test.rb"]
36
+ end
37
+
38
+ when /frameworks/
39
+ t.test_files = FileList['test/frameworks/sinatra*_test.rb'] +
40
+ FileList['test/frameworks/padrino*_test.rb'] +
41
+ FileList['test/frameworks/grape*_test.rb']
42
+ when /libraries/
43
+ t.test_files = FileList['test/support/*_test.rb'] +
44
+ FileList['test/reporter/*_test.rb'] +
45
+ FileList['test/instrumentation/*_test.rb'] +
46
+ FileList['test/profiling/*_test.rb'] -
47
+ ['test/instrumentation/twitter-cassandra_test.rb']
48
+ when /instrumentation_mocked/
49
+ # WebMock is interfering with other tests, so these have to run separately
50
+ t.test_files = FileList['test/mocked/*_test.rb']
51
+ when /noop/
52
+ t.test_files = FileList['test/noop/*_test.rb']
53
+ when /unit/
54
+ t.test_files = FileList['test/unit/*_test.rb'] +
55
+ FileList['test/unit/*/*_test.rb']
56
+ end
57
+
58
+ if defined?(JRUBY_VERSION)
59
+ t.ruby_opts << ['-J-javaagent:/usr/local/tracelytics/tracelyticsagent.jar']
60
+ end
61
+ end
62
+
63
+ desc "Run all test suites defined by travis"
64
+ task "docker_tests" do
65
+ Dir.chdir('test/run_tests')
66
+ exec('docker-compose run --service-ports ruby_appoptics /code/ruby-appoptics/test/run_tests/ruby_setup.sh test')
67
+ end
68
+
69
+ desc "Start docker container for testing and debugging"
70
+ task "docker" do
71
+ Dir.chdir('test/run_tests')
72
+ exec('docker-compose run --service-ports ruby_appoptics /code/ruby-appoptics/test/run_tests/ruby_setup.sh bash')
73
+ end
74
+
75
+ desc "Fetch extension dependency files"
76
+ task :fetch_ext_deps do
77
+ swig_version = %x{swig -version} rescue ''
78
+ swig_version = swig_version.scan(/swig version 3.0.\d*/i)
79
+ if swig_version.empty?
80
+ $stderr.puts '== ERROR ================================================================='
81
+ $stderr.puts "Could not find required swig version 3.0.*, found #{swig_version.inspect}"
82
+ $stderr.puts 'Please install swig "~ 3.0.8" and try again.'
83
+ $stderr.puts '=========================================================================='
84
+ raise
85
+ end
86
+
87
+ # The c-lib version is different from the gem version
88
+ oboe_version = ENV['OBOE_VERSION'] || 'latest'
89
+ oboe_s3_dir = "https://s3-us-west-2.amazonaws.com/rc-files-t2/c-lib/#{oboe_version}"
90
+ ext_src_dir = File.expand_path('ext/oboe_metal/src')
91
+
92
+ # VERSION is used by extconf.rb to download the correct liboboe when installing the gem
93
+ remote_file = File.join(oboe_s3_dir, 'VERSION')
94
+ local_file = File.join(ext_src_dir, 'VERSION')
95
+ puts "fetching #{remote_file} to #{local_file}"
96
+ open(remote_file, 'rb') do |rf|
97
+ content = rf.read
98
+ File.open(local_file, 'wb') { |f| f.puts content }
99
+ puts "!!!!!!! C-Lib VERSION: #{content.strip} !!!!!!!!"
100
+ end
101
+
102
+ # oboe and bson header files
103
+ FileUtils.mkdir_p(File.join(ext_src_dir, 'bson'))
104
+ %w(oboe.h oboe.hpp oboe_debug.h oboe.i bson/bson.h bson/platform_hacks.h).each do |filename|
105
+ remote_file = File.join(oboe_s3_dir, 'include', filename)
106
+ local_file = File.join(ext_src_dir, filename)
107
+
108
+ puts "fetching #{remote_file} to #{local_file}"
109
+ open(remote_file, 'rb') do |rf|
110
+ content = rf.read
111
+ File.open(local_file, 'wb') { |f| f.puts content }
112
+ end
113
+ end
114
+
115
+ FileUtils.cd(ext_src_dir) do
116
+ system('swig -c++ -ruby -module oboe_metal oboe.i')
117
+ FileUtils.rm('oboe.i')
118
+ end
119
+ end
120
+
121
+ desc "Build the gem's c extension"
122
+ task :compile do
123
+ if !defined?(JRUBY_VERSION)
124
+ puts "== Building the c extension against Ruby #{RUBY_VERSION}"
125
+
126
+ pwd = Dir.pwd
127
+ ext_dir = File.expand_path('ext/oboe_metal')
128
+ final_so = File.expand_path('lib/oboe_metal.so')
129
+ so_file = File.expand_path('ext/oboe_metal/oboe_metal.so')
130
+
131
+ Dir.chdir ext_dir
132
+ ENV['APPOPTICS_FROM_S3'] = 'true'
133
+ cmd = [Gem.ruby, 'extconf.rb']
134
+ sh cmd.join(' ')
135
+ sh '/usr/bin/env make'
136
+
137
+ File.delete(final_so) if File.exist?(final_so)
138
+
139
+ if File.exist?(so_file)
140
+ FileUtils.mv(so_file, final_so)
141
+ Dir.chdir(pwd)
142
+ puts "== Extension built and moved to #{final_so}"
143
+ else
144
+ Dir.chdir(pwd)
145
+ puts '!! Extension failed to build (see above). Have the required binary and header files been fetched?'
146
+ puts '!! Try the tasks in this order: clean > fetch_ext_deps > compile.'
147
+ end
148
+ else
149
+ puts '== Nothing to do under JRuby.'
150
+ end
151
+ end
152
+
153
+ desc 'Clean up extension build files'
154
+ task :clean do
155
+ if !defined?(JRUBY_VERSION)
156
+ pwd = Dir.pwd
157
+ ext_dir = File.expand_path('ext/oboe_metal')
158
+ symlinks = [
159
+ File.expand_path('lib/oboe_metal.so'),
160
+ File.expand_path('ext/oboe_metal/lib/liboboe.so'),
161
+ File.expand_path('ext/oboe_metal/lib/liboboe-1.0.so.0')
162
+ ]
163
+
164
+ symlinks.each do |symlink|
165
+ FileUtils.rm_f symlink
166
+ end
167
+ Dir.chdir ext_dir
168
+ sh '/usr/bin/env make clean' if File.exist? 'Makefile'
169
+
170
+ Dir.chdir pwd
171
+ else
172
+ puts '== Nothing to do under JRuby.'
173
+ end
174
+ end
175
+
176
+ desc 'Remove all built files and extensions'
177
+ task :distclean do
178
+ if !defined?(JRUBY_VERSION)
179
+ pwd = Dir.pwd
180
+ ext_dir = File.expand_path('ext/oboe_metal')
181
+ mkmf_log = File.expand_path('ext/oboe_metal/mkmf.log')
182
+ symlinks = [
183
+ File.expand_path('lib/oboe_metal.so'),
184
+ File.expand_path('ext/oboe_metal/lib/liboboe.so'),
185
+ File.expand_path('ext/oboe_metal/lib/liboboe-1.0.so.0')
186
+ ]
187
+
188
+ if File.exist? mkmf_log
189
+ symlinks.each do |symlink|
190
+ FileUtils.rm_f symlink
191
+ end
192
+ Dir.chdir ext_dir
193
+ sh '/usr/bin/env make distclean' if File.exist? 'Makefile'
194
+
195
+ Dir.chdir pwd
196
+ else
197
+ puts 'Nothing to distclean. (nothing built yet?)'
198
+ end
199
+ else
200
+ puts '== Nothing to do under JRuby.'
201
+ end
202
+ end
203
+
204
+ desc "Rebuild the gem's c extension"
205
+ task :recompile => [:distclean, :compile]
206
+
207
+ task :environment do
208
+ ENV['APPOPTICS_GEM_VERBOSE'] = 'true'
209
+
210
+ Bundler.require(:default, :development)
211
+ AppOpticsAPM::Config[:tracing_mode] = :always
212
+ AppOpticsAPM::Test.load_extras
213
+
214
+ if AppOpticsAPM::Test.gemfile?(:delayed_job)
215
+ require 'delayed/tasks'
216
+ end
217
+ end
218
+
219
+ task :console => :environment do
220
+ ARGV.clear
221
+ if AppOpticsAPM::Test.gemfile?(:delayed_job)
222
+ require './test/servers/delayed_job'
223
+ end
224
+ Pry.start
225
+ end
226
+
227
+ # Used when testing Resque locally
228
+ task 'resque:setup' => :environment do
229
+ require 'resque/tasks'
230
+ end
@@ -0,0 +1,61 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "appoptics_apm/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{appoptics_apm_mnfst}
6
+ s.version = AppOpticsAPM::Version::STRING
7
+ s.date = Time.now.strftime('%Y-%m-%d')
8
+
9
+ s.license = "Librato Open License, Version 1.0"
10
+
11
+ s.authors = ["Maia Engeli", "Peter Giacomo Lombardo", "Spiros Eliopoulos"]
12
+ s.email = %q{support@appoptics.com}
13
+ s.homepage = %q{https://www.appoptics.com/}
14
+ s.summary = %q{AppOptics APM performance instrumentation gem for Ruby}
15
+ s.description = <<-EOF
16
+ Automatic tracing and metrics for Ruby applications. Get started at appoptics.com. @AppOptics
17
+ EOF
18
+
19
+ s.metadata = {
20
+ 'changelog_uri' => 'https://github.com/appoptics/appoptics-apm-ruby/releases',
21
+ 'documentation_uri' => 'https://docs.appoptics.com/kb/apm_tracing/ruby/',
22
+ 'homepage_uri' => 'https://www.appoptics.com/',
23
+ 'source_code_uri' => 'https://github.com/appoptics/appoptics-apm-ruby',
24
+ }
25
+
26
+ s.extra_rdoc_files = ['LICENSE']
27
+ s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|gemfiles)/}) }
28
+ s.files += ['ext/oboe_metal/src/oboe.h',
29
+ 'ext/oboe_metal/src/oboe.hpp',
30
+ 'ext/oboe_metal/src/oboe_debug.h',
31
+ 'ext/oboe_metal/src/oboe_wrap.cxx',
32
+ 'ext/oboe_metal/src/bson/bson.h',
33
+ 'ext/oboe_metal/src/bson/platform_hacks.h',
34
+ 'ext/oboe_metal/src/VERSION']
35
+
36
+ # TODO this is commented out util we can actually provide gems for different platforms
37
+ # it will create a gem that goes into noop on Darwin and other unsupported platforms
38
+ # s.platform = defined?(JRUBY_VERSION) ? 'java' : Gem::Platform::CURRENT
39
+
40
+ s.extensions = ['ext/oboe_metal/extconf.rb'] unless defined?(JRUBY_VERSION)
41
+
42
+ s.add_runtime_dependency('json', '>= 0')
43
+ s.add_runtime_dependency('no_proxy_fix', '~> 0.1.2', '>= 0.1.2')
44
+
45
+ # Development dependencies used in gem development & testing
46
+ s.add_development_dependency('rake', '>= 0.9.0')
47
+ s.add_development_dependency('simplecov', '>= 0.16.0') if ENV["SIMPLECOV_COVERAGE"]
48
+ s.add_development_dependency('simplecov-console', '>= 0.4.0') if ENV["SIMPLECOV_COVERAGE"]
49
+
50
+ unless defined?(JRUBY_VERSION)
51
+ s.add_development_dependency('byebug', '>= 8.0.0')
52
+ s.add_development_dependency('pry', '>= 0.10.0')
53
+ s.add_development_dependency('pry-byebug', '>= 3.0.0')
54
+ s.add_development_dependency('minitest-hooks', '>= 1.5.0')
55
+ else
56
+ s.add_development_dependency('pry', '>= 0.10.0')
57
+ end
58
+
59
+ s.required_ruby_version = '>= 2.0.0'
60
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
61
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##
4
+ # execute this with `bundle exec appoptics_apm_config`
5
+ # copies the configuration template file into the current directory
6
+ #
7
+
8
+ puts "Copying the configuration template file to appoptics_apm_config_tmp.rb"
9
+ puts "Edit and save as appoptics_apm_config.rb"
10
+
11
+ target_file = File.join(Dir.pwd, 'appoptics_apm_config_tmp.rb')
12
+ temp_orig = File.join(File.dirname(File.dirname(__FILE__)),
13
+ 'lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb')
14
+
15
+ FileUtils.copy(temp_orig, target_file)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ # builds the appoptics_apm gem for MRI.
3
+
4
+ # we currently only build for MRI, no JRuby
5
+ echo -e "\n=== building for MRI ===\n"
6
+ rm -f Gemfile.lock
7
+ bundle install
8
+ bundle exec rake distclean
9
+ bundle exec rake fetch_ext_deps
10
+ gem build appoptics_apm.gemspec
11
+
12
+ echo -e "\n=== built gems ===\n"
13
+ ls -la appoptics_apm*.gem
14
+
15
+ echo -e "\n=== publish to rubygems via: gem push <gem> ===\n"
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+
3
+ # build the gem,
4
+ # oboe/c-lib version can be given as optional parameter
5
+ if [ "$1" != "" ]; then
6
+ OBOE_VERSION=$1 ./build_gem.sh
7
+ else
8
+ ./build_gem.sh
9
+ fi
10
+
11
+ # save current rbenv setting and switch to 2.4.1 for the package_cloud commands
12
+ current_ruby=`rbenv global`
13
+ rbenv global 2.4.1
14
+
15
+ # prerequisite: package_cloud token needs to be in ~/.packagecloud
16
+ gem=`ls -dt1 appoptics_apm-[^pre]*.gem | head -1`
17
+ package_cloud push solarwinds/appoptics-apm-ruby $gem
18
+
19
+ # restore ruby version
20
+ rbenv global $current_ruby
@@ -0,0 +1,67 @@
1
+
2
+ ###############################################################
3
+ # BASIC TRACING EXAMPLES
4
+ ###############################################################
5
+
6
+ # set APPOPTICS_SERVICE_KEY and run with
7
+ # `bundle exec ruby 01_basic_tracing.rb`
8
+
9
+ require 'appoptics_apm'
10
+ unless AppopticsAPM::SDK.appoptics_ready(10_000)
11
+ puts "aborting!!! Agent not ready after 10 seconds"
12
+ exit false
13
+ end
14
+
15
+
16
+ ###############################################################
17
+ # Starting a trace and adding a span
18
+ ###############################################################
19
+
20
+ # USE CASE:
21
+ # You may want to either trace a piece of your own code or a
22
+ # call to a method from a gem that isn't auto-instrumented by
23
+ # appoptics_apm
24
+
25
+ # The first example will not create a span, because no trace has
26
+ # been started, but the second and third ones will.
27
+
28
+ # The string argument is the name for the span
29
+
30
+ ##
31
+ # AppOpticsAPM::SDK.trace()
32
+ # most of the time this is the method you need. It adds a span
33
+ # to a trace that has probably been started by rack.
34
+
35
+ # Example 1
36
+ def do_work
37
+ 42
38
+ end
39
+
40
+ AppOpticsAPM::SDK.trace('simple_span') do
41
+ do_work
42
+ end
43
+
44
+ ##
45
+ # AppOpticsAPM::SDK.start_trace()
46
+ # This method starts a trace. It is handy for background jobs,
47
+ # workers, or scripts, that are not part of a rack application
48
+
49
+ # Example 2
50
+ AppOpticsAPM::SDK.start_trace('outer_span') do
51
+
52
+ AppOpticsAPM::SDK.trace('simple_span') do
53
+ do_work
54
+ end
55
+
56
+ end
57
+
58
+ # Example 3
59
+ def do_traced_work
60
+ AppOpticsAPM::SDK.trace('simple_span_2') do
61
+ do_work
62
+ end
63
+ end
64
+
65
+ AppOpticsAPM::SDK.start_trace('outer_span_2') do
66
+ do_traced_work
67
+ end
@@ -0,0 +1,220 @@
1
+ ###############################################################
2
+ # A brief overview of AppOpticsAPM tracing context
3
+ ###############################################################
4
+ #
5
+ # Tracing context is the state held when AppOpticsAPM is instrumenting a
6
+ # transaction, block, request etc.. This context is advanced as
7
+ # new blocks are instrumented and this chain of context is used
8
+ # by AppOpticsAPM to later reassemble performance data to be displayed
9
+ # in the AppOptics dashboard.
10
+ #
11
+ # Tracing context is non-existent until established by calling
12
+ # `AppOpticsAPM::API.start_trace` or `AppOpticsAPM::API.log_start`. Those methods
13
+ # are part of the high-level and low-level API respectively.
14
+ #
15
+ # After a tracing context is established, that context can be
16
+ # continued by calling `AppOpticsAPM::API.trace` or `AppOpticsAPM::API.log_entry`.
17
+ # These methods will advance an existing context but not start
18
+ # new one.
19
+ #
20
+ # For example, when a web request comes into a stack, a tracing
21
+ # context is established using `AppOpticsAPM::API.log_start` as the request
22
+ # enters through the rack middleware via `AppOpticsAPM::Rack`.
23
+ #
24
+ # That tracing context is then continued using `AppOpticsAPM::API.trace` or
25
+ # `AppOpticsAPM::API.log_entry` for each subsequent layer such as Rails,
26
+ # ActiveRecord, Redis, Memcache, ActionView, Mongo (etc...) until
27
+ # finally request processing is complete and the tracing context
28
+ # is cleared (AppOpticsAPM::Context.clear)
29
+ #
30
+
31
+ ###############################################################
32
+ # Carrying Context
33
+ ###############################################################
34
+ #
35
+ # The tracing context exists in the form of an X-Trace string and
36
+ # can be retrieved using 'AppOpticsAPM::Context.toString'
37
+ #
38
+ # xtrace = AppOpticsAPM::Context.toString
39
+ #
40
+ # => "1B4EDAB9E028CA3C81BCD57CC4644B4C4AE239C7B713F0BCB9FAD6D562"
41
+ #
42
+ # Tracing context can also be picked up from a pre-existing
43
+ # X-Trace string:
44
+ #
45
+ # xtrace = "1B4EDAB9E028CA3C81BCD57CC4644B4C4AE239C7B713F0BCB9FAD6D562"
46
+ #
47
+ # AppOpticsAPM::Context.fromString(xtrace)
48
+ #
49
+ # With these two methods, context can be passed across threads,
50
+ # processes (via fork) and in requests (such as external HTTP
51
+ # requests where the X-Trace is inserted in request headers).
52
+ #
53
+ #
54
+
55
+ ###############################################################
56
+ # Two Options for Spawned Tracing
57
+ ###############################################################
58
+ #
59
+ # When your application needs to instrument code that forks,
60
+ # spawns a thread or does something in-parallel, you have the
61
+ # option to either link those child traces to the parent or
62
+ # trace them as individuals (but with identifying information).
63
+ #
64
+ # Linking parent and child has it's benefits as in the
65
+ # AppOptics dashboard, you will see how a process may spawn
66
+ # a task in parallel and in a single view see the performance
67
+ # of both.
68
+ #
69
+ # The limitation of this is that this is only useful if your
70
+ # parent process spawns only a limited number of child traces.
71
+ #
72
+ # If your parent process is spawning many child tasks (e.g.
73
+ # twenty, hundreds, thousands or more) it's best to trace those
74
+ # child tasks as individuals and pass in identifier Key-Values
75
+ # (such as task ID, job ID etc..)
76
+ #
77
+ # In the examples below, I show implementations of both linked
78
+ # asynchronous traces and separated independent traces.
79
+
80
+ ###############################################################
81
+ # Thread - with separated traces
82
+ ###############################################################
83
+
84
+ AppOpticsAPM::API.log_start('parent')
85
+
86
+ # Get the work to be done
87
+ job = get_work
88
+
89
+ Thread.new do
90
+ # This is a new thread so there is no pre-existing context so
91
+ # we'll call `AppOpticsAPM::API.log_start` to start a new trace context.
92
+ AppOpticsAPM::API.log_start('worker_thread', :job_id => job.id)
93
+
94
+ # Do the work
95
+ do_the_work(job)
96
+
97
+ AppOpticsAPM::API.log_end('worker_thread')
98
+ end
99
+
100
+ AppOpticsAPM::API.log_end('parent')
101
+
102
+ ###############################################################
103
+ #
104
+ # This will generate two independent traces with the following
105
+ # topology.
106
+ #
107
+ # 'parent'
108
+ # ------------------------------------------------------------
109
+ #
110
+ # 'worker_thread'
111
+ # ------------------------------------------------------------
112
+ #
113
+
114
+ ###############################################################
115
+ # Thread - with linked asynchronous traces
116
+ ###############################################################
117
+
118
+ # Since the following example spawns a thread without waiting
119
+ # for it to return, we carry over the context and we mark the
120
+ # trace generated in that thread to be asynchronous using
121
+ # the `Async` flag.
122
+
123
+ AppOpticsAPM::API.log_start('parent')
124
+
125
+ # Save the context to be imported in spawned thread
126
+ tracing_context = AppOpticsAPM::Context.toString
127
+
128
+ # Get the work to be done
129
+ job = get_work
130
+
131
+ Thread.new do
132
+ # Restore context
133
+ AppOpticsAPM::Context.fromString(tracing_context)
134
+
135
+ AppOpticsAPM::API.log_entry('worker_thread')
136
+
137
+ # Do the work
138
+ do_the_work(job)
139
+
140
+ AppOpticsAPM::API.log_exit('worker_thread', :Async => 1)
141
+ end
142
+
143
+ AppOpticsAPM::API.log_end('parent')
144
+
145
+ ###############################################################
146
+ #
147
+ # This will generate a single trace with an asynchronous
148
+ # branch like the following
149
+ #
150
+ # 'parent'
151
+ # ------------------------------------------------------------
152
+ # \
153
+ # \
154
+ # ------------------------------------------------------
155
+ # 'worker_thread'
156
+ #
157
+
158
+ ###############################################################
159
+ # Process via fork - with separated traces
160
+ ###############################################################
161
+
162
+ AppOpticsAPM::API.start_trace('parent_process') do
163
+ # Get some work to process
164
+ job = get_job
165
+
166
+ # fork process to handle work
167
+ fork do
168
+ # Since fork does a complete process copy, the tracing_context still exists
169
+ # so we have to clear it and start again.
170
+ AppOpticsAPM::Context.clear
171
+
172
+ AppOpticsAPM::API.start_trace('worker_process', nil, :job_id => job.id) do
173
+ do_work(job)
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+ ###############################################################
180
+ #
181
+ # This will generate two independent traces:
182
+ #
183
+ # 'parent_process'
184
+ # ------------------------------------------------------------
185
+ #
186
+ # 'worker_process'
187
+ # ------------------------------------------------------------
188
+ #
189
+ ###############################################################
190
+ # Process via fork - with linked asynchronous traces
191
+ ###############################################################
192
+
193
+ AppOpticsAPM::API.start_trace('parent_process') do
194
+ # Get some work to process
195
+ job = get_job
196
+
197
+ # fork process to handle work
198
+ fork do
199
+ # Since fork does a complete process copy, the tracing_context still exists
200
+ # although we'll have to mark these traces as asynchronous to denote
201
+ # that it has split off from the main program flow
202
+
203
+ AppOpticsAPM::API.trace('worker_process', :Async => 1) do
204
+ do_work(job)
205
+ end
206
+ end
207
+ end
208
+
209
+ ###############################################################
210
+ #
211
+ # This will generate a single trace with an asynchronous
212
+ # branch like the following
213
+ #
214
+ # 'parent_process'
215
+ # ------------------------------------------------------------
216
+ # \
217
+ # \
218
+ # ------------------------------------------------------
219
+ # 'worker_process'
220
+ #