elastic-apm 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.asciidoc +15 -0
- data/Gemfile +1 -0
- data/SECURITY.md +7 -0
- data/docker-compose.yml +1 -1
- data/lib/elastic_apm.rb +1 -0
- data/lib/elastic_apm/agent.rb +2 -2
- data/lib/elastic_apm/central_config.rb +2 -2
- data/lib/elastic_apm/config.rb +1 -0
- data/lib/elastic_apm/fields.rb +88 -0
- data/lib/elastic_apm/span.rb +18 -0
- data/lib/elastic_apm/span/context/destination.rb +39 -58
- data/lib/elastic_apm/spies.rb +20 -0
- data/lib/elastic_apm/spies/azure_storage_table.rb +148 -0
- data/lib/elastic_apm/spies/dynamo_db.rb +2 -8
- data/lib/elastic_apm/spies/faraday.rb +25 -11
- data/lib/elastic_apm/spies/http.rb +3 -4
- data/lib/elastic_apm/spies/net_http.rb +21 -14
- data/lib/elastic_apm/spies/s3.rb +4 -7
- data/lib/elastic_apm/spies/sequel.rb +1 -1
- data/lib/elastic_apm/spies/sns.rb +3 -9
- data/lib/elastic_apm/spies/sqs.rb +3 -11
- data/lib/elastic_apm/subscriber.rb +1 -0
- data/lib/elastic_apm/transport/connection/http.rb +3 -1
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +4 -8
- data/lib/elastic_apm/version.rb +1 -1
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81641cee86d90236fac69836ed6b6e4e858e0650d099c7cf0ab2fbc58e9d8550
|
4
|
+
data.tar.gz: a8f13b6c5b4b430c4cba21f92167b784634bc151ef802472e9a4fc1af6f95c1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3db0a577687ac11af79c29de68c3935cb0df9572bed2583c5d9666dd15aefabb97a0ab0a081b79fd41ee7e53e1e3319700d0ebd74a30883eaa55b45684ea9862
|
7
|
+
data.tar.gz: a191284ee54fd8be1511927ff1af81f13bb129c6f282d2078099cf8a79fe124ec5f995243260d66a23920f6d82fdb1955614cdbe260b58413bb9863ee0226a3a
|
data/CHANGELOG.asciidoc
CHANGED
@@ -35,6 +35,21 @@ endif::[]
|
|
35
35
|
[[release-notes-4.x]]
|
36
36
|
=== Ruby Agent version 4.x
|
37
37
|
|
38
|
+
[[release-notes-4.2.0]]
|
39
|
+
==== 4.2.0
|
40
|
+
|
41
|
+
[float]
|
42
|
+
===== Added
|
43
|
+
|
44
|
+
- Add support for AWS Storage Table/CosmosDB {pull}999[#999]
|
45
|
+
|
46
|
+
[float]
|
47
|
+
===== Fixed
|
48
|
+
|
49
|
+
- Align HTTP span types/subtypes with spec {pull}1014[#1014]
|
50
|
+
- Passing a full URL as a path to `Net::HTTP` {pull}1029[#1029]
|
51
|
+
- Fix growing number of open file descriptors {pull}1033[#1033]
|
52
|
+
|
38
53
|
[[release-notes-4.1.0]]
|
39
54
|
==== 4.1.0
|
40
55
|
|
data/Gemfile
CHANGED
@@ -36,6 +36,7 @@ gem 'aws-sdk-dynamodb', require: nil
|
|
36
36
|
gem 'aws-sdk-s3', require: nil
|
37
37
|
gem 'aws-sdk-sqs', require: nil
|
38
38
|
gem 'aws-sdk-sns', require: nil
|
39
|
+
gem 'azure-storage-table', require: nil if RUBY_VERSION < '3.0'
|
39
40
|
gem 'elasticsearch', require: nil
|
40
41
|
gem 'fakeredis', require: nil
|
41
42
|
gem 'faraday', require: nil
|
data/SECURITY.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Security Policy
|
2
|
+
|
3
|
+
Thanks for your interest in the security of our products.
|
4
|
+
Our security policy can be found at [https://www.elastic.co/community/security](https://www.elastic.co/community/security).
|
5
|
+
|
6
|
+
## Reporting a Vulnerability
|
7
|
+
Please send security vulnerability reports to security@elastic.co.
|
data/docker-compose.yml
CHANGED
data/lib/elastic_apm.rb
CHANGED
data/lib/elastic_apm/agent.rb
CHANGED
@@ -280,8 +280,8 @@ module ElasticAPM
|
|
280
280
|
def detect_forking!
|
281
281
|
return if @pid == Process.pid
|
282
282
|
|
283
|
-
config.logger.debug
|
284
|
-
restarting threads in process [PID:#{Process.pid}]"
|
283
|
+
config.logger.debug(
|
284
|
+
"Forked process detected, restarting threads in process [PID:#{Process.pid}]")
|
285
285
|
|
286
286
|
central_config.handle_forking!
|
287
287
|
transport.handle_forking!
|
@@ -119,7 +119,7 @@ module ElasticAPM
|
|
119
119
|
end
|
120
120
|
|
121
121
|
if resp.status == 304
|
122
|
-
|
122
|
+
debug 'Received 304 Not Modified'
|
123
123
|
else
|
124
124
|
if resp.body && !resp.body.empty?
|
125
125
|
update = JSON.parse(resp.body.to_s)
|
@@ -169,7 +169,7 @@ module ElasticAPM
|
|
169
169
|
end
|
170
170
|
|
171
171
|
def headers
|
172
|
-
{ '
|
172
|
+
{ 'If-None-Match': @etag }
|
173
173
|
end
|
174
174
|
|
175
175
|
def schedule_next_fetch(resp = nil)
|
data/lib/elastic_apm/config.rb
CHANGED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
+
# not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
module ElasticAPM
|
21
|
+
# An interface for creating simple, value holding objects that correspond to
|
22
|
+
# object fields in the API.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
# class MyThing
|
26
|
+
# include Fields
|
27
|
+
# field :name
|
28
|
+
# field :address, optional: true
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# MyThing.new(name: 'AJ').to_h
|
32
|
+
# # => { name: 'AJ' }
|
33
|
+
# MyThing.new().empty?
|
34
|
+
# # => true
|
35
|
+
module Fields
|
36
|
+
module InstanceMethods
|
37
|
+
def initialize(**attrs)
|
38
|
+
attrs.each do |key, value|
|
39
|
+
self.send(:"#{key}=", value)
|
40
|
+
end
|
41
|
+
|
42
|
+
super()
|
43
|
+
end
|
44
|
+
|
45
|
+
def empty?
|
46
|
+
self.class.fields.each do |key|
|
47
|
+
next if send(key)
|
48
|
+
next if optionals.include?(key)
|
49
|
+
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_h
|
57
|
+
self.class.fields.each_with_object({}) do |key, fields|
|
58
|
+
fields[key] = send(key)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def optionals
|
65
|
+
self.class.optionals
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module ClassMethods
|
70
|
+
def field(key, optional: false)
|
71
|
+
attr_accessor(key)
|
72
|
+
|
73
|
+
fields.push(key)
|
74
|
+
optionals.push(key) if optional
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_reader :fields, :optionals
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.included(cls)
|
81
|
+
cls.extend(ClassMethods)
|
82
|
+
cls.include(InstanceMethods)
|
83
|
+
|
84
|
+
cls.instance_variable_set(:@fields, [])
|
85
|
+
cls.instance_variable_set(:@optionals, [])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/elastic_apm/span.rb
CHANGED
@@ -106,6 +106,18 @@ module ElasticAPM
|
|
106
106
|
@duration ||= (clock_end - @clock_start)
|
107
107
|
@parent.child_stopped
|
108
108
|
@self_time = @duration - child_durations.duration
|
109
|
+
|
110
|
+
if exit_span?
|
111
|
+
context.destination ||= Context::Destination.new
|
112
|
+
context.destination.service ||= Context::Destination::Service.new
|
113
|
+
context.destination.service.resource ||= (subtype || type)
|
114
|
+
|
115
|
+
# Deprecated fields but required by some versions of APM Server, so
|
116
|
+
# we auto-infer them from existing fields
|
117
|
+
context.destination.service.name ||= (subtype || type)
|
118
|
+
context.destination.service.type ||= type
|
119
|
+
end
|
120
|
+
|
109
121
|
self
|
110
122
|
end
|
111
123
|
|
@@ -144,6 +156,8 @@ module ElasticAPM
|
|
144
156
|
"<ElasticAPM::Span id:#{trace_context&.id}" \
|
145
157
|
" name:#{name.inspect}" \
|
146
158
|
" type:#{type.inspect}" \
|
159
|
+
" subtype:#{subtype.inspect}" \
|
160
|
+
" action:#{action.inspect}" \
|
147
161
|
'>'
|
148
162
|
end
|
149
163
|
|
@@ -166,5 +180,9 @@ module ElasticAPM
|
|
166
180
|
|
167
181
|
duration >= min_duration
|
168
182
|
end
|
183
|
+
|
184
|
+
def exit_span?
|
185
|
+
context.destination || context.db || context.message || context.http
|
186
|
+
end
|
169
187
|
end
|
170
188
|
end
|
@@ -14,7 +14,7 @@
|
|
14
14
|
# KIND, either express or implied. See the License for the
|
15
15
|
# specific language governing permissions and limitations
|
16
16
|
# under the License.
|
17
|
-
|
17
|
+
#
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
20
|
module ElasticAPM
|
@@ -22,74 +22,53 @@ module ElasticAPM
|
|
22
22
|
class Context
|
23
23
|
# @api private
|
24
24
|
class Destination
|
25
|
+
include Fields
|
26
|
+
|
27
|
+
field :address
|
28
|
+
field :port
|
29
|
+
field :service
|
30
|
+
field :cloud
|
25
31
|
|
26
32
|
# @api private
|
27
33
|
class Service
|
28
|
-
|
29
|
-
|
30
|
-
def initialize(name: nil, type: nil, resource: nil)
|
31
|
-
@name = name
|
32
|
-
@type = type
|
33
|
-
@resource = resource
|
34
|
+
include Fields
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
attr_accessor :name, :type, :resource
|
36
|
+
field :name
|
37
|
+
field :type
|
38
|
+
field :resource
|
40
39
|
end
|
41
40
|
|
42
41
|
# @api private
|
43
42
|
class Cloud
|
44
|
-
|
45
|
-
@region = region
|
46
|
-
end
|
43
|
+
include Fields
|
47
44
|
|
48
|
-
|
45
|
+
field :region
|
49
46
|
end
|
50
47
|
|
51
|
-
def initialize(
|
52
|
-
|
53
|
-
port: nil,
|
54
|
-
service: nil,
|
55
|
-
cloud: nil
|
56
|
-
)
|
57
|
-
@address = address
|
58
|
-
@port = port
|
59
|
-
@service = build_service(service)
|
60
|
-
@cloud = build_cloud(cloud)
|
61
|
-
end
|
48
|
+
def initialize(service: nil, cloud: nil, **attrs)
|
49
|
+
super(**attrs)
|
62
50
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
:service,
|
67
|
-
:cloud
|
68
|
-
)
|
51
|
+
self.service = build_service(service)
|
52
|
+
self.cloud = build_cloud(cloud)
|
53
|
+
end
|
69
54
|
|
70
|
-
def self.from_uri(uri_or_str, type:
|
55
|
+
def self.from_uri(uri_or_str, type: nil, **attrs)
|
71
56
|
uri = normalize(uri_or_str)
|
72
57
|
|
73
|
-
service =
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
58
|
+
service =
|
59
|
+
case type
|
60
|
+
when 'http' then http_service(uri)
|
61
|
+
else nil
|
62
|
+
end
|
78
63
|
|
79
64
|
new(
|
80
65
|
address: uri.hostname,
|
81
|
-
port:
|
82
|
-
service: service
|
66
|
+
port: uri.port,
|
67
|
+
service: service,
|
68
|
+
**attrs
|
83
69
|
)
|
84
70
|
end
|
85
71
|
|
86
|
-
def self.only_scheme_and_host(uri_or_str)
|
87
|
-
uri = normalize(uri_or_str)
|
88
|
-
uri.path = ''
|
89
|
-
uri.password = uri.query = uri.fragment = nil
|
90
|
-
uri.to_s
|
91
|
-
end
|
92
|
-
|
93
72
|
class << self
|
94
73
|
private
|
95
74
|
|
@@ -97,25 +76,27 @@ module ElasticAPM
|
|
97
76
|
return uri_or_str.dup if uri_or_str.is_a?(URI)
|
98
77
|
URI(uri_or_str)
|
99
78
|
end
|
79
|
+
|
80
|
+
def http_service(uri)
|
81
|
+
Service.new(resource: "#{uri.host}:#{uri.port}")
|
82
|
+
end
|
100
83
|
end
|
101
84
|
|
102
85
|
private
|
103
86
|
|
104
|
-
def build_service(service = nil)
|
105
|
-
return unless service
|
106
|
-
return service if service.is_a?(Service)
|
107
|
-
|
108
|
-
Service.new(**service)
|
109
|
-
rescue Service::MissingValues
|
110
|
-
nil # If we are missing any service value, return nothing
|
111
|
-
end
|
112
|
-
|
113
87
|
def build_cloud(cloud = nil)
|
114
|
-
return unless cloud
|
88
|
+
return Cloud.new unless cloud
|
115
89
|
return cloud if cloud.is_a?(Cloud)
|
116
90
|
|
117
91
|
Cloud.new(**cloud)
|
118
92
|
end
|
93
|
+
|
94
|
+
def build_service(service = nil)
|
95
|
+
return Service.new unless service
|
96
|
+
return service if service.is_a?(Service)
|
97
|
+
|
98
|
+
Service.new(**service)
|
99
|
+
end
|
119
100
|
end
|
120
101
|
end
|
121
102
|
end
|
data/lib/elastic_apm/spies.rb
CHANGED
@@ -56,6 +56,26 @@ module ElasticAPM
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
def self.without_faraday
|
60
|
+
return yield unless defined?(FaradaySpy)
|
61
|
+
|
62
|
+
# rubocop:disable Style/ExplicitBlockArgument
|
63
|
+
ElasticAPM::Spies::FaradaySpy.disable_in do
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
# rubocop:enable Style/ExplicitBlockArgument
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.without_net_http
|
70
|
+
return yield unless defined?(NetHTTPSpy)
|
71
|
+
|
72
|
+
# rubocop:disable Style/ExplicitBlockArgument
|
73
|
+
ElasticAPM::Spies::NetHTTPSpy.disable_in do
|
74
|
+
yield
|
75
|
+
end
|
76
|
+
# rubocop:enable Style/ExplicitBlockArgument
|
77
|
+
end
|
78
|
+
|
59
79
|
def self.register_require_hook(registration)
|
60
80
|
registration.require_paths.each do |path|
|
61
81
|
require_hooks[path] = registration
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
+
# not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
module ElasticAPM
|
21
|
+
# @api private
|
22
|
+
module Spies
|
23
|
+
# @api private
|
24
|
+
class AzureStorageTableSpy
|
25
|
+
TYPE = "storage"
|
26
|
+
SUBTYPE = "azuretable"
|
27
|
+
|
28
|
+
module Helpers
|
29
|
+
class << self
|
30
|
+
def instrument(operation_name, table_name = nil, service:)
|
31
|
+
span_name = span_name(operation_name, table_name)
|
32
|
+
action = formatted_op_name(operation_name)
|
33
|
+
account_name = account_name_from_storage_table_host(service.storage_service_host[:primary])
|
34
|
+
|
35
|
+
destination = ElasticAPM::Span::Context::Destination.from_uri(service.storage_service_host[:primary])
|
36
|
+
destination.service.resource = "#{SUBTYPE}/#{account_name}"
|
37
|
+
|
38
|
+
context = ElasticAPM::Span::Context.new(destination: destination)
|
39
|
+
|
40
|
+
ElasticAPM.with_span(span_name, TYPE, subtype: SUBTYPE, action: action, context: context) do
|
41
|
+
ElasticAPM::Spies.without_faraday do
|
42
|
+
ElasticAPM::Spies.without_net_http do
|
43
|
+
yield
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
DEFAULT_OP_NAMES = {
|
52
|
+
"create_table" => "Create",
|
53
|
+
"delete_table" => "Delete",
|
54
|
+
"get_table_acl" => "GetAcl",
|
55
|
+
"set_table_acl" => "SetAcl",
|
56
|
+
"insert_entity" => "Insert",
|
57
|
+
"query_entities" => "Query",
|
58
|
+
"update_entity" => "Update",
|
59
|
+
"merge_entity" => "Merge",
|
60
|
+
"delete_entity" => "Delete"
|
61
|
+
}.freeze
|
62
|
+
|
63
|
+
def formatted_op_names
|
64
|
+
@formatted_op_names ||= Concurrent::Map.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def account_names
|
68
|
+
@account_names ||= Concurrent::Map.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def span_name(operation_name, table_name = nil)
|
72
|
+
base = "AzureTable #{formatted_op_name(operation_name)}"
|
73
|
+
|
74
|
+
return base unless table_name
|
75
|
+
|
76
|
+
"#{base} #{table_name}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def formatted_op_name(operation_name)
|
80
|
+
formatted_op_names.compute_if_absent(operation_name) do
|
81
|
+
DEFAULT_OP_NAMES.fetch(operation_name) do
|
82
|
+
operation_name.to_s.split("_").collect(&:capitalize).join
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def account_name_from_storage_table_host(host)
|
88
|
+
account_names.compute_if_absent(host) do
|
89
|
+
URI(host).host.split(".").first || "unknown"
|
90
|
+
end
|
91
|
+
rescue Exception
|
92
|
+
"unknown"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api private
|
98
|
+
module Ext
|
99
|
+
# Methods with table_name as first parameter
|
100
|
+
%i[
|
101
|
+
create_table
|
102
|
+
delete_table
|
103
|
+
get_table
|
104
|
+
get_table_acl
|
105
|
+
set_table_acl
|
106
|
+
insert_entity
|
107
|
+
query_entities
|
108
|
+
update_entity
|
109
|
+
merge_entity
|
110
|
+
delete_entity
|
111
|
+
].each do |method_name|
|
112
|
+
define_method(method_name) do |table_name, *args|
|
113
|
+
unless (transaction = ElasticAPM.current_transaction)
|
114
|
+
return super(table_name, *args)
|
115
|
+
end
|
116
|
+
|
117
|
+
ElasticAPM::Spies::AzureStorageTableSpy::Helpers.instrument(
|
118
|
+
method_name.to_s, table_name, service: self
|
119
|
+
) do
|
120
|
+
super(table_name, *args)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Methods WITHOUT table_name as first parameter
|
126
|
+
def query_tables(*args)
|
127
|
+
unless (transaction = ElasticAPM.current_transaction)
|
128
|
+
return super(*args)
|
129
|
+
end
|
130
|
+
|
131
|
+
ElasticAPM::Spies::AzureStorageTableSpy::Helpers.instrument("query_tables", service: self) do
|
132
|
+
super(*args)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def install
|
138
|
+
::Azure::Storage::Table::TableService.prepend(Ext)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
register(
|
143
|
+
"Azure::Storage::Table::TableService",
|
144
|
+
"azure/storage/table",
|
145
|
+
AzureStorageTableSpy.new
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
@@ -56,8 +56,6 @@ module ElasticAPM
|
|
56
56
|
# Alias all available operations
|
57
57
|
mod.api.operation_names.each do |operation_name|
|
58
58
|
define_method(operation_name) do |params = {}, options = {}|
|
59
|
-
cloud = ElasticAPM::Span::Context::Destination::Cloud.new(region: config.region)
|
60
|
-
|
61
59
|
context = ElasticAPM::Span::Context.new(
|
62
60
|
db: {
|
63
61
|
instance: config.region,
|
@@ -65,12 +63,8 @@ module ElasticAPM
|
|
65
63
|
statement: params[:key_condition_expression]
|
66
64
|
},
|
67
65
|
destination: {
|
68
|
-
|
69
|
-
|
70
|
-
name: NAME,
|
71
|
-
resource: SUBTYPE,
|
72
|
-
type: TYPE
|
73
|
-
}
|
66
|
+
service: { resource: "#{SUBTYPE}/#{config.region}" },
|
67
|
+
cloud: { region: config.region }
|
74
68
|
}
|
75
69
|
)
|
76
70
|
|
@@ -22,17 +22,28 @@ module ElasticAPM
|
|
22
22
|
module Spies
|
23
23
|
# @api private
|
24
24
|
class FaradaySpy
|
25
|
-
|
26
|
-
|
25
|
+
DISABLE_KEY = :__elastic_apm_faraday_disabled
|
26
|
+
TYPE = 'external'
|
27
|
+
SUBTYPE = 'http'
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
class << self
|
30
|
+
def disabled=(disabled)
|
31
|
+
Thread.current[DISABLE_KEY] = disabled
|
32
|
+
end
|
33
|
+
|
34
|
+
def disabled?
|
35
|
+
Thread.current[DISABLE_KEY] ||= false
|
36
|
+
end
|
37
|
+
|
38
|
+
def disable_in
|
39
|
+
self.disabled = true
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
41
|
+
begin
|
42
|
+
yield
|
43
|
+
ensure
|
44
|
+
self.disabled = false
|
45
|
+
end
|
34
46
|
end
|
35
|
-
# rubocop:enable Style/ExplicitBlockArgument
|
36
47
|
end
|
37
48
|
|
38
49
|
# @api private
|
@@ -43,6 +54,10 @@ module ElasticAPM
|
|
43
54
|
return super(method, url, body, headers, &block)
|
44
55
|
end
|
45
56
|
|
57
|
+
if ElasticAPM::Spies::FaradaySpy.disabled?
|
58
|
+
return super(method, url, body, headers, &block)
|
59
|
+
end
|
60
|
+
|
46
61
|
uri = URI(build_url(url))
|
47
62
|
|
48
63
|
# If url is set inside block it isn't available until yield,
|
@@ -61,7 +76,7 @@ module ElasticAPM
|
|
61
76
|
upcased_method = method.to_s.upcase
|
62
77
|
|
63
78
|
if uri
|
64
|
-
destination = ElasticAPM::Span::Context::Destination.from_uri(uri)
|
79
|
+
destination = ElasticAPM::Span::Context::Destination.from_uri(uri, type: SUBTYPE)
|
65
80
|
|
66
81
|
context =
|
67
82
|
ElasticAPM::Span::Context.new(
|
@@ -83,10 +98,9 @@ module ElasticAPM
|
|
83
98
|
"#{upcased_method} #{host}",
|
84
99
|
TYPE,
|
85
100
|
subtype: SUBTYPE,
|
86
|
-
action: upcased_method,
|
87
101
|
context: context
|
88
102
|
) do |span|
|
89
|
-
ElasticAPM::Spies
|
103
|
+
ElasticAPM::Spies.without_net_http do
|
90
104
|
trace_context = span&.trace_context || transaction.trace_context
|
91
105
|
|
92
106
|
result = super(method, url, body, headers) do |req|
|
@@ -22,8 +22,8 @@ module ElasticAPM
|
|
22
22
|
module Spies
|
23
23
|
# @api private
|
24
24
|
class HTTPSpy
|
25
|
-
TYPE = '
|
26
|
-
SUBTYPE = '
|
25
|
+
TYPE = 'external'
|
26
|
+
SUBTYPE = 'http'
|
27
27
|
|
28
28
|
# @api private
|
29
29
|
module Ext
|
@@ -37,7 +37,7 @@ module ElasticAPM
|
|
37
37
|
|
38
38
|
context = ElasticAPM::Span::Context.new(
|
39
39
|
http: { url: req.uri, method: method },
|
40
|
-
destination: ElasticAPM::Span::Context::Destination.from_uri(req.uri)
|
40
|
+
destination: ElasticAPM::Span::Context::Destination.from_uri(req.uri, type: SUBTYPE)
|
41
41
|
)
|
42
42
|
|
43
43
|
name = "#{method} #{host}"
|
@@ -46,7 +46,6 @@ module ElasticAPM
|
|
46
46
|
name,
|
47
47
|
TYPE,
|
48
48
|
subtype: SUBTYPE,
|
49
|
-
action: method,
|
50
49
|
context: context
|
51
50
|
) do |span|
|
52
51
|
trace_context = span&.trace_context || transaction.trace_context
|
@@ -22,17 +22,17 @@ module ElasticAPM
|
|
22
22
|
module Spies
|
23
23
|
# @api private
|
24
24
|
class NetHTTPSpy
|
25
|
-
|
26
|
-
TYPE = '
|
27
|
-
SUBTYPE = '
|
25
|
+
DISABLE_KEY = :__elastic_apm_net_http_disabled
|
26
|
+
TYPE = 'external'
|
27
|
+
SUBTYPE = 'http'
|
28
28
|
|
29
29
|
class << self
|
30
30
|
def disabled=(disabled)
|
31
|
-
Thread.current[
|
31
|
+
Thread.current[DISABLE_KEY] = disabled
|
32
32
|
end
|
33
33
|
|
34
34
|
def disabled?
|
35
|
-
Thread.current[
|
35
|
+
Thread.current[DISABLE_KEY] ||= false
|
36
36
|
end
|
37
37
|
|
38
38
|
def disable_in
|
@@ -60,26 +60,33 @@ module ElasticAPM
|
|
60
60
|
|
61
61
|
host = req['host']&.split(':')&.first || address || 'localhost'
|
62
62
|
method = req.method.to_s.upcase
|
63
|
-
path, query = req.path.split('?')
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
url
|
68
|
-
|
69
|
-
|
70
|
-
|
64
|
+
uri_or_path = URI(req.path)
|
65
|
+
|
66
|
+
# Support the case where a whole url is passed as a path to a nil host
|
67
|
+
uri =
|
68
|
+
if uri_or_path.host
|
69
|
+
uri_or_path
|
70
|
+
else
|
71
|
+
path, query = req.path.split('?')
|
72
|
+
url = use_ssl? ? +'https://' : +'http://'
|
73
|
+
url << host
|
74
|
+
url << ":#{port}" if port
|
75
|
+
url << path
|
76
|
+
url << "?#{query}" if query
|
77
|
+
URI(url)
|
78
|
+
end
|
71
79
|
|
72
80
|
context =
|
73
81
|
ElasticAPM::Span::Context.new(
|
74
82
|
http: { url: uri, method: method },
|
75
|
-
destination: ElasticAPM::Span::Context::Destination.from_uri(uri)
|
83
|
+
destination: ElasticAPM::Span::Context::Destination.from_uri(uri, type: SUBTYPE)
|
76
84
|
)
|
77
85
|
|
78
86
|
ElasticAPM.with_span(
|
79
87
|
"#{method} #{host}",
|
80
88
|
TYPE,
|
81
89
|
subtype: SUBTYPE,
|
82
|
-
action: method,
|
83
90
|
context: context
|
84
91
|
) do |span|
|
85
92
|
trace_context = span&.trace_context || transaction.trace_context
|
data/lib/elastic_apm/spies/s3.rb
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
# KIND, either express or implied. See the License for the
|
15
15
|
# specific language governing permissions and limitations
|
16
16
|
# under the License.
|
17
|
-
|
17
|
+
#
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
20
|
module ElasticAPM
|
@@ -85,14 +85,11 @@ module ElasticAPM
|
|
85
85
|
bucket_name = ElasticAPM::Spies::S3Spy.bucket_name(params)
|
86
86
|
region = ElasticAPM::Spies::S3Spy.accesspoint_region(params) || config.region
|
87
87
|
|
88
|
+
resource = "#{SUBTYPE}/#{bucket_name || 'unknown-bucket'}"
|
88
89
|
context = ElasticAPM::Span::Context.new(
|
89
90
|
destination: {
|
90
|
-
|
91
|
-
|
92
|
-
resource: bucket_name,
|
93
|
-
type: TYPE,
|
94
|
-
name: SUBTYPE
|
95
|
-
}
|
91
|
+
service: { resource: resource },
|
92
|
+
cloud: { region: region }
|
96
93
|
}
|
97
94
|
)
|
98
95
|
|
@@ -46,7 +46,7 @@ module ElasticAPM
|
|
46
46
|
|
47
47
|
context = ElasticAPM::Span::Context.new(
|
48
48
|
db: { statement: sql, type: 'sql', user: opts[:user] },
|
49
|
-
destination: { service: {
|
49
|
+
destination: { service: { resource: subtype } }
|
50
50
|
)
|
51
51
|
|
52
52
|
span = ElasticAPM.start_span(
|
@@ -65,16 +65,10 @@ module ElasticAPM
|
|
65
65
|
|
66
66
|
def self.span_context(topic, region)
|
67
67
|
ElasticAPM::Span::Context.new(
|
68
|
-
message: {
|
69
|
-
queue_name: topic
|
70
|
-
},
|
68
|
+
message: { queue_name: topic },
|
71
69
|
destination: {
|
72
|
-
service: {
|
73
|
-
|
74
|
-
type: TYPE,
|
75
|
-
name: SUBTYPE,
|
76
|
-
},
|
77
|
-
cloud: ElasticAPM::Span::Context::Destination::Cloud.new(region: region)
|
70
|
+
service: { resource: "#{SUBTYPE}/#{topic}" },
|
71
|
+
cloud: { region: region }
|
78
72
|
}
|
79
73
|
)
|
80
74
|
end
|
@@ -50,19 +50,11 @@ module ElasticAPM
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def self.span_context(queue_name, region)
|
53
|
-
cloud = ElasticAPM::Span::Context::Destination::Cloud.new(region: region)
|
54
|
-
|
55
53
|
ElasticAPM::Span::Context.new(
|
56
|
-
message: {
|
57
|
-
queue_name: queue_name
|
58
|
-
},
|
54
|
+
message: { queue_name: queue_name },
|
59
55
|
destination: {
|
60
|
-
service: {
|
61
|
-
|
62
|
-
type: TYPE,
|
63
|
-
name: SUBTYPE
|
64
|
-
},
|
65
|
-
cloud: cloud
|
56
|
+
service: { resource: "#{SUBTYPE}/#{queue_name}" },
|
57
|
+
cloud: { region: region }
|
66
58
|
}
|
67
59
|
)
|
68
60
|
end
|
@@ -85,7 +85,7 @@ module ElasticAPM
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def closed?
|
88
|
-
@closed.true?
|
88
|
+
@rd.closed? && @closed.true?
|
89
89
|
end
|
90
90
|
|
91
91
|
def inspect
|
@@ -117,6 +117,8 @@ module ElasticAPM
|
|
117
117
|
error(
|
118
118
|
"Couldn't establish connection to APM Server:\n%p", e.inspect
|
119
119
|
)
|
120
|
+
ensure
|
121
|
+
@rd&.close
|
120
122
|
end
|
121
123
|
end
|
122
124
|
end
|
@@ -100,16 +100,12 @@ module ElasticAPM
|
|
100
100
|
port: destination.port
|
101
101
|
}
|
102
102
|
|
103
|
-
|
104
|
-
base[:service] =
|
105
|
-
name: keyword_field(destination.service.name),
|
106
|
-
resource: keyword_field(destination.service.resource),
|
107
|
-
type: keyword_field(destination.service.type)
|
108
|
-
}
|
103
|
+
unless destination.service&.empty?
|
104
|
+
base[:service] = destination.service.to_h
|
109
105
|
end
|
110
106
|
|
111
|
-
|
112
|
-
base[:cloud] =
|
107
|
+
unless destination.cloud&.empty?
|
108
|
+
base[:cloud] = destination.cloud.to_h
|
113
109
|
end
|
114
110
|
|
115
111
|
base
|
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: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
|
-
description:
|
41
|
+
description:
|
42
42
|
email:
|
43
43
|
- mikkel@elastic.co
|
44
44
|
executables: []
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- LICENSE
|
86
86
|
- README.md
|
87
87
|
- Rakefile
|
88
|
+
- SECURITY.md
|
88
89
|
- bench/.gitignore
|
89
90
|
- bench/app.rb
|
90
91
|
- bench/benchmark.rb
|
@@ -148,6 +149,7 @@ files:
|
|
148
149
|
- lib/elastic_apm/error/exception.rb
|
149
150
|
- lib/elastic_apm/error/log.rb
|
150
151
|
- lib/elastic_apm/error_builder.rb
|
152
|
+
- lib/elastic_apm/fields.rb
|
151
153
|
- lib/elastic_apm/grape.rb
|
152
154
|
- lib/elastic_apm/graphql.rb
|
153
155
|
- lib/elastic_apm/grpc.rb
|
@@ -193,6 +195,7 @@ files:
|
|
193
195
|
- lib/elastic_apm/span_helpers.rb
|
194
196
|
- lib/elastic_apm/spies.rb
|
195
197
|
- lib/elastic_apm/spies/action_dispatch.rb
|
198
|
+
- lib/elastic_apm/spies/azure_storage_table.rb
|
196
199
|
- lib/elastic_apm/spies/delayed_job.rb
|
197
200
|
- lib/elastic_apm/spies/dynamo_db.rb
|
198
201
|
- lib/elastic_apm/spies/elasticsearch.rb
|
@@ -254,7 +257,7 @@ licenses:
|
|
254
257
|
- Apache-2.0
|
255
258
|
metadata:
|
256
259
|
source_code_uri: https://github.com/elastic/apm-agent-ruby
|
257
|
-
post_install_message:
|
260
|
+
post_install_message:
|
258
261
|
rdoc_options: []
|
259
262
|
require_paths:
|
260
263
|
- lib
|
@@ -269,8 +272,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
269
272
|
- !ruby/object:Gem::Version
|
270
273
|
version: '0'
|
271
274
|
requirements: []
|
272
|
-
rubygems_version: 3.1
|
273
|
-
signing_key:
|
275
|
+
rubygems_version: 3.0.3.1
|
276
|
+
signing_key:
|
274
277
|
specification_version: 4
|
275
278
|
summary: The official Elastic APM agent for Ruby
|
276
279
|
test_files: []
|