elastic-apm 0.1.0 → 0.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.
Potentially problematic release.
This version of elastic-apm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -0
- data/README.md +7 -1
- data/docs/api.asciidoc +210 -0
- data/docs/configuration.asciidoc +32 -0
- data/docs/context.asciidoc +27 -0
- data/docs/custom-instrumentation.asciidoc +14 -0
- data/docs/getting-started-rack.asciidoc +26 -0
- data/docs/getting-started-rails.asciidoc +13 -0
- data/docs/index.asciidoc +33 -0
- data/elastic-apm.gemspec +1 -0
- data/lib/elastic_apm.rb +54 -7
- data/lib/elastic_apm/agent.rb +20 -4
- data/lib/elastic_apm/config.rb +16 -3
- data/lib/elastic_apm/context.rb +22 -0
- data/lib/elastic_apm/context/request.rb +13 -0
- data/lib/elastic_apm/context/request/socket.rb +21 -0
- data/lib/elastic_apm/context/request/url.rb +44 -0
- data/lib/elastic_apm/context/response.rb +24 -0
- data/lib/elastic_apm/context/user.rb +26 -0
- data/lib/elastic_apm/context_builder.rb +93 -0
- data/lib/elastic_apm/error.rb +6 -3
- data/lib/elastic_apm/error_builder.rb +26 -10
- data/lib/elastic_apm/http.rb +4 -2
- data/lib/elastic_apm/injectors/action_dispatch.rb +1 -1
- data/lib/elastic_apm/instrumenter.rb +18 -0
- data/lib/elastic_apm/middleware.rb +15 -3
- data/lib/elastic_apm/naively_hashable.rb +21 -0
- data/lib/elastic_apm/process_info.rb +22 -0
- data/lib/elastic_apm/serializers/errors.rb +10 -3
- data/lib/elastic_apm/serializers/transactions.rb +4 -2
- data/lib/elastic_apm/service_info.rb +0 -3
- data/lib/elastic_apm/span/context.rb +2 -4
- data/lib/elastic_apm/stacktrace/frame.rb +2 -18
- data/lib/elastic_apm/transaction.rb +20 -7
- data/lib/elastic_apm/version.rb +1 -1
- metadata +20 -4
- data/lib/elastic_apm/error/context.rb +0 -119
data/lib/elastic_apm/http.rb
CHANGED
@@ -4,6 +4,7 @@ require 'net/http'
|
|
4
4
|
|
5
5
|
require 'elastic_apm/service_info'
|
6
6
|
require 'elastic_apm/system_info'
|
7
|
+
require 'elastic_apm/process_info'
|
7
8
|
|
8
9
|
module ElasticAPM
|
9
10
|
# @api private
|
@@ -19,6 +20,7 @@ module ElasticAPM
|
|
19
20
|
@adapter = adapter.new(config)
|
20
21
|
@base_payload = {
|
21
22
|
service: ServiceInfo.build(config),
|
23
|
+
process: ProcessInfo.build(config),
|
22
24
|
system: SystemInfo.build(config)
|
23
25
|
}
|
24
26
|
end
|
@@ -57,7 +59,7 @@ module ElasticAPM
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def url_for(path)
|
60
|
-
"#{@config.
|
62
|
+
"#{@config.server_url}#{path}"
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
@@ -97,7 +99,7 @@ module ElasticAPM
|
|
97
99
|
end
|
98
100
|
|
99
101
|
def server_uri
|
100
|
-
@uri ||= URI(@config.
|
102
|
+
@uri ||= URI(@config.server_url)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
end
|
@@ -13,6 +13,10 @@ module ElasticAPM
|
|
13
13
|
|
14
14
|
# @api private
|
15
15
|
class TransactionInfo
|
16
|
+
def initialize
|
17
|
+
self.current = nil
|
18
|
+
end
|
19
|
+
|
16
20
|
def current
|
17
21
|
Thread.current[KEY]
|
18
22
|
end
|
@@ -80,6 +84,14 @@ module ElasticAPM
|
|
80
84
|
transaction.span(*args, &block)
|
81
85
|
end
|
82
86
|
|
87
|
+
def set_tag(key, value)
|
88
|
+
transaction.context.tags[key] = value.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_custom_context(context)
|
92
|
+
transaction.context.custom.merge!(context)
|
93
|
+
end
|
94
|
+
|
83
95
|
def submit_transaction(transaction)
|
84
96
|
@pending_transactions << transaction
|
85
97
|
|
@@ -108,5 +120,11 @@ module ElasticAPM
|
|
108
120
|
|
109
121
|
true
|
110
122
|
end
|
123
|
+
|
124
|
+
def inspect
|
125
|
+
'<ElasticAPM::Instrumenter ' \
|
126
|
+
"current_transaction=#{current_transaction.inspect}" \
|
127
|
+
'>'
|
128
|
+
end
|
111
129
|
end
|
112
130
|
end
|
@@ -10,13 +10,16 @@ module ElasticAPM
|
|
10
10
|
# rubocop:disable Metrics/MethodLength
|
11
11
|
def call(env)
|
12
12
|
begin
|
13
|
-
transaction = ElasticAPM.transaction 'Rack',
|
13
|
+
transaction = ElasticAPM.transaction 'Rack', type_for(env),
|
14
|
+
context: ElasticAPM.build_context(env)
|
15
|
+
|
14
16
|
resp = @app.call env
|
15
|
-
|
17
|
+
|
18
|
+
transaction.submit(resp[0], headers: resp[1]) if transaction
|
16
19
|
rescue InternalError
|
17
20
|
raise # Don't report ElasticAPM errors
|
18
21
|
rescue ::Exception => e
|
19
|
-
ElasticAPM.report(e,
|
22
|
+
ElasticAPM.report(e, handled: false)
|
20
23
|
transaction.submit(500) if transaction
|
21
24
|
raise
|
22
25
|
ensure
|
@@ -26,5 +29,14 @@ module ElasticAPM
|
|
26
29
|
resp
|
27
30
|
end
|
28
31
|
# rubocop:enable Metrics/MethodLength
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def type_for(env)
|
36
|
+
format(
|
37
|
+
'request.%s'.freeze,
|
38
|
+
env.fetch('REQUEST_METHOD'.freeze, 'unknown'.freeze)
|
39
|
+
)
|
40
|
+
end
|
29
41
|
end
|
30
42
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module NaivelyHashable
|
6
|
+
def naively_hashable?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
instance_variables.each_with_object({}) do |name, h|
|
12
|
+
key = name.to_s.delete('@').to_sym
|
13
|
+
value = instance_variable_get(name)
|
14
|
+
is_hashable =
|
15
|
+
value.respond_to?(:naively_hashable?) && value.naively_hashable?
|
16
|
+
|
17
|
+
h[key] = is_hashable ? value.to_h : value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
class ProcessInfo
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def build
|
11
|
+
{
|
12
|
+
argv: ARGV,
|
13
|
+
pid: $PID,
|
14
|
+
title: $PROGRAM_NAME
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.build(config)
|
19
|
+
new(config).build
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,19 +4,26 @@ module ElasticAPM
|
|
4
4
|
module Serializers
|
5
5
|
# @api private
|
6
6
|
class Errors < Serializer
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
7
8
|
def build(error)
|
8
9
|
base = {
|
9
|
-
id:
|
10
|
+
id: error.id,
|
10
11
|
culprit: error.culprit,
|
11
|
-
timestamp: micros_to_time(error.timestamp).utc.iso8601
|
12
|
+
timestamp: micros_to_time(error.timestamp).utc.iso8601,
|
13
|
+
context: error.context.to_h
|
12
14
|
}
|
13
15
|
|
14
16
|
if (exception = error.exception)
|
15
17
|
base[:exception] = build_exception exception
|
16
18
|
end
|
17
19
|
|
20
|
+
if (transaction_id = error.transaction_id)
|
21
|
+
base[:transaction] = { id: transaction_id }
|
22
|
+
end
|
23
|
+
|
18
24
|
base
|
19
25
|
end
|
26
|
+
# rubocop:enable Metrics/MethodLength
|
20
27
|
|
21
28
|
def build_all(errors)
|
22
29
|
{ errors: Array(errors).map(&method(:build)) }
|
@@ -32,7 +39,7 @@ module ElasticAPM
|
|
32
39
|
code: exception.code,
|
33
40
|
attributes: exception.attributes,
|
34
41
|
stacktrace: exception.stacktrace.to_a,
|
35
|
-
|
42
|
+
handled: exception.handled
|
36
43
|
}
|
37
44
|
end
|
38
45
|
end
|
@@ -7,7 +7,7 @@ module ElasticAPM
|
|
7
7
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
8
8
|
def build(transaction)
|
9
9
|
{
|
10
|
-
id:
|
10
|
+
id: transaction.id,
|
11
11
|
name: transaction.name,
|
12
12
|
type: transaction.type,
|
13
13
|
result: transaction.result.to_s,
|
@@ -23,7 +23,9 @@ module ElasticAPM
|
|
23
23
|
duration: ms(span.duration),
|
24
24
|
context: span.context && { db: span.context.to_h }
|
25
25
|
}
|
26
|
-
end
|
26
|
+
end,
|
27
|
+
sampled: transaction.sampled,
|
28
|
+
context: transaction.context.to_h
|
27
29
|
}
|
28
30
|
end
|
29
31
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
@@ -4,6 +4,8 @@ module ElasticAPM
|
|
4
4
|
class Span
|
5
5
|
# @api private
|
6
6
|
class Context
|
7
|
+
include NaivelyHashable
|
8
|
+
|
7
9
|
def initialize(**args)
|
8
10
|
args.each do |key, val|
|
9
11
|
send(:"#{key}=", val)
|
@@ -11,10 +13,6 @@ module ElasticAPM
|
|
11
13
|
end
|
12
14
|
|
13
15
|
attr_accessor :instance, :statement, :type, :user
|
14
|
-
|
15
|
-
def to_h
|
16
|
-
{ instance: instance, statement: statement, type: type, user: user }
|
17
|
-
end
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -4,6 +4,8 @@ module ElasticAPM
|
|
4
4
|
class Stacktrace
|
5
5
|
# @api private
|
6
6
|
class Frame
|
7
|
+
include NaivelyHashable
|
8
|
+
|
7
9
|
attr_accessor(
|
8
10
|
:abs_path,
|
9
11
|
:filename,
|
@@ -32,24 +34,6 @@ module ElasticAPM
|
|
32
34
|
end
|
33
35
|
# rubocop:enable Metrics/AbcSize
|
34
36
|
|
35
|
-
# rubocop:disable Metrics/MethodLength
|
36
|
-
def to_h
|
37
|
-
{
|
38
|
-
abs_path: abs_path,
|
39
|
-
filename: filename,
|
40
|
-
function: function,
|
41
|
-
vars: vars,
|
42
|
-
pre_context: pre_context,
|
43
|
-
context_line: context_line,
|
44
|
-
post_context: post_context,
|
45
|
-
in_app: in_app,
|
46
|
-
lineno: lineno,
|
47
|
-
module: self.module,
|
48
|
-
coln: colno
|
49
|
-
}
|
50
|
-
end
|
51
|
-
# rubocop:enable Metrics/MethodLength
|
52
|
-
|
53
37
|
private
|
54
38
|
|
55
39
|
def read_lines(path)
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module ElasticAPM
|
4
4
|
# @api private
|
5
5
|
class Transaction
|
6
|
-
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
7
|
+
def initialize(instrumenter, name, type = 'custom', context: nil)
|
8
|
+
@id = SecureRandom.uuid
|
7
9
|
@instrumenter = instrumenter
|
8
10
|
@name = name
|
9
11
|
@type = type
|
@@ -16,20 +18,25 @@ module ElasticAPM
|
|
16
18
|
|
17
19
|
@notifications = [] # for AS::Notifications
|
18
20
|
|
21
|
+
@context = context || Context.new
|
22
|
+
|
23
|
+
@sampled = true
|
24
|
+
|
19
25
|
yield self if block_given?
|
20
26
|
end
|
27
|
+
# rubocop:enable Metrics/MethodLength
|
21
28
|
|
22
|
-
attr_accessor :name, :result, :type
|
23
|
-
attr_reader :duration, :root_span, :timestamp, :spans,
|
29
|
+
attr_accessor :id, :name, :result, :type
|
30
|
+
attr_reader :context, :duration, :root_span, :timestamp, :spans,
|
31
|
+
:notifications, :sampled
|
24
32
|
|
25
33
|
def release
|
26
34
|
@instrumenter.current_transaction = nil
|
27
35
|
end
|
28
36
|
|
29
37
|
def done(result = nil)
|
30
|
-
@result = result
|
31
|
-
|
32
38
|
@duration = Util.micros - @timestamp
|
39
|
+
@result = result
|
33
40
|
|
34
41
|
self
|
35
42
|
end
|
@@ -38,8 +45,10 @@ module ElasticAPM
|
|
38
45
|
!!(@result && @duration)
|
39
46
|
end
|
40
47
|
|
41
|
-
def submit(
|
42
|
-
done
|
48
|
+
def submit(status = nil, headers: {})
|
49
|
+
done status
|
50
|
+
|
51
|
+
context.response = Context::Response.new(status, headers: headers)
|
43
52
|
|
44
53
|
release
|
45
54
|
|
@@ -72,6 +81,10 @@ module ElasticAPM
|
|
72
81
|
spans.reverse.lazy.find(&:running?)
|
73
82
|
end
|
74
83
|
|
84
|
+
def inspect
|
85
|
+
"<ElasticAPM::Transaction id:#{id}>"
|
86
|
+
end
|
87
|
+
|
75
88
|
private
|
76
89
|
|
77
90
|
def next_span_id
|
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.2.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:
|
11
|
+
date: 2018-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -43,13 +43,26 @@ files:
|
|
43
43
|
- bin/console
|
44
44
|
- bin/setup
|
45
45
|
- bin/with_framework
|
46
|
+
- docs/api.asciidoc
|
47
|
+
- docs/configuration.asciidoc
|
48
|
+
- docs/context.asciidoc
|
49
|
+
- docs/custom-instrumentation.asciidoc
|
50
|
+
- docs/getting-started-rack.asciidoc
|
51
|
+
- docs/getting-started-rails.asciidoc
|
52
|
+
- docs/index.asciidoc
|
46
53
|
- elastic-apm.gemspec
|
47
54
|
- lib/elastic-apm.rb
|
48
55
|
- lib/elastic_apm.rb
|
49
56
|
- lib/elastic_apm/agent.rb
|
50
57
|
- lib/elastic_apm/config.rb
|
58
|
+
- lib/elastic_apm/context.rb
|
59
|
+
- lib/elastic_apm/context/request.rb
|
60
|
+
- lib/elastic_apm/context/request/socket.rb
|
61
|
+
- lib/elastic_apm/context/request/url.rb
|
62
|
+
- lib/elastic_apm/context/response.rb
|
63
|
+
- lib/elastic_apm/context/user.rb
|
64
|
+
- lib/elastic_apm/context_builder.rb
|
51
65
|
- lib/elastic_apm/error.rb
|
52
|
-
- lib/elastic_apm/error/context.rb
|
53
66
|
- lib/elastic_apm/error/exception.rb
|
54
67
|
- lib/elastic_apm/error/log.rb
|
55
68
|
- lib/elastic_apm/error_builder.rb
|
@@ -66,10 +79,12 @@ files:
|
|
66
79
|
- lib/elastic_apm/internal_error.rb
|
67
80
|
- lib/elastic_apm/log.rb
|
68
81
|
- lib/elastic_apm/middleware.rb
|
82
|
+
- lib/elastic_apm/naively_hashable.rb
|
69
83
|
- lib/elastic_apm/normalizers.rb
|
70
84
|
- lib/elastic_apm/normalizers/action_controller.rb
|
71
85
|
- lib/elastic_apm/normalizers/action_view.rb
|
72
86
|
- lib/elastic_apm/normalizers/active_record.rb
|
87
|
+
- lib/elastic_apm/process_info.rb
|
73
88
|
- lib/elastic_apm/railtie.rb
|
74
89
|
- lib/elastic_apm/serializers.rb
|
75
90
|
- lib/elastic_apm/serializers/errors.rb
|
@@ -92,7 +107,8 @@ files:
|
|
92
107
|
homepage: https://github.com/elastic/apm-agent-ruby
|
93
108
|
licenses:
|
94
109
|
- Apache-2.0
|
95
|
-
metadata:
|
110
|
+
metadata:
|
111
|
+
source_code_uri: https://github.com/elastic/apm-agent-ruby
|
96
112
|
post_install_message:
|
97
113
|
rdoc_options: []
|
98
114
|
require_paths:
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ElasticAPM
|
4
|
-
class Error
|
5
|
-
# @api private
|
6
|
-
class Context
|
7
|
-
# @api private
|
8
|
-
class Request
|
9
|
-
def initialize
|
10
|
-
@socket = {}
|
11
|
-
@headers = {}
|
12
|
-
@cookies = {}
|
13
|
-
@env = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
attr_accessor(
|
17
|
-
:socket,
|
18
|
-
:http_version,
|
19
|
-
:method,
|
20
|
-
:url,
|
21
|
-
:headers,
|
22
|
-
:cookies,
|
23
|
-
:env,
|
24
|
-
:body
|
25
|
-
)
|
26
|
-
|
27
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
28
|
-
def add_rack_env(rack_env)
|
29
|
-
req = rails_req?(rack_env) ? rack_env : Rack::Request.new(rack_env)
|
30
|
-
|
31
|
-
self.socket = {
|
32
|
-
remote_address: req.ip,
|
33
|
-
encrypted: req.scheme == 'https'
|
34
|
-
}
|
35
|
-
http_version = rack_env['HTTP_VERSION']
|
36
|
-
self.http_version =
|
37
|
-
http_version && http_version.gsub(%r{HTTP/}, '')
|
38
|
-
self.method = req.request_method
|
39
|
-
self.url = {
|
40
|
-
protocol: req.scheme,
|
41
|
-
hostname: req.host,
|
42
|
-
port: req.port,
|
43
|
-
pathname: req.path,
|
44
|
-
search: req.query_string,
|
45
|
-
hash: nil,
|
46
|
-
raw: req.fullpath
|
47
|
-
}
|
48
|
-
|
49
|
-
add_headers(rack_env)
|
50
|
-
add_body(req)
|
51
|
-
|
52
|
-
self
|
53
|
-
end
|
54
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
55
|
-
|
56
|
-
def self.from_rack_env(rack_env)
|
57
|
-
request = new
|
58
|
-
request.add_rack_env rack_env
|
59
|
-
request
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def add_body(req)
|
65
|
-
if req.form_data?
|
66
|
-
self.body = req.POST
|
67
|
-
else
|
68
|
-
self.body = req.body.read
|
69
|
-
req.body.rewind
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def rails_req?(env)
|
74
|
-
defined?(ActionDispatch::Request) &&
|
75
|
-
env.is_a?(ActionDispatch::Request)
|
76
|
-
end
|
77
|
-
|
78
|
-
def add_headers(rack_env)
|
79
|
-
get_headers(rack_env).each do |key, value|
|
80
|
-
next unless key.upcase == key
|
81
|
-
|
82
|
-
if key.start_with?('HTTP_')
|
83
|
-
headers[camel_key(key)] = value
|
84
|
-
else
|
85
|
-
env[key] = value
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def camel_key(key)
|
91
|
-
key.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
|
92
|
-
end
|
93
|
-
|
94
|
-
def get_headers(rack_env)
|
95
|
-
# In Rails < 5 ActionDispatch::Request inherits from Hash
|
96
|
-
rack_env.respond_to?(:headers) ? rack_env.headers : rack_env
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# @api private
|
101
|
-
class Response
|
102
|
-
attr_accessor(
|
103
|
-
:status_code,
|
104
|
-
:headers,
|
105
|
-
:headers_sent,
|
106
|
-
:finished
|
107
|
-
)
|
108
|
-
end
|
109
|
-
|
110
|
-
attr_accessor(
|
111
|
-
:request,
|
112
|
-
:response,
|
113
|
-
:user,
|
114
|
-
:tags,
|
115
|
-
:custom
|
116
|
-
)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|