opentelemetry-instrumentation-action_pack 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01fdccf711bd55c9f8e6df0d15bc871698058ba9500523696dbb22d2f3a28a4a
4
- data.tar.gz: 55ecb33d2d56eec21b2cedee82df3189cb1c056a44464c34a2feadba6c327c76
3
+ metadata.gz: 5af8d8cb9038f564234140ffaa6d87f1b07ecb7021e4fe579ec5efc938b2898e
4
+ data.tar.gz: '091d78c0c499b98b31a31ea31aa6f0990f8cabe53dab62dd532036985def42ef'
5
5
  SHA512:
6
- metadata.gz: d403b045b944b7062988e5e4a3a2e0a6c17d4a1e50409e1a920d36c27bcb19cd95b9de3aa8422dbcaa5b05443919165611478283ee2cc2477d0faf5a69d5f151
7
- data.tar.gz: 2bc7459a91c2331288aebb7076c0f3e834aa966d7e8f751b79c14efcbc23eb5386147a4ce1acb65de750b6587f030a2cc4960f68e3296193773e92f0b13a4bd1
6
+ metadata.gz: 1e7782f0b1b04ab4a019677bd81a68c01954af5ece9a7f3b0073a764490241fed82b8173cc435fcbbcd7ec46786e1237a7b5e4406982de61674ad8285aafe60c
7
+ data.tar.gz: 97404fce81bd10262a19e129f6397aeaabe39ae54850a0f3d085952e6264e1392617727bab6a1fd22837338d48b2e603444a2392499168a0872abd0b62a71f06
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Release History: opentelemetry-instrumentation-action_pack
2
2
 
3
+ ### v0.10.0 / 2024-11-19
4
+
5
+ * ADDED: Use Semconv Naming For ActionPack
6
+
7
+ ### v0.9.0 / 2024-01-09
8
+
9
+ * BREAKING CHANGE: Use ActiveSupport instead of patches #703
10
+
3
11
  ### v0.8.0 / 2023-11-22
4
12
 
5
13
  * BREAKING CHANGE: Drop Rails 6.0 EOL
data/README.md CHANGED
@@ -6,7 +6,7 @@ The Action Pack instrumentation is a community-maintained instrumentation for th
6
6
 
7
7
  Install the gem using:
8
8
 
9
- ```
9
+ ```console
10
10
  gem install opentelemetry-instrumentation-action_pack
11
11
  ```
12
12
 
@@ -30,6 +30,43 @@ OpenTelemetry::SDK.configure do |c|
30
30
  end
31
31
  ```
32
32
 
33
+ ## Active Support Instrumentation
34
+
35
+ Earlier versions of this instrumentation relied on patching custom `dispatch` hooks from Rails's [Action Controller](https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal.rb#L224) to extract request information.
36
+
37
+ This instrumentation now relies on `ActiveSupport::Notifications` and registers a custom Subscriber that listens to relevant events to modify the Rack span.
38
+
39
+ See the table below for details of what [Rails Framework Hook Events](https://guides.rubyonrails.org/active_support_instrumentation.html#action-controller) are recorded by this instrumentation:
40
+
41
+ | Event Name | Subscribe? | Creates Span? | Notes |
42
+ | - | - | - | - |
43
+ | `process_action.action_controller` | :white_check_mark: | :x: | It modifies the existing Rack span |
44
+
45
+ ## Semantic Conventions
46
+
47
+ This instrumentation generally uses [HTTP server semantic conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/) to update the existing Rack span.
48
+
49
+ For Rails 7.1+, the span name is updated to match the HTTP method and route that was matched for the request using [`ActionDispatch::Request#route_uri_pattern`](https://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-route_uri_pattern), e.g.: `GET /users/:id`
50
+
51
+ For older versions of Rails the span name is updated to match the HTTP method, controller, and action name that was the target of the request, e.g.: `GET /example/index`
52
+
53
+ > ![NOTE]: Users may override the `span_naming` option to default to Legacy Span Naming Behavior that uses the controller's class name and action in Ruby documentation syntax, e.g. `ExampleController#index`.
54
+
55
+ This instrumentation does not emit any custom attributes.
56
+
57
+ | Attribute Name | Type | Notes |
58
+ | - | - | - |
59
+ | `code.namespace` | String | `ActionController` class name |
60
+ | `code.function` | String | `ActionController` action name e.g. `index`, `show`, `edit`, etc... |
61
+ | `http.route` | String | (Rails 7.1+) the route that was matched for the request |
62
+ | `http.target` | String | The `request.filtered_path` |
63
+
64
+ ### Error Handling for Action Controller
65
+
66
+ If an error is triggered by Action Controller (such as a 500 internal server error), Action Pack will typically employ the default `ActionDispatch::PublicExceptions.new(Rails.public_path)` as the `exceptions_app`, as detailed in the [documentation](https://guides.rubyonrails.org/configuring.html#config-exceptions-app).
67
+
68
+ The error object will be retained within `payload[:exception_object]`. Additionally, its storage in `request.env['action_dispatch.exception']` is contingent upon the configuration of `action_dispatch.show_exceptions` in Rails.
69
+
33
70
  ## Examples
34
71
 
35
72
  Example usage can be seen in the `./example/trace_demonstration.rb` file [here](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/action_pack/example/trace_demonstration.ru)
@@ -38,7 +75,7 @@ Example usage can be seen in the `./example/trace_demonstration.rb` file [here](
38
75
 
39
76
  The `opentelemetry-instrumentation-action_pack` gem source is [on github][repo-github], along with related gems including `opentelemetry-api` and `opentelemetry-sdk`.
40
77
 
41
- The OpenTelemetry Ruby gems are maintained by the OpenTelemetry-Ruby special interest group (SIG). You can get involved by joining us in [GitHub Discussions][discussions-url] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig].
78
+ The OpenTelemetry Ruby gems are maintained by the OpenTelemetry Ruby special interest group (SIG). You can get involved by joining us on our [GitHub Discussions][discussions-url], [Slack Channel][slack-channel] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig].
42
79
 
43
80
  ## License
44
81
 
@@ -49,4 +86,6 @@ The `opentelemetry-instrumentation-action_pack` gem is distributed under the Apa
49
86
  [license-github]: https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/LICENSE
50
87
  [ruby-sig]: https://github.com/open-telemetry/community#ruby-sig
51
88
  [community-meetings]: https://github.com/open-telemetry/community#community-meetings
89
+ [slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY
52
90
  [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
91
+ [rails-home]: https://rubyonrails.org/
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ module ActionPack
10
+ module Handlers
11
+ # Action Controller handler to handle the notification from Active Support
12
+ class ActionController
13
+ # @param config [Hash] of instrumentation options
14
+ def initialize(config)
15
+ @config = config
16
+ @span_naming = config.fetch(:span_naming)
17
+ end
18
+
19
+ # Invoked by ActiveSupport::Notifications at the start of the instrumentation block
20
+ #
21
+ # @param _name [String] of the event (unused)
22
+ # @param _id [String] of the event (unused)
23
+ # @param payload [Hash] the payload passed as a method argument
24
+ # @return [Hash] the payload passed as a method argument
25
+ def start(_name, _id, payload)
26
+ span_name, attributes = to_span_name_and_attributes(payload)
27
+
28
+ span = OpenTelemetry::Instrumentation::Rack.current_span
29
+ span.name = span_name
30
+ span.add_attributes(attributes)
31
+ rescue StandardError => e
32
+ OpenTelemetry.handle_error(exception: e)
33
+ end
34
+
35
+ # Invoked by ActiveSupport::Notifications at the end of the instrumentation block
36
+ #
37
+ # @param _name [String] of the event (unused)
38
+ # @param _id [String] of the event (unused)
39
+ # @param payload [Hash] the payload passed as a method argument
40
+ # @return [Hash] the payload passed as a method argument
41
+ def finish(_name, _id, payload)
42
+ span = OpenTelemetry::Instrumentation::Rack.current_span
43
+ span.record_exception(payload[:exception_object]) if payload[:exception_object]
44
+ rescue StandardError => e
45
+ OpenTelemetry.handle_error(exception: e)
46
+ end
47
+
48
+ private
49
+
50
+ # Extracts the span name and attributes from the payload
51
+ #
52
+ # @param payload [Hash] the payload passed from ActiveSupport::Notifications
53
+ # @return [Array<String, Hash>] the span name and attributes
54
+ def to_span_name_and_attributes(payload)
55
+ request = payload[:request]
56
+ http_route = request.route_uri_pattern if request.respond_to?(:route_uri_pattern)
57
+
58
+ attributes = {
59
+ OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => String(payload[:controller]),
60
+ OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => String(payload[:action])
61
+ }
62
+ attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE] = http_route if http_route
63
+ attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] = request.filtered_path if request.filtered_path != request.fullpath
64
+
65
+ if @span_naming == :semconv
66
+ return ["#{request.method} #{http_route.gsub('(.:format)', '')}", attributes] if http_route
67
+
68
+ return ["#{request.method} /#{payload.dig(:params, :controller)}/#{payload.dig(:params, :action)}", attributes]
69
+ end
70
+
71
+ ["#{payload[:controller]}##{payload[:action]}", attributes]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require_relative 'handlers/action_controller'
8
+
9
+ module OpenTelemetry
10
+ module Instrumentation
11
+ module ActionPack
12
+ # Module that contains custom event handlers, which are used to generate spans per event
13
+ module Handlers
14
+ module_function
15
+
16
+ def subscribe
17
+ return unless Array(@subscriptions).empty?
18
+
19
+ config = ActionPack::Instrumentation.instance.config
20
+ handlers_by_pattern = {
21
+ 'process_action.action_controller' => Handlers::ActionController.new(config)
22
+ }
23
+
24
+ @subscriptions = handlers_by_pattern.map do |key, handler|
25
+ ::ActiveSupport::Notifications.subscribe(key, handler)
26
+ end
27
+ end
28
+
29
+ # Removes Event Handler Subscriptions for Action Controller notifications
30
+ # @note this method is not thread-safe and should not be used in a multi-threaded context
31
+ def unsubscribe
32
+ @subscriptions&.each { |subscriber| ::ActiveSupport::Notifications.unsubscribe(subscriber) }
33
+ @subscriptions = nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -7,7 +7,31 @@
7
7
  module OpenTelemetry
8
8
  module Instrumentation
9
9
  module ActionPack
10
- # The Instrumentation class contains logic to detect and install the ActionPack instrumentation
10
+ # The {OpenTelemetry::Instrumentation::ActionPack::Instrumentation} class contains logic to detect and install the ActionPack instrumentation
11
+ #
12
+ # Installation and configuration of this instrumentation is done within the
13
+ # {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry/SDK#configure-instance_method OpenTelemetry::SDK#configure}
14
+ # block, calling {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use use()}
15
+ # or {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use_all use_all()}.
16
+ #
17
+ # ## Configuration keys and options
18
+ #
19
+ # ### `:span_naming`
20
+ #
21
+ # Specifies how the span names are set. Can be one of:
22
+ #
23
+ # - `:semconv` **(default)** - The span name will use HTTP semantic conventions '{method http.route}', for example `GET /users/:id`
24
+ # - `:class` - The span name will appear as '<ActionController class name>#<action>',
25
+ # for example `UsersController#show`.
26
+ #
27
+ # @example An explicit default configuration
28
+ # OpenTelemetry::SDK.configure do |c|
29
+ # c.use_all({
30
+ # 'OpenTelemetry::Instrumentation::ActionPack' => {
31
+ # span_naming: :class
32
+ # },
33
+ # })
34
+ # end
11
35
  class Instrumentation < OpenTelemetry::Instrumentation::Base
12
36
  MINIMUM_VERSION = Gem::Version.new('6.1.0')
13
37
 
@@ -17,6 +41,8 @@ module OpenTelemetry
17
41
  patch
18
42
  end
19
43
 
44
+ option :span_naming, default: :semconv, validate: %i[semconv class]
45
+
20
46
  present do
21
47
  defined?(::ActionController)
22
48
  end
@@ -32,11 +58,11 @@ module OpenTelemetry
32
58
  end
33
59
 
34
60
  def patch
35
- ::ActionController::Metal.prepend(Patches::ActionController::Metal)
61
+ Handlers.subscribe
36
62
  end
37
63
 
38
64
  def require_dependencies
39
- require_relative 'patches/action_controller/metal'
65
+ require_relative 'handlers'
40
66
  end
41
67
 
42
68
  def require_railtie
@@ -7,7 +7,7 @@
7
7
  module OpenTelemetry
8
8
  module Instrumentation
9
9
  module ActionPack
10
- VERSION = '0.8.0'
10
+ VERSION = '0.10.0'
11
11
  end
12
12
  end
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-instrumentation-action_pack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenTelemetry Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-22 00:00:00.000000000 Z
11
+ date: 2024-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -123,47 +123,47 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0.3'
125
125
  - !ruby/object:Gem::Dependency
126
- name: rails
126
+ name: rake
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '6.1'
131
+ version: '13.0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '6.1'
138
+ version: '13.0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: rake
140
+ name: rubocop
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '13.0'
145
+ version: 1.68.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '13.0'
152
+ version: 1.68.0
153
153
  - !ruby/object:Gem::Dependency
154
- name: rubocop
154
+ name: rubocop-performance
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: 1.56.1
159
+ version: 1.22.0
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: 1.56.1
166
+ version: 1.22.0
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: simplecov
169
169
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: '3.19'
187
+ version: 3.24.0
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: '3.19'
194
+ version: 3.24.0
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: yard
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -220,18 +220,19 @@ files:
220
220
  - lib/opentelemetry-instrumentation-action_pack.rb
221
221
  - lib/opentelemetry/instrumentation.rb
222
222
  - lib/opentelemetry/instrumentation/action_pack.rb
223
+ - lib/opentelemetry/instrumentation/action_pack/handlers.rb
224
+ - lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb
223
225
  - lib/opentelemetry/instrumentation/action_pack/instrumentation.rb
224
- - lib/opentelemetry/instrumentation/action_pack/patches/action_controller/metal.rb
225
226
  - lib/opentelemetry/instrumentation/action_pack/railtie.rb
226
227
  - lib/opentelemetry/instrumentation/action_pack/version.rb
227
228
  homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
228
229
  licenses:
229
230
  - Apache-2.0
230
231
  metadata:
231
- changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-action_pack/0.8.0/file/CHANGELOG.md
232
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-action_pack/0.10.0/file/CHANGELOG.md
232
233
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/action_pack
233
234
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
234
- documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-action_pack/0.8.0
235
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-action_pack/0.10.0
235
236
  post_install_message:
236
237
  rdoc_options: []
237
238
  require_paths:
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module OpenTelemetry
8
- module Instrumentation
9
- module ActionPack
10
- module Patches
11
- module ActionController
12
- # Module to prepend to ActionController::Metal for instrumentation
13
- module Metal
14
- def dispatch(name, request, response)
15
- rack_span = OpenTelemetry::Instrumentation::Rack.current_span
16
- if rack_span.recording?
17
- rack_span.name = "#{self.class.name}##{name}" unless request.env['action_dispatch.exception']
18
-
19
- attributes_to_append = {
20
- OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => self.class.name,
21
- OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => String(name)
22
- }
23
- attributes_to_append[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] = request.filtered_path if request.filtered_path != request.fullpath
24
- rack_span.add_attributes(attributes_to_append)
25
- end
26
-
27
- super(name, request, response)
28
- end
29
-
30
- private
31
-
32
- def instrumentation_config
33
- ActionPack::Instrumentation.instance.config
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end