elastic-apm 0.1.0 → 0.2.0

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.

Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +3 -0
  4. data/README.md +7 -1
  5. data/docs/api.asciidoc +210 -0
  6. data/docs/configuration.asciidoc +32 -0
  7. data/docs/context.asciidoc +27 -0
  8. data/docs/custom-instrumentation.asciidoc +14 -0
  9. data/docs/getting-started-rack.asciidoc +26 -0
  10. data/docs/getting-started-rails.asciidoc +13 -0
  11. data/docs/index.asciidoc +33 -0
  12. data/elastic-apm.gemspec +1 -0
  13. data/lib/elastic_apm.rb +54 -7
  14. data/lib/elastic_apm/agent.rb +20 -4
  15. data/lib/elastic_apm/config.rb +16 -3
  16. data/lib/elastic_apm/context.rb +22 -0
  17. data/lib/elastic_apm/context/request.rb +13 -0
  18. data/lib/elastic_apm/context/request/socket.rb +21 -0
  19. data/lib/elastic_apm/context/request/url.rb +44 -0
  20. data/lib/elastic_apm/context/response.rb +24 -0
  21. data/lib/elastic_apm/context/user.rb +26 -0
  22. data/lib/elastic_apm/context_builder.rb +93 -0
  23. data/lib/elastic_apm/error.rb +6 -3
  24. data/lib/elastic_apm/error_builder.rb +26 -10
  25. data/lib/elastic_apm/http.rb +4 -2
  26. data/lib/elastic_apm/injectors/action_dispatch.rb +1 -1
  27. data/lib/elastic_apm/instrumenter.rb +18 -0
  28. data/lib/elastic_apm/middleware.rb +15 -3
  29. data/lib/elastic_apm/naively_hashable.rb +21 -0
  30. data/lib/elastic_apm/process_info.rb +22 -0
  31. data/lib/elastic_apm/serializers/errors.rb +10 -3
  32. data/lib/elastic_apm/serializers/transactions.rb +4 -2
  33. data/lib/elastic_apm/service_info.rb +0 -3
  34. data/lib/elastic_apm/span/context.rb +2 -4
  35. data/lib/elastic_apm/stacktrace/frame.rb +2 -18
  36. data/lib/elastic_apm/transaction.rb +20 -7
  37. data/lib/elastic_apm/version.rb +1 -1
  38. metadata +20 -4
  39. data/lib/elastic_apm/error/context.rb +0 -119
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf4e0bb9099082e09c366d33a1a1e028ee4c4d9cd7f6eea76427471ea483e293
4
- data.tar.gz: 241dcd61a548362966a6899b1690f0aa7c7f4a4f13e72e0463d78eccab3af317
3
+ metadata.gz: 4e0d3d869c607c4a439fb2c19ae77c35572cadf74f34f6bb4c2075e393a00127
4
+ data.tar.gz: a126c14da9817c69b4b76ba17bd12521d865ea2b791b59ff978d0fa6bbafa256
5
5
  SHA512:
6
- metadata.gz: efdd3acfcc32adfbcad767bcb674ddb9441b84931a2511093a072292e718670cc744ee6bce660f54a4a9310389773a71477afa723af80608d81f337a46ba5b2f
7
- data.tar.gz: a6444edc4142d3dc5ef13c6a669efe147929c8dbc08fcca1247f69761796178c82d448fb0cc135dd1fc261befcebdd6dc8a7ad5b57e6de188b792b499c6b4d37
6
+ metadata.gz: c4951d4fce0cb88c5cb45006a24f272156785d2bf9558ce93b84b2756a178957dbb75149bf6a529e018845f626cdf581721750131227f095e09e06ed228ba208
7
+ data.tar.gz: 66407124c6987fffc19a0340a57cf781dc8655ca7385da04d3ebc08f4c1342195b7dce0b0c0e87ebbc1f79e81ec60697556fe1dfae7630ff9b893d8edd7c3edf
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  .rspec_status
12
12
 
13
13
  Gemfile.lock
14
+ /html_docs/
data/.rubocop.yml CHANGED
@@ -28,6 +28,9 @@ Naming/FileName:
28
28
  Exclude:
29
29
  - 'lib/elastic-apm.rb'
30
30
 
31
+ Naming/AccessorMethodName:
32
+ Enabled: false
33
+
31
34
  Style/Alias:
32
35
  Enabled: false
33
36
 
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # ElasticAPM (ALPHA)
1
+ # elastic-apm – Elastic APM agent for Ruby (ALPHA)
2
+
3
+ [![Jenkins](https://img.shields.io/jenkins/s/https/apm-ci.elastic.co/job/elastic+apm-agent-ruby+master.svg)](https://apm-ci.elastic.co/job/elastic+apm-agent-ruby+master/) [![Gem](https://img.shields.io/gem/v/formatador.svg?style=flat-square)](https://rubygems.org/gems/elastic-apm)
2
4
 
3
5
  This is the official Rubygem for adding [Elastic][]'s [APM][] to your Ruby app.
4
6
 
@@ -51,5 +53,9 @@ run MySinatraApp
51
53
  at_exit { ElasticAPM.stop }
52
54
  ```
53
55
 
56
+ # License
57
+
58
+ Apache 2.0
59
+
54
60
  [Elastic]: https://elastic.co
55
61
  [APM]: https://www.elastic.co/guide/en/apm/server/index.html
data/docs/api.asciidoc ADDED
@@ -0,0 +1,210 @@
1
+ [[api]]
2
+ == Public API
3
+
4
+ Although most usage is covered automatically when using the APM Agent it also has a public API that allows custom usage.
5
+
6
+ [float]
7
+ [[agent-life-cycle]]
8
+ === Agent life cycle
9
+
10
+ Controlling when the agent starts and stops.
11
+
12
+ [float]
13
+ [[api-start]]
14
+ ==== `ElasticAPM.start`
15
+
16
+ To create and start an ElasticAPM agent use `ElasticAPM.start`:
17
+
18
+ [source,ruby]
19
+ ----
20
+ ElasticAPM.start(server_url: 'http://localhost:8200')
21
+ ----
22
+
23
+ * `config`: A hash or `ElasticAPM::Config` instance with configuration options. See <<configuration,Configuration>>.
24
+
25
+ If you are using Rails this is done automatically for you.
26
+
27
+ **ElasticAPM expects a single instance of the Agent.**
28
+
29
+ [float]
30
+ [[api-stop]]
31
+ ==== `ElasticAPM.stop`
32
+
33
+ Stop the currently running agent. Use this inside `at_exit` in your <<getting-started-rack,Rack app>> to gracefully shut down.
34
+
35
+ [float]
36
+ [[api-running]]
37
+ ==== `ElasticAPM.running?`
38
+
39
+ Returns whether the ElasticAPM Agent is currently running.
40
+
41
+ [float]
42
+ [[api-agent]]
43
+ ==== `ElasticAPM.agent`
44
+
45
+ Returns the currently running agent or nil.
46
+
47
+ === Instrumentation
48
+
49
+ [float]
50
+ [[api-current-transaction]]
51
+ ==== `ElasticAPM.current_transaction`
52
+
53
+ Returns the current `ElasticAPM::Transaction` or nil.
54
+
55
+ [float]
56
+ [[api-transaction]]
57
+ ==== `ElasticAPM.transaction`
58
+
59
+ Start a _transaction_ eg. a web request or background job.
60
+
61
+ If called without a block you are expected to end and submit the transaction yourself.
62
+ If given a block, the code inside will be wrapped in a transaction. You still need to submit it yourself with `transaction.submit(status)`.
63
+
64
+ [source,ruby]
65
+ ----
66
+ transaction = ElasticAPM.transaction('Do things') do
67
+ # ...
68
+ end
69
+
70
+ transaction.submit(200)
71
+ ----
72
+
73
+ Arguments:
74
+
75
+ * `name`: A name for your transaction. Transactions are grouped by name. **Required**.
76
+ * `type`: A `type` for your transaction eg. `db.postgresql.sql`.
77
+ * `rack_env: env`: An optional Rack `env` used to enrich the transaction with information about the current request.
78
+ * `&block`: An optional block to wrap with the transaction. The block is passed the transaction as an optional argument.
79
+
80
+ Returns the transaction.
81
+
82
+ [float]
83
+ [[api-span]]
84
+ ==== `ElasticAPM.span`
85
+
86
+ Most transactions have nested spans signifying work of a specific sort eg. database queries or external web requests.
87
+
88
+ If given a block, wrap the code inside in a span. If not you are expected to close the span yourself with `span.done(result)`.
89
+
90
+ [source,ruby]
91
+ ----
92
+ ElasticAPM.transaction 'Do things' do
93
+ ElasticAPM.span 'Do one of the things' do
94
+ Database.query # ...
95
+ end
96
+ end
97
+ ----
98
+
99
+ Arguments:
100
+
101
+ * `name`: A name for your span. **Required**.
102
+ * `type`: The type of work eg. `db.postgresql.query`.
103
+ * `context`: An instance of `Span::Context`.
104
+ * `&block`: An optional block to wrap with the span. The block is passed the span as an optional argument.
105
+
106
+ Return the span or the return value of the given block.
107
+
108
+ [float]
109
+ [[api-build-context]]
110
+ ==== `ElasticAPM.build_context`
111
+
112
+ Build a new _Context_ from a Rack `env`.
113
+
114
+ A context provides information about the current request, response, user and more.
115
+
116
+ Arguments:
117
+
118
+ * `rack_env`: An instance of Rack::Env
119
+
120
+ Returns the built context.
121
+
122
+ === Errors
123
+
124
+ [float]
125
+ [[api-report]]
126
+ ==== `ElasticAPM.report`
127
+
128
+ Send an `Exception` to Elastic APM.
129
+
130
+ If reported inside a transaction, the context from that will be added.
131
+
132
+ [source,ruby]
133
+ ----
134
+ begin
135
+ do_a_thing_and_fail
136
+ rescue Exception => e
137
+ ElasticAPM.report(e)
138
+ end
139
+ ----
140
+
141
+ Arguments:
142
+
143
+ * `exception`: An instance of `Exception`. **Required**.
144
+ * `handled`: Whether the error was _handled_ eg. wasn't rescued and was represented to the user. Default: `true`.
145
+
146
+ Returns `[ElasticAPM::Error]`.
147
+
148
+ [float]
149
+ [[api-report-message]]
150
+ ==== `ElasticAPM.report_message`
151
+
152
+ Send a custom message to Elastic APM.
153
+
154
+ If reported inside a transaction, the context from that will be added.
155
+
156
+ [source,ruby]
157
+ ----
158
+ ElasticAPM.report_message('This should probably never happen?!')
159
+ ----
160
+
161
+ Arguments:
162
+
163
+ * `message`: A custom error string. **Required**.
164
+ * `handled`: Whether the error was _handled_ eg. wasn't rescued and was represented to the user. Default: `true`.
165
+
166
+ Returns `[ElasticAPM::Error]`.
167
+
168
+ === Context
169
+
170
+ [float]
171
+ [[api-set-tag]]
172
+ ==== `ElasticAPM.set_tag`
173
+
174
+ Add a tag to the current transaction. Tags are basic key-value pairs that are indexed in your Elasticsearch database and therefore searchable.
175
+
176
+ [source,ruby]
177
+ ----
178
+ before_action do
179
+ ElasticAPM.set_tag(company_id: current_user.company.id)
180
+ end
181
+ ----
182
+
183
+ Arguments:
184
+
185
+ * `key`: A string key.
186
+ * `value`: A string value.
187
+
188
+ Returns the set `value`.
189
+
190
+ [float]
191
+ [[api-set-custom-context]]
192
+ ==== `ElasticAPM.set_custom_context`
193
+
194
+ Add custom context to the current transaction. Use this to further specify a context that will help you track or diagnose what's going on inside your app.
195
+
196
+ If called several times during a transaction the custom context will be destructively merged with `merge!`.
197
+
198
+ [source,ruby]
199
+ ----
200
+ before_action do
201
+ ElasticAPM.set_custom_context(company: current_user.company.to_h)
202
+ end
203
+ ----
204
+
205
+ Arguments:
206
+
207
+ * `context`: A hash of JSON-compatible key-values. Can be nested.
208
+
209
+ Returns current custom context.
210
+
@@ -0,0 +1,32 @@
1
+ [[configuration]]
2
+ == Configuration
3
+
4
+ There are several ways to shape how Elastic APM behaves.
5
+
6
+ === Rails
7
+
8
+ The recommended way to configure Elastic APM for Rails is to create a file `config/elastic_apm.yml` and specify options in there:
9
+
10
+ [source,yaml]
11
+ ----
12
+ ---
13
+ server_url: 'http://localhost:8200'
14
+ secret_token: 'very_very_secret'
15
+ ----
16
+
17
+ === Sinatra and Rack
18
+
19
+ When using APM with Sinatra and Rack, you should configure it when starting the agent:
20
+
21
+ [source,ruby]
22
+ ----
23
+ ElasticAPM.start(
24
+ server_url: 'http://localhost:8200',
25
+ secret_token: 'very_very_secret'
26
+ )
27
+ ----
28
+
29
+ See <<getting-started-rack>>.
30
+
31
+ NOTE: This part of the documentation is still lacking. For full list of configuration options, see https://github.com/elastic/apm-agent-ruby/blob/master/lib/elastic_apm/config.rb.
32
+
@@ -0,0 +1,27 @@
1
+ [[context]]
2
+ === Adding additional context
3
+
4
+ ==== Adding custom context
5
+
6
+ You can add your own custom, nested JSON-compatible data to the current transaction using `ElasticAPM.add_custom_context(hash)` eg.:
7
+
8
+ [source,ruby]
9
+ ----
10
+ class ThingsController < ApplicationController
11
+ before_action do
12
+ ElasticAPM.add_custom_context(company: current_user.company)
13
+ end
14
+
15
+ # ...
16
+ end
17
+ ----
18
+
19
+ ==== Adding tags
20
+
21
+ Tags are special in that they are indexed in your Elasticsearch database and therefore searchable.
22
+
23
+ [source,ruby]
24
+ ----
25
+ ElasticAPM.set_tag(:company_name, 'Acme, Inc.')
26
+ ----
27
+
@@ -0,0 +1,14 @@
1
+ [[custom-instrumentation]]
2
+ === Custom instrumentation
3
+
4
+ When installed ElasticAPM will automatically wrap your app's request/responses in transactions and report its errors.
5
+
6
+ But it is possible to create your own transactions as well as provide spans for any automatic or custom transaction.
7
+
8
+ See <<api-transaction,`ElasticAPM.transaction`>> and <<api-span,`ElasticAPM.span`>>.
9
+
10
+ [[injectors]]
11
+ === Injectors -- automatic integrations with third-party libraries
12
+
13
+ ElasticAPM has built-in integrations for some popular libraries. Use `config.enabled_injectors` to add or remove specific integrations. See <<configuration,Configuration>>.
14
+
@@ -0,0 +1,26 @@
1
+ [[getting-started-rack]]
2
+ == Getting started with Rack
3
+
4
+ [source,ruby]
5
+ ----
6
+ # config.ru
7
+
8
+ require 'sinatra/base'
9
+
10
+ class MySinatraApp < Sinatra::Base
11
+ use ElasticAPM::Middleware
12
+
13
+ # ...
14
+ end
15
+
16
+ # Takes optional ElasticAPM::Config values
17
+ ElasticAPM.start(
18
+ app: MySinatraApp, # required
19
+ server_url: 'http://localhost:8200'
20
+ )
21
+
22
+ run MySinatraApp
23
+
24
+ at_exit { ElasticAPM.stop }
25
+ ----
26
+
@@ -0,0 +1,13 @@
1
+ [[getting-started-rails]]
2
+ == Getting started with Rails
3
+
4
+ === Setup
5
+
6
+ Add the gem to your `Gemfile`:
7
+
8
+ [source,ruby]
9
+ ----
10
+ gem 'elastic-apm'
11
+ ----
12
+
13
+ This automatically sets up error logging and performance tracking but of course there are knobs to turn if you'd like to. See <<configuration>>.
@@ -0,0 +1,33 @@
1
+ ifdef::env-github[]
2
+ NOTE: For the best reading experience, please view this documentation at https://www.elastic.co/guide/en/apm/agent/ruby[elastic.co]
3
+ endif::[]
4
+
5
+ = APM Ruby Agent Reference (Alpha)
6
+
7
+ == Introduction
8
+
9
+ The Elastic APM Ruby Agent sends performance metrics and error logs to an Elastic APM Server.
10
+
11
+ It has built-in support for <<getting-started-rails,Rails>> and other <<getting-started-rack,Rack-compatible>> applications.
12
+
13
+ This agent is one of several components you need to get started collecting APM data. See also:
14
+
15
+ * https://www.elastic.co/guide/en/apm/server/current/index.html[APM Server]
16
+ * https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html[Elasticsearch]
17
+
18
+ [[framework-support]]
19
+ The Elastic APM Ruby Agent officially supports <<getting-started-rails,Rails>> versions 4.x on onwards.
20
+
21
+ For Sinatra and other Rack compatible frameworks, see <<getting-started-rack,Getting started with Rack>>.
22
+
23
+ include::./getting-started-rails.asciidoc[]
24
+ include::./getting-started-rack.asciidoc[]
25
+ include::./configuration.asciidoc[]
26
+
27
+ [[advanced]]
28
+ == Advanced Topics
29
+ include::./context.asciidoc[]
30
+ include::./custom-instrumentation.asciidoc[]
31
+
32
+ include::./api.asciidoc[]
33
+
data/elastic-apm.gemspec CHANGED
@@ -10,6 +10,7 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = 'The official Elastic APM agent for Ruby'
12
12
  spec.homepage = 'https://github.com/elastic/apm-agent-ruby'
13
+ spec.metadata = { 'source_code_uri' => 'https://github.com/elastic/apm-agent-ruby' }
13
14
  spec.license = 'Apache-2.0'
14
15
  spec.required_ruby_version = ">= 2.0.0"
15
16
 
data/lib/elastic_apm.rb CHANGED
@@ -6,6 +6,7 @@ require 'elastic_apm/log'
6
6
  # Core
7
7
  require 'elastic_apm/agent'
8
8
  require 'elastic_apm/config'
9
+ require 'elastic_apm/context'
9
10
  require 'elastic_apm/instrumenter'
10
11
  require 'elastic_apm/internal_error'
11
12
  require 'elastic_apm/util'
@@ -57,10 +58,12 @@ module ElasticAPM
57
58
  # `ExamplesController#index`
58
59
  # @param type [String] The kind of the transaction, eg `app.request.get` or
59
60
  # `db.mysql2.query`
61
+ # @param context [Context] An optional [Context]
60
62
  # @yield [Transaction] Optional block encapsulating transaction
61
63
  # @return [Transaction] Unless block given
62
- def self.transaction(name, type = nil, &block)
63
- agent && agent.transaction(name, type, &block)
64
+ def self.transaction(name, type = nil, context: nil, &block)
65
+ return call_through(&block) unless agent
66
+ agent.transaction(name, type, context: context, &block)
64
67
  end
65
68
 
66
69
  # Starts a new span under the current Transaction
@@ -71,7 +74,17 @@ module ElasticAPM
71
74
  # @yield [Span] Optional block encapsulating span
72
75
  # @return [Span] Unless block given
73
76
  def self.span(name, type = nil, context: nil, &block)
74
- agent && agent.span(name, type, context: context, &block)
77
+ return call_through(&block) unless agent
78
+ agent.span(name, type, context: context, &block)
79
+ end
80
+
81
+ # Build a [Context] from a Rack `env`. The context may include information
82
+ # about the request, response, current user and more
83
+ #
84
+ # @param rack_env [Rack::Env] A Rack env
85
+ # @return [Context] The built context
86
+ def self.build_context(rack_env)
87
+ agent && agent.build_context(rack_env)
75
88
  end
76
89
 
77
90
  ### Errors
@@ -79,14 +92,48 @@ module ElasticAPM
79
92
  # Report and exception to APM
80
93
  #
81
94
  # @param exception [Exception] The exception
82
- # @param rack_env [Rack::Env] An optional Rack env
83
95
  # @param handled [Boolean] Whether the exception was rescued
84
- # @return [Error] An [Error] instance
85
- def self.report(exception, rack_env: nil, handled: true)
86
- agent && agent.report(exception, rack_env: rack_env, handled: handled)
96
+ # @return [Error] The generated [Error]
97
+ def self.report(exception, handled: true)
98
+ agent && agent.report(exception, handled: handled)
87
99
  end
88
100
 
101
+ # Report a custom string error message to APM
102
+ #
103
+ # @param message [String] The message
104
+ # @return [Error] The generated [Error]
89
105
  def self.report_message(message, **attrs)
90
106
  agent && agent.report_message(message, backtrace: caller, **attrs)
91
107
  end
108
+
109
+ ### Context
110
+
111
+ # Set a _tag_ value for the current transaction
112
+ #
113
+ # @param key [String,Symbol] A key
114
+ # @param value [Object] A value (will be converted to string)
115
+ # @return [Object] The given value
116
+ def self.set_tag(key, value)
117
+ agent && agent.set_tag(key, value)
118
+ end
119
+
120
+ # Provide further context for the current transaction
121
+ #
122
+ # @param custom [Hash] A hash with custom information. Can be nested.
123
+ # @return [Hash] The current custom context
124
+ def self.set_custom_context(custom)
125
+ agent && agent.set_custom_context(custom)
126
+ end
127
+
128
+ class << self
129
+ private
130
+
131
+ def call_through
132
+ unless agent
133
+ return yield if block_given?
134
+ end
135
+
136
+ nil
137
+ end
138
+ end
92
139
  end