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.

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