appoptics_apm 4.2.2 → 4.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -3
  3. data/Gemfile +0 -2
  4. data/README.md +119 -95
  5. data/examples/SDK/01_basic_tracing.rb +67 -0
  6. data/ext/oboe_metal/src/VERSION +1 -1
  7. data/lib/appoptics_apm/api.rb +10 -9
  8. data/lib/appoptics_apm/api/layerinit.rb +1 -1
  9. data/lib/appoptics_apm/api/logging.rb +41 -14
  10. data/lib/appoptics_apm/api/metrics.rb +34 -0
  11. data/lib/appoptics_apm/api/profiling.rb +5 -0
  12. data/lib/appoptics_apm/api/tracing.rb +33 -148
  13. data/lib/appoptics_apm/api/util.rb +3 -9
  14. data/lib/appoptics_apm/base.rb +11 -12
  15. data/lib/appoptics_apm/frameworks/padrino/templates.rb +1 -1
  16. data/lib/appoptics_apm/frameworks/rails.rb +1 -1
  17. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +1 -1
  18. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +1 -1
  19. data/lib/appoptics_apm/inst/bunny-consumer.rb +1 -2
  20. data/lib/appoptics_apm/inst/delayed_job.rb +4 -4
  21. data/lib/appoptics_apm/inst/em-http-request.rb +1 -1
  22. data/lib/appoptics_apm/inst/rack.rb +1 -0
  23. data/lib/appoptics_apm/inst/redis.rb +1 -1
  24. data/lib/appoptics_apm/inst/resque.rb +1 -1
  25. data/lib/appoptics_apm/inst/sidekiq-worker.rb +1 -3
  26. data/lib/appoptics_apm/loading.rb +3 -4
  27. data/lib/appoptics_apm/logger.rb +1 -1
  28. data/lib/appoptics_apm/sdk.rb +317 -0
  29. data/lib/appoptics_apm/support.rb +0 -17
  30. data/lib/appoptics_apm/test.rb +1 -1
  31. data/lib/appoptics_apm/util.rb +4 -3
  32. data/lib/appoptics_apm/version.rb +1 -1
  33. data/lib/appoptics_apm/xtrace.rb +3 -3
  34. data/lib/joboe_metal.rb +2 -4
  35. data/lib/oboe_metal.rb +5 -5
  36. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +5 -4
  37. data/run_tests_docker.rb +6 -0
  38. metadata +5 -9
  39. data/examples/DNT.md +0 -35
  40. data/examples/instrumenting_metal_controller.rb +0 -8
  41. data/examples/puma_on_heroku_config.rb +0 -17
  42. data/examples/tracing_async_threads.rb +0 -124
  43. data/examples/tracing_background_jobs.rb +0 -53
  44. data/examples/tracing_forked_processes.rb +0 -99
  45. data/examples/unicorn_on_heroku_config.rb +0 -28
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.0.2
@@ -2,16 +2,17 @@
2
2
  # All rights reserved.
3
3
 
4
4
  module AppOpticsAPM
5
- ##
6
- # This module implements the AppOpticsAPM tracing API.
7
- # See: https://docs.appoptics.com/kb/apm_tracing/ruby/sdk/
5
+
8
6
  module API
9
- def self.extend_with_tracing
10
- extend AppOpticsAPM::API::Logging
11
- extend AppOpticsAPM::API::Tracing
12
- extend AppOpticsAPM::API::Profiling
13
- extend AppOpticsAPM::API::LayerInit
14
- end
7
+ extend AppOpticsAPM::API::Logging
8
+ extend AppOpticsAPM::API::Metrics
9
+ extend AppOpticsAPM::API::Profiling
10
+ extend AppOpticsAPM::API::LayerInit
15
11
  extend AppOpticsAPM::API::Util
12
+
13
+ require_relative './sdk'
14
+
15
+ extend AppOpticsAPM::SDK::Tracing
16
+ extend AppOpticsAPM::API::Tracing
16
17
  end
17
18
  end
@@ -27,7 +27,7 @@ module AppOpticsAPM
27
27
  # force_trace has been deprecated and will be removed in a subsequent version.
28
28
  #
29
29
  def force_trace
30
- AppOpticsAPM.logger.warn 'AppOpticsAPM::API::LayerInit.force_trace has been deprecated and will be ' \
30
+ AppOpticsAPM.logger.warn '[appoptics_apm/api] AppOpticsAPM::API::LayerInit.force_trace has been deprecated and will be ' \
31
31
  'removed in a subsequent version.'
32
32
 
33
33
  saved_mode = AppOpticsAPM::Config[:tracing_mode]
@@ -16,7 +16,7 @@ module AppOpticsAPM
16
16
  ##
17
17
  # This modules provides the X-Trace logging facilities.
18
18
  #
19
- # These are the lower level methods, please see AppOpticsAPM::API::Tracing
19
+ # These are the lower level methods, please see AppOpticsAPM::SDK
20
20
  # for the higher level methods
21
21
  module Logging
22
22
  @@ints_or_nil = [Integer, Float, NilClass, String]
@@ -52,7 +52,7 @@ module AppOpticsAPM
52
52
  # ==== Arguments
53
53
  #
54
54
  # * +layer+ - The layer the reported event belongs to
55
- # * +exn+ - The exception to report
55
+ # * +exception+ - The exception to report
56
56
  # * +opts+ - Custom params if you want to log extra information
57
57
  #
58
58
  # ==== Example
@@ -65,19 +65,19 @@ module AppOpticsAPM
65
65
  # end
66
66
  #
67
67
  # Returns nothing.
68
- def log_exception(layer, exn, opts = {})
69
- return AppOpticsAPM::Context.toString if !AppOpticsAPM.tracing? || exn.instance_variable_get(:@oboe_logged)
68
+ def log_exception(layer, exception, opts = {})
69
+ return AppOpticsAPM::Context.toString if !AppOpticsAPM.tracing? || exception.instance_variable_get(:@exn_logged)
70
70
 
71
- unless exn
71
+ unless exception
72
72
  AppOpticsAPM.logger.debug '[appoptics_apm/debug] log_exception called with nil exception'
73
73
  return AppOpticsAPM::Context.toString
74
74
  end
75
75
 
76
- opts.merge!(:ErrorClass => exn.class.name,
77
- :ErrorMsg => exn.message,
78
- :Backtrace => exn.backtrace.join("\r\n")) if exn.backtrace
76
+ opts.merge!(:ErrorClass => exception.class.name,
77
+ :ErrorMsg => exception.message,
78
+ :Backtrace => exception.backtrace.join("\r\n")) if exception.backtrace
79
79
 
80
- exn.instance_variable_set(:@oboe_logged, true)
80
+ exception.instance_variable_set(:@exn_logged, true)
81
81
  log(layer, :error, opts)
82
82
  end
83
83
 
@@ -125,7 +125,7 @@ module AppOpticsAPM
125
125
  # end
126
126
  #++
127
127
 
128
- if AppOpticsAPM.sample?(opts.merge(:layer => layer, :xtrace => xtrace))
128
+ if AppOpticsAPM.sample?(opts.merge(:xtrace => xtrace))
129
129
  # Yes, we're sampling this request
130
130
  # Probablistic tracing of a subset of requests based off of
131
131
  # sample rate and sample source
@@ -179,13 +179,18 @@ module AppOpticsAPM
179
179
  # AppOpticsAPM::API.log_end(:layer_name, { :id => @user.id })
180
180
  #
181
181
  # Returns an xtrace metadata string if we are tracing
182
- def log_end(layer, opts = {})
182
+ def log_end(layer, opts = {}, event = nil)
183
183
  return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
184
184
 
185
- log_event(layer, :exit, AppOpticsAPM::Context.createEvent, opts)
185
+ # Deal with the transaction name
186
+ opts[:TransactionName] = determine_transaction_name(layer, opts)
187
+
188
+ event ||= AppOpticsAPM::Context.createEvent
189
+ log_event(layer, :exit, event, opts)
186
190
  ensure
187
191
  # FIXME has_incoming_context commented out, it has importance for JRuby only but breaks Ruby tests
188
192
  AppOpticsAPM::Context.clear # unless AppOpticsAPM.has_incoming_context?
193
+ AppOpticsAPM.transaction_name = nil
189
194
  end
190
195
 
191
196
  ##
@@ -301,6 +306,25 @@ module AppOpticsAPM
301
306
  AppOpticsAPM::Context.toString
302
307
  end
303
308
 
309
+ ##
310
+ # Determine the transaction name to be set on the trace
311
+ #
312
+ # A transaction name set via the opts key `:TransactionName` takes precedence
313
+ # over a currently set custom transaction name. if neither are provided it
314
+ # returns `"custom_#{span}"`
315
+ #
316
+ # === Argument:
317
+ # * +opts+ (hash) the value of :TransactionName will be set as custom transaction name
318
+ #
319
+ # === Returns:
320
+ # (string) the current transaction name
321
+ #
322
+ def determine_transaction_name(span, opts = {})
323
+ opts[:TransactionName] ||= opts.delete('TransactionName')
324
+ AppOpticsAPM::API.set_transaction_name(opts[:TransactionName])
325
+ AppOpticsAPM.transaction_name || "custom-#{span}"
326
+ end
327
+
304
328
  private
305
329
 
306
330
  ##
@@ -347,8 +371,8 @@ module AppOpticsAPM
347
371
  begin
348
372
  event.addInfo(k.to_s, value)
349
373
  rescue ArgumentError => e
350
- AppOpticsAPM.logger.debug "[AppOpticsAPM/debug] Couldn't add event KV: #{k} => #{v.class}"
351
- AppOpticsAPM.logger.debug "[AppOpticsAPM/debug] #{e.message}"
374
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Couldn't add event KV: #{k} => #{v.class}"
375
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{e.message}"
352
376
  end
353
377
  end if !opts.nil? && opts.any?
354
378
 
@@ -356,6 +380,9 @@ module AppOpticsAPM
356
380
  AppOpticsAPM::Context.toString
357
381
  end
358
382
 
383
+ # need to set the context to public, otherwise the following `extends` will be private in api.rb
384
+ public
385
+
359
386
  end
360
387
  end
361
388
  end
@@ -0,0 +1,34 @@
1
+ module AppOpticsAPM
2
+ module API
3
+ module Metrics
4
+
5
+ ##
6
+ # Internal: method to send duration for a transaction
7
+ # it checks if it can send metrics with the current transaction name
8
+ # or a default transaction name and sets the transaction name accordingly
9
+ #
10
+ # === Arguments
11
+ #
12
+ # * +span+ the name of the current span (used to construct a transaction name if none is defined)
13
+ # * +kvs+ A hash containing key/value pairs, only the value of :TransactionName will be relevant
14
+ #
15
+ # Returns the result of the block.
16
+ #
17
+
18
+ def send_metrics(span, kvs = {})
19
+ # This is a new span, we do not know the transaction name yet
20
+ AppOpticsAPM.transaction_name = nil
21
+
22
+ # if a transaction name is provided it will take precedence over transaction names defined
23
+ # later or in lower spans
24
+ start = Time.now
25
+
26
+ yield
27
+ ensure
28
+ duration =(1000 * 1000 * (Time.now - start)).round(0)
29
+ transaction_name = AppOpticsAPM::API.determine_transaction_name(span, kvs)
30
+ kvs[:TransactionName] = AppOpticsAPM::API.set_transaction_name(AppOpticsAPM::Span.createSpan(transaction_name, nil, duration))
31
+ end
32
+ end
33
+ end
34
+ end
@@ -198,6 +198,11 @@ module AppOpticsAPM
198
198
  # Merge in any extra_kvs requested
199
199
  report_kvs.merge!(extra_kvs)
200
200
  end
201
+
202
+
203
+ # need to set the context to public, otherwise the following `extends` will be private in api.rb
204
+ public
205
+
201
206
  end
202
207
  end
203
208
  end
@@ -6,77 +6,29 @@
6
6
  module AppOpticsAPM
7
7
  module API
8
8
  ##
9
- # Provides the higher-level tracing interface for the API.
9
+ # Provides the higher-level tracing interface for the API
10
10
  #
11
- # Traces are best created with a <tt>AppOpticsAPM:API.start_trace</tt> block and
12
- # <tt>AppOpticsAPM:API.trace</tt> blocks around calls to be traced.
13
- # These two methods guarantee proper nesting of tracing and handling of the tracing context.
11
+ # The tracing methods have been moved to AppOpticsAPM::SDK and AppOpticsAPM::API extends all methods from the SDK
12
+ # except for start_trace.
13
+ # AppOpticsAPM::API.start_trace is kept for backwards compatibility because it returns an array
14
+ # whereas AppOpticsAPM::SDK.start_trace will only return the result of the block.
14
15
  #
15
- # Some optional keys that can be used in the +opts+ hash:
16
- # * +:TransactionName+ - this will show up in the transactions column in the traces dashboard
17
- # * +:Controller+ - if present will be combined with +Action+ and show up as transaction in the traces dashboard
18
- # * +:Action+ - if present will be combined with +Controller+ and show up as transaction in the traces dashboard
19
- # * +:HTTP-Host+ - domain portion of URL
20
- # * +:URL+ - request URI
21
- # * +:Method+
22
- #
23
- # TODO complete the above
24
- #
25
- # Invalid keys: +:Label+, +:Layer+, +:Edge+, +:Timestamp+, +:Timestamp_u+
26
- #
27
- module Tracing
28
- # Public: Trace a given block of code. Detect any exceptions thrown by
29
- # the block and report errors.
30
- #
31
- # * +:layer+ - The layer the block of code belongs to.
32
- # * +:opts+ - A hash containing key/value pairs that will be reported along
33
- # with the first event of this layer (optional).
34
- # * +:protect_op+ - The operation being traced. Used to avoid
35
- # double tracing operations that call each other
36
- #
37
- # Example
38
- #
39
- # def computation(n)
40
- # fib(n)
41
- # raise Exception.new
42
- # end
43
- #
44
- # def computation_with_oboe(n)
45
- # trace('fib', { :number => n }, :fib) do
46
- # computation(n)
47
- # end
48
- # end
49
- #
50
- # result = computation_with_oboe(1000)
51
- #
52
- # Returns the result of the block.
53
- def trace(layer, opts = {}, protect_op = nil)
54
- return if !AppOpticsAPM.loaded || (protect_op && AppOpticsAPM.layer_op == protect_op.to_sym)
55
16
 
56
- log_entry(layer, opts, protect_op)
57
- begin
58
- yield
59
- rescue Exception => e
60
- log_exception(layer, e)
61
- raise
62
- ensure
63
- log_exit(layer, opts, protect_op)
64
- end
65
- end
17
+ module Tracing
66
18
 
67
- # Public: Trace a given block of code which can start a trace depending
68
- # on configuration and probability. Detect any exceptions thrown by the
69
- # block and report errors.
19
+ # Public: Collect metrics and start tracing a given block of code. A
20
+ # trace will be started depending on configuration and probability.
21
+ # Detect any exceptions thrown by the block and report errors.
70
22
  #
71
- # When start_trace returns control to the calling context, the oboe
72
- # context will be cleared.
23
+ # When start_trace returns control to the calling context, the trace will be
24
+ # completed and the tracing context will be cleared.
73
25
  #
74
26
  # ==== Arguments
75
27
  #
76
- # * +layer+ - name for the layer to be used as label in the trace view
28
+ # * +span+ - name for the span to be used as label in the trace view
77
29
  # * +xtrace+ - (optional) incoming X-Trace identifier to be continued
78
30
  # * +opts+ - (optional) hash containing key/value pairs that will be reported along
79
- # with the first event of this layer (optional)
31
+ # with the first event of this span
80
32
  #
81
33
  # ==== Example
82
34
  #
@@ -85,106 +37,39 @@ module AppOpticsAPM
85
37
  # end
86
38
  #
87
39
  # def handle_request_with_appoptics(request, response)
88
- # result, xtrace = start_trace('rails', request['X-Trace']) do
40
+ # start_trace('custom_span', nil, :TransactionName => 'handle_request') do
89
41
  # handle_request(request, response)
90
42
  # end
91
- # result
92
- # rescue Exception => e
93
- # xtrace = e.xtrace
94
- # ensure
95
- # response['X-trace'] = xtrace
96
43
  # end
97
44
  #
98
- # Returns a list of length two, the first element of which is the result
99
- # of the block, and the second element of which is the oboe context that
100
- # was set when the block completed execution.
101
- def start_trace(layer, xtrace = nil, opts = {})
45
+ # Returns an array with the result of the block and the last xtrace used
46
+ def start_trace(span, xtrace = nil, opts = {})
102
47
  return [yield, nil] unless AppOpticsAPM.loaded
103
48
 
104
- log_start(layer, xtrace, opts)
105
- begin
106
- result = yield
107
- rescue Exception => e
108
- log_exception(layer, e)
109
- e.instance_variable_set(:@xtrace, log_end(layer))
110
- raise
111
- end
112
- xtrace = log_end(layer)
113
-
114
- [result, xtrace]
115
- end
49
+ # if it is not an entry span!
50
+ return [trace(span, opts) { yield }, AppopticsAPM::Context.toString] if AppOpticsAPM::Context.isValid
116
51
 
117
- # Public: Trace a given block of code which can start a trace depending
118
- # on configuration and probability. Detect any exceptions thrown by the
119
- # block and report errors. Assign an X-Trace to the target.
120
- #
121
- # The motivating use case for this is HTTP streaming in rails3. We need
122
- # access to the exit event's trace id so we can set the header before any
123
- # work is done, and before any headers are sent back to the client.
124
- #
125
- # ===== Arguments
126
- # * +layer+ - The layer the block of code belongs to.
127
- # * +xtrace+ - string - The X-Trace to continue by the target
128
- # * +target+ - has to respond to #[]=, The target object in which to place the trace information
129
- # * +opts+ - A hash containing key/value pairs that will be reported along
130
- # with the first event of this layer (optional).
131
- #
132
- # ==== Example
133
- #
134
- # def handle_request(request, response)
135
- # # ... code that does something with request and response ...
136
- # end
137
- #
138
- # def handle_request_with_appoptics(request, response)
139
- # start_trace_with_target('rails', request['X-Trace'], response) do
140
- # handle_request(request, response)
141
- # end
142
- # end
143
- #
144
- # Returns the result of the block.
145
- def start_trace_with_target(layer, xtrace, target, opts = {})
146
- return yield unless AppOpticsAPM.loaded
52
+ log_start(span, xtrace, opts)
147
53
 
148
- log_start(layer, xtrace, opts)
149
- exit_evt = AppOpticsAPM::Context.createEvent
150
- begin
151
- target['X-Trace'] = AppOpticsAPM::EventUtil.metadataString(exit_evt) if AppOpticsAPM.tracing?
152
- yield
153
- rescue Exception => e
154
- log_exception(layer, e)
155
- raise
156
- ensure
157
- exit_evt.addEdge(AppOpticsAPM::Context.get)
158
- log(layer, :exit, {}, exit_evt)
159
- AppOpticsAPM::Context.clear
54
+ # send_metrics deals with the logic for setting AppOpticsAPM.transaction_name
55
+ # and ensures that metrics are sent
56
+ # log_end sets the transaction_name
57
+ result = send_metrics(span, opts) do
58
+ begin
59
+ yield
60
+ rescue Exception => e # rescue everything ok, since we are raising
61
+ AppOpticsAPM::API.log_exception(span, e)
62
+ e.instance_variable_set(:@xtrace, log_end(span))
63
+ raise
64
+ end
160
65
  end
161
- end
66
+ xtrace = AppopticsAPM::Context.toString
67
+ log_end(span, opts)
162
68
 
163
- # Public: Set a ThreadLocal custom transaction name to be used when sending a trace or metrics for the
164
- # current transaction
165
- #
166
- # In addition to setting a transaction name here there is also a configuration
167
- # AppOpticsAPM::Config['transaction_name']['prepend_domain'] which allows to have the domain prepended
168
- # to the transaction name
169
- #
170
- # ===== Arguments
171
- # * +name+ - A non-empty string with the custom transaction name
172
- #
173
- def set_transaction_name(name)
174
- if name.is_a?(String) && name.strip != ''
175
- AppOpticsAPM.transaction_name = name
176
- else
177
- AppOpticsAPM.logger.debug "[appoptics_apm/api] Could not set transaction name, provided name is empty or not a String."
178
- end
179
- AppOpticsAPM.transaction_name
69
+ [result, xtrace]
180
70
  end
181
71
 
182
72
 
183
- # this is provided for testing
184
- # returns the current transaction name
185
- def get_transaction_name
186
- AppOpticsAPM.transaction_name
187
- end
188
73
  end
189
74
  end
190
75
  end
@@ -42,16 +42,10 @@ module AppOpticsAPM
42
42
  #
43
43
  # Returns a trimmed backtrace
44
44
  def trim_backtrace(backtrace)
45
- return backtrace unless backtrace.is_a?(Array)
45
+ return backtrace unless backtrace.is_a?(Array) && backtrace.size > BACKTRACE_CUTOFF
46
46
 
47
- length = backtrace.size
48
- if length > BACKTRACE_CUTOFF
49
- # Trim backtraces by getting the first 180 and last 20 lines
50
- trimmed = backtrace[0, 180] + ['...[snip]...'] + backtrace[length - 20, 20]
51
- else
52
- trimmed = backtrace
53
- end
54
- trimmed
47
+ # Trim backtraces by getting the first 180 and last 20 lines
48
+ backtrace[0, 180] + ['...[snip]...'] + backtrace[length - 20, 20]
55
49
  end
56
50
 
57
51
  # Internal: Check if a host is blacklisted from tracing
@@ -2,25 +2,24 @@
2
2
  # All rights reserved.
3
3
 
4
4
  # Constants from liboboe
5
- OBOE_TRACE_NEVER = 0
6
- OBOE_TRACE_ALWAYS = 1
7
- OBOE_TRACE_THROUGH = 2
5
+ APPOPTICS_TRACE_NEVER = 0
6
+ APPOPTICS_TRACE_ALWAYS = 1
8
7
 
9
- OBOE_SAMPLE_RATE_SOURCE_FILE = 1
10
- OBOE_SAMPLE_RATE_SOURCE_DEFAULT = 2
11
- OBOE_SAMPLE_RATE_SOURCE_OBOE = 3
12
- OBOE_SAMPLE_RATE_SOURCE_LAST_OBOE = 4
13
- OBOE_SAMPLE_RATE_SOURCE_DEFAULT_MISCONFIGURED = 5
14
- OBOE_SAMPLE_RATE_SOURCE_OBOE_DEFAULT = 6
8
+ # OBOE_SAMPLE_RATE_SOURCE_FILE = 1
9
+ # OBOE_SAMPLE_RATE_SOURCE_DEFAULT = 2
10
+ # OBOE_SAMPLE_RATE_SOURCE_OBOE = 3
11
+ # OBOE_SAMPLE_RATE_SOURCE_LAST_OBOE = 4
12
+ # OBOE_SAMPLE_RATE_SOURCE_DEFAULT_MISCONFIGURED = 5
13
+ # OBOE_SAMPLE_RATE_SOURCE_OBOE_DEFAULT = 6
15
14
 
16
15
  # Masks for bitwise ops
17
- ZERO_MASK = 0b0000000000000000000000000000
16
+ # ZERO_MASK = 0b0000000000000000000000000000
18
17
 
19
18
  SAMPLE_RATE_MASK = 0b0000111111111111111111111111
20
19
  SAMPLE_SOURCE_MASK = 0b1111000000000000000000000000
21
20
 
22
- ZERO_SAMPLE_RATE_MASK = 0b1111000000000000000000000000
23
- ZERO_SAMPLE_SOURCE_MASK = 0b0000111111111111111111111111
21
+ # ZERO_SAMPLE_RATE_MASK = 0b1111000000000000000000000000
22
+ # ZERO_SAMPLE_SOURCE_MASK = 0b0000111111111111111111111111
24
23
 
25
24
  APPOPTICS_STR_BLANK = ''.freeze
26
25
  APPOPTICS_STR_LAYER = 'Layer'.freeze