elastic-apm 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of elastic-apm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +2 -5
- data/lib/elastic_apm.rb +1 -1
- data/lib/elastic_apm/config.rb +1 -8
- data/lib/elastic_apm/http.rb +1 -2
- data/lib/elastic_apm/injectors.rb +2 -0
- data/lib/elastic_apm/injectors/mongo.rb +57 -0
- data/lib/elastic_apm/injectors/net_http.rb +3 -14
- data/lib/elastic_apm/normalizers.rb +6 -1
- data/lib/elastic_apm/normalizers/action_mailer.rb +24 -0
- data/lib/elastic_apm/serializers/errors.rb +16 -2
- data/lib/elastic_apm/stacktrace.rb +28 -21
- data/lib/elastic_apm/transaction.rb +7 -1
- data/lib/elastic_apm/util/lru_cache.rb +8 -3
- data/lib/elastic_apm/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e3f8d9490f60e28d99b6e15e7efa2823fb773bacbdc9762f91fc92a4214b05b
|
4
|
+
data.tar.gz: 655814ff9046d8e9dd2d586688b9bc45acdb95f0102626af5ad0886330b58c16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4b9cace9b89eddb0ec281061fd098daa1e9297feb7fbc1c5de8ba44746ad2ab225df877480b5a213847d65502e39c321a79d4f35bee257d60d4a63a254c76e5
|
7
|
+
data.tar.gz: ae713fe3ad97666862ed91ecaeb8a199cfdaacb69edeb011840bb34e7da7692e97dffe15b729e3ec1275663bf2e381f241cb7579ca366a1ac7224c7465cbe9db
|
data/Gemfile
CHANGED
@@ -7,9 +7,9 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
7
7
|
gemspec
|
8
8
|
|
9
9
|
gem 'elasticsearch'
|
10
|
-
gem 'fakeredis', require: nil
|
11
|
-
github: 'guilleiguaran/fakeredis' # needs master right now
|
10
|
+
gem 'fakeredis', require: nil
|
12
11
|
gem 'json-schema'
|
12
|
+
gem 'mongo'
|
13
13
|
gem 'pry'
|
14
14
|
gem 'rack-test'
|
15
15
|
gem 'redis', require: nil
|
@@ -39,8 +39,5 @@ else
|
|
39
39
|
gem framework
|
40
40
|
end
|
41
41
|
|
42
|
-
# doesn't work with Rails master, so skip testing
|
43
|
-
gem 'delayed_job', '~> 4' unless [framework, version] == %w[rails 5.2]
|
44
|
-
|
45
42
|
gem 'rails' if framework == 'sinatra'
|
46
43
|
gem 'sinatra' if framework == 'rails'
|
data/lib/elastic_apm.rb
CHANGED
@@ -61,7 +61,7 @@ module ElasticAPM
|
|
61
61
|
# @param context [Context] An optional [Context]
|
62
62
|
# @yield [Transaction] Optional block encapsulating transaction
|
63
63
|
# @return [Transaction] Unless block given
|
64
|
-
def self.transaction(name, type = nil, context: nil, &block)
|
64
|
+
def self.transaction(name = nil, type = nil, context: nil, &block)
|
65
65
|
return (block_given? ? yield : nil) unless agent
|
66
66
|
|
67
67
|
agent.transaction(name, type, context: context, &block)
|
data/lib/elastic_apm/config.rb
CHANGED
@@ -8,21 +8,13 @@ module ElasticAPM
|
|
8
8
|
class Config
|
9
9
|
DEFAULTS = {
|
10
10
|
config_file: 'config/elastic_apm.yml',
|
11
|
-
|
12
11
|
server_url: 'http://localhost:8200',
|
13
|
-
secret_token: nil,
|
14
12
|
|
15
|
-
service_name: nil,
|
16
|
-
service_version: nil,
|
17
13
|
environment: ENV['RAILS_ENV'] || ENV['RACK_ENV'],
|
18
14
|
enabled_environments: %w[production],
|
19
|
-
framework_name: nil,
|
20
|
-
framework_version: nil,
|
21
|
-
hostname: nil,
|
22
15
|
|
23
16
|
log_path: '-',
|
24
17
|
log_level: Logger::INFO,
|
25
|
-
logger: nil,
|
26
18
|
|
27
19
|
max_queue_size: 500,
|
28
20
|
flush_interval: 10,
|
@@ -184,6 +176,7 @@ module ElasticAPM
|
|
184
176
|
delayed_job
|
185
177
|
elasticsearch
|
186
178
|
json
|
179
|
+
mongo
|
187
180
|
net_http
|
188
181
|
redis
|
189
182
|
sequel
|
data/lib/elastic_apm/http.rb
CHANGED
@@ -37,8 +37,7 @@ module ElasticAPM
|
|
37
37
|
request = prepare_request path, payload.to_json
|
38
38
|
response = @adapter.perform request
|
39
39
|
|
40
|
-
|
41
|
-
return response if status >= 200 && status <= 299
|
40
|
+
return response if response.is_a?(Net::HTTPSuccess)
|
42
41
|
|
43
42
|
error 'POST returned an unsuccessful status code (%d)', response.code
|
44
43
|
error "apm-server's response: %s", response.body
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Injectors
|
6
|
+
# @api private
|
7
|
+
class MongoInjector
|
8
|
+
def install
|
9
|
+
::Mongo::Monitoring::Global.subscribe(
|
10
|
+
::Mongo::Monitoring::COMMAND,
|
11
|
+
Subscriber.new
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
class Subscriber
|
17
|
+
TYPE = 'db.mongodb.query'.freeze
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@events = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def started(event)
|
24
|
+
push_event(event)
|
25
|
+
end
|
26
|
+
|
27
|
+
def failed(event)
|
28
|
+
pop_event(event)
|
29
|
+
end
|
30
|
+
|
31
|
+
def succeeded(event)
|
32
|
+
pop_event(event)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def push_event(event)
|
38
|
+
ctx = Span::Context.new(
|
39
|
+
instance: event.database_name,
|
40
|
+
statement: nil,
|
41
|
+
type: 'mongodb'.freeze,
|
42
|
+
user: nil
|
43
|
+
)
|
44
|
+
span = ElasticAPM.span(event.command_name, TYPE, context: ctx)
|
45
|
+
@events[event.operation_id] = span
|
46
|
+
end
|
47
|
+
|
48
|
+
def pop_event(event)
|
49
|
+
span = @events[event.operation_id]
|
50
|
+
span.done
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
register 'Mongo', 'mongo', MongoInjector.new
|
56
|
+
end
|
57
|
+
end
|
@@ -5,7 +5,7 @@ module ElasticAPM
|
|
5
5
|
module Injectors
|
6
6
|
# @api private
|
7
7
|
class NetHTTPInjector
|
8
|
-
# rubocop:disable Metrics/
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
9
9
|
def install
|
10
10
|
Net::HTTP.class_eval do
|
11
11
|
alias request_without_apm request
|
@@ -15,21 +15,10 @@ module ElasticAPM
|
|
15
15
|
return request_without_apm(req, body, &block)
|
16
16
|
end
|
17
17
|
|
18
|
-
host,
|
18
|
+
host, = req['host'] && req['host'].split(':')
|
19
19
|
method = req.method
|
20
|
-
path = req.path
|
21
|
-
scheme = use_ssl? ? 'https' : 'http'
|
22
20
|
|
23
|
-
# inside a session
|
24
21
|
host ||= address
|
25
|
-
port ||= 80
|
26
|
-
|
27
|
-
# TODO: investigate
|
28
|
-
_extra = {
|
29
|
-
scheme: scheme,
|
30
|
-
port: port,
|
31
|
-
path: path
|
32
|
-
}
|
33
22
|
|
34
23
|
name = "#{method} #{host}"
|
35
24
|
type = "ext.net_http.#{method}"
|
@@ -40,7 +29,7 @@ module ElasticAPM
|
|
40
29
|
end
|
41
30
|
end
|
42
31
|
end
|
43
|
-
# rubocop:enable Metrics/
|
32
|
+
# rubocop:enable Metrics/MethodLength
|
44
33
|
end
|
45
34
|
|
46
35
|
register 'Net::HTTP', 'net/http', NetHTTPInjector.new
|
@@ -57,7 +57,12 @@ module ElasticAPM # :nodoc:
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
%w[
|
60
|
+
%w[
|
61
|
+
action_controller
|
62
|
+
action_mailer
|
63
|
+
action_view
|
64
|
+
active_record
|
65
|
+
].each do |lib|
|
61
66
|
require "elastic_apm/normalizers/#{lib}"
|
62
67
|
end
|
63
68
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
module Normalizers
|
5
|
+
module ActionMailer
|
6
|
+
# @api private
|
7
|
+
class ProcessActionNormalizer < Normalizer
|
8
|
+
register 'process.action_mailer'
|
9
|
+
TYPE = 'app.mailer.action'.freeze
|
10
|
+
|
11
|
+
def normalize(transaction, _name, payload)
|
12
|
+
transaction.name = endpoint(payload)
|
13
|
+
[transaction.name, TYPE, nil]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def endpoint(payload)
|
19
|
+
"#{payload[:mailer]}##{payload[:action]}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,7 +4,7 @@ module ElasticAPM
|
|
4
4
|
module Serializers
|
5
5
|
# @api private
|
6
6
|
class Errors < Serializer
|
7
|
-
# rubocop:disable Metrics/MethodLength
|
7
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
8
8
|
def build(error)
|
9
9
|
base = {
|
10
10
|
id: error.id,
|
@@ -17,13 +17,17 @@ module ElasticAPM
|
|
17
17
|
base[:exception] = build_exception exception
|
18
18
|
end
|
19
19
|
|
20
|
+
if (log = error.log)
|
21
|
+
base[:log] = build_log log
|
22
|
+
end
|
23
|
+
|
20
24
|
if (transaction_id = error.transaction_id)
|
21
25
|
base[:transaction] = { id: transaction_id }
|
22
26
|
end
|
23
27
|
|
24
28
|
base
|
25
29
|
end
|
26
|
-
# rubocop:enable Metrics/MethodLength
|
30
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
27
31
|
|
28
32
|
def build_all(errors)
|
29
33
|
{ errors: Array(errors).map(&method(:build)) }
|
@@ -42,6 +46,16 @@ module ElasticAPM
|
|
42
46
|
handled: exception.handled
|
43
47
|
}
|
44
48
|
end
|
49
|
+
|
50
|
+
def build_log(log)
|
51
|
+
{
|
52
|
+
message: log.message,
|
53
|
+
level: log.level,
|
54
|
+
logger_name: log.logger_name,
|
55
|
+
param_message: log.param_message,
|
56
|
+
stacktrace: log.stacktrace.to_a
|
57
|
+
}
|
58
|
+
end
|
45
59
|
end
|
46
60
|
end
|
47
61
|
end
|
@@ -71,38 +71,45 @@ module ElasticAPM
|
|
71
71
|
false
|
72
72
|
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
frame = Frame.new
|
79
|
-
frame.abs_path = abs_path
|
80
|
-
frame.filename = strip_load_path(abs_path)
|
81
|
-
frame.function = function
|
82
|
-
frame.lineno = lineno.to_i
|
83
|
-
frame.library_frame = library_frame?(config, abs_path)
|
74
|
+
class << self
|
75
|
+
attr_accessor :frame_cache
|
76
|
+
end
|
84
77
|
|
85
|
-
|
86
|
-
|
87
|
-
|
78
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
79
|
+
def build_frame(config, line, type)
|
80
|
+
# TODO: Eventually move this to agent 'context'
|
81
|
+
self.class.frame_cache ||= Util::LruCache.new(2048) do |cache, keys|
|
82
|
+
line, type = keys
|
83
|
+
abs_path, lineno, function, _module_name = parse_line(line)
|
84
|
+
|
85
|
+
frame = Frame.new
|
86
|
+
frame.abs_path = abs_path
|
87
|
+
frame.filename = strip_load_path(abs_path)
|
88
|
+
frame.function = function
|
89
|
+
frame.lineno = lineno.to_i
|
90
|
+
frame.library_frame = library_frame?(config, abs_path)
|
91
|
+
|
92
|
+
line_count =
|
93
|
+
context_lines_for(config, type, library_frame: frame.library_frame)
|
94
|
+
frame.build_context line_count
|
95
|
+
|
96
|
+
cache[[line, type]] = frame
|
97
|
+
end
|
88
98
|
|
89
|
-
|
99
|
+
self.class.frame_cache[[line, type]]
|
90
100
|
end
|
91
|
-
# rubocop:enable Metrics/MethodLength
|
101
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
92
102
|
|
93
103
|
def strip_load_path(path)
|
94
|
-
return nil
|
104
|
+
return nil if path.nil?
|
95
105
|
|
96
106
|
prefix =
|
97
107
|
$LOAD_PATH
|
98
108
|
.map(&:to_s)
|
99
109
|
.select { |s| path.start_with?(s) }
|
100
|
-
.
|
101
|
-
.last
|
102
|
-
|
103
|
-
return path unless prefix
|
110
|
+
.max_by(&:length)
|
104
111
|
|
105
|
-
path[prefix.chomp(File::SEPARATOR).length + 1..-1]
|
112
|
+
prefix ? path[prefix.chomp(File::SEPARATOR).length + 1..-1] : path
|
106
113
|
end
|
107
114
|
|
108
115
|
def context_lines_for(config, type, library_frame:)
|
@@ -6,7 +6,13 @@ module ElasticAPM
|
|
6
6
|
DEFAULT_TYPE = 'custom'.freeze
|
7
7
|
|
8
8
|
# rubocop:disable Metrics/MethodLength
|
9
|
-
def initialize(
|
9
|
+
def initialize(
|
10
|
+
instrumenter,
|
11
|
+
name = nil,
|
12
|
+
type = nil,
|
13
|
+
context: nil,
|
14
|
+
sampled: true
|
15
|
+
)
|
10
16
|
@id = SecureRandom.uuid
|
11
17
|
@instrumenter = instrumenter
|
12
18
|
@name = name
|
@@ -4,16 +4,21 @@ module ElasticAPM
|
|
4
4
|
module Util
|
5
5
|
# @api private
|
6
6
|
class LruCache
|
7
|
-
def initialize(max_size = 512)
|
7
|
+
def initialize(max_size = 512, &block)
|
8
8
|
@max_size = max_size
|
9
|
-
@data =
|
9
|
+
@data = Hash.new(&block)
|
10
|
+
@missing_key_block = block
|
10
11
|
end
|
11
12
|
|
12
13
|
def [](key)
|
13
14
|
found = true
|
14
15
|
value = @data.delete(key) { found = false }
|
15
16
|
|
16
|
-
found
|
17
|
+
if found
|
18
|
+
@data[key] = value
|
19
|
+
else
|
20
|
+
@missing_key_block && @missing_key_block.call(self, key)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def []=(key, val)
|
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.6.
|
4
|
+
version: 0.6.2
|
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-04-
|
11
|
+
date: 2018-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/elastic_apm/injectors/delayed_job.rb
|
77
77
|
- lib/elastic_apm/injectors/elasticsearch.rb
|
78
78
|
- lib/elastic_apm/injectors/json.rb
|
79
|
+
- lib/elastic_apm/injectors/mongo.rb
|
79
80
|
- lib/elastic_apm/injectors/net_http.rb
|
80
81
|
- lib/elastic_apm/injectors/redis.rb
|
81
82
|
- lib/elastic_apm/injectors/sequel.rb
|
@@ -89,6 +90,7 @@ files:
|
|
89
90
|
- lib/elastic_apm/naively_hashable.rb
|
90
91
|
- lib/elastic_apm/normalizers.rb
|
91
92
|
- lib/elastic_apm/normalizers/action_controller.rb
|
93
|
+
- lib/elastic_apm/normalizers/action_mailer.rb
|
92
94
|
- lib/elastic_apm/normalizers/action_view.rb
|
93
95
|
- lib/elastic_apm/normalizers/active_record.rb
|
94
96
|
- lib/elastic_apm/process_info.rb
|