elastic-apm 2.10.1 → 2.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dbd55033ad5acde5c178afb8af7e3c49aea9e64391901ddd571e6eb4a5db139
4
- data.tar.gz: 0c117a6853b5e54af3f1ad2b42e0ff99e4d061c95da66a89ee35f525b7d11fd0
3
+ metadata.gz: 45fe1b55dccff365970dd59f2a4f58d9cb76141fd3651e7ce9c166b796bfce0a
4
+ data.tar.gz: 66a2df97b05471613e7d1b5eecdb739ccbf94514b15730cb065153c7128503da
5
5
  SHA512:
6
- metadata.gz: 4e5a48afa71841e62e52917e71d6201b68d4b7d36636b93e5b0076999e5a6b13a31f6dac0f39501245122d143497648dafef50fa02a15a30dc767482b4a1181d
7
- data.tar.gz: 671f26c821de9e4090aef5f1af8855729d86f4b3b1ef824d3f5114231e9ecb34ef2e1aa81cb9b84ffcfab7a307418bf95a90df4e034075c5d9bc56798344b31c
6
+ metadata.gz: e542f184535be90fee811ceee0fd404f65b59575b0e90a8dc8023807ec5b535f9d1c084b7654f5c59fed9d5521a2cbf5f2bd70dac8691db009be1dd24b07be5f
7
+ data.tar.gz: 7d87ebdbbfc32727017f6f0fa8451640ac3fef289366bc3a077899d874bb346a3b94dbadafe96596f2b1a8163c42d79b1b41ce940c6e1fd8fb358fc96767ca84
data/.ci/Jenkinsfile CHANGED
@@ -23,6 +23,7 @@ pipeline {
23
23
  DOCKER_SECRET = 'secret/apm-team/ci/docker-registry/prod'
24
24
  GITHUB_CHECK_ITS_NAME = 'Integration Tests'
25
25
  ITS_PIPELINE = 'apm-integration-tests-selector-mbp/master'
26
+ RELEASE_SECRET = 'secret/apm-team/ci/apm-agent-ruby-rubygems-release'
26
27
  }
27
28
  options {
28
29
  timeout(time: 2, unit: 'HOURS')
@@ -178,6 +179,39 @@ pipeline {
178
179
  githubNotify(context: "${env.GITHUB_CHECK_ITS_NAME}", description: "${env.GITHUB_CHECK_ITS_NAME} ...", status: 'PENDING', targetUrl: "${env.JENKINS_URL}search/?q=${env.ITS_PIPELINE.replaceAll('/','+')}")
179
180
  }
180
181
  }
182
+ stage('Release') {
183
+ options { skipDefaultCheckout() }
184
+ environment {
185
+ RUBY_DOCKER_TAG = 'ruby:2.6'
186
+ }
187
+ when {
188
+ beforeAgent true
189
+ anyOf {
190
+ tag pattern: 'v\\d+.*', comparator: 'REGEXP'
191
+ }
192
+ }
193
+ steps {
194
+ withGithubNotify(context: 'Release') {
195
+ deleteDir()
196
+ unstash 'source'
197
+ script {
198
+ dir(BASE_DIR){
199
+ docker.image("${env.RUBY_DOCKER_TAG}").inside('-v /etc/passwd:/etc/passwd -v ${HOME}/.ssh:${HOME}/.ssh') {
200
+ withEnv(["HOME=${env.WORKSPACE}/${env.BASE_DIR ?: ''}"]) {
201
+ rubygemsLogin.withApi(secret: "${env.RELEASE_SECRET}") {
202
+ sshagent(['f6c7695a-671e-4f4f-a331-acdce44ff9ba']) {
203
+ sh '.ci/prepare-git-context.sh'
204
+ sh 'gem install rake yard rspec'
205
+ sh 'rake release'
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
181
215
  }
182
216
  post {
183
217
  cleanup {
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ set -exo pipefail
3
+
4
+ # Enable git+ssh. Env variables are created on the fly with the gitCheckout
5
+ git config remote.origin.url "git@github.com:${ORG_NAME}/${REPO_NAME}.git"
6
+
7
+ # Enable to fetch branches when cloning with a detached and shallow clone
8
+ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
9
+
10
+ # Force the git user details when pushing using the last commit details
11
+ USER_MAIL=$(git log -1 --pretty=format:'%ae')
12
+ USER_NAME=$(git log -1 --pretty=format:'%an')
13
+ git config --global user.email "${USER_MAIL}"
14
+ git config --global user.name "${USER_NAME}"
15
+
16
+ # Checkout the branch as it's detached based by default.
17
+ # See https://issues.jenkins-ci.org/browse/JENKINS-33171
18
+ git fetch --all
19
+ git checkout "${BRANCH_NAME}"
20
+
21
+ # Ensure the master branch points to the original commit to avoid commit injection
22
+ # when running the release pipeline.
23
+ git reset --hard "${GIT_COMMIT}"
data/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 2.11.0 (2019-09-23)
8
+
9
+ ### Added
10
+
11
+ - Add `Rails` module with `#start` method to run Rails setup explicitly ([#522](https://github.com/elastic/apm-agent-ruby/pull/522))
12
+ - Support for log/trace correlation ([#527](https://github.com/elastic/apm-agent-ruby/pull/527))
13
+
14
+ ### Changed
15
+
16
+ - Split dot-separated `span.type` into `.type`, `.subtype` and `.action` (auto-upgrades dot style) ([#531](https://github.com/elastic/apm-agent-ruby/pull/531))
17
+
7
18
  ## 2.10.1
8
19
 
9
20
  ### Fixed
@@ -11,11 +22,14 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
11
22
  - Fixed loading options from a config file specified by `ELASTIC_APM_CONFIG_FILE` ([#518](https://github.com/elastic/apm-agent-ruby/pull/518))
12
23
  - Fixed an issue with CentralConfig polling not starting ([#525](https://github.com/elastic/apm-agent-ruby/pull/525))
13
24
 
25
+ ### Added
26
+
27
+ - Support for chained exceptions ([#488](https://github.com/elastic/apm-agent-ruby/pull/488))
28
+
14
29
  ## 2.10.0
15
30
 
16
31
  ### Added
17
32
 
18
- - Support for chained exceptions ([#488](https://github.com/elastic/apm-agent-ruby/pull/488))
19
33
  - Add Ruby specific metrics ([#437](https://github.com/elastic/apm-agent-ruby/pull/437))
20
34
  - Support for APM Agent Configuration via Kibana ([#464](https://github.com/elastic/apm-agent-ruby/pull/464))
21
35
  - Change span name format and add command to context's db.statement for `MongoSpy` ([#488](https://github.com/elastic/apm-agent-ruby/pull/490))
data/docs/api.asciidoc CHANGED
@@ -30,9 +30,10 @@ ElasticAPM.start(server_url: 'http://localhost:8200')
30
30
  * `config`: An optional hash or `ElasticAPM::Config` instance with configuration
31
31
  options. See <<configuration,Configuration>>.
32
32
 
33
- If you are using <<getting-started-rails,Ruby on Rails>> this is done
34
- automatically for you.
35
- If not see <<getting-started-rack,Getting started with Rack>>.
33
+ If you are using <<getting-started-rails,Ruby on Rails>> this is done automatically for you.
34
+ If you choose not to require the `elastic_apm` gem and instead want to start the
35
+ agent and hook into Rails manually, see <<rails-start,hooking into Rails explicitly>>.
36
+ If you're not using Rails, see <<getting-started-rack,Getting started with Rack>>.
36
37
 
37
38
  [float]
38
39
  [[api-agent-stop]]
@@ -140,7 +141,9 @@ end
140
141
  Arguments:
141
142
 
142
143
  * `name`: A name for your span. **Required**.
143
- * `type`: The type of work eg. `db.postgresql.query`.
144
+ * `type`: The type of span eg. `db`.
145
+ * `subtype`: The subtype of span eg. `postgresql`.
146
+ * `action`: The action type of span eg. `connect` or `query`.
144
147
  * `context`: An instance of `Span::Context`.
145
148
  * `include_stacktrace`: Whether or not to collect a Stacktrace.
146
149
  * `&block`: An optional block to wrap with the span.
@@ -163,7 +166,9 @@ Wraps a block in a Span.
163
166
  Arguments:
164
167
 
165
168
  * `name`: A name for your span. **Required**.
166
- * `type`: The type of work eg. `db.postgresql.query`.
169
+ * `type`: The type of span eg. `db`.
170
+ * `subtype`: The subtype of span eg. `postgresql`.
171
+ * `action`: The action type of span eg. `connect` or `query`.
167
172
  * `context`: An instance of `Span::Context`.
168
173
  * `include_stacktrace`: Whether or not to collect a Stacktrace.
169
174
  * `&block`: An optional block to wrap with the span.
@@ -186,6 +191,18 @@ Arguments:
186
191
 
187
192
  Returns the built context.
188
193
 
194
+ [float]
195
+ [[rails-start]]
196
+ === Manually hooking into Rails
197
+
198
+ Start the agent and hook into Rails explicitly. This is useful if you skip requiring
199
+ the gem and using the `Railtie`.
200
+
201
+ [source,ruby]
202
+ ----
203
+ ElasticAPM::Rails.start(server_url: 'http://localhost:8200')
204
+ ----
205
+
189
206
  [float]
190
207
  === Errors
191
208
 
data/docs/index.asciidoc CHANGED
@@ -18,6 +18,8 @@ include::./getting-started-rack.asciidoc[]
18
18
 
19
19
  include::./configuration.asciidoc[]
20
20
 
21
+ include::./log-correlation.asciidoc[]
22
+
21
23
  include::./metrics.asciidoc[]
22
24
 
23
25
  include::./advanced.asciidoc[]
@@ -0,0 +1,96 @@
1
+ ifdef::env-github[]
2
+ NOTE: For the best reading experience,
3
+ please view this documentation at https://www.elastic.co/guide/en/apm/agent/ruby[elastic.co]
4
+ endif::[]
5
+
6
+ [[log-correlation]]
7
+ == Log correlation
8
+
9
+ Trace/log correlation can be set up in three different ways.
10
+
11
+ [float]
12
+ [[rails-tagged-logging]]
13
+ ==== Rails TaggedLogging
14
+
15
+ Rails applications configured with an `ActiveSupport::TaggedLogging` logger can append the correlation IDs to log output.
16
+ For example in your `config/environments/production.rb` file, add the following:
17
+
18
+ [source,ruby]
19
+ ----
20
+ config.log_tags = [ :request_id, proc { ElasticAPM.log_ids } ]
21
+
22
+ # Logs will then include the correlation IDs:
23
+ #
24
+ # [transaction.id=c1ae84c8642891eb trace.id=b899fc7915e801b7558e336e4952bafe] Started GET "/" for 127.0.0.1 at 2019-09-16 11:28:46 +0200
25
+ # [transaction.id=c1ae84c8642891eb trace.id=b899fc7915e801b7558e336e4952bafe] Processing by ApplicationController#index as HTML
26
+ # [transaction.id=c1ae84c8642891eb trace.id=b899fc7915e801b7558e336e4952bafe] Rendering text template
27
+ # [transaction.id=c1ae84c8642891eb trace.id=b899fc7915e801b7558e336e4952bafe] Rendered text template (Duration: 0.1ms | Allocations: 17)
28
+ # [transaction.id=c1ae84c8642891eb trace.id=b899fc7915e801b7558e336e4952bafe] Completed 200 OK in 1ms (Views: 0.4ms | Allocations: 171)
29
+ ----
30
+ **Note:** Because of the order in which Rails computes the tags for logs and executes the request, the span id might not be included.
31
+ Consider using `Lograge` instead, as the timing of its hooks allow the span id to be captured in logs.
32
+
33
+ [float]
34
+ [[lograge]]
35
+ ==== Lograge
36
+
37
+ With `lograge` enabled and set up in your Rails application, modify the `custom_options` block in the Rails environment
38
+ configuration file. The returned `Hash` will be included in the structured Lograge logs.
39
+
40
+ [source,ruby]
41
+ ----
42
+ config.lograge.custom_options = lambda do |event|
43
+ ElasticAPM.log_ids do |transaction_id, span_id, trace_id|
44
+ { :'transaction.id' => transaction_id,
45
+ :'span.id' => span_id,
46
+ :'trace.id' => trace_id }
47
+ end
48
+ end
49
+
50
+ # Logs will then include the correlation IDs:
51
+ #
52
+ # I, [2019-09-16T11:59:05.439602 #8674] INFO -- : method=GET path=/ format=html controller=ApplicationController action=index status=200 duration=0.36 view=0.20 transaction.id=56a9186a9257aa08 span.id=8e84a786ab0abbb2 trace.id=1bbab8ac4c7c9584f53eb882ff0dfdd8
53
+ ----
54
+
55
+ You can also nest the ids in a separate document as in the following example:
56
+
57
+ [source,ruby]
58
+ ----
59
+ config.lograge.custom_options = lambda do |event|
60
+ ElasticAPM.log_ids do |transaction_id, span_id, trace_id|
61
+ { elastic_apm: { :'transaction.id' => transaction_id,
62
+ :'span.id' => span_id,
63
+ :'trace.id' => trace_id } }
64
+ end
65
+ end
66
+
67
+ # Logs will then include the correlation IDs in a separate document:
68
+ #
69
+ # I, [2019-09-16T13:39:35.962603 #9327] INFO -- : method=GET path=/ format=html controller=ApplicationController action=index status=200 duration=0.37 view=0.20 elastic_apm={:transaction_id=>"2fb84f5d0c48a296", :span_id=>"2e5c5a7c85f83be7", :trace_id=>"43e1941c4a6fff343a4e018ff7b92000"}
70
+ ----
71
+
72
+ [float]
73
+ [[manually-formatting-logs]]
74
+ ==== Manually formatting logs
75
+
76
+ You can access the correlation ids directly and add them through the log formatter.
77
+
78
+ [source,ruby]
79
+ ----
80
+ require 'elastic_apm'
81
+ require 'logger'
82
+
83
+ logger = Logger.new(STDOUT)
84
+ logger.progname = 'TestRubyApp'
85
+ logger.formatter = proc do |severity, datetime, progname, msg|
86
+ "[#{datetime}][#{progname}][#{severity}][#{ElasticAPM.log_ids}] #{msg}\n"
87
+ end
88
+
89
+ # Logs will then include the correlation IDs:
90
+ #
91
+ # [2019-09-16 11:54:59 +0200][RailsTestApp][INFO][transaction.id=3b92edcccc0a6d1e trace.id=1275686e35de91f776557637e799651e] Started GET "/" for 127.0.0.1 at 2019-09-16 11:54:59 +0200
92
+ # [2019-09-16 11:54:59 +0200][RailsTestApp][INFO][transaction.id=3b92edcccc0a6d1e trace.id=1275686e35de91f776557637e799651e] Processing by ApplicationController#index as HTML
93
+ # [2019-09-16 11:54:59 +0200][RailsTestApp][INFO][transaction.id=3b92edcccc0a6d1e span.id=3bde4e9c85ab359c trace.id=1275686e35de91f776557637e799651e] Rendering text template
94
+ # [2019-09-16 11:54:59 +0200][RailsTestApp][INFO][transaction.id=3b92edcccc0a6d1e span.id=f3d7e32f176d4c93 trace.id=1275686e35de91f776557637e799651e] Rendered text template (Duration: 0.1ms | Allocations: 17)
95
+ # [2019-09-16 11:54:59 +0200][RailsTestApp][INFO][transaction.id=3b92edcccc0a6d1e span.id=3bde4e9c85ab359c trace.id=1275686e35de91f776557637e799651e] Completed 200 OK in 1ms (Views: 0.3ms | Allocations: 187)
96
+ ----
data/lib/elastic_apm.rb CHANGED
@@ -62,6 +62,26 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
62
62
  agent&.current_span
63
63
  end
64
64
 
65
+ # rubocop:disable Metrics/AbcSize
66
+ # Get a formatted string containing transaction, span, and trace ids.
67
+ # If a block is provided, the ids are yielded.
68
+ #
69
+ # @yield [String|nil, String|nil, String|nil] The transaction, span, and trace ids.
70
+ # @return [String] Unless block given
71
+ def log_ids
72
+ trace_id = (current_transaction || current_span)&.trace_id
73
+ if block_given?
74
+ return yield(current_transaction&.id, current_span&.id, trace_id)
75
+ end
76
+
77
+ ids = []
78
+ ids << "transaction.id=#{current_transaction.id}" if current_transaction
79
+ ids << "span.id=#{current_span.id}" if current_span
80
+ ids << "trace.id=#{trace_id}" if trace_id
81
+ ids.join(' ')
82
+ end
83
+ # rubocop:enable Metrics/AbcSize
84
+
65
85
  # Start a new transaction or return the currently running
66
86
  #
67
87
  # @param name [String] A description of the transaction, eg
@@ -207,16 +227,21 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
207
227
 
208
228
  deprecate :span, :with_span
209
229
 
230
+ # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
210
231
  # Start a new span
211
232
  #
212
233
  # @param name [String] A description of the span, eq `SELECT FROM "users"`
213
- # @param type [String] The kind of span, eq `db.mysql2.query`
234
+ # @param type [String] The span type, eq `db`
235
+ # @param subtype [String] The span subtype, eq `postgresql`
236
+ # @param action [String] The span action type, eq `connect` or `query`
214
237
  # @param context [Span::Context] Context information about the span
215
238
  # @param include_stacktrace [Boolean] Whether or not to capture a stacktrace
216
239
  # @return [Span]
217
240
  def start_span(
218
241
  name,
219
242
  type = nil,
243
+ subtype: nil,
244
+ action: nil,
220
245
  context: nil,
221
246
  include_stacktrace: true,
222
247
  trace_context: nil
@@ -224,6 +249,8 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
224
249
  agent&.start_span(
225
250
  name,
226
251
  type,
252
+ subtype: subtype,
253
+ action: action,
227
254
  context: context,
228
255
  trace_context: trace_context
229
256
  ).tap do |span|
@@ -233,6 +260,7 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
233
260
  span.original_backtrace ||= caller
234
261
  end
235
262
  end
263
+ # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
236
264
 
237
265
  # Ends the current span
238
266
  #
@@ -241,7 +269,7 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
241
269
  agent&.end_span
242
270
  end
243
271
 
244
- # rubocop:disable Metrics/MethodLength
272
+ # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
245
273
  # Wrap a block in a Span, ending it after the block
246
274
  #
247
275
  # @param name [String] A description of the span, eq `SELECT FROM "users"`
@@ -253,6 +281,8 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
253
281
  def with_span(
254
282
  name,
255
283
  type = nil,
284
+ subtype: nil,
285
+ action: nil,
256
286
  context: nil,
257
287
  include_stacktrace: true,
258
288
  trace_context: nil
@@ -269,6 +299,8 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
269
299
  start_span(
270
300
  name,
271
301
  type,
302
+ subtype: subtype,
303
+ action: action,
272
304
  context: context,
273
305
  include_stacktrace: include_stacktrace,
274
306
  trace_context: trace_context
@@ -278,7 +310,7 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
278
310
  end_span
279
311
  end
280
312
  end
281
- # rubocop:enable Metrics/MethodLength
313
+ # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
282
314
 
283
315
  # Build a [Context] from a Rack `env`. The context may include information
284
316
  # about the request, response, current user and more
@@ -159,9 +159,12 @@ module ElasticAPM
159
159
  instrumenter.end_transaction(result)
160
160
  end
161
161
 
162
+ # rubocop:disable Metrics/ParameterLists
162
163
  def start_span(
163
164
  name = nil,
164
165
  type = nil,
166
+ subtype: nil,
167
+ action: nil,
165
168
  backtrace: nil,
166
169
  context: nil,
167
170
  trace_context: nil
@@ -169,11 +172,14 @@ module ElasticAPM
169
172
  instrumenter.start_span(
170
173
  name,
171
174
  type,
175
+ subtype: subtype,
176
+ action: action,
172
177
  backtrace: backtrace,
173
178
  context: context,
174
179
  trace_context: trace_context
175
180
  )
176
181
  end
182
+ # rubocop:enable Metrics/ParameterLists
177
183
 
178
184
  def end_span
179
185
  instrumenter.end_span
@@ -234,7 +234,7 @@ module ElasticAPM
234
234
  end
235
235
 
236
236
  def app_type?(app)
237
- if defined?(Rails::Application) && app.is_a?(Rails::Application)
237
+ if defined?(::Rails::Application) && app.is_a?(::Rails::Application)
238
238
  return :rails
239
239
  end
240
240
 
@@ -255,15 +255,15 @@ module ElasticAPM
255
255
  def set_rails(app) # rubocop:disable Metrics/AbcSize
256
256
  self.service_name ||= format_name(service_name || rails_app_name(app))
257
257
  self.framework_name ||= 'Ruby on Rails'
258
- self.framework_version ||= Rails::VERSION::STRING
259
- self.logger ||= Rails.logger
258
+ self.framework_version ||= ::Rails::VERSION::STRING
259
+ self.logger ||= ::Rails.logger
260
260
 
261
- self.__root_path = Rails.root.to_s
261
+ self.__root_path = ::Rails.root.to_s
262
262
  self.__view_paths = app.config.paths['app/views'].existent
263
263
  end
264
264
 
265
265
  def rails_app_name(app)
266
- if Rails::VERSION::MAJOR >= 6
266
+ if ::Rails::VERSION::MAJOR >= 6
267
267
  app.class.module_parent_name
268
268
  else
269
269
  app.class.parent_name
@@ -134,9 +134,12 @@ module ElasticAPM
134
134
 
135
135
  # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
136
136
  # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
137
+ # rubocop:disable Metrics/ParameterLists
137
138
  def start_span(
138
139
  name,
139
140
  type = nil,
141
+ subtype: nil,
142
+ action: nil,
140
143
  backtrace: nil,
141
144
  context: nil,
142
145
  trace_context: nil
@@ -155,6 +158,8 @@ module ElasticAPM
155
158
 
156
159
  span = Span.new(
157
160
  name: name,
161
+ subtype: subtype,
162
+ action: action,
158
163
  transaction_id: transaction.id,
159
164
  trace_context: trace_context || parent.trace_context.child,
160
165
  type: type,
@@ -170,6 +175,7 @@ module ElasticAPM
170
175
 
171
176
  span.start
172
177
  end
178
+ # rubocop:enable Metrics/ParameterLists
173
179
  # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
174
180
  # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
175
181
 
@@ -6,11 +6,14 @@ module ElasticAPM
6
6
  # @api private
7
7
  class ProcessActionNormalizer < Normalizer
8
8
  register 'process_action.action_controller'
9
- TYPE = 'app.controller.action'
9
+
10
+ TYPE = 'app'
11
+ SUBTYPE = 'controller'
12
+ ACTION = 'action'
10
13
 
11
14
  def normalize(transaction, _name, payload)
12
15
  transaction.name = endpoint(payload)
13
- [transaction.name, TYPE, nil]
16
+ [transaction.name, TYPE, SUBTYPE, ACTION, nil]
14
17
  end
15
18
 
16
19
  private
@@ -6,10 +6,13 @@ module ElasticAPM
6
6
  # @api private
7
7
  class ProcessActionNormalizer < Normalizer
8
8
  register 'process.action_mailer'
9
- TYPE = 'app.mailer.action'
9
+
10
+ TYPE = 'app'
11
+ SUBTYPE = 'mailer'
12
+ ACTION = 'action'
10
13
 
11
14
  def normalize(_transaction, _name, payload)
12
- [endpoint(payload), TYPE, nil]
15
+ [endpoint(payload), TYPE, SUBTYPE, ACTION, nil]
13
16
  end
14
17
 
15
18
  private
@@ -7,8 +7,8 @@ module ElasticAPM
7
7
  class RenderNormalizer < Normalizer
8
8
  private
9
9
 
10
- def normalize_render(payload, type)
11
- [path_for(payload[:identifier]), type, nil]
10
+ def normalize_render(payload, type, subtype, action)
11
+ [path_for(payload[:identifier]), type, subtype, action, nil]
12
12
  end
13
13
 
14
14
  def path_for(path)
@@ -41,30 +41,35 @@ module ElasticAPM
41
41
  # @api private
42
42
  class RenderTemplateNormalizer < RenderNormalizer
43
43
  register 'render_template.action_view'
44
- TYPE = 'template.view'
44
+ TYPE = 'template'
45
+ SUBTYPE = 'view'
45
46
 
46
47
  def normalize(_transaction, _name, payload)
47
- normalize_render(payload, TYPE)
48
+ normalize_render(payload, TYPE, SUBTYPE, nil)
48
49
  end
49
50
  end
50
51
 
51
52
  # @api private
52
53
  class RenderPartialNormalizer < RenderNormalizer
53
54
  register 'render_partial.action_view'
54
- TYPE = 'template.view.partial'
55
+ TYPE = 'template'
56
+ SUBTYPE = 'view'
57
+ ACTION = 'partial'
55
58
 
56
59
  def normalize(_transaction, _name, payload)
57
- normalize_render(payload, TYPE)
60
+ normalize_render(payload, TYPE, SUBTYPE, ACTION)
58
61
  end
59
62
  end
60
63
 
61
64
  # @api private
62
65
  class RenderCollectionNormalizer < RenderNormalizer
63
66
  register 'render_collection.action_view'
64
- TYPE = 'template.view.collection'
67
+ TYPE = 'template'
68
+ SUBTYPE = 'view'
69
+ ACTION = 'collection'
65
70
 
66
71
  def normalize(_transaction, _name, payload)
67
- normalize_render(payload, TYPE)
72
+ normalize_render(payload, TYPE, SUBTYPE, ACTION)
68
73
  end
69
74
  end
70
75
  end
@@ -9,10 +9,13 @@ module ElasticAPM
9
9
  class SqlNormalizer < Normalizer
10
10
  register 'sql.active_record'
11
11
 
12
+ TYPE = 'db'
13
+ ACTION = 'sql'
14
+
12
15
  def initialize(*args)
13
16
  super
14
17
 
15
- @type = format('db.%s.sql', lookup_adapter || 'unknown').freeze
18
+ @subtype = lookup_adapter || 'unknown'
16
19
  @summarizer = SqlSummarizer.new
17
20
  end
18
21
 
@@ -22,7 +25,7 @@ module ElasticAPM
22
25
  name = summarize(payload[:sql]) || payload[:name]
23
26
  context =
24
27
  Span::Context.new(db: { statement: payload[:sql], type: 'sql' })
25
- [name, @type, context]
28
+ [name, TYPE, @subtype, ACTION, context]
26
29
  end
27
30
 
28
31
  private
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elastic_apm/subscriber'
4
+
5
+ module ElasticAPM
6
+ # Module for explicitly starting the ElasticAPM agent and hooking into Rails.
7
+ # It is recommended to use the Railtie instead.
8
+ module Rails
9
+ extend self
10
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
11
+ # rubocop:disable Metrics/CyclomaticComplexity
12
+ # Start the ElasticAPM agent and hook into Rails.
13
+ # Note that the agent won't be started if the Rails console is being used.
14
+ #
15
+ # @param config [Config, Hash] An instance of Config or a Hash config.
16
+ # @return [true, nil] true if the agent was started, nil otherwise.
17
+ def start(config)
18
+ config = Config.new(config) unless config.is_a?(Config)
19
+ if (reason = should_skip?(config))
20
+ unless config.disable_start_message?
21
+ config.logger.info "Skipping because: #{reason}. " \
22
+ "Start manually with `ElasticAPM.start'"
23
+ end
24
+ return
25
+ end
26
+
27
+ ElasticAPM.start(config).tap do |agent|
28
+ attach_subscriber(agent)
29
+ end
30
+
31
+ if ElasticAPM.running? &&
32
+ !ElasticAPM.agent.config.disabled_spies.include?('action_dispatch')
33
+ require 'elastic_apm/spies/action_dispatch'
34
+ end
35
+ ElasticAPM.running?
36
+ rescue StandardError => e
37
+ config.logger.error format('Failed to start: %s', e.message)
38
+ config.logger.debug "Backtrace:\n" + e.backtrace.join("\n")
39
+ end
40
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
41
+ # rubocop:enable Metrics/CyclomaticComplexity
42
+
43
+ private
44
+
45
+ def should_skip?(_config)
46
+ if ::Rails.const_defined? 'Rails::Console'
47
+ return 'Rails console'
48
+ end
49
+
50
+ nil
51
+ end
52
+
53
+ def attach_subscriber(agent)
54
+ return unless agent
55
+
56
+ agent.instrumenter.subscriber = ElasticAPM::Subscriber.new(agent)
57
+ end
58
+ end
59
+ end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'elastic_apm/subscriber'
3
+ require 'elastic_apm/rails'
4
4
 
5
5
  module ElasticAPM
6
6
  # @api private
7
- class Railtie < Rails::Railtie
7
+ class Railtie < ::Rails::Railtie
8
8
  config.elastic_apm = ActiveSupport::OrderedOptions.new
9
9
 
10
10
  Config.schema.each do |key, args|
@@ -18,55 +18,13 @@ module ElasticAPM
18
18
 
19
19
  # Prepend Rails.root to log_path if present
20
20
  if c.log_path && !c.log_path.start_with?('/')
21
- c.log_path = Rails.root.join(c.log_path)
21
+ c.log_path = ::Rails.root.join(c.log_path)
22
22
  end
23
23
  end
24
24
 
25
- if start(config)
25
+ if Rails.start(config)
26
26
  app.middleware.insert 0, Middleware
27
27
  end
28
28
  end
29
-
30
- config.after_initialize do
31
- if ElasticAPM.running? &&
32
- !ElasticAPM.agent.config.disabled_spies.include?('action_dispatch')
33
- require 'elastic_apm/spies/action_dispatch'
34
- end
35
- end
36
-
37
- private
38
-
39
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
40
- def start(config)
41
- if (reason = should_skip?(config))
42
- unless config.disable_start_message?
43
- config.logger.info "Skipping because: #{reason}. " \
44
- "Start manually with `ElasticAPM.start'"
45
- end
46
- return
47
- end
48
-
49
- ElasticAPM.start(config).tap do |agent|
50
- attach_subscriber(agent)
51
- end
52
- rescue StandardError => e
53
- config.logger.error format('Failed to start: %s', e.message)
54
- config.logger.debug "Backtrace:\n" + e.backtrace.join("\n")
55
- end
56
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
57
-
58
- def should_skip?(_config)
59
- if Rails.const_defined? 'Rails::Console'
60
- return 'Rails console'
61
- end
62
-
63
- nil
64
- end
65
-
66
- def attach_subscriber(agent)
67
- return unless agent
68
-
69
- agent.instrumenter.subscriber = ElasticAPM::Subscriber.new(agent)
70
- end
71
29
  end
72
30
  end
@@ -14,17 +14,26 @@ module ElasticAPM
14
14
 
15
15
  DEFAULT_TYPE = 'custom'
16
16
 
17
- # rubocop:disable Metrics/ParameterLists
17
+ # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
18
18
  def initialize(
19
19
  name:,
20
20
  transaction_id:,
21
21
  trace_context:,
22
22
  type: nil,
23
+ subtype: nil,
24
+ action: nil,
23
25
  context: nil,
24
26
  stacktrace_builder: nil
25
27
  )
26
28
  @name = name
27
- @type = type || DEFAULT_TYPE
29
+
30
+ if subtype.nil? && type&.include?('.')
31
+ @type, @subtype, @action = type.split('.')
32
+ else
33
+ @type = type || DEFAULT_TYPE
34
+ @subtype = subtype
35
+ @action = action
36
+ end
28
37
 
29
38
  @transaction_id = transaction_id
30
39
  @trace_context = trace_context
@@ -32,10 +41,23 @@ module ElasticAPM
32
41
  @context = context || Span::Context.new
33
42
  @stacktrace_builder = stacktrace_builder
34
43
  end
35
- # rubocop:enable Metrics/ParameterLists
36
-
37
- attr_accessor :name, :type, :original_backtrace, :trace_context
38
- attr_reader :context, :stacktrace, :duration, :timestamp, :transaction_id
44
+ # rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
45
+
46
+ attr_accessor(
47
+ :action,
48
+ :name,
49
+ :original_backtrace,
50
+ :subtype,
51
+ :trace_context,
52
+ :type
53
+ )
54
+ attr_reader(
55
+ :context,
56
+ :duration,
57
+ :stacktrace,
58
+ :timestamp,
59
+ :transaction_id
60
+ )
39
61
 
40
62
  # life cycle
41
63
 
@@ -5,6 +5,9 @@ module ElasticAPM
5
5
  module Spies
6
6
  # @api private
7
7
  class FaradaySpy
8
+ TYPE = 'ext'
9
+ SUBTYPE = 'faraday'
10
+
8
11
  def self.without_net_http
9
12
  return yield unless defined?(NetHTTPSpy)
10
13
 
@@ -37,9 +40,13 @@ module ElasticAPM
37
40
  end
38
41
 
39
42
  name = "#{method.upcase} #{host}"
40
- type = "ext.faraday.#{method}"
41
43
 
42
- ElasticAPM.with_span name, type do |span|
44
+ ElasticAPM.with_span(
45
+ name,
46
+ TYPE,
47
+ subtype: SUBTYPE,
48
+ action: method.to_s
49
+ ) do |span|
43
50
  ElasticAPM::Spies::FaradaySpy.without_net_http do
44
51
  trace_context = span&.trace_context || transaction.trace_context
45
52
 
@@ -5,6 +5,9 @@ module ElasticAPM
5
5
  module Spies
6
6
  # @api private
7
7
  class HTTPSpy
8
+ TYPE = 'ext'
9
+ SUBTYPE = 'http_rb'
10
+
8
11
  # rubocop:disable Metrics/MethodLength
9
12
  def install
10
13
  ::HTTP::Client.class_eval do
@@ -19,9 +22,13 @@ module ElasticAPM
19
22
  host = req.uri.host
20
23
 
21
24
  name = "#{method} #{host}"
22
- type = "ext.http_rb.#{method}"
23
25
 
24
- ElasticAPM.with_span name, type do |span|
26
+ ElasticAPM.with_span(
27
+ name,
28
+ TYPE,
29
+ subtype: SUBTYPE,
30
+ action: method
31
+ ) do |span|
25
32
  trace_context = span&.trace_context || transaction.trace_context
26
33
  req['Elastic-Apm-Traceparent'] = trace_context.to_header
27
34
  perform_without_apm(req, options)
@@ -14,7 +14,9 @@ module ElasticAPM
14
14
 
15
15
  # @api private
16
16
  class Subscriber
17
- TYPE = 'db.mongodb.query'
17
+ TYPE = 'db'
18
+ SUBTYPE = 'mongodb'
19
+ ACTION = 'query'
18
20
 
19
21
  def initialize
20
22
  @events = {}
@@ -51,6 +53,8 @@ module ElasticAPM
51
53
  ElasticAPM.start_span(
52
54
  name,
53
55
  TYPE,
56
+ subtype: SUBTYPE,
57
+ action: ACTION,
54
58
  context: build_context(event)
55
59
  )
56
60
 
@@ -6,6 +6,8 @@ module ElasticAPM
6
6
  # @api private
7
7
  class NetHTTPSpy
8
8
  KEY = :__elastic_apm_net_http_disabled
9
+ TYPE = 'ext'
10
+ SUBTYPE = 'net_http'
9
11
 
10
12
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
11
13
  class << self
@@ -46,9 +48,13 @@ module ElasticAPM
46
48
  host ||= address
47
49
 
48
50
  name = "#{method} #{host}"
49
- type = "ext.net_http.#{method}"
50
51
 
51
- ElasticAPM.with_span name, type do |span|
52
+ ElasticAPM.with_span(
53
+ name,
54
+ TYPE,
55
+ subtype: SUBTYPE,
56
+ action: method.to_s
57
+ ) do |span|
52
58
  trace_context = span&.trace_context || transaction.trace_context
53
59
  req['Elastic-Apm-Traceparent'] = trace_context.to_header
54
60
  request_without_apm(req, body, &block)
@@ -29,8 +29,8 @@ module ElasticAPM
29
29
 
30
30
  Notification = Struct.new(:id, :span)
31
31
 
32
+ # rubocop:disable Metrics/MethodLength
32
33
  def start(name, id, payload)
33
- # debug "AS::Notification#start:#{name}:#{id}"
34
34
  return unless (transaction = @agent.current_transaction)
35
35
 
36
36
  normalized = @normalizers.normalize(transaction, name, payload)
@@ -39,12 +39,20 @@ module ElasticAPM
39
39
  if normalized == :skip
40
40
  nil
41
41
  else
42
- name, type, context = normalized
43
- @agent.start_span(name, type, context: context)
42
+ name, type, subtype, action, context = normalized
43
+
44
+ @agent.start_span(
45
+ name,
46
+ type,
47
+ subtype: subtype,
48
+ action: action,
49
+ context: context
50
+ )
44
51
  end
45
52
 
46
53
  transaction.notifications << Notification.new(id, span)
47
54
  end
55
+ # rubocop:enable Metrics/MethodLength
48
56
 
49
57
  def finish(_name, id, _payload)
50
58
  # debug "AS::Notification#finish:#{name}:#{id}"
@@ -13,7 +13,7 @@ module ElasticAPM
13
13
 
14
14
  attr_reader :context_serializer
15
15
 
16
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
16
+ # rubocop:disable Metrics/MethodLength
17
17
  def build(span)
18
18
  {
19
19
  span: {
@@ -21,7 +21,7 @@ module ElasticAPM
21
21
  transaction_id: span.transaction_id,
22
22
  parent_id: span.parent_id,
23
23
  name: keyword_field(span.name),
24
- type: keyword_field(span.type),
24
+ type: join_type(span),
25
25
  duration: ms(span.duration),
26
26
  context: context_serializer.build(span.context),
27
27
  stacktrace: span.stacktrace.to_a,
@@ -30,7 +30,7 @@ module ElasticAPM
30
30
  }
31
31
  }
32
32
  end
33
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
33
+ # rubocop:enable Metrics/MethodLength
34
34
 
35
35
  # @api private
36
36
  class ContextSerializer < Serializer
@@ -66,6 +66,14 @@ module ElasticAPM
66
66
  }
67
67
  end
68
68
  end
69
+
70
+ private
71
+
72
+ def join_type(span)
73
+ combined = [span.type, span.subtype, span.action]
74
+ combined.compact!
75
+ combined.join '.'
76
+ end
69
77
  end
70
78
  end
71
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElasticAPM
4
- VERSION = '2.10.1'
4
+ VERSION = '2.11.0'
5
5
  end
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: 2.10.1
4
+ version: 2.11.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: 2019-09-16 00:00:00.000000000 Z
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -59,6 +59,7 @@ files:
59
59
  - ".ci/jobs/apm-agent-ruby.yml"
60
60
  - ".ci/jobs/defaults.yml"
61
61
  - ".ci/linting.groovy"
62
+ - ".ci/prepare-git-context.sh"
62
63
  - ".gitignore"
63
64
  - ".hound.yml"
64
65
  - ".pre-commit-config.yaml"
@@ -92,6 +93,7 @@ files:
92
93
  - docs/getting-started-rails.asciidoc
93
94
  - docs/index.asciidoc
94
95
  - docs/introduction.asciidoc
96
+ - docs/log-correlation.asciidoc
95
97
  - docs/metrics.asciidoc
96
98
  - docs/opentracing.asciidoc
97
99
  - docs/release-notes.asciidoc
@@ -139,6 +141,7 @@ files:
139
141
  - lib/elastic_apm/normalizers/action_view.rb
140
142
  - lib/elastic_apm/normalizers/active_record.rb
141
143
  - lib/elastic_apm/opentracing.rb
144
+ - lib/elastic_apm/rails.rb
142
145
  - lib/elastic_apm/railtie.rb
143
146
  - lib/elastic_apm/span.rb
144
147
  - lib/elastic_apm/span/context.rb
@@ -206,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
209
  - !ruby/object:Gem::Version
207
210
  version: '0'
208
211
  requirements: []
209
- rubygems_version: 3.0.6
212
+ rubygems_version: 3.0.3
210
213
  signing_key:
211
214
  specification_version: 4
212
215
  summary: The official Elastic APM agent for Ruby