appoptics_apm 4.1.2 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 279e04ea7b50365f82a752e34561e98553accfbf
4
- data.tar.gz: 6c164062efc035368cec63f422689ae0317b8986
3
+ metadata.gz: f75eee6a2dc08842b68a7dce1a083c6f122fd462
4
+ data.tar.gz: 7a70d00b5f659de3cb11c2828a6d9695363cce09
5
5
  SHA512:
6
- metadata.gz: 58716fc2e035939241428b70b45ce5e090238c71758d72fa9b29e2fbdc11fd34f89e97d5a44d6f769d8a3edf80f6ce4e02aaea6e3b1a4b001778970cf43a81ca
7
- data.tar.gz: aacc0674ebe52dda370cec24c6a194a4e57bc0e41dddbae3e9e93b0565350f96d42a41119fe895e4148741bfe7262a7396e1c513242a2e6f4d6303f2f3d0022f
6
+ metadata.gz: 44f247b3789ab9bbd385324a42eb61025759eec224bc85dd7d3abeee6f3e0d4facc0af8541ab99b0897a8286835cc0ba88f6b1f61fa8a59995b359c54796ab1c
7
+ data.tar.gz: a38c975e81913efad14a501ec159aeba97825ded8f7ade3188443be33025cc76771c813d37bcf9e47f35bd10ebd0aa5900d6526321f194524ad7ef6d2c0bc560
data/.travis.yml CHANGED
@@ -5,9 +5,14 @@ cache:
5
5
  directories:
6
6
  - vendor/bundle
7
7
 
8
+ env:
9
+ - DBTYPE=mysql
10
+ - DBTYPE=mysql2
11
+ - DBTYPE=postgresql
12
+
8
13
  rvm:
9
14
  - 2.5.0
10
- - 2.4.3
15
+ # - 2.4.3
11
16
  - 2.3.6
12
17
  # - jruby-9.0.5.0
13
18
 
@@ -23,11 +28,6 @@ gemfile:
23
28
  - gemfiles/rails51.gemfile
24
29
  - gemfiles/delayed_job.gemfile
25
30
 
26
- env:
27
- - DBTYPE=mysql
28
- - DBTYPE=mysql2
29
- - DBTYPE=postgresql
30
-
31
31
  matrix:
32
32
  exclude:
33
33
  - rvm: 2.5.0
@@ -103,6 +103,8 @@ before_script:
103
103
  - psql -c 'create database travis_ci_test;' -U postgres
104
104
  - mysql -e 'create database travis_ci_test;'
105
105
  - sleep 10
106
+ - export APPOPTICS_TOKEN_BUCKET_CAPACITY=1000
107
+ - export APPOPTICS_TOKEN_BUCKET_RATE=1000
106
108
 
107
109
  script: "N=1 bundle exec rake test"
108
110
 
data/Dockerfile_test CHANGED
@@ -1,7 +1,7 @@
1
1
  FROM ubuntu:16.04
2
2
 
3
3
  # to use with ./run_tests_docker.rb
4
- # docker build -f Dockerfile-test -t ruby_appoptics_apm .
4
+ # docker build -f Dockerfile_test -t ruby_appoptics_apm .
5
5
 
6
6
  # install OS packages
7
7
  RUN apt-get update \
@@ -39,7 +39,7 @@ RUN . ~/.profile \
39
39
  && rbenv install 2.3.6 \
40
40
  && rbenv install 2.4.3 \
41
41
  && rbenv install 2.5.0
42
- && rbenv install jruby-9.1.16.0
42
+ # && rbenv install jruby-9.1.16.0
43
43
 
44
44
  # install swig 3.0.8
45
45
  RUN curl -SL http://kent.dl.sourceforge.net/project/swig/swig/swig-3.0.8/swig-3.0.8.tar.gz \
@@ -68,3 +68,5 @@ RUN apt-get update && \
68
68
  ENV PATH="/root/.rbenv/bin:/root/.rbenv/shims:$PATH"
69
69
  ENV RUBY_ENV=test
70
70
  ENV DOCKER_PSQL_PASS=docker
71
+ ENV APPOPTICS_TOKEN_BUCKET_CAPACITY=1000
72
+ ENV APPOPTICS_TOKEN_BUCKET_RATE=1000
data/Rakefile CHANGED
@@ -73,13 +73,23 @@ task :fetch_ext_deps do
73
73
  end
74
74
 
75
75
  # The c-lib version is different from the gem version
76
- oboe_version = ENV['OBOE_VERSION'] || '2.0.10' # 'latest'
77
- oboe_src_dir = "https://s3-us-west-2.amazonaws.com/rc-files-t2/c-lib/#{oboe_version}"
76
+ oboe_version = ENV['OBOE_VERSION'] || 'latest'
77
+ oboe_s3_dir = "https://s3-us-west-2.amazonaws.com/rc-files-t2/c-lib/#{oboe_version}"
78
78
  ext_src_dir = File.expand_path('ext/oboe_metal/src')
79
79
 
80
80
  # VERSION is used by extconf.rb to download the correct liboboe when installing the gem
81
- %w(oboe.i oboe.h oboe.hpp oboe_debug.h VERSION).each do |filename|
82
- remote_file = File.join(oboe_src_dir, filename)
81
+ remote_file = File.join(oboe_s3_dir, 'VERSION')
82
+ local_file = File.join(ext_src_dir, 'VERSION')
83
+ puts "fetching #{remote_file} to #{local_file}"
84
+ open(remote_file, 'rb') do |rf|
85
+ content = rf.read
86
+ File.open(local_file, 'wb') { |f| f.puts content }
87
+ end
88
+
89
+ # oboe and bson header files
90
+ FileUtils.mkdir_p(File.join(ext_src_dir, 'bson'))
91
+ %w(oboe.h oboe.hpp oboe_debug.h oboe.i bson/bson.h bson/platform_hacks.h).each do |filename|
92
+ remote_file = File.join(oboe_s3_dir, 'include', filename)
83
93
  local_file = File.join(ext_src_dir, filename)
84
94
 
85
95
  puts "fetching #{remote_file} to #{local_file}"
@@ -88,6 +98,7 @@ task :fetch_ext_deps do
88
98
  File.open(local_file, 'wb') { |f| f.puts content }
89
99
  end
90
100
  end
101
+
91
102
  FileUtils.cd(ext_src_dir) do
92
103
  system('swig -c++ -ruby -module oboe_metal oboe.i')
93
104
  FileUtils.rm('oboe.i')
@@ -15,11 +15,13 @@ Gem::Specification.new do |s|
15
15
  s.description = %q{The AppOpticsAPM gem provides performance instrumentation for MRI Ruby and related frameworks.}
16
16
 
17
17
  s.extra_rdoc_files = ["LICENSE"]
18
- s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|gemfiles|examples)/}) }
18
+ s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|gemfiles)/}) }
19
19
  s.files += ['ext/oboe_metal/src/oboe.h',
20
20
  'ext/oboe_metal/src/oboe.hpp',
21
21
  'ext/oboe_metal/src/oboe_debug.h',
22
22
  'ext/oboe_metal/src/oboe_wrap.cxx',
23
+ 'ext/oboe_metal/src/bson/bson.h',
24
+ 'ext/oboe_metal/src/bson/platform_hacks.h',
23
25
  'ext/oboe_metal/src/VERSION']
24
26
 
25
27
  # TODO this is commented out util we can actually provide gems for different platforms
data/examples/DNT.md ADDED
@@ -0,0 +1,35 @@
1
+ By default, the AppOpticsAPM 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
+ `AppOpticsAPM::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 `AppOpticsAPM::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
+ AppOpticsAPM::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/tracelytics/ruby-appoptics/blob/master/lib/appoptics/config.rb#L129).
@@ -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
+ #
@@ -0,0 +1,8 @@
1
+ class MetalController < ActionController::Metal
2
+ def index
3
+ self.response_body = 'Hello Metal!'
4
+ end
5
+
6
+ include AppOpticsAPMMethodProfiling
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
+ ::AppOpticsAPM.reconnect! if defined?(::AppOpticsAPM)
13
+ end
14
+
15
+ on_worker_shutdown do
16
+ ::AppOpticsAPM.disconnect! if defined?(::AppOpticsAPM)
17
+ end
@@ -0,0 +1,124 @@
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
+ AppOpticsAPM::Config[:tracing_mode] = :always
10
+ AppOpticsAPM::Config[:verbose] = true
11
+
12
+ # The parent process/loop which collects data
13
+ Kernel.loop do
14
+
15
+ # For each loop, we instrument the work retrieval. These traces
16
+ # will show up as layer 'get_the_work'.
17
+ AppOpticsAPM::API.start_trace('get_the_work') do
18
+ work = get_the_work
19
+
20
+ # Loop through work and pass to `do_the_work` method
21
+ # that spawns a thread each time
22
+ work.each do |j|
23
+
24
+ # In the new Thread block, the AppOpticsAPM tracing context isn't there
25
+ # so we carry it over manually and pass it to the `start_trace`
26
+ # method.
27
+
28
+ # In the AppOptics dashboard, this will show up as parent traces
29
+ # (layer 'get_the_work') with child traces (layer 'do_the_work').
30
+
31
+ tracing_context = AppOpticsAPM::Context.toString
32
+
33
+ Thread.new do
34
+ result = nil
35
+
36
+ AppOpticsAPM::API.start_trace('do_the_work', tracing_context, :Async => 1) do
37
+ result = do_the_work(j)
38
+ end
39
+
40
+ result
41
+ end
42
+ end
43
+ end
44
+ sleep 5
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 AppOptics
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 AppOptics 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 AppOptics 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 AppOptics 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
+ # AppOpticsAPM::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 (support@appoptics.com).
124
+ #