elastic-apm 0.4.5 → 0.5.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.
Potentially problematic release.
This version of elastic-apm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/Gemfile +8 -0
- data/lib/elastic_apm/agent.rb +6 -7
- data/lib/elastic_apm/config.rb +28 -14
- data/lib/elastic_apm/http.rb +1 -1
- data/lib/elastic_apm/injectors.rb +1 -1
- data/lib/elastic_apm/injectors/delayed_job.rb +68 -0
- data/lib/elastic_apm/injectors/elasticsearch.rb +33 -0
- data/lib/elastic_apm/injectors/sidekiq.rb +86 -0
- data/lib/elastic_apm/instrumenter.rb +12 -4
- data/lib/elastic_apm/middleware.rb +5 -2
- data/lib/elastic_apm/railtie.rb +1 -17
- data/lib/elastic_apm/span.rb +3 -3
- data/lib/elastic_apm/transaction.rb +9 -11
- data/lib/elastic_apm/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98b3dde3453861c6e77db385bea9d0bd54c6d76dd2cb8dd253c046a4f42beb8c
|
4
|
+
data.tar.gz: a1b948919538e6e5c3eecd1db3fc6bcccff95eef8be335c7cc8913183b47f9fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d454b1c732c8acc5b2e5ce5cb1b3d5243f563cd0697ae126a104a9bd1c1be8c9b1adbdcadc50d45e9c9e6e9e31aebb6ed6dfc74e68620d859d591d4b7597e9aa
|
7
|
+
data.tar.gz: 77b6649b0b80b2a1294e1d628cee48b47db707c688766fa517ad2e360ae88ae9ff75645f8b8d9fe50a69afb17dd4f15f94e2c7320c5a5521dd9333dc3360c82d
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -6,6 +6,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
6
6
|
|
7
7
|
gemspec
|
8
8
|
|
9
|
+
gem 'elasticsearch'
|
9
10
|
gem 'fakeredis', require: nil,
|
10
11
|
github: 'guilleiguaran/fakeredis' # needs master right now
|
11
12
|
gem 'json-schema'
|
@@ -15,6 +16,7 @@ gem 'redis', require: nil
|
|
15
16
|
gem 'rspec'
|
16
17
|
gem 'rubocop'
|
17
18
|
gem 'sequel'
|
19
|
+
gem 'sidekiq'
|
18
20
|
gem 'timecop'
|
19
21
|
gem 'webmock'
|
20
22
|
gem 'yard'
|
@@ -36,3 +38,9 @@ when /.+/
|
|
36
38
|
else
|
37
39
|
gem framework
|
38
40
|
end
|
41
|
+
|
42
|
+
# doesn't work with Rails master, so skip testing
|
43
|
+
gem 'delayed_job' unless [framework, version] == %w[rails master]
|
44
|
+
|
45
|
+
gem 'rails' if framework == 'sinatra'
|
46
|
+
gem 'sinatra' if framework == 'rails'
|
data/lib/elastic_apm/agent.rb
CHANGED
@@ -23,15 +23,15 @@ module ElasticAPM
|
|
23
23
|
@instance
|
24
24
|
end
|
25
25
|
|
26
|
-
# rubocop:disable Metrics/MethodLength
|
27
|
-
def self.start(config)
|
26
|
+
def self.start(config) # rubocop:disable Metrics/MethodLength
|
28
27
|
return @instance if @instance
|
29
28
|
|
30
|
-
config = Config.new(config)
|
29
|
+
config = Config.new(config) unless config.is_a?(Config)
|
31
30
|
|
32
31
|
unless config.enabled_environments.include?(config.environment)
|
33
|
-
|
34
|
-
|
32
|
+
puts format(
|
33
|
+
'%sNot tracking anything in "%s" env',
|
34
|
+
Log::PREFIX, config.environment
|
35
35
|
)
|
36
36
|
return
|
37
37
|
end
|
@@ -39,10 +39,9 @@ module ElasticAPM
|
|
39
39
|
LOCK.synchronize do
|
40
40
|
return @instance if @instance
|
41
41
|
|
42
|
-
@instance = new(config
|
42
|
+
@instance = new(config).start
|
43
43
|
end
|
44
44
|
end
|
45
|
-
# rubocop:enable Metrics/MethodLength
|
46
45
|
|
47
46
|
def self.stop
|
48
47
|
LOCK.synchronize do
|
data/lib/elastic_apm/config.rb
CHANGED
@@ -7,6 +7,9 @@ module ElasticAPM
|
|
7
7
|
# @api private
|
8
8
|
class Config
|
9
9
|
DEFAULTS = {
|
10
|
+
config_file: 'config/elastic_apm.yml',
|
11
|
+
worker_process: false,
|
12
|
+
|
10
13
|
server_url: 'http://localhost:8200',
|
11
14
|
secret_token: nil,
|
12
15
|
|
@@ -78,16 +81,19 @@ module ElasticAPM
|
|
78
81
|
'ELASTIC_APM_TRANSACTION_MAX_SPANS' => [:int, 'transaction_max_spans']
|
79
82
|
}.freeze
|
80
83
|
|
81
|
-
def initialize(options =
|
82
|
-
options = {} if options.nil?
|
83
|
-
|
84
|
+
def initialize(options = {})
|
84
85
|
set_defaults
|
85
|
-
|
86
|
+
|
86
87
|
set_from_args(options)
|
88
|
+
set_from_config_file
|
89
|
+
set_from_env
|
87
90
|
|
88
91
|
yield self if block_given?
|
89
92
|
end
|
90
93
|
|
94
|
+
attr_accessor :config_file
|
95
|
+
attr_accessor :worker_process
|
96
|
+
|
91
97
|
attr_accessor :server_url
|
92
98
|
attr_accessor :secret_token
|
93
99
|
|
@@ -167,12 +173,16 @@ module ElasticAPM
|
|
167
173
|
|
168
174
|
private
|
169
175
|
|
170
|
-
def
|
171
|
-
|
176
|
+
def assign(options)
|
177
|
+
options.each do |key, value|
|
172
178
|
send("#{key}=", value)
|
173
179
|
end
|
174
180
|
end
|
175
181
|
|
182
|
+
def set_defaults
|
183
|
+
assign(DEFAULTS)
|
184
|
+
end
|
185
|
+
|
176
186
|
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
177
187
|
def set_from_env
|
178
188
|
ENV_TO_KEY.each do |env_key, key|
|
@@ -195,9 +205,12 @@ module ElasticAPM
|
|
195
205
|
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
196
206
|
|
197
207
|
def set_from_args(options)
|
198
|
-
options
|
199
|
-
|
200
|
-
|
208
|
+
assign(options)
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_from_config_file
|
212
|
+
return unless File.exist?(config_file)
|
213
|
+
assign(YAML.load_file(config_file) || {})
|
201
214
|
end
|
202
215
|
|
203
216
|
def set_sinatra(app)
|
@@ -208,11 +221,12 @@ module ElasticAPM
|
|
208
221
|
self.root_path = Dir.pwd
|
209
222
|
end
|
210
223
|
|
211
|
-
def set_rails(app)
|
212
|
-
self.service_name
|
213
|
-
self.framework_name
|
214
|
-
self.framework_version
|
215
|
-
self.logger
|
224
|
+
def set_rails(app) # rubocop:disable Metrics/AbcSize
|
225
|
+
self.service_name ||= format_name(service_name || app.class.parent_name)
|
226
|
+
self.framework_name ||= 'Ruby on Rails'
|
227
|
+
self.framework_version ||= Rails::VERSION::STRING
|
228
|
+
self.logger ||= Rails.logger
|
229
|
+
|
216
230
|
self.root_path = Rails.root.to_s
|
217
231
|
self.view_paths = app.config.paths['app/views'].existent
|
218
232
|
end
|
data/lib/elastic_apm/http.rb
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Injectors
|
6
|
+
# @api private
|
7
|
+
class DelayedJobInjector
|
8
|
+
CLASS_SEPARATOR = '.'.freeze
|
9
|
+
METHOD_SEPARATOR = '#'.freeze
|
10
|
+
TYPE = 'Delayed::Job'.freeze
|
11
|
+
|
12
|
+
def install
|
13
|
+
::Delayed::Backend::Base.class_eval do
|
14
|
+
alias invoke_job_without_apm invoke_job
|
15
|
+
|
16
|
+
def invoke_job(*args, &block)
|
17
|
+
::ElasticAPM::Injectors::DelayedJobInjector
|
18
|
+
.invoke_job(self, *args, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.invoke_job(job, *args, &block)
|
24
|
+
job_name = name_from_payload(job.payload_object)
|
25
|
+
transaction = ElasticAPM.transaction(job_name, TYPE)
|
26
|
+
job.invoke_job_without_apm(*args, &block)
|
27
|
+
transaction.submit 'success'
|
28
|
+
rescue ::Exception => e
|
29
|
+
ElasticAPM.report(e, handled: false)
|
30
|
+
transaction.submit 'error'
|
31
|
+
raise
|
32
|
+
ensure
|
33
|
+
transaction.release if transaction
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.name_from_payload(payload_object)
|
37
|
+
if payload_object.is_a?(::Delayed::PerformableMethod)
|
38
|
+
performable_method_name(payload_object)
|
39
|
+
else
|
40
|
+
payload_object.class.name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.performable_method_name(payload_object)
|
45
|
+
class_name = object_name(payload_object)
|
46
|
+
separator = name_separator(payload_object)
|
47
|
+
method_name = payload_object.method_name
|
48
|
+
"#{class_name}#{separator}#{method_name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.object_name(payload_object)
|
52
|
+
object = payload_object.object
|
53
|
+
klass = object.is_a?(Class) ? object : object.class
|
54
|
+
klass.name
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.name_separator(payload_object)
|
58
|
+
payload_object.object.is_a?(Class) ? CLASS_SEPARATOR : METHOD_SEPARATOR
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
register(
|
63
|
+
'Delayed::Backend::Base',
|
64
|
+
'delayed/backend/base',
|
65
|
+
DelayedJobInjector.new
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Injectors
|
6
|
+
# @api private
|
7
|
+
class ElasticsearchInjector
|
8
|
+
NAME_FORMAT = '%s %s'.freeze
|
9
|
+
TYPE = 'db.elasticsearch'.freeze
|
10
|
+
|
11
|
+
def install
|
12
|
+
::Elasticsearch::Transport::Client.class_eval do
|
13
|
+
alias perform_request_without_apm perform_request
|
14
|
+
|
15
|
+
def perform_request(method, path, *args, &block)
|
16
|
+
name = format(NAME_FORMAT, method, path)
|
17
|
+
context = Span::Context.new(statement: args[0])
|
18
|
+
|
19
|
+
ElasticAPM.span name, TYPE, context: context do
|
20
|
+
perform_request_without_apm(method, path, *args, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register(
|
28
|
+
'Elasticsearch::Transport::Client',
|
29
|
+
'elasticsearch-transport',
|
30
|
+
ElasticsearchInjector.new
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Injectors
|
6
|
+
# @api private
|
7
|
+
class SidekiqInjector
|
8
|
+
ACTIVE_JOB_WRAPPER =
|
9
|
+
'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
class Middleware
|
13
|
+
# rubocop:disable Metrics/MethodLength
|
14
|
+
def call(_worker, job, queue)
|
15
|
+
name = SidekiqInjector.name_for(job)
|
16
|
+
transaction = ElasticAPM.transaction(name, 'Sidekiq')
|
17
|
+
ElasticAPM.set_tag(:queue, queue)
|
18
|
+
|
19
|
+
yield
|
20
|
+
|
21
|
+
transaction.submit('success') if transaction
|
22
|
+
rescue ::Exception => e
|
23
|
+
ElasticAPM.report(e, handled: false)
|
24
|
+
transaction.submit(:error) if transaction
|
25
|
+
raise
|
26
|
+
ensure
|
27
|
+
transaction.release if transaction
|
28
|
+
end
|
29
|
+
# rubocop:enable Metrics/MethodLength
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.name_for(job)
|
33
|
+
klass = job['class']
|
34
|
+
|
35
|
+
case klass
|
36
|
+
when ACTIVE_JOB_WRAPPER
|
37
|
+
job['wrapped']
|
38
|
+
else
|
39
|
+
klass
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def install_middleware
|
44
|
+
Sidekiq.configure_server do |config|
|
45
|
+
config.server_middleware do |chain|
|
46
|
+
chain.add Middleware
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# rubocop:disable Metrics/MethodLength
|
52
|
+
def install_processor
|
53
|
+
require 'sidekiq/processor'
|
54
|
+
|
55
|
+
Sidekiq::Processor.class_eval do
|
56
|
+
alias start_without_apm start
|
57
|
+
alias terminate_without_apm terminate
|
58
|
+
|
59
|
+
def start
|
60
|
+
result = start_without_apm
|
61
|
+
ElasticAPM.start # might already be running from railtie
|
62
|
+
|
63
|
+
return result unless ElasticAPM.running?
|
64
|
+
ElasticAPM.agent.config.logger = Sidekiq.logger
|
65
|
+
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def terminate
|
70
|
+
terminate_without_apm
|
71
|
+
|
72
|
+
ElasticAPM.stop
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
# rubocop:enable Metrics/MethodLength
|
77
|
+
|
78
|
+
def install
|
79
|
+
install_processor
|
80
|
+
install_middleware
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
register 'Sidekiq', 'sidekiq', SidekiqInjector.new
|
85
|
+
end
|
86
|
+
end
|
@@ -89,19 +89,27 @@ module ElasticAPM
|
|
89
89
|
# rubocop:enable Metrics/MethodLength
|
90
90
|
|
91
91
|
def span(*args, &block)
|
92
|
-
|
92
|
+
unless current_transaction
|
93
|
+
return yield if block_given?
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
current_transaction.span(*args, &block)
|
93
98
|
end
|
94
99
|
|
95
100
|
def set_tag(key, value)
|
96
|
-
|
101
|
+
return unless current_transaction
|
102
|
+
current_transaction.context.tags[key] = value.to_s
|
97
103
|
end
|
98
104
|
|
99
105
|
def set_custom_context(context)
|
100
|
-
|
106
|
+
return unless current_transaction
|
107
|
+
current_transaction.context.custom.merge!(context)
|
101
108
|
end
|
102
109
|
|
103
110
|
def set_user(user)
|
104
|
-
|
111
|
+
return unless current_transaction
|
112
|
+
current_transaction.context.user = Context::User.new(config, user)
|
105
113
|
end
|
106
114
|
|
107
115
|
def submit_transaction(transaction)
|
@@ -14,13 +14,16 @@ module ElasticAPM
|
|
14
14
|
context: ElasticAPM.build_context(env)
|
15
15
|
|
16
16
|
resp = @app.call env
|
17
|
+
status, headers, = resp
|
17
18
|
|
18
|
-
|
19
|
+
if transaction
|
20
|
+
transaction.submit(status, status: status, headers: headers)
|
21
|
+
end
|
19
22
|
rescue InternalError
|
20
23
|
raise # Don't report ElasticAPM errors
|
21
24
|
rescue ::Exception => e
|
22
25
|
ElasticAPM.report(e, handled: false)
|
23
|
-
transaction.submit(500) if transaction
|
26
|
+
transaction.submit(500, status: 500) if transaction
|
24
27
|
raise
|
25
28
|
ensure
|
26
29
|
transaction.release if transaction
|
data/lib/elastic_apm/railtie.rb
CHANGED
@@ -7,14 +7,7 @@ module ElasticAPM
|
|
7
7
|
Config::DEFAULTS.each { |option, value| config.elastic_apm[option] = value }
|
8
8
|
|
9
9
|
initializer 'elastic_apm.initialize' do |app|
|
10
|
-
config =
|
11
|
-
c.app = app
|
12
|
-
end
|
13
|
-
|
14
|
-
file_config = load_config(app)
|
15
|
-
file_config.each do |option, value|
|
16
|
-
config.send(:"#{option}=", value)
|
17
|
-
end
|
10
|
+
config = app.config.elastic_apm.merge(app: app)
|
18
11
|
|
19
12
|
begin
|
20
13
|
ElasticAPM.start config
|
@@ -29,14 +22,5 @@ module ElasticAPM
|
|
29
22
|
config.after_initialize do
|
30
23
|
require 'elastic_apm/injectors/action_dispatch'
|
31
24
|
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def load_config(app)
|
36
|
-
config_path = app.root.join('config', 'elastic_apm.yml')
|
37
|
-
return {} unless File.exist?(config_path)
|
38
|
-
|
39
|
-
YAML.load_file(config_path) || {}
|
40
|
-
end
|
41
25
|
end
|
42
26
|
end
|
data/lib/elastic_apm/span.rb
CHANGED
@@ -5,21 +5,21 @@ require 'elastic_apm/span/context'
|
|
5
5
|
module ElasticAPM
|
6
6
|
# @api private
|
7
7
|
class Span
|
8
|
-
|
8
|
+
DEFAULT_TYPE = 'custom'.freeze
|
9
9
|
|
10
10
|
# rubocop:disable Metrics/ParameterLists
|
11
11
|
def initialize(
|
12
12
|
transaction,
|
13
13
|
id,
|
14
14
|
name,
|
15
|
-
type =
|
15
|
+
type = nil,
|
16
16
|
parent: nil,
|
17
17
|
context: nil
|
18
18
|
)
|
19
19
|
@transaction = transaction
|
20
20
|
@id = id
|
21
21
|
@name = name
|
22
|
-
@type = type
|
22
|
+
@type = type || DEFAULT_TYPE
|
23
23
|
@parent = parent
|
24
24
|
@context = context
|
25
25
|
@stacktrace = nil
|
@@ -3,18 +3,14 @@
|
|
3
3
|
module ElasticAPM
|
4
4
|
# @api private
|
5
5
|
class Transaction
|
6
|
+
DEFAULT_TYPE = 'custom'.freeze
|
7
|
+
|
6
8
|
# rubocop:disable Metrics/MethodLength
|
7
|
-
def initialize(
|
8
|
-
instrumenter,
|
9
|
-
name,
|
10
|
-
type = 'custom',
|
11
|
-
context: nil,
|
12
|
-
sampled: true
|
13
|
-
)
|
9
|
+
def initialize(instrumenter, name, type = nil, context: nil, sampled: true)
|
14
10
|
@id = SecureRandom.uuid
|
15
11
|
@instrumenter = instrumenter
|
16
12
|
@name = name
|
17
|
-
@type = type
|
13
|
+
@type = type || DEFAULT_TYPE
|
18
14
|
|
19
15
|
@timestamp = Util.micros
|
20
16
|
|
@@ -51,10 +47,12 @@ module ElasticAPM
|
|
51
47
|
!!(@result && @duration)
|
52
48
|
end
|
53
49
|
|
54
|
-
def submit(
|
55
|
-
done
|
50
|
+
def submit(result = nil, status: nil, headers: {})
|
51
|
+
done result
|
56
52
|
|
57
|
-
|
53
|
+
if status
|
54
|
+
context.response = Context::Response.new(status, headers: headers)
|
55
|
+
end
|
58
56
|
|
59
57
|
release
|
60
58
|
|
data/lib/elastic_apm/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastic-apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -73,10 +73,13 @@ files:
|
|
73
73
|
- lib/elastic_apm/http.rb
|
74
74
|
- lib/elastic_apm/injectors.rb
|
75
75
|
- lib/elastic_apm/injectors/action_dispatch.rb
|
76
|
+
- lib/elastic_apm/injectors/delayed_job.rb
|
77
|
+
- lib/elastic_apm/injectors/elasticsearch.rb
|
76
78
|
- lib/elastic_apm/injectors/json.rb
|
77
79
|
- lib/elastic_apm/injectors/net_http.rb
|
78
80
|
- lib/elastic_apm/injectors/redis.rb
|
79
81
|
- lib/elastic_apm/injectors/sequel.rb
|
82
|
+
- lib/elastic_apm/injectors/sidekiq.rb
|
80
83
|
- lib/elastic_apm/injectors/sinatra.rb
|
81
84
|
- lib/elastic_apm/injectors/tilt.rb
|
82
85
|
- lib/elastic_apm/instrumenter.rb
|