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 +4 -4
- data/.travis.yml +8 -6
- data/Dockerfile_test +4 -2
- data/Rakefile +15 -4
- data/appoptics_apm.gemspec +3 -1
- data/examples/DNT.md +35 -0
- data/examples/carrying_context.rb +220 -0
- data/examples/instrumenting_metal_controller.rb +8 -0
- data/examples/puma_on_heroku_config.rb +17 -0
- data/examples/tracing_async_threads.rb +124 -0
- data/examples/tracing_background_jobs.rb +53 -0
- data/examples/tracing_forked_processes.rb +99 -0
- data/examples/unicorn_on_heroku_config.rb +28 -0
- data/ext/oboe_metal/src/VERSION +1 -1
- data/lib/appoptics_apm.rb +2 -0
- data/lib/appoptics_apm/api/logging.rb +13 -12
- data/lib/appoptics_apm/api/tracing.rb +28 -1
- data/lib/appoptics_apm/base.rb +7 -1
- data/lib/appoptics_apm/config.rb +15 -13
- data/lib/appoptics_apm/frameworks/grape.rb +7 -6
- data/lib/appoptics_apm/inst/rack.rb +102 -69
- data/lib/appoptics_apm/noop/README.md +9 -0
- data/lib/appoptics_apm/noop/context.rb +19 -0
- data/lib/appoptics_apm/support.rb +17 -18
- data/lib/appoptics_apm/version.rb +2 -2
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +8 -0
- data/run_tests_docker.rb +0 -6
- metadata +12 -2
@@ -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
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
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
|
-
|
85
|
-
|
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
|
-
#
|
89
|
-
#
|
90
|
-
|
91
|
-
|
92
|
-
AppOpticsAPM.
|
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
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
158
|
+
raise
|
159
|
+
end
|
108
160
|
|
109
|
-
xtrace = AppOpticsAPM::API.log_end(:rack, :Status => status)
|
110
161
|
|
111
|
-
|
112
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
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
|
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
|
-
|
85
|
-
AppOpticsAPM.logger.warn '
|
86
|
-
AppOpticsAPM.logger.warn '
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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.
|
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'
|
@@ -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.
|
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-
|
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
|