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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Appraisals +19 -0
- data/CHANGELOG.md +15 -1
- data/CODE_OF_CONDUCT.md +13 -17
- data/Gemfile +3 -0
- data/README.md +60 -63
- data/Rakefile +14 -0
- data/lib/rage/all.rb +3 -0
- data/lib/rage/cable/cable.rb +11 -7
- data/lib/rage/cable/channel.rb +6 -1
- data/lib/rage/cable/connection.rb +4 -0
- data/lib/rage/cable/router.rb +14 -9
- data/lib/rage/configuration.rb +235 -21
- data/lib/rage/controller/api.rb +49 -44
- data/lib/rage/deferred/context.rb +30 -2
- data/lib/rage/deferred/deferred.rb +18 -6
- data/lib/rage/deferred/metadata.rb +39 -0
- data/lib/rage/deferred/middleware_chain.rb +67 -0
- data/lib/rage/deferred/task.rb +45 -17
- data/lib/rage/events/events.rb +3 -3
- data/lib/rage/events/subscriber.rb +36 -25
- data/lib/rage/fiber.rb +33 -31
- data/lib/rage/fiber_scheduler.rb +6 -2
- data/lib/rage/logger/logger.rb +7 -1
- data/lib/rage/middleware/body_finalizer.rb +14 -0
- data/lib/rage/response.rb +10 -5
- data/lib/rage/rspec.rb +17 -17
- data/lib/rage/setup.rb +2 -2
- data/lib/rage/telemetry/handler.rb +131 -0
- data/lib/rage/telemetry/spans/await_fiber.rb +50 -0
- data/lib/rage/telemetry/spans/broadcast_cable_stream.rb +50 -0
- data/lib/rage/telemetry/spans/create_websocket_connection.rb +50 -0
- data/lib/rage/telemetry/spans/dispatch_fiber.rb +48 -0
- data/lib/rage/telemetry/spans/enqueue_deferred_task.rb +52 -0
- data/lib/rage/telemetry/spans/process_cable_action.rb +56 -0
- data/lib/rage/telemetry/spans/process_cable_connection.rb +56 -0
- data/lib/rage/telemetry/spans/process_controller_action.rb +56 -0
- data/lib/rage/telemetry/spans/process_deferred_task.rb +54 -0
- data/lib/rage/telemetry/spans/process_event_subscriber.rb +54 -0
- data/lib/rage/telemetry/spans/publish_event.rb +54 -0
- data/lib/rage/telemetry/spans/spawn_fiber.rb +50 -0
- data/lib/rage/telemetry/telemetry.rb +121 -0
- data/lib/rage/telemetry/tracer.rb +97 -0
- data/lib/rage/version.rb +1 -1
- data/rage.gemspec +4 -3
- 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 }
|