traceview 3.0.0-java

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 (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +58 -0
  5. data/Appraisals +10 -0
  6. data/CHANGELOG.md +490 -0
  7. data/CONFIG.md +16 -0
  8. data/Gemfile +95 -0
  9. data/LICENSE +199 -0
  10. data/README.md +380 -0
  11. data/Rakefile +109 -0
  12. data/examples/DNT.md +35 -0
  13. data/examples/carrying_context.rb +225 -0
  14. data/examples/instrumenting_metal_controller.rb +8 -0
  15. data/examples/puma_on_heroku_config.rb +17 -0
  16. data/examples/tracing_async_threads.rb +125 -0
  17. data/examples/tracing_background_jobs.rb +52 -0
  18. data/examples/tracing_forked_processes.rb +100 -0
  19. data/examples/unicorn_on_heroku_config.rb +28 -0
  20. data/ext/oboe_metal/extconf.rb +61 -0
  21. data/ext/oboe_metal/noop/noop.c +7 -0
  22. data/ext/oboe_metal/src/bson/bson.h +221 -0
  23. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  24. data/ext/oboe_metal/src/oboe.h +275 -0
  25. data/ext/oboe_metal/src/oboe.hpp +352 -0
  26. data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
  27. data/ext/oboe_metal/tests/test.rb +11 -0
  28. data/gemfiles/mongo.gemfile +33 -0
  29. data/gemfiles/moped.gemfile +33 -0
  30. data/get_version.rb +5 -0
  31. data/init.rb +4 -0
  32. data/lib/joboe_metal.rb +206 -0
  33. data/lib/oboe/README +2 -0
  34. data/lib/oboe/backward_compatibility.rb +59 -0
  35. data/lib/oboe/inst/rack.rb +11 -0
  36. data/lib/oboe.rb +7 -0
  37. data/lib/oboe_metal.rb +151 -0
  38. data/lib/rails/generators/traceview/install_generator.rb +76 -0
  39. data/lib/rails/generators/traceview/templates/traceview_initializer.rb +159 -0
  40. data/lib/traceview/api/layerinit.rb +51 -0
  41. data/lib/traceview/api/logging.rb +209 -0
  42. data/lib/traceview/api/memcache.rb +31 -0
  43. data/lib/traceview/api/profiling.rb +50 -0
  44. data/lib/traceview/api/tracing.rb +135 -0
  45. data/lib/traceview/api/util.rb +121 -0
  46. data/lib/traceview/api.rb +18 -0
  47. data/lib/traceview/base.rb +225 -0
  48. data/lib/traceview/config.rb +238 -0
  49. data/lib/traceview/frameworks/grape.rb +97 -0
  50. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  53. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  55. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  56. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  57. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  59. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  60. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  61. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  65. data/lib/traceview/frameworks/rails.rb +145 -0
  66. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/inst/cassandra.rb +279 -0
  69. data/lib/traceview/inst/dalli.rb +86 -0
  70. data/lib/traceview/inst/em-http-request.rb +99 -0
  71. data/lib/traceview/inst/excon.rb +111 -0
  72. data/lib/traceview/inst/faraday.rb +73 -0
  73. data/lib/traceview/inst/http.rb +87 -0
  74. data/lib/traceview/inst/httpclient.rb +173 -0
  75. data/lib/traceview/inst/memcache.rb +102 -0
  76. data/lib/traceview/inst/memcached.rb +94 -0
  77. data/lib/traceview/inst/mongo.rb +238 -0
  78. data/lib/traceview/inst/moped.rb +474 -0
  79. data/lib/traceview/inst/rack.rb +122 -0
  80. data/lib/traceview/inst/redis.rb +271 -0
  81. data/lib/traceview/inst/resque.rb +192 -0
  82. data/lib/traceview/inst/rest-client.rb +38 -0
  83. data/lib/traceview/inst/sequel.rb +162 -0
  84. data/lib/traceview/inst/typhoeus.rb +102 -0
  85. data/lib/traceview/instrumentation.rb +21 -0
  86. data/lib/traceview/loading.rb +94 -0
  87. data/lib/traceview/logger.rb +41 -0
  88. data/lib/traceview/method_profiling.rb +84 -0
  89. data/lib/traceview/ruby.rb +36 -0
  90. data/lib/traceview/support.rb +113 -0
  91. data/lib/traceview/thread_local.rb +26 -0
  92. data/lib/traceview/util.rb +250 -0
  93. data/lib/traceview/version.rb +16 -0
  94. data/lib/traceview/xtrace.rb +90 -0
  95. data/lib/traceview.rb +62 -0
  96. data/test/frameworks/apps/grape_nested.rb +30 -0
  97. data/test/frameworks/apps/grape_simple.rb +24 -0
  98. data/test/frameworks/apps/padrino_simple.rb +45 -0
  99. data/test/frameworks/apps/sinatra_simple.rb +24 -0
  100. data/test/frameworks/grape_test.rb +142 -0
  101. data/test/frameworks/padrino_test.rb +30 -0
  102. data/test/frameworks/sinatra_test.rb +30 -0
  103. data/test/instrumentation/cassandra_test.rb +380 -0
  104. data/test/instrumentation/dalli_test.rb +171 -0
  105. data/test/instrumentation/em_http_request_test.rb +86 -0
  106. data/test/instrumentation/excon_test.rb +207 -0
  107. data/test/instrumentation/faraday_test.rb +235 -0
  108. data/test/instrumentation/http_test.rb +140 -0
  109. data/test/instrumentation/httpclient_test.rb +296 -0
  110. data/test/instrumentation/memcache_test.rb +251 -0
  111. data/test/instrumentation/memcached_test.rb +226 -0
  112. data/test/instrumentation/mongo_test.rb +462 -0
  113. data/test/instrumentation/moped_test.rb +496 -0
  114. data/test/instrumentation/rack_test.rb +116 -0
  115. data/test/instrumentation/redis_hashes_test.rb +265 -0
  116. data/test/instrumentation/redis_keys_test.rb +318 -0
  117. data/test/instrumentation/redis_lists_test.rb +310 -0
  118. data/test/instrumentation/redis_misc_test.rb +160 -0
  119. data/test/instrumentation/redis_sets_test.rb +293 -0
  120. data/test/instrumentation/redis_sortedsets_test.rb +325 -0
  121. data/test/instrumentation/redis_strings_test.rb +333 -0
  122. data/test/instrumentation/resque_test.rb +62 -0
  123. data/test/instrumentation/rest-client_test.rb +294 -0
  124. data/test/instrumentation/sequel_mysql2_test.rb +326 -0
  125. data/test/instrumentation/sequel_mysql_test.rb +326 -0
  126. data/test/instrumentation/sequel_pg_test.rb +330 -0
  127. data/test/instrumentation/typhoeus_test.rb +285 -0
  128. data/test/minitest_helper.rb +187 -0
  129. data/test/profiling/method_test.rb +198 -0
  130. data/test/servers/rackapp_8101.rb +22 -0
  131. data/test/support/backcompat_test.rb +269 -0
  132. data/test/support/config_test.rb +128 -0
  133. data/test/support/dnt_test.rb +73 -0
  134. data/test/support/liboboe_settings_test.rb +104 -0
  135. data/test/support/xtrace_test.rb +35 -0
  136. data/traceview.gemspec +29 -0
  137. metadata +248 -0
data/Rakefile ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'rake/testtask'
6
+ require 'appraisal'
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.libs << "test"
10
+ t.test_files = FileList['test/**/*_test.rb']
11
+ t.verbose = true
12
+ t.ruby_opts = []
13
+ # t.ruby_opts << ['-w']
14
+ if defined?(JRUBY_VERSION)
15
+ t.ruby_opts << ["-J-javaagent:/usr/local/tracelytics/tracelyticsagent.jar"]
16
+ end
17
+ end
18
+
19
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
20
+ task :default => :appraisal
21
+ else
22
+ task :default => :test
23
+ end
24
+
25
+ desc "Build the gem's c extension"
26
+ task :compile do
27
+ unless defined?(JRUBY_VERSION)
28
+ puts "== Building the c extension against Ruby #{RUBY_VERSION}"
29
+
30
+ pwd = Dir.pwd
31
+ ext_dir = File.expand_path('ext/oboe_metal')
32
+ lib_dir = File.expand_path('lib')
33
+ symlink = File.expand_path('lib/oboe_metal.so')
34
+ so_file = File.expand_path('ext/oboe_metal/oboe_metal.so')
35
+
36
+ Dir.chdir ext_dir
37
+ cmd = [ Gem.ruby, 'extconf.rb']
38
+ sh cmd.join(' ')
39
+ sh '/usr/bin/env make'
40
+ File.delete symlink if File.exist? symlink
41
+
42
+ if File.exists? so_file
43
+ File.symlink so_file, symlink
44
+ Dir.chdir pwd
45
+ puts "== Extension built and symlink'd to #{symlink}"
46
+ else
47
+ Dir.chdir pwd
48
+ puts "!! Extension failed to build (see above). Are the base TraceView packages installed?"
49
+ puts "!! See https://support.appneta.com/cloud/installing-traceview"
50
+ end
51
+ else
52
+ puts "== Nothing to do under JRuby."
53
+ end
54
+ end
55
+
56
+ desc "Clean up extension build files"
57
+ task :clean do
58
+ unless defined?(JRUBY_VERSION)
59
+ pwd = Dir.pwd
60
+ ext_dir = File.expand_path('ext/oboe_metal')
61
+ lib_dir = File.expand_path('lib')
62
+ symlink = File.expand_path('lib/oboe_metal.so')
63
+ so_file = File.expand_path('ext/oboe_metal/oboe_metal.so')
64
+
65
+ Dir.chdir ext_dir
66
+ sh '/usr/bin/env make clean'
67
+
68
+ Dir.chdir pwd
69
+ else
70
+ puts "== Nothing to do under JRuby."
71
+ end
72
+ end
73
+
74
+ desc "Remove all built files and extensions"
75
+ task :distclean do
76
+ unless defined?(JRUBY_VERSION)
77
+ pwd = Dir.pwd
78
+ ext_dir = File.expand_path('ext/oboe_metal')
79
+ lib_dir = File.expand_path('lib')
80
+ symlink = File.expand_path('lib/oboe_metal.so')
81
+ so_file = File.expand_path('ext/oboe_metal/oboe_metal.so')
82
+ mkmf_log = File.expand_path('ext/oboe_metal/mkmf.log')
83
+
84
+ if File.exists? mkmf_log
85
+ Dir.chdir ext_dir
86
+ File.delete symlink if File.exist? symlink
87
+ sh '/usr/bin/env make distclean'
88
+
89
+ Dir.chdir pwd
90
+ else
91
+ puts "Nothing to distclean. (nothing built yet?)"
92
+ end
93
+ else
94
+ puts "== Nothing to do under JRuby."
95
+ end
96
+ end
97
+
98
+ desc "Rebuild the gem's c extension"
99
+ task :recompile => [ :distclean, :compile ]
100
+
101
+ task :console do
102
+ ENV['TRACEVIEW_GEM_VERBOSE'] = 'true'
103
+ Bundler.require(:default, :development)
104
+ TraceView::Config[:tracing_mode] = :always
105
+ ARGV.clear
106
+ Pry.start
107
+ end
108
+
109
+
data/examples/DNT.md ADDED
@@ -0,0 +1,35 @@
1
+ By default, the TraceView oboe gem will not trace routes with extensions
2
+ for common static files. Examples of such files may be images,
3
+ javascript, pdfs and text files.
4
+
5
+ This is done by using the regular expression stored in
6
+ `Oboe::Config[:dnt_regexp]`:
7
+
8
+ .(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|svg|less)$
9
+
10
+ This string is used as a regular expression and is tested against
11
+ candidate URLs to be instrumented.
12
+
13
+ To replace the pattern in use, you can update this regular expression
14
+ string. Here are some examples.
15
+
16
+ If you prefer that you want your javascript and CSS files instrumented,
17
+ you can update `Oboe::Config[:dnt_regexp]` with an updated regexp
18
+ pattern (without the "js" and "css" entries):
19
+
20
+ .(jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|flv|swf|ttf|woff|svg|less)$
21
+
22
+ If you prefer to not instrument all javascript files except for one
23
+ named `show.js`, you could put this assignment into your initializer,
24
+ rackup file or application.rb (note that this example uses a standard
25
+ regexp [negative
26
+ look-behind](http://www.regular-expressions.info/lookaround.html) that
27
+ isn't supported in Ruby 1.8):
28
+
29
+ Oboe::Config[:dnt_regexp] = "(\.js$)(?<!show.js)"
30
+
31
+ Since this pattern is used with the standard Ruby Regexp class, you can
32
+ use any Regexp supported pattern. See the documentation on Ruby Regexp
33
+ [here](https://www.omniref.com/ruby/2.2.0/symbols/Regexp?d=380181456&n=0#doc_uncollapsed=true&d=380181456&n=0)
34
+ or you can also view the oboe gem [source code documentation for this
35
+ feature](https://github.com/appneta/oboe-ruby/blob/master/lib/oboe/config.rb#L74).
@@ -0,0 +1,225 @@
1
+ ###############################################################
2
+ # A brief overview of TraceView tracing context
3
+ ###############################################################
4
+ #
5
+ # Tracing context is the state held when TraceView 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 TraceView to later reassemble performance data to be displayed
9
+ # in the TraceView dashboard.
10
+ #
11
+ # Tracing context is non-existent until established by calling
12
+ # `Oboe::API.start_trace` or `Oboe::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 `Oboe::API.trace` or `Oboe::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 `Oboe::API.log_start` as the request
22
+ # enters through the rack middleware via `::Oboe::Rack`.
23
+ #
24
+ # That tracing context is then continued using `Oboe::API.trace` or
25
+ # `Oboe::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 (Oboe::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 'Oboe::Context.toString'
37
+ #
38
+ # xtrace = Oboe::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
+ # Oboe::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
+ # TraceView 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
+ Oboe::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 `Oboe::API.log_start` to start a new trace context.
92
+ Oboe::API.log_start('worker_thread', { :job_id => job.id })
93
+
94
+ # Do the work
95
+ do_the_work(job)
96
+
97
+ Oboe::API.log_end('worker_thread')
98
+ end
99
+
100
+ Oboe::API.log_end('parent')
101
+
102
+
103
+
104
+ ###############################################################
105
+ #
106
+ # This will generate two independent traces with the following
107
+ # topology.
108
+ #
109
+ # 'parent'
110
+ # ------------------------------------------------------------
111
+ #
112
+ # 'worker_thread'
113
+ # ------------------------------------------------------------
114
+ #
115
+
116
+ ###############################################################
117
+ # Thread - with linked asynchronous traces
118
+ ###############################################################
119
+
120
+ # Since the following example spawns a thread without waiting
121
+ # for it to return, we carry over the context and we mark the
122
+ # trace generated in that thread to be asynchronous using
123
+ # the `Async` flag.
124
+
125
+ Oboe::API.log_start('parent')
126
+
127
+ # Save the context to be imported in spawned thread
128
+ tracing_context = Oboe::Context.toString
129
+
130
+ # Get the work to be done
131
+ job = get_work
132
+
133
+ Thread.new do
134
+ # Restore context
135
+ Oboe::Context.fromString(tracing_context)
136
+
137
+ Oboe::API.log_entry('worker_thread')
138
+
139
+ # Do the work
140
+ do_the_work(job)
141
+
142
+ Oboe::API.log_exit('worker_thread', { 'Async' => 1 })
143
+ end
144
+
145
+ Oboe::API.log_end('parent')
146
+
147
+ ###############################################################
148
+ #
149
+ # This will generate a single trace with an asynchronous
150
+ # branch like the following
151
+ #
152
+ # 'parent'
153
+ # ------------------------------------------------------------
154
+ # \
155
+ # \
156
+ # ------------------------------------------------------
157
+ # 'worker_thread'
158
+ #
159
+
160
+ ###############################################################
161
+ # Process via fork - with separated traces
162
+ ###############################################################
163
+
164
+ Oboe::API.start_trace('parent_process') do
165
+
166
+ # Get some work to process
167
+ job = get_job
168
+
169
+ # fork process to handle work
170
+ fork do
171
+ # Since fork does a complete process copy, the tracing_context still exists
172
+ # so we have to clear it and start again.
173
+ Oboe::Context.clear
174
+
175
+ Oboe::API.start_trace('worker_process', nil, { :job_id => job.id }) do
176
+ do_work(job)
177
+ end
178
+ end
179
+
180
+ end
181
+
182
+ ###############################################################
183
+ #
184
+ # This will generate two independent traces:
185
+ #
186
+ # 'parent_process'
187
+ # ------------------------------------------------------------
188
+ #
189
+ # 'worker_process'
190
+ # ------------------------------------------------------------
191
+ #
192
+ ###############################################################
193
+ # Process via fork - with linked asynchronous traces
194
+ ###############################################################
195
+
196
+ Oboe::API.start_trace('parent_process') do
197
+
198
+ # Get some work to process
199
+ job = get_job
200
+
201
+ # fork process to handle work
202
+ fork do
203
+ # Since fork does a complete process copy, the tracing_context still exists
204
+ # although we'll have to mark these traces as asynchronous to denote
205
+ # that it has split off from the main program flow
206
+
207
+ Oboe::API.trace('worker_process', { 'Async' => 1 }) do
208
+ do_work(job)
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ ###############################################################
215
+ #
216
+ # This will generate a single trace with an asynchronous
217
+ # branch like the following
218
+ #
219
+ # 'parent_process'
220
+ # ------------------------------------------------------------
221
+ # \
222
+ # \
223
+ # ------------------------------------------------------
224
+ # 'worker_process'
225
+ #
@@ -0,0 +1,8 @@
1
+ class MetalController < ActionController::Metal
2
+ def index
3
+ self.response_body = 'Hello Metal!'
4
+ end
5
+
6
+ include OboeMethodProfiling
7
+ profile_method :index, 'metal-index'
8
+ end
@@ -0,0 +1,17 @@
1
+ workers Integer(ENV['WEB_CONCURRENCY'] || 2)
2
+ threads_count = Integer(ENV['MAX_THREADS'] || 5)
3
+ threads threads_count, threads_count
4
+
5
+ preload_app!
6
+
7
+ rackup DefaultRackup
8
+ port ENV['PORT'] || 3000
9
+ environment ENV['RACK_ENV'] || 'development'
10
+
11
+ on_worker_boot do
12
+ ::Oboe.reconnect! if defined?(::Oboe)
13
+ end
14
+
15
+ on_worker_shutdown do
16
+ ::Oboe.disconnect! if defined?(::Oboe)
17
+ end
@@ -0,0 +1,125 @@
1
+ #
2
+ # This sample demonstrates how to instrument a main loop that
3
+ # retrieves work and spawn threads that do the actual work
4
+ #
5
+
6
+ require 'math'
7
+ require 'oboe'
8
+
9
+ Oboe::Config[:tracing_mode] = :always
10
+ Oboe::Config[:verbose] = true
11
+
12
+ # The parent process/loop which collects data
13
+ while true do
14
+
15
+ # For each loop, we instrument the work retrieval. These traces
16
+ # will show up as layer 'get_the_work'.
17
+ Oboe::API.start_trace('get_the_work') do
18
+
19
+ work = get_the_work
20
+
21
+ # Loop through work and pass to `do_the_work` method
22
+ # that spawns a thread each time
23
+ work.each do |j|
24
+
25
+ # In the new Thread block, the Oboe tracing context isn't there
26
+ # so we carry it over manually and pass it to the `start_trace`
27
+ # method.
28
+
29
+ # In the TraceView dashboard, this will show up as parent traces
30
+ # (layer 'get_the_work') with child traces (layer 'do_the_work').
31
+
32
+ tracing_context = Oboe::Context.toString
33
+
34
+ Thread.new do
35
+ result = nil
36
+
37
+ Oboe::API.start_trace('do_the_work', tracing_context, { 'Async' => 1 }) do
38
+ result = do_the_work(j)
39
+ end
40
+
41
+ result
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ ##
49
+ # get_the_work
50
+ #
51
+ # Method to retrieve work to do
52
+ #
53
+ def get_the_work
54
+ # We'll just return random integers as a
55
+ # fake work load
56
+ w = []
57
+ w << rand(25)
58
+ w << rand(25)
59
+ w << rand(25)
60
+ end
61
+
62
+ ##
63
+ # do_the_work
64
+ #
65
+ # The work-horse method
66
+ #
67
+ def do_the_work(job_to_do)
68
+ i = job_to_do
69
+ i * Math::PI
70
+ end
71
+
72
+ ####################################################
73
+ # Notes
74
+ ####################################################
75
+
76
+ # The above code generates a trace for each loop of the parent data collection process.
77
+ # Those traces have the layer name of `get_the_work` and will show up in the TraceView
78
+ # dashboard as such.
79
+ #
80
+ # Then as threads are spawned to process individual bits of work, we carry over the
81
+ # `tracing_context` and start a new asynchronous trace using `start_trace`. (An
82
+ # asynchronous trace is noted by passing the `Async` Hash key with a value of `1`).
83
+ #
84
+ # In the TraceView dashboard, the two traces (parent and child; or one to many) will
85
+ # be linked and displayed together as a single trace.
86
+
87
+ ####################################################
88
+ # Caveats
89
+ ####################################################
90
+
91
+ # If the main loop is retrieving many jobs (work) to process on each loop then
92
+ # linking the traces may not be the best strategy as such large relationships
93
+ # are difficult to display correctly in the TraceView dashboard and provide little
94
+ # added value.
95
+ #
96
+ # If there are more than 8 - 12 threads spawned from each loop, then you may want to consider
97
+ # NOT carrying over tracing context into the spawned threads.
98
+ #
99
+ # In this case, you can simply omit `tracing_context` and passing it to `start_trace` in
100
+ # the `Thread.new` block. (lines 32 + 37). Also remove the `{ Async => 1 }` Hash!
101
+ #
102
+ # This will produce two sets of traces with two the layer names 'get_the_work' +
103
+ # 'do_the_work'.
104
+ #
105
+ # In the TraceView dashboard, you can then separate or unify these traces into
106
+ # independent applications. e.g. job processor, data retrieval, thread worker etc...
107
+ #
108
+ # An implementation of the work loop without carrying over tracing context would look
109
+ # like the following:
110
+ #
111
+ # work.each do |j|
112
+ # Thread.new do
113
+ # result = nil
114
+ #
115
+ # Oboe::API.start_trace('do_the_work') do
116
+ # result = do_the_work(j)
117
+ # end
118
+ #
119
+ # result
120
+ # end
121
+ # end
122
+ #
123
+ # If anything isn't clear, please don't hesitate to reach us at support (traceviewsupport@appneta.com)
124
+ # or on IRC #appneta @ freenode.
125
+ #
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require
5
+
6
+ # Make sure oboe is at the bottom of your Gemfile.
7
+ # This is likely redundant but just in case.
8
+ require 'oboe'
9
+
10
+ # Tracing mode can be 'never', 'through' (to follow upstream) or 'always'
11
+ Oboe::Config[:tracing_mode] = 'always'
12
+
13
+ #
14
+ # Update April 9, 2015 - this is done automagically now
15
+ # and doesn't have to be called manually
16
+ #
17
+ # Load library instrumentation to auto-capture stuff we know about...
18
+ # e.g. ActiveRecord, Cassandra, Dalli, Redis, memcache, mongo
19
+ # Oboe::Ruby.load
20
+
21
+ # Some KVs to report to the dashboard
22
+ report_kvs = {}
23
+ report_kvs[:command_line_params] = ARGV.to_s
24
+ report_kvs[:user_id] = `whoami`
25
+
26
+ Oboe::API.start_trace('my_background_job', nil, report_kvs ) do
27
+ #
28
+ # Initialization code
29
+ #
30
+
31
+ tasks = get_all_tasks
32
+
33
+ tasks.each do |t|
34
+ # Optional: Here we embed another 'trace' to separate actual
35
+ # work for each task. In the TV dashboard, this will show
36
+ # up as a large 'my_background_job' parent layer with many
37
+ # child 'task" layers.
38
+ Oboe::API.trace('task', { :task_id => t.id }) do
39
+ t.perform
40
+ end
41
+ end
42
+ #
43
+ # cleanup code
44
+ #
45
+ end
46
+
47
+ # Note that we use 'start_trace' in the outer block and 'trace' for
48
+ # any sub-blocks of code we wish to instrument. The arguments for
49
+ # both methods vary slightly. Details in RubyDoc:
50
+ # https://www.omniref.com/ruby/gems/oboe/2.7.10.1/symbols/Oboe::API::Tracing#tab=Methods
51
+
52
+
@@ -0,0 +1,100 @@
1
+ #
2
+ # This sample demonstrates how to instrument a main loop that
3
+ # retrieves work and calls fork to do the actual work
4
+ #
5
+
6
+ require 'math'
7
+ require 'oboe'
8
+
9
+ Oboe::Config[:tracing_mode] = :always
10
+ Oboe::Config[:verbose] = true
11
+
12
+ # The parent process/loop which collects data
13
+ while true do
14
+
15
+ # For each loop, we instrument the work retrieval. These traces
16
+ # will show up as layer 'get_the_work'.
17
+ Oboe::API.start_trace('get_the_work') do
18
+
19
+ work = get_the_work
20
+
21
+ # Loop through work and pass to `do_the_work` method
22
+ # that spawns a thread each time
23
+ work.each do |job|
24
+ fork do
25
+ # Since the context is copied from the parent process, we clear it
26
+ # and start a new trace via `Oboe::API.start_trace`.
27
+ Oboe::Context.clear
28
+ result = nil
29
+
30
+ Oboe::API.start_trace('do_the_work', nil, :job_id => job.id) do
31
+ result = do_the_work(job)
32
+ end
33
+
34
+ result
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ ##
41
+ # get_the_work
42
+ #
43
+ # Method to retrieve work to do
44
+ #
45
+ def get_the_work
46
+ # We'll just return random integers as a
47
+ # fake work load
48
+ w = []
49
+ w << rand(25)
50
+ w << rand(25)
51
+ w << rand(25)
52
+ end
53
+
54
+ ##
55
+ # do_the_work
56
+ #
57
+ # The work-horse method
58
+ #
59
+ def do_the_work(job_to_do)
60
+ i = job_to_do
61
+ i * Math::PI
62
+ end
63
+
64
+ #########################################################################
65
+ # Notes
66
+ #########################################################################
67
+
68
+ # If your parent process only forks a small number of processes per loop (< 5..10),
69
+ # you may want to mark the child traces as asynchronous and have them directly
70
+ # linked to the parent tracing context.
71
+ #
72
+ # The benefit of this is that instead of having two independent traces (parent
73
+ # and child), you will have a single view of the parent trace showing the
74
+ # spawned child process and it's performance in the TraceView dashboard.
75
+ #
76
+ # To do this:
77
+ # 1. Don't clear the context in the child process
78
+ # 2. Use `Oboe::API.trace` instead
79
+ # 3. Pass the `Async` flag to mark this child as asynchronous
80
+ #
81
+ while true do
82
+ Oboe::API.start_trace('get_the_work') do
83
+
84
+ work = get_the_work
85
+
86
+ work.each do |job|
87
+ fork do
88
+ result = nil
89
+ # 1 Don't clear context
90
+ # 2 Use `Oboe::API.trace` instead
91
+ # 3 Pass the Async flag
92
+ Oboe::API.trace('do_the_work', { :job_id => job.id, 'Async' => 1 }) do
93
+ result = do_the_work(job)
94
+ end
95
+
96
+ result
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,28 @@
1
+ worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
2
+ timeout 15
3
+ preload_app true
4
+
5
+ before_fork do |server, worker|
6
+ Signal.trap 'TERM' do
7
+ puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
8
+ Process.kill 'QUIT', Process.pid
9
+ end
10
+
11
+ defined?(ActiveRecord::Base) and
12
+ ActiveRecord::Base.connection.disconnect!
13
+
14
+ defined?(::Oboe) and
15
+ ::Oboe.disconnect!
16
+ end
17
+
18
+ after_fork do |server, worker|
19
+ Signal.trap 'TERM' do
20
+ puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
21
+ end
22
+
23
+ defined?(ActiveRecord::Base) and
24
+ ActiveRecord::Base.establish_connection
25
+
26
+ defined?(::Oboe) and
27
+ ::Oboe.reconnect!
28
+ end