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.
@@ -26,6 +26,26 @@ if AppOpticsAPM.loaded
26
26
  @app = app
27
27
  end
28
28
 
29
+ def call(env)
30
+ # In the case of nested Ruby apps such as Grape inside of Rails
31
+ # or Grape inside of Grape, each app has it's own instance
32
+ # of rack middleware. We avoid tracing rack more than once and
33
+ # instead start instrumenting from the first rack pass.
34
+ return call_app(env) if AppOpticsAPM.tracing? && AppOpticsAPM.layer == :rack
35
+
36
+ # if we already have a context, we don't want to send metrics in the end
37
+ return sampling_call(env) if AppOpticsAPM::Context.isValid
38
+
39
+ # else we also send metrics
40
+ metrics_sampling_call(env)
41
+ end
42
+
43
+ def self.noop?
44
+ false
45
+ end
46
+
47
+ private
48
+
29
49
  def collect(req, env)
30
50
  report_kvs = {}
31
51
 
@@ -61,92 +81,105 @@ if AppOpticsAPM.loaded
61
81
  report_kvs
62
82
  end
63
83
 
64
- def call(env)
65
- start = Time.now
66
- status = 500
67
- req = ::Rack::Request.new(env)
68
- req_url = req.url # saving it here because rails3.2 overrides it when there is a 500 error
69
-
70
- # In the case of nested Ruby apps such as Grape inside of Rails
71
- # or Grape inside of Grape, each app has it's own instance
72
- # of rack middleware. We avoid tracing rack more than once and
73
- # instead start instrumenting from the first rack pass.
74
- if AppOpticsAPM.tracing? && AppOpticsAPM.layer == :rack
75
- AppOpticsAPM.logger.debug "[appoptics_apm/rack] Rack skipped!"
76
- return @app.call(env)
77
- end
78
-
79
- begin
80
- report_kvs = {}
84
+ def call_app(env)
85
+ AppOpticsAPM.logger.debug "[appoptics_apm/rack] Rack skipped!"
86
+ @app.call(env)
87
+ end
81
88
 
82
- report_kvs[:URL] = AppOpticsAPM::Config[:rack][:log_args] ? ::CGI.unescape(req.fullpath) : ::CGI.unescape(req.path)
89
+ # in this case we have an existing context
90
+ def sampling_call(env)
91
+ req = ::Rack::Request.new(env)
92
+ report_kvs = {}
93
+ report_kvs[:URL] = AppOpticsAPM::Config[:rack][:log_args] ? ::CGI.unescape(req.fullpath) : ::CGI.unescape(req.path)
83
94
 
84
- # Check for and validate X-Trace request header to pick up tracing context
85
- xtrace = env.is_a?(Hash) ? env['HTTP_X_TRACE'] : nil
86
- xtrace_header = AppOpticsAPM::XTrace.valid?(xtrace) ? xtrace : nil
95
+ AppOpticsAPM::API.trace(:rack, report_kvs) do
96
+ report_kvs = collect(req, env)
87
97
 
88
- # Under JRuby, JAppOpticsAPM may have already started a trace. Make note of this
89
- # if so and don't clear context on log_end (see appoptics_apm/api/logging.rb)
90
- AppOpticsAPM.has_incoming_context = AppOpticsAPM.tracing?
91
- AppOpticsAPM.has_xtrace_header = xtrace_header
92
- AppOpticsAPM.is_continued_trace = AppOpticsAPM.has_incoming_context || AppOpticsAPM.has_xtrace_header
98
+ # We log an info event with the HTTP KVs found in AppOpticsAPM::Rack.collect
99
+ # This is done here so in the case of stacks that try/catch/abort
100
+ # (looking at you Grape) we're sure the KVs get reported now as
101
+ # this code may not be returned to later.
102
+ AppOpticsAPM::API.log_info(:rack, report_kvs)
103
+ @app.call(env)
104
+ end
105
+ end
93
106
 
94
- xtrace = AppOpticsAPM::API.log_start(:rack, xtrace_header, report_kvs)
107
+ def metrics_sampling_call(env)
108
+ start = Time.now
109
+ AppOpticsAPM.transaction_name = nil
110
+ req = ::Rack::Request.new(env)
111
+ req_url = req.url # saving it here because rails3.2 overrides it when there is a 500 error
95
112
 
96
- # We only trace a subset of requests based off of sample rate so if
97
- # AppOpticsAPM::API.log_start really did start a trace, we act accordingly here.
98
- if AppOpticsAPM.tracing?
99
- report_kvs = collect(req, env)
113
+ report_kvs = {}
114
+ report_kvs[:URL] = AppOpticsAPM::Config[:rack][:log_args] ? ::CGI.unescape(req.fullpath) : ::CGI.unescape(req.path)
115
+
116
+ # Check for and validate X-Trace request header to pick up tracing context
117
+ xtrace = env.is_a?(Hash) ? env['HTTP_X_TRACE'] : nil
118
+ xtrace = AppOpticsAPM::XTrace.valid?(xtrace) ? xtrace : nil
119
+
120
+ # TODO JRUBY
121
+ # Under JRuby, JAppOpticsAPM may have already started a trace. Make note of this
122
+ # if so and don't clear context on log_end (see appoptics_apm/api/logging.rb)
123
+ # AppOpticsAPM.has_incoming_context = AppOpticsAPM.tracing?
124
+ # AppOpticsAPM.has_xtrace_header = xtrace
125
+ # AppOpticsAPM.is_continued_trace = AppOpticsAPM.has_incoming_context || AppOpticsAPM.has_xtrace_header
126
+
127
+ AppOpticsAPM::API.log_start(:rack, xtrace, report_kvs) unless ::AppOpticsAPM::Util.static_asset?(env['PATH_INFO'])
128
+
129
+ # We log an info event with the HTTP KVs found in AppOpticsAPM::Rack.collect
130
+ # This is done here so in the case of stacks that try/catch/abort
131
+ # (looking at you Grape) we're sure the KVs get reported now as
132
+ # this code may not be returned to later.
133
+ AppOpticsAPM::API.log_info(:rack, collect(req, env))
134
+
135
+ status, headers, response = @app.call(env)
136
+ confirmed_transaction_name = send_metrics(env, req, req_url, start, status)
137
+ xtrace = AppOpticsAPM::API.log_end(:rack, :Status => status, :TransactionName => confirmed_transaction_name)
138
+
139
+ if headers && AppOpticsAPM::XTrace.valid?(xtrace)
140
+ # TODO revisit this JRUBY condition
141
+ # headers['X-Trace'] = xtrace if headers.is_a?(Hash) unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
142
+ headers['X-Trace'] = xtrace if headers.is_a?(Hash) unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
143
+ end
100
144
 
101
- # We log an info event with the HTTP KVs found in AppOpticsAPM::Rack.collect
102
- # This is done here so in the case of stacks that try/catch/abort
103
- # (looking at you Grape) we're sure the KVs get reported now as
104
- # this code may not be returned to later.
105
- AppOpticsAPM::API.log_info(:rack, report_kvs)
145
+ [status, headers, response]
146
+ rescue Exception => e
147
+ # it is ok to rescue Exception here because we are reraising it (we just need a chance to log_end)
148
+ AppOpticsAPM::API.log_exception(:rack, e)
149
+ confirmed_transaction_name ||= send_metrics(env, req, req_url, start, status)
150
+ xtrace = AppOpticsAPM::API.log_end(:rack, :Status => status, :TransactionName => confirmed_transaction_name)
151
+
152
+ if headers && AppOpticsAPM::XTrace.valid?(xtrace)
153
+ # TODO revisit this JRUBY condition
154
+ # headers['X-Trace'] = xtrace if headers.is_a?(Hash) unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
155
+ headers['X-Trace'] = xtrace if headers.is_a?(Hash) unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
156
+ end
106
157
 
107
- status, headers, response = @app.call(env)
158
+ raise
159
+ end
108
160
 
109
- xtrace = AppOpticsAPM::API.log_end(:rack, :Status => status)
110
161
 
111
- else
112
- status, headers, response = @app.call(env)
113
- end
162
+ def send_metrics(env, req, req_url, start, status)
163
+ return if ::AppOpticsAPM::Util.static_asset?(env['PATH_INFO'])
114
164
 
115
- [status, headers, response]
116
- rescue Exception => e
117
- # it is ok to rescue Exception here because we are reraising it (we just need a chance to log_end)
118
- if AppOpticsAPM.tracing?
119
- AppOpticsAPM::API.log_exception(:rack, e)
120
- xtrace = AppOpticsAPM::API.log_end(:rack, :Status => 500, 'TransactionName' => transaction_name(env))
121
- end
122
- raise
123
- ensure
124
- if headers && AppOpticsAPM::XTrace.valid?(xtrace)
125
- unless defined?(JRUBY_VERSION) && AppOpticsAPM.is_continued_trace?
126
- headers['X-Trace'] = xtrace if headers.is_a?(Hash)
127
- end
128
- end
129
- end
130
- ensure
131
- unless ::AppOpticsAPM::Util.static_asset?(env['PATH_INFO'])
132
- status = status.to_i
133
- error = status.between?(500,599) ? 1 : 0
134
- duration =(1000 * 1000 * (Time.now - start)).round(0)
135
- AppOpticsAPM::Span.createHttpSpan(transaction_name(env), req_url, duration, status, req.request_method, error)
165
+ domain = nil
166
+ if AppOpticsAPM::Config['transaction_name']['prepend_domain']
167
+ domain = [80, 443].include?(req.port) ? req.host : "#{req.host}:#{req.port}"
136
168
  end
169
+ status = status.to_i
170
+ error = status.between?(500,599) ? 1 : 0
171
+ duration =(1000 * 1000 * (Time.now - start)).round(0)
172
+ AppOpticsAPM::Span.createHttpSpan(transaction_name(env), req_url, domain, duration, status, req.request_method, error) || ''
137
173
  end
138
174
 
139
- def self.noop?
140
- false
141
- end
142
-
143
- private
144
-
145
175
  def transaction_name(env)
146
- if env['appoptics_apm.controller'] || env['appoptics_apm.action']
176
+ if AppOpticsAPM.transaction_name
177
+ AppOpticsAPM.transaction_name
178
+ elsif env['appoptics_apm.controller'] || env['appoptics_apm.action']
147
179
  [env['appoptics_apm.controller'], env['appoptics_apm.action']].join('.')
148
180
  end
149
181
  end
182
+
150
183
  end
151
184
  end
152
185
  else
@@ -0,0 +1,9 @@
1
+ Here we can define modules and classes for noop mode.
2
+
3
+ Instead of polluting code with AppOpticsAPM.loaded conditionals
4
+
5
+ we load these classes when in noop mode and they expose noop behavior.
6
+
7
+ so far only one class is needed:
8
+
9
+ - AppOpticsAPM::Context and its toString() method from oboe
@@ -0,0 +1,19 @@
1
+ ####
2
+ # noop version of AppOpticsAPM::Context
3
+ #
4
+ #
5
+
6
+ module AppOpticsAPM
7
+ module Context
8
+
9
+ ##
10
+ # noop version of toString
11
+ # toString would return the current context (xtrace) as string
12
+ #
13
+ # the noop version returns an empty string
14
+ #
15
+ def self.toString
16
+ ''
17
+ end
18
+ end
19
+ end
@@ -81,28 +81,27 @@ module AppOpticsAPM
81
81
  AppOpticsAPM.logger.warn 'No ActiveRecord'
82
82
  end
83
83
 
84
- AppOpticsAPM.logger.warn '********************************************************'
85
- AppOpticsAPM.logger.warn '* AppOpticsAPM Libraries'
86
- AppOpticsAPM.logger.warn '********************************************************'
87
- files = []
88
- ['/usr/lib/liboboe*', '/usr/lib64/liboboe*'].each do |d|
89
- files = Dir.glob(d)
90
- break if !files.empty?
91
- end
92
- if files.empty?
93
- AppOpticsAPM.logger.warn 'Error: No liboboe libs!'
94
- else
95
- files.each { |f|
96
- AppOpticsAPM.logger.warn f
97
- }
98
- end
84
+ # TODO we don't have libs in /usr/lib anymore, is this still needed???
85
+ # AppOpticsAPM.logger.warn '********************************************************'
86
+ # AppOpticsAPM.logger.warn '* AppOpticsAPM Libraries'
87
+ # AppOpticsAPM.logger.warn '********************************************************'
88
+ # files = []
89
+ # ['/usr/lib/liboboe*', '/usr/lib64/liboboe*'].each do |d|
90
+ # files = Dir.glob(d)
91
+ # break if !files.empty?
92
+ # end
93
+ # if files.empty?
94
+ # AppOpticsAPM.logger.warn 'Error: No liboboe libs!'
95
+ # else
96
+ # files.each { |f|
97
+ # AppOpticsAPM.logger.warn f
98
+ # }
99
+ # end
99
100
 
100
101
  AppOpticsAPM.logger.warn '********************************************************'
101
102
  AppOpticsAPM.logger.warn '* AppOpticsAPM::Config Values'
102
103
  AppOpticsAPM.logger.warn '********************************************************'
103
- AppOpticsAPM::Config.config.each { |k,v|
104
- AppOpticsAPM.logger.warn "#{k}: #{v}"
105
- }
104
+ AppOpticsAPM::Config.print_config
106
105
 
107
106
  AppOpticsAPM.logger.warn '********************************************************'
108
107
  AppOpticsAPM.logger.warn '* OS, Platform + Env'
@@ -7,8 +7,8 @@ module AppOpticsAPM
7
7
  # appoptics_apm.gemspec during gem build process
8
8
  module Version
9
9
  MAJOR = 4
10
- MINOR = 1
11
- PATCH = 2
10
+ MINOR = 2
11
+ PATCH = 0
12
12
 
13
13
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
14
14
  end
@@ -21,7 +21,15 @@ if defined?(AppOpticsAPM::Config)
21
21
  # Verbose output of instrumentation initialization
22
22
  #
23
23
  AppOpticsAPM::Config[:verbose] = ENV.key?('APPOPTICS_GEM_VERBOSE') && ENV['APPOPTICS_GEM_VERBOSE'] == 'true' ? true : false
24
+
25
+ #
26
+ # Prepend domain to transaction name
27
+ #
28
+ # If this is set to `true` transaction names will be composed as `my.host.com/controller.action` instead of
29
+ # `controller.action`. This configuration applies to all transaction names, whether decducted by the instrumentation
30
+ # or implicitly set.
24
31
  #
32
+ AppOpticsAPM::Config[:transaction_name][:prepend_domain] = false
25
33
 
26
34
  #
27
35
  # Sanitize SQL Statements
data/run_tests_docker.rb CHANGED
@@ -7,10 +7,6 @@
7
7
 
8
8
  # `docker build -f Dockerfile -t ruby_appoptics .`
9
9
  # (docker-compose will build it too if missing)
10
- #
11
- # `docker-compose up -d`
12
- # or to rebuild ruby_appoptics
13
- # `docker-compose up --build -d`
14
10
 
15
11
  require 'yaml'
16
12
  travis = YAML.load_file('.travis.yml')
@@ -34,5 +30,3 @@ matrix.each do |args|
34
30
  `docker-compose run --rm --service-ports ruby_appoptics_apm /code/ruby-appoptics_apm/ruby_setup.sh #{args['rvm']} #{args['gemfile']} #{args['env']}`
35
31
  puts "docker-compose run --rm --service-ports ruby_appoptics_apm /code/ruby-appoptics_apm/ruby_setup.sh #{args['rvm']} #{args['gemfile']} #{args['env']}"
36
32
  end
37
-
38
- # `docker-compose down --rmi all`
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appoptics_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maia Engeli
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-05-09 00:00:00.000000000 Z
13
+ date: 2018-05-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -133,6 +133,14 @@ files:
133
133
  - build_gems.sh
134
134
  - config/initializers/.keep
135
135
  - docker-compose.yml
136
+ - examples/DNT.md
137
+ - examples/carrying_context.rb
138
+ - examples/instrumenting_metal_controller.rb
139
+ - examples/puma_on_heroku_config.rb
140
+ - examples/tracing_async_threads.rb
141
+ - examples/tracing_background_jobs.rb
142
+ - examples/tracing_forked_processes.rb
143
+ - examples/unicorn_on_heroku_config.rb
136
144
  - ext/oboe_metal/extconf.rb
137
145
  - ext/oboe_metal/lib/.keep
138
146
  - ext/oboe_metal/noop/noop.c
@@ -204,6 +212,8 @@ files:
204
212
  - lib/appoptics_apm/loading.rb
205
213
  - lib/appoptics_apm/logger.rb
206
214
  - lib/appoptics_apm/method_profiling.rb
215
+ - lib/appoptics_apm/noop/README.md
216
+ - lib/appoptics_apm/noop/context.rb
207
217
  - lib/appoptics_apm/ruby.rb
208
218
  - lib/appoptics_apm/support.rb
209
219
  - lib/appoptics_apm/test.rb