appoptics_apm_mnfst 4.5.2

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 (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
+ #