appoptics_apm 4.1.2 → 4.2.0

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