rage-rb 1.19.2 → 1.20.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/Appraisals +19 -0
  4. data/CHANGELOG.md +15 -1
  5. data/CODE_OF_CONDUCT.md +13 -17
  6. data/Gemfile +3 -0
  7. data/README.md +60 -63
  8. data/Rakefile +14 -0
  9. data/lib/rage/all.rb +3 -0
  10. data/lib/rage/cable/cable.rb +11 -7
  11. data/lib/rage/cable/channel.rb +6 -1
  12. data/lib/rage/cable/connection.rb +4 -0
  13. data/lib/rage/cable/router.rb +14 -9
  14. data/lib/rage/configuration.rb +235 -21
  15. data/lib/rage/controller/api.rb +49 -44
  16. data/lib/rage/deferred/context.rb +30 -2
  17. data/lib/rage/deferred/deferred.rb +18 -6
  18. data/lib/rage/deferred/metadata.rb +39 -0
  19. data/lib/rage/deferred/middleware_chain.rb +67 -0
  20. data/lib/rage/deferred/task.rb +45 -17
  21. data/lib/rage/events/events.rb +3 -3
  22. data/lib/rage/events/subscriber.rb +36 -25
  23. data/lib/rage/fiber.rb +33 -31
  24. data/lib/rage/fiber_scheduler.rb +6 -2
  25. data/lib/rage/logger/logger.rb +7 -1
  26. data/lib/rage/middleware/body_finalizer.rb +14 -0
  27. data/lib/rage/response.rb +10 -5
  28. data/lib/rage/rspec.rb +17 -17
  29. data/lib/rage/setup.rb +2 -2
  30. data/lib/rage/telemetry/handler.rb +131 -0
  31. data/lib/rage/telemetry/spans/await_fiber.rb +50 -0
  32. data/lib/rage/telemetry/spans/broadcast_cable_stream.rb +50 -0
  33. data/lib/rage/telemetry/spans/create_websocket_connection.rb +50 -0
  34. data/lib/rage/telemetry/spans/dispatch_fiber.rb +48 -0
  35. data/lib/rage/telemetry/spans/enqueue_deferred_task.rb +52 -0
  36. data/lib/rage/telemetry/spans/process_cable_action.rb +56 -0
  37. data/lib/rage/telemetry/spans/process_cable_connection.rb +56 -0
  38. data/lib/rage/telemetry/spans/process_controller_action.rb +56 -0
  39. data/lib/rage/telemetry/spans/process_deferred_task.rb +54 -0
  40. data/lib/rage/telemetry/spans/process_event_subscriber.rb +54 -0
  41. data/lib/rage/telemetry/spans/publish_event.rb +54 -0
  42. data/lib/rage/telemetry/spans/spawn_fiber.rb +50 -0
  43. data/lib/rage/telemetry/telemetry.rb +121 -0
  44. data/lib/rage/telemetry/tracer.rb +97 -0
  45. data/lib/rage/version.rb +1 -1
  46. data/rage.gemspec +4 -3
  47. metadata +38 -5
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **cable.websocket.handshake** span wraps the WebSocket connection handshake process.
5
+ #
6
+ # This span is started when a WebSocket connection is being established and is finished once the handshake is complete.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::CreateWebsocketConnection
12
+ class << self
13
+ # @private
14
+ def id
15
+ "cable.websocket.handshake"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[env:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"WebSocket.handshake"',
27
+ env: "env"
28
+ }
29
+ end
30
+
31
+ # @!parse [ruby]
32
+ # # @param id ["cable.websocket.handshake"] ID of the span
33
+ # # @param name ["WebSocket.handshake"] human-readable name of the operation
34
+ # # @param env [Hash] Rack environment hash that will be attached to the underlying WebSocket connection, allowing you to associate arbitrary data with the connection
35
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
36
+ # #
37
+ # # @example
38
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
39
+ # # handle "cable.websocket.handshake", with: :my_handler
40
+ # #
41
+ # # def my_handler(id:, name:, env:)
42
+ # # yield
43
+ # # end
44
+ # # end
45
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
46
+ # # You can omit any of the parameters described here.
47
+ # def handle(id:, name:, env:)
48
+ # end
49
+ end
50
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **core.fiber.dispatch** span tracks the scheduling and processing of system-level fibers created by the framework to process requests and deferred tasks.
5
+ #
6
+ # This span is started when a system fiber begins processing and ends when the fiber has completed processing.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::DispatchFiber
12
+ class << self
13
+ # @private
14
+ def id
15
+ "core.fiber.dispatch"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ []
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"Fiber.dispatch"'
27
+ }
28
+ end
29
+
30
+ # @!parse [ruby]
31
+ # # @param id ["core.fiber.dispatch"] ID of the span
32
+ # # @param name ["Fiber.dispatch"] human-readable name of the operation
33
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
34
+ # #
35
+ # # @example
36
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
37
+ # # handle "core.fiber.dispatch", with: :my_handler
38
+ # #
39
+ # # def my_handler(id:, name:)
40
+ # # yield
41
+ # # end
42
+ # # end
43
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
44
+ # # You can omit any of the parameters described here.
45
+ # def handle(id:, name:)
46
+ # end
47
+ end
48
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **deferred.task.enqueue** span tracks the enqueuing of a deferred task.
5
+ #
6
+ # This span is triggered when a deferred task is enqueued.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::EnqueueDeferredTask
12
+ class << self
13
+ # @private
14
+ def id
15
+ "deferred.task.enqueue"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[task_class: context:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{task_class}#enqueue"',
27
+ task_class: "task_class",
28
+ task_context: "Rage::Deferred::Context.get_or_create_user_context(context)"
29
+ }
30
+ end
31
+
32
+ # @!parse [ruby]
33
+ # # @param id ["deferred.task.enqueue"] ID of the span
34
+ # # @param name [String] human-readable name of the operation (e.g., `SendConfirmationEmail#enqueue`)
35
+ # # @param task_class [Class] the deferred task being enqueued
36
+ # # @param task_context [Hash] the context is serialized together with the deferred task and allows passing data between telemetry handlers or deferred middleware without exposing it to the task itself
37
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
38
+ # #
39
+ # # @example
40
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
41
+ # # handle "deferred.task.enqueue", with: :my_handler
42
+ # #
43
+ # # def my_handler(id:, name:, task_class:, task_context:)
44
+ # # yield
45
+ # # end
46
+ # # end
47
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
48
+ # # You can omit any of the parameters described here.
49
+ # def handle(id:, name:, task_class:, task_context:)
50
+ # end
51
+ end
52
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **cable.action.process** span wraps the processing of a single {Rage::Cable Rage::Cable} channel action.
5
+ #
6
+ # This span is started just before the action method is invoked on the channel, and is ended immediately after the action method returns.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::ProcessCableAction
12
+ class << self
13
+ # @private
14
+ def id
15
+ "cable.action.process"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[channel: data: action:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{channel.class}##{action}"',
27
+ channel: "channel",
28
+ action: "action",
29
+ data: "data",
30
+ env: "channel.__connection.env"
31
+ }
32
+ end
33
+
34
+ # @!parse [ruby]
35
+ # # @param id ["cable.action.process"] ID of the span
36
+ # # @param name [String] human-readable name of the operation (e.g., `ChatChannel#receive`)
37
+ # # @param channel [Rage::Cable::Channel] the channel instance processing the action
38
+ # # @param action [Symbol] the name of the action method being invoked
39
+ # # @param data [Hash, nil] the data payload sent with the action
40
+ # # @param env [Hash] the Rack environment associated with the WebSocket connection
41
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
42
+ # #
43
+ # # @example
44
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
45
+ # # handle "cable.action.process", with: :my_handler
46
+ # #
47
+ # # def my_handler(id:, name:, channel:, action:, data:, env:)
48
+ # # yield
49
+ # # end
50
+ # # end
51
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
52
+ # # You can omit any of the parameters described here.
53
+ # def handle(id:, name:, channel:, action:, data:, env:)
54
+ # end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **cable.connection.process** span wraps the processing of a connection action in {Rage::Cable Rage::Cable}.
5
+ #
6
+ # This span is started just before the action method is invoked on the channel, and is ended immediately after the action method returns.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::ProcessCableConnection
12
+ class << self
13
+ # @private
14
+ def id
15
+ "cable.connection.process"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[connection: env: action:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{connection.class}##{action}"',
27
+ connection: "connection",
28
+ request: "connection.request",
29
+ action: "action",
30
+ env: "env"
31
+ }
32
+ end
33
+
34
+ # @!parse [ruby]
35
+ # # @param id ["cable.connection.process"] ID of the span
36
+ # # @param name [String] human-readable name of the operation (e.g., `RageCable::Connection#connect`)
37
+ # # @param connection [Rage::Cable::Connection] the connection being processed
38
+ # # @param request [Rage::Request] the request object associated with the WebSocket connection
39
+ # # @param action [:connect, :disconnect] the action being performed on the connection
40
+ # # @param env [Hash] the Rack environment associated with the WebSocket connection
41
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
42
+ # #
43
+ # # @example
44
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
45
+ # # handle "cable.connection.process", with: :my_handler
46
+ # #
47
+ # # def my_handler(id:, name:, connection:, request:, action:, env:)
48
+ # # yield
49
+ # # end
50
+ # # end
51
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
52
+ # # You can omit any of the parameters described here.
53
+ # def handle(id:, name:, connection:, request:, action:, env:)
54
+ # end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **controller.action.process** span wraps the processing of a controller action.
5
+ #
6
+ # This span is emitted for every controller action that is executed.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::ProcessControllerAction
12
+ class << self
13
+ # @private
14
+ def id
15
+ "controller.action.process"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[controller: params:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{controller.class}##{params[:action]}"',
27
+ controller: "controller",
28
+ request: "controller.request",
29
+ response: "controller.response",
30
+ env: "controller.__env"
31
+ }
32
+ end
33
+
34
+ # @!parse [ruby]
35
+ # # @param id ["controller.action.process"] ID of the span
36
+ # # @param name [String] human-readable name of the operation (e.g., `"UsersController#index"`)
37
+ # # @param controller [RageController::API] the controller instance being executed
38
+ # # @param request [Rage::Request] the request object associated with the action
39
+ # # @param response [Rage::Response] the response object associated with the action
40
+ # # @param env [Hash] the Rack environment
41
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
42
+ # #
43
+ # # @example
44
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
45
+ # # handle "controller.action.process", with: :my_handler
46
+ # #
47
+ # # def my_handler(id:, name:, controller:, request:, response:, env:)
48
+ # # yield
49
+ # # end
50
+ # # end
51
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
52
+ # # You can omit any of the parameters described here.
53
+ # def handle(id:, name:, controller:, request:, response:, env:)
54
+ # end
55
+ end
56
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **deferred.task.process** span tracks the processing of a deferred task.
5
+ #
6
+ # This span is started when a deferred task begins processing and ends when the task has completed processing.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::ProcessDeferredTask
12
+ class << self
13
+ # @private
14
+ def id
15
+ "deferred.task.process"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[task: context:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{task.class}#perform"',
27
+ task: "task",
28
+ task_class: "task.class",
29
+ task_context: "Rage::Deferred::Context.get_or_create_user_context(context)"
30
+ }
31
+ end
32
+
33
+ # @!parse [ruby]
34
+ # # @param id ["deferred.task.process"] ID of the span
35
+ # # @param name [String] human-readable name of the operation (e.g., `SendConfirmationEmail#perform`)
36
+ # # @param task [Rage::Deferred::Task] the deferred task being processed
37
+ # # @param task_class [Class] the class of the deferred task being processed
38
+ # # @param task_context [Hash] the context is serialized together with the deferred task and allows passing data between telemetry handlers or deferred middleware without exposing it to the task itself
39
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
40
+ # #
41
+ # # @example
42
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
43
+ # # handle "deferred.task.process", with: :my_handler
44
+ # #
45
+ # # def my_handler(id:, name:, task:, task_class:, task_context:)
46
+ # # yield
47
+ # # end
48
+ # # end
49
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
50
+ # # You can omit any of the parameters described here.
51
+ # def handle(id:, name:, task:, task_class:, task_context:)
52
+ # end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **events.subscriber.process** span tracks the processing of an event by a subscriber.
5
+ #
6
+ # This span is started when an event begins processing by a subscriber and ends when the processing has completed.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::ProcessEventSubscriber
12
+ class << self
13
+ # @private
14
+ def id
15
+ "events.subscriber.process"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[event: context: subscriber:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"#{subscriber.class}#call"',
27
+ subscriber: "subscriber",
28
+ event: "event",
29
+ context: "context"
30
+ }
31
+ end
32
+
33
+ # @!parse [ruby]
34
+ # # @param id ["events.subscriber.process"] ID of the span
35
+ # # @param name [String] human-readable name of the operation (e.g., `UpdateRecommendations#call`)
36
+ # # @param subscriber [Rage::Events::Subscriber] the subscriber instance processing the event
37
+ # # @param event [Object] the event being processed
38
+ # # @param context [Object, nil] the additional context passed along with the event
39
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
40
+ # #
41
+ # # @example
42
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
43
+ # # handle "events.subscriber.process", with: :my_handler
44
+ # #
45
+ # # def my_handler(id:, name:, subscriber:, event:, context:)
46
+ # # yield
47
+ # # end
48
+ # # end
49
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
50
+ # # You can omit any of the parameters described here.
51
+ # def handle(id:, name:, subscriber:, event:, context:)
52
+ # end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **events.event.publish** span tracks the publishing of an event.
5
+ #
6
+ # This span is triggered whenever an event is published via {Rage::Events.publish Rage::Events.publish}.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::PublishEvent
12
+ class << self
13
+ # @private
14
+ def id
15
+ "events.event.publish"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[event: context:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"Events.publish(#{event.class})"',
27
+ event: "event",
28
+ context: "context",
29
+ subscriber_classes: "Rage::Events.__get_subscribers(event.class)"
30
+ }
31
+ end
32
+
33
+ # @!parse [ruby]
34
+ # # @param id ["events.event.publish"] ID of the span
35
+ # # @param name [String] human-readable name of the operation (e.g., `Events.publish(UpdateRecommendations)`)
36
+ # # @param event [Object] the event being published
37
+ # # @param context [Object, nil] the additional context passed along with the event
38
+ # # @param subscriber_classes [Array<Rage::Events::Subscriber>] the list of subscriber classes that will receive the event
39
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
40
+ # #
41
+ # # @example
42
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
43
+ # # handle "events.event.publish", with: :my_handler
44
+ # #
45
+ # # def my_handler(id:, name:, event:, context:, subscriber_classes:)
46
+ # # yield
47
+ # # end
48
+ # # end
49
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
50
+ # # You can omit any of the parameters described here.
51
+ # def handle(id:, name:, event:, context:, subscriber_classes:)
52
+ # end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The **core.fiber.spawn** span tracks the scheduling and processing of application-level fibers created via {Fiber.schedule}.
5
+ #
6
+ # This span is started when a fiber begins processing and ends when the fiber has completed processing.
7
+ # See {handle handle} for the list of arguments passed to handler methods.
8
+ #
9
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
10
+ #
11
+ class Rage::Telemetry::Spans::SpawnFiber
12
+ class << self
13
+ # @private
14
+ def id
15
+ "core.fiber.spawn"
16
+ end
17
+
18
+ # @private
19
+ def span_parameters
20
+ %w[parent:]
21
+ end
22
+
23
+ # @private
24
+ def handler_arguments
25
+ {
26
+ name: '"Fiber.schedule"',
27
+ parent: "parent"
28
+ }
29
+ end
30
+
31
+ # @!parse [ruby]
32
+ # # @param id ["core.fiber.spawn"] ID of the span
33
+ # # @param name ["Fiber.schedule"] human-readable name of the operation
34
+ # # @param parent [Fiber] the parent fiber that the current fiber was scheduled from
35
+ # # @yieldreturn [Rage::Telemetry::SpanResult]
36
+ # #
37
+ # # @example
38
+ # # class MyTelemetryHandler < Rage::Telemetry::Handler
39
+ # # handle "core.fiber.spawn", with: :my_handler
40
+ # #
41
+ # # def my_handler(id:, name:, parent:)
42
+ # # yield
43
+ # # end
44
+ # # end
45
+ # # @note Rage automatically detects which parameters your handler method accepts and only passes those parameters.
46
+ # # You can omit any of the parameters described here.
47
+ # def handle(id:, name:, parent:)
48
+ # end
49
+ end
50
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The `Rage::Telemetry` component provides an interface to monitor various operations and events within the Rage framework.
5
+ #
6
+ # To start using telemetry, define and register custom handlers that will process the telemetry data.
7
+ #
8
+ # 1. **Define Handlers**: Create custom telemetry handlers by subclassing {Rage::Telemetry::Handler Rage::Telemetry::Handler} and implementing the desired logic for processing telemetry data.
9
+ #
10
+ # ```ruby
11
+ # class MyTelemetryHandler < Rage::Telemetry::Handler
12
+ # handle "controller.action.process", with: :log_action
13
+ #
14
+ # def log_action(controller:)
15
+ # puts "Processing action: #{controller.action_name}"
16
+ # yield
17
+ # end
18
+ # end
19
+ # ```
20
+ #
21
+ # 2. **Register Handlers**: Register your custom handlers in the Rage configuration.
22
+ #
23
+ # ```ruby
24
+ # Rage.configure do
25
+ # config.telemetry.use MyTelemetryHandler.new
26
+ # end
27
+ # ```
28
+ #
29
+ # @see Rage::Telemetry::Handler Rage::Telemetry::Handler
30
+ # @see Rage::Telemetry::Spans Rage::Telemetry::Spans
31
+ #
32
+ module Rage::Telemetry
33
+ # Returns the list of all available telemetry spans.
34
+ # @return [Array<String>] the list of available telemetry spans
35
+ def self.available_spans
36
+ __registry.keys
37
+ end
38
+
39
+ # @private
40
+ def self.__registry
41
+ @__registry ||= Spans.constants.each_with_object({}) do |const, memo|
42
+ span = Spans.const_get(const)
43
+ memo[span.id] = span
44
+ end
45
+ end
46
+
47
+ # @private
48
+ def self.tracer
49
+ @tracer ||= Tracer.new(__registry, Rage.config.telemetry.handlers_map)
50
+ end
51
+
52
+ # @private
53
+ def self.__setup
54
+ tracer.setup
55
+ end
56
+
57
+ ##
58
+ # The namespace contains all telemetry span definitions.
59
+ # Each span represents a specific operation or event within the framework that can be monitored and traced.
60
+ #
61
+ # Spans always pass two standard keyword arguments to their handlers:
62
+ #
63
+ # * `:id` - The unique identifier of the span.
64
+ # * `:name` - The human-readable name of the operation.
65
+ #
66
+ # Handlers can also receive additional context-specific keyword arguments as defined by each span.
67
+ #
68
+ # # Available Spans
69
+ #
70
+ # | ID | Reference | Description |
71
+ # | --- | --- |
72
+ # | `core.fiber.dispatch` | {DispatchFiber} | Wraps the scheduling and processing of system-level fibers created by the framework to process requests and deferred tasks |
73
+ # | `core.fiber.spawn` | {SpawnFiber} | Wraps the scheduling and processing of application-level fibers created via {Fiber.schedule} |
74
+ # | `core.fiber.await` | {AwaitFiber} | Wraps the processing of the {Fiber.await} calls |
75
+ # | `controller.action.process` | {ProcessControllerAction} | Wraps the processing of controller actions |
76
+ # | `cable.websocket.handshake` | {CreateWebsocketConnection} | Wraps the WebSocket connection handshake process |
77
+ # | `cable.connection.process` | {ProcessCableConnection} | Wraps the processing of connect actions in {Rage::Cable Rage::Cable} |
78
+ # | `cable.action.process` | {ProcessCableAction} | Wraps the processing of {Rage::Cable Rage::Cable} channel actions |
79
+ # | `cable.stream.broadcast` | {BroadcastCableStream} | Wraps the broadcasting of messages to {Rage::Cable Rage::Cable} streams |
80
+ # | `deferred.task.enqueue` | {EnqueueDeferredTask} | Wraps the enqueuing of deferred tasks |
81
+ # | `deferred.task.process` | {ProcessDeferredTask} | Wraps the processing of deferred tasks |
82
+ # | `events.event.publish` | {PublishEvent} | Wraps the publishing of events via {Rage::Events Rage::Events} |
83
+ # | `events.subscriber.process` | {ProcessEventSubscriber} | Wraps the processing of events by subscribers |
84
+ #
85
+ module Spans
86
+ end
87
+
88
+ # @private
89
+ HandlerRef = Data.define(:instance, :method_name)
90
+
91
+ # Contains the result of a span execution.
92
+ # @!attribute [r] exception
93
+ # @return [Exception, nil] The exception raised during the span execution, if any.
94
+ # @example
95
+ # class MyTelemetryHandler < Rage::Telemetry::Handler
96
+ # handle "controller.action.process", with: :monitor_500
97
+ #
98
+ # def monitor_500
99
+ # result = yield
100
+ #
101
+ # if result.error?
102
+ # MyObservabilitySDK.notify("500 Error Detected", result.exception)
103
+ # end
104
+ # end
105
+ # end
106
+ SpanResult = Struct.new(:exception) do
107
+ # Returns `true` if the span resulted in an error.
108
+ def error?
109
+ !!exception
110
+ end
111
+
112
+ # Returns `true` if the span executed successfully.
113
+ def success?
114
+ !error?
115
+ end
116
+ end
117
+ end
118
+
119
+ require_relative "tracer"
120
+ require_relative "handler"
121
+ Dir["#{__dir__}/spans/*.rb"].each { |span| require_relative span }