brainzlab 0.1.2 → 0.1.4
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/LICENSE +6 -21
- data/README.md +16 -2
- data/lib/brainzlab/beacon/client.rb +38 -40
- data/lib/brainzlab/beacon/provisioner.rb +1 -1
- data/lib/brainzlab/beacon.rb +15 -15
- data/lib/brainzlab/configuration.rb +112 -90
- data/lib/brainzlab/context.rb +2 -3
- data/lib/brainzlab/cortex/client.rb +29 -31
- data/lib/brainzlab/cortex/provisioner.rb +1 -1
- data/lib/brainzlab/cortex.rb +7 -11
- data/lib/brainzlab/dendrite/client.rb +42 -44
- data/lib/brainzlab/dendrite/provisioner.rb +1 -1
- data/lib/brainzlab/dendrite.rb +4 -4
- data/lib/brainzlab/devtools/data/collector.rb +22 -22
- data/lib/brainzlab/devtools/middleware/asset_server.rb +14 -14
- data/lib/brainzlab/devtools/middleware/database_handler.rb +52 -55
- data/lib/brainzlab/devtools/middleware/debug_panel.rb +19 -19
- data/lib/brainzlab/devtools/middleware/error_page.rb +45 -44
- data/lib/brainzlab/devtools/renderers/debug_panel_renderer.rb +39 -35
- data/lib/brainzlab/devtools/renderers/error_page_renderer.rb +13 -9
- data/lib/brainzlab/devtools.rb +11 -11
- data/lib/brainzlab/flux/buffer.rb +3 -3
- data/lib/brainzlab/flux/client.rb +14 -16
- data/lib/brainzlab/flux/provisioner.rb +13 -13
- data/lib/brainzlab/flux.rb +8 -8
- data/lib/brainzlab/instrumentation/action_cable.rb +351 -0
- data/lib/brainzlab/instrumentation/action_controller.rb +649 -0
- data/lib/brainzlab/instrumentation/action_dispatch.rb +259 -0
- data/lib/brainzlab/instrumentation/action_mailbox.rb +197 -0
- data/lib/brainzlab/instrumentation/action_mailer.rb +14 -13
- data/lib/brainzlab/instrumentation/action_view.rb +380 -0
- data/lib/brainzlab/instrumentation/active_job.rb +569 -0
- data/lib/brainzlab/instrumentation/active_record.rb +467 -36
- data/lib/brainzlab/instrumentation/active_storage.rb +541 -0
- data/lib/brainzlab/instrumentation/active_support_cache.rb +700 -0
- data/lib/brainzlab/instrumentation/aws.rb +43 -39
- data/lib/brainzlab/instrumentation/dalli.rb +20 -20
- data/lib/brainzlab/instrumentation/delayed_job.rb +27 -29
- data/lib/brainzlab/instrumentation/elasticsearch.rb +23 -24
- data/lib/brainzlab/instrumentation/excon.rb +27 -27
- data/lib/brainzlab/instrumentation/faraday.rb +3 -4
- data/lib/brainzlab/instrumentation/good_job.rb +28 -28
- data/lib/brainzlab/instrumentation/grape.rb +24 -24
- data/lib/brainzlab/instrumentation/graphql.rb +24 -23
- data/lib/brainzlab/instrumentation/httparty.rb +13 -14
- data/lib/brainzlab/instrumentation/mongodb.rb +7 -7
- data/lib/brainzlab/instrumentation/net_http.rb +6 -6
- data/lib/brainzlab/instrumentation/rails_deprecation.rb +139 -0
- data/lib/brainzlab/instrumentation/railties.rb +134 -0
- data/lib/brainzlab/instrumentation/redis.rb +14 -21
- data/lib/brainzlab/instrumentation/resque.rb +23 -24
- data/lib/brainzlab/instrumentation/sidekiq.rb +29 -28
- data/lib/brainzlab/instrumentation/solid_queue.rb +37 -41
- data/lib/brainzlab/instrumentation/stripe.rb +36 -37
- data/lib/brainzlab/instrumentation/typhoeus.rb +19 -17
- data/lib/brainzlab/instrumentation.rb +111 -21
- data/lib/brainzlab/nerve/client.rb +38 -40
- data/lib/brainzlab/nerve/provisioner.rb +1 -1
- data/lib/brainzlab/nerve.rb +6 -6
- data/lib/brainzlab/pulse/client.rb +15 -11
- data/lib/brainzlab/pulse/instrumentation.rb +61 -57
- data/lib/brainzlab/pulse/propagation.rb +28 -28
- data/lib/brainzlab/pulse/provisioner.rb +12 -12
- data/lib/brainzlab/pulse/tracer.rb +3 -3
- data/lib/brainzlab/pulse.rb +13 -13
- data/lib/brainzlab/rails/log_formatter.rb +127 -121
- data/lib/brainzlab/rails/log_subscriber.rb +70 -76
- data/lib/brainzlab/rails/railtie.rb +66 -89
- data/lib/brainzlab/recall/buffer.rb +1 -1
- data/lib/brainzlab/recall/client.rb +14 -10
- data/lib/brainzlab/recall/logger.rb +16 -18
- data/lib/brainzlab/recall/provisioner.rb +16 -16
- data/lib/brainzlab/recall.rb +11 -13
- data/lib/brainzlab/reflex/breadcrumbs.rb +2 -2
- data/lib/brainzlab/reflex/client.rb +14 -10
- data/lib/brainzlab/reflex/provisioner.rb +12 -12
- data/lib/brainzlab/reflex.rb +29 -29
- data/lib/brainzlab/sentinel/client.rb +40 -42
- data/lib/brainzlab/sentinel/provisioner.rb +1 -1
- data/lib/brainzlab/sentinel.rb +5 -5
- data/lib/brainzlab/signal/client.rb +12 -14
- data/lib/brainzlab/signal/provisioner.rb +12 -12
- data/lib/brainzlab/signal.rb +7 -7
- data/lib/brainzlab/synapse/client.rb +42 -44
- data/lib/brainzlab/synapse/provisioner.rb +1 -1
- data/lib/brainzlab/synapse.rb +6 -6
- data/lib/brainzlab/utilities/circuit_breaker.rb +37 -41
- data/lib/brainzlab/utilities/health_check.rb +53 -55
- data/lib/brainzlab/utilities/log_formatter.rb +38 -40
- data/lib/brainzlab/utilities/rate_limiter.rb +5 -5
- data/lib/brainzlab/utilities.rb +4 -4
- data/lib/brainzlab/vault/cache.rb +1 -1
- data/lib/brainzlab/vault/client.rb +39 -41
- data/lib/brainzlab/vault/provisioner.rb +1 -1
- data/lib/brainzlab/vault.rb +19 -25
- data/lib/brainzlab/version.rb +1 -1
- data/lib/brainzlab/vision/client.rb +20 -20
- data/lib/brainzlab/vision/provisioner.rb +21 -21
- data/lib/brainzlab/vision.rb +17 -19
- data/lib/brainzlab-sdk.rb +1 -1
- data/lib/brainzlab.rb +22 -24
- data/lib/generators/brainzlab/install/install_generator.rb +29 -27
- metadata +11 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'uri'
|
|
6
6
|
|
|
7
7
|
module BrainzLab
|
|
8
8
|
module Flux
|
|
@@ -12,23 +12,23 @@ module BrainzLab
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def send_event(event)
|
|
15
|
-
post(
|
|
15
|
+
post('/api/v1/events', event)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def send_events(events)
|
|
19
|
-
post(
|
|
19
|
+
post('/api/v1/events/batch', { events: events })
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def send_metric(metric)
|
|
23
|
-
post(
|
|
23
|
+
post('/api/v1/metrics', metric)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def send_metrics(metrics)
|
|
27
|
-
post(
|
|
27
|
+
post('/api/v1/metrics/batch', { metrics: metrics })
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def send_batch(events:, metrics:)
|
|
31
|
-
post(
|
|
31
|
+
post('/api/v1/flux/batch', { events: events, metrics: metrics })
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
private
|
|
@@ -36,24 +36,22 @@ module BrainzLab
|
|
|
36
36
|
def post(path, body)
|
|
37
37
|
uri = URI.parse("#{base_url}#{path}")
|
|
38
38
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
39
|
-
http.use_ssl = uri.scheme ==
|
|
39
|
+
http.use_ssl = uri.scheme == 'https'
|
|
40
40
|
http.open_timeout = 5
|
|
41
41
|
http.read_timeout = 10
|
|
42
42
|
|
|
43
43
|
request = Net::HTTP::Post.new(uri.path)
|
|
44
|
-
request[
|
|
45
|
-
request[
|
|
46
|
-
request[
|
|
44
|
+
request['Content-Type'] = 'application/json'
|
|
45
|
+
request['Authorization'] = "Bearer #{api_key}"
|
|
46
|
+
request['User-Agent'] = "brainzlab-sdk/#{BrainzLab::VERSION}"
|
|
47
47
|
request.body = body.to_json
|
|
48
48
|
|
|
49
49
|
response = http.request(request)
|
|
50
50
|
|
|
51
|
-
unless response.is_a?(Net::HTTPSuccess)
|
|
52
|
-
BrainzLab.debug("[Flux] Request failed: #{response.code} - #{response.body}")
|
|
53
|
-
end
|
|
51
|
+
BrainzLab.debug("[Flux] Request failed: #{response.code} - #{response.body}") unless response.is_a?(Net::HTTPSuccess)
|
|
54
52
|
|
|
55
53
|
response
|
|
56
|
-
rescue => e
|
|
54
|
+
rescue StandardError => e
|
|
57
55
|
BrainzLab.debug("[Flux] Request error: #{e.message}")
|
|
58
56
|
nil
|
|
59
57
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'uri'
|
|
6
6
|
|
|
7
7
|
module BrainzLab
|
|
8
8
|
module Flux
|
|
@@ -17,7 +17,7 @@ module BrainzLab
|
|
|
17
17
|
return unless @config.flux_url && !@config.flux_url.to_s.empty?
|
|
18
18
|
return unless @config.secret_key && !@config.secret_key.to_s.empty?
|
|
19
19
|
|
|
20
|
-
BrainzLab.debug_log(
|
|
20
|
+
BrainzLab.debug_log('[Flux] Auto-provisioning project...')
|
|
21
21
|
provision_project
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -26,16 +26,16 @@ module BrainzLab
|
|
|
26
26
|
def provision_project
|
|
27
27
|
uri = URI.parse("#{@config.flux_url}/api/v1/projects/provision")
|
|
28
28
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
29
|
-
http.use_ssl = uri.scheme ==
|
|
29
|
+
http.use_ssl = uri.scheme == 'https'
|
|
30
30
|
http.open_timeout = 10
|
|
31
31
|
http.read_timeout = 30
|
|
32
32
|
|
|
33
33
|
request = Net::HTTP::Post.new(uri.path)
|
|
34
|
-
request[
|
|
35
|
-
request[
|
|
36
|
-
request[
|
|
34
|
+
request['Content-Type'] = 'application/json'
|
|
35
|
+
request['Authorization'] = "Bearer #{@config.secret_key}"
|
|
36
|
+
request['User-Agent'] = "brainzlab-sdk/#{BrainzLab::VERSION}"
|
|
37
37
|
request.body = {
|
|
38
|
-
name: @config.service ||
|
|
38
|
+
name: @config.service || 'default',
|
|
39
39
|
environment: @config.environment
|
|
40
40
|
}.to_json
|
|
41
41
|
|
|
@@ -43,13 +43,13 @@ module BrainzLab
|
|
|
43
43
|
|
|
44
44
|
if response.is_a?(Net::HTTPSuccess)
|
|
45
45
|
data = JSON.parse(response.body)
|
|
46
|
-
@config.flux_ingest_key = data[
|
|
47
|
-
@config.flux_api_key = data[
|
|
48
|
-
BrainzLab.debug_log(
|
|
46
|
+
@config.flux_ingest_key = data['ingest_key']
|
|
47
|
+
@config.flux_api_key = data['api_key']
|
|
48
|
+
BrainzLab.debug_log('[Flux] Project provisioned successfully')
|
|
49
49
|
else
|
|
50
50
|
BrainzLab.debug_log("[Flux] Provisioning failed: #{response.code} - #{response.body}")
|
|
51
51
|
end
|
|
52
|
-
rescue => e
|
|
52
|
+
rescue StandardError => e
|
|
53
53
|
BrainzLab.debug_log("[Flux] Provisioning error: #{e.message}")
|
|
54
54
|
end
|
|
55
55
|
end
|
data/lib/brainzlab/flux.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
3
|
+
require_relative 'flux/client'
|
|
4
|
+
require_relative 'flux/buffer'
|
|
5
|
+
require_relative 'flux/provisioner'
|
|
6
6
|
|
|
7
7
|
module BrainzLab
|
|
8
8
|
module Flux
|
|
@@ -49,7 +49,7 @@ module BrainzLab
|
|
|
49
49
|
return unless BrainzLab.configuration.flux_valid?
|
|
50
50
|
|
|
51
51
|
metric = {
|
|
52
|
-
type:
|
|
52
|
+
type: 'gauge',
|
|
53
53
|
name: name,
|
|
54
54
|
value: value,
|
|
55
55
|
tags: tags,
|
|
@@ -67,7 +67,7 @@ module BrainzLab
|
|
|
67
67
|
return unless BrainzLab.configuration.flux_valid?
|
|
68
68
|
|
|
69
69
|
metric = {
|
|
70
|
-
type:
|
|
70
|
+
type: 'counter',
|
|
71
71
|
name: name,
|
|
72
72
|
value: value,
|
|
73
73
|
tags: tags,
|
|
@@ -90,7 +90,7 @@ module BrainzLab
|
|
|
90
90
|
return unless BrainzLab.configuration.flux_valid?
|
|
91
91
|
|
|
92
92
|
metric = {
|
|
93
|
-
type:
|
|
93
|
+
type: 'distribution',
|
|
94
94
|
name: name,
|
|
95
95
|
value: value,
|
|
96
96
|
tags: tags,
|
|
@@ -108,7 +108,7 @@ module BrainzLab
|
|
|
108
108
|
return unless BrainzLab.configuration.flux_valid?
|
|
109
109
|
|
|
110
110
|
metric = {
|
|
111
|
-
type:
|
|
111
|
+
type: 'set',
|
|
112
112
|
name: name,
|
|
113
113
|
value: value.to_s,
|
|
114
114
|
tags: tags,
|
|
@@ -127,7 +127,7 @@ module BrainzLab
|
|
|
127
127
|
yield
|
|
128
128
|
ensure
|
|
129
129
|
duration_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000
|
|
130
|
-
distribution(name, duration_ms, tags: tags.merge(unit:
|
|
130
|
+
distribution(name, duration_ms, tags: tags.merge(unit: 'ms'))
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
133
|
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BrainzLab
|
|
4
|
+
module Instrumentation
|
|
5
|
+
class ActionCable
|
|
6
|
+
# Thresholds for slow operations (in milliseconds)
|
|
7
|
+
SLOW_ACTION_THRESHOLD = 100
|
|
8
|
+
VERY_SLOW_ACTION_THRESHOLD = 500
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def install!
|
|
12
|
+
return unless defined?(::ActionCable)
|
|
13
|
+
return if @installed
|
|
14
|
+
|
|
15
|
+
install_perform_action_subscriber!
|
|
16
|
+
install_transmit_subscriber!
|
|
17
|
+
install_transmit_subscription_confirmation_subscriber!
|
|
18
|
+
install_transmit_subscription_rejection_subscriber!
|
|
19
|
+
install_broadcast_subscriber!
|
|
20
|
+
|
|
21
|
+
@installed = true
|
|
22
|
+
BrainzLab.debug_log('ActionCable instrumentation installed')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def installed?
|
|
26
|
+
@installed == true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# ============================================
|
|
32
|
+
# perform_action.action_cable
|
|
33
|
+
# ============================================
|
|
34
|
+
def install_perform_action_subscriber!
|
|
35
|
+
ActiveSupport::Notifications.subscribe('perform_action.action_cable') do |*args|
|
|
36
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
37
|
+
handle_perform_action(event)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def handle_perform_action(event)
|
|
42
|
+
payload = event.payload
|
|
43
|
+
duration = event.duration.round(2)
|
|
44
|
+
|
|
45
|
+
channel_class = payload[:channel_class]
|
|
46
|
+
action = payload[:action]
|
|
47
|
+
data = payload[:data]
|
|
48
|
+
|
|
49
|
+
# Determine level based on duration
|
|
50
|
+
level = case duration
|
|
51
|
+
when 0...SLOW_ACTION_THRESHOLD then :info
|
|
52
|
+
when SLOW_ACTION_THRESHOLD...VERY_SLOW_ACTION_THRESHOLD then :warning
|
|
53
|
+
else :error
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Record breadcrumb
|
|
57
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
58
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
59
|
+
"Cable action: #{channel_class}##{action} (#{duration}ms)",
|
|
60
|
+
category: 'cable.action',
|
|
61
|
+
level: level,
|
|
62
|
+
data: {
|
|
63
|
+
channel: channel_class,
|
|
64
|
+
action: action,
|
|
65
|
+
duration_ms: duration
|
|
66
|
+
}.compact
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Add Pulse span
|
|
71
|
+
record_action_span(event, channel_class, action, duration, data)
|
|
72
|
+
|
|
73
|
+
# Log slow actions
|
|
74
|
+
log_slow_action(channel_class, action, duration) if duration >= SLOW_ACTION_THRESHOLD
|
|
75
|
+
rescue StandardError => e
|
|
76
|
+
BrainzLab.debug_log("ActionCable perform_action instrumentation failed: #{e.message}")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# ============================================
|
|
80
|
+
# transmit.action_cable
|
|
81
|
+
# ============================================
|
|
82
|
+
def install_transmit_subscriber!
|
|
83
|
+
ActiveSupport::Notifications.subscribe('transmit.action_cable') do |*args|
|
|
84
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
85
|
+
handle_transmit(event)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def handle_transmit(event)
|
|
90
|
+
payload = event.payload
|
|
91
|
+
duration = event.duration.round(2)
|
|
92
|
+
|
|
93
|
+
channel_class = payload[:channel_class]
|
|
94
|
+
data = payload[:data]
|
|
95
|
+
via = payload[:via]
|
|
96
|
+
|
|
97
|
+
# Record breadcrumb
|
|
98
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
99
|
+
message = via ? "Cable transmit via #{via}" : 'Cable transmit'
|
|
100
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
101
|
+
"#{message}: #{channel_class} (#{duration}ms)",
|
|
102
|
+
category: 'cable.transmit',
|
|
103
|
+
level: :info,
|
|
104
|
+
data: {
|
|
105
|
+
channel: channel_class,
|
|
106
|
+
via: via,
|
|
107
|
+
duration_ms: duration
|
|
108
|
+
}.compact
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Add Pulse span
|
|
113
|
+
record_transmit_span(event, channel_class, duration, via)
|
|
114
|
+
rescue StandardError => e
|
|
115
|
+
BrainzLab.debug_log("ActionCable transmit instrumentation failed: #{e.message}")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# ============================================
|
|
119
|
+
# transmit_subscription_confirmation.action_cable
|
|
120
|
+
# ============================================
|
|
121
|
+
def install_transmit_subscription_confirmation_subscriber!
|
|
122
|
+
ActiveSupport::Notifications.subscribe('transmit_subscription_confirmation.action_cable') do |*args|
|
|
123
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
124
|
+
handle_subscription_confirmation(event)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def handle_subscription_confirmation(event)
|
|
129
|
+
payload = event.payload
|
|
130
|
+
duration = event.duration.round(2)
|
|
131
|
+
|
|
132
|
+
channel_class = payload[:channel_class]
|
|
133
|
+
|
|
134
|
+
# Record breadcrumb
|
|
135
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
136
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
137
|
+
"Cable subscribed: #{channel_class}",
|
|
138
|
+
category: 'cable.subscribe',
|
|
139
|
+
level: :info,
|
|
140
|
+
data: {
|
|
141
|
+
channel: channel_class,
|
|
142
|
+
status: 'confirmed',
|
|
143
|
+
duration_ms: duration
|
|
144
|
+
}.compact
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Add Pulse span
|
|
149
|
+
record_subscription_span(event, channel_class, 'confirmed', duration)
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
BrainzLab.debug_log("ActionCable subscription confirmation instrumentation failed: #{e.message}")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# ============================================
|
|
155
|
+
# transmit_subscription_rejection.action_cable
|
|
156
|
+
# ============================================
|
|
157
|
+
def install_transmit_subscription_rejection_subscriber!
|
|
158
|
+
ActiveSupport::Notifications.subscribe('transmit_subscription_rejection.action_cable') do |*args|
|
|
159
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
160
|
+
handle_subscription_rejection(event)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def handle_subscription_rejection(event)
|
|
165
|
+
payload = event.payload
|
|
166
|
+
duration = event.duration.round(2)
|
|
167
|
+
|
|
168
|
+
channel_class = payload[:channel_class]
|
|
169
|
+
|
|
170
|
+
# Record breadcrumb - rejection is a warning
|
|
171
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
172
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
173
|
+
"Cable subscription rejected: #{channel_class}",
|
|
174
|
+
category: 'cable.subscribe',
|
|
175
|
+
level: :warning,
|
|
176
|
+
data: {
|
|
177
|
+
channel: channel_class,
|
|
178
|
+
status: 'rejected',
|
|
179
|
+
duration_ms: duration
|
|
180
|
+
}.compact
|
|
181
|
+
)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Add Pulse span
|
|
185
|
+
record_subscription_span(event, channel_class, 'rejected', duration)
|
|
186
|
+
|
|
187
|
+
# Log rejection to Recall
|
|
188
|
+
if BrainzLab.configuration.recall_effectively_enabled?
|
|
189
|
+
BrainzLab::Recall.warn(
|
|
190
|
+
"ActionCable subscription rejected",
|
|
191
|
+
channel: channel_class
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
rescue StandardError => e
|
|
195
|
+
BrainzLab.debug_log("ActionCable subscription rejection instrumentation failed: #{e.message}")
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# ============================================
|
|
199
|
+
# broadcast.action_cable
|
|
200
|
+
# ============================================
|
|
201
|
+
def install_broadcast_subscriber!
|
|
202
|
+
ActiveSupport::Notifications.subscribe('broadcast.action_cable') do |*args|
|
|
203
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
|
204
|
+
handle_broadcast(event)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def handle_broadcast(event)
|
|
209
|
+
payload = event.payload
|
|
210
|
+
duration = event.duration.round(2)
|
|
211
|
+
|
|
212
|
+
broadcasting = payload[:broadcasting]
|
|
213
|
+
message = payload[:message]
|
|
214
|
+
coder = payload[:coder]
|
|
215
|
+
|
|
216
|
+
# Record breadcrumb
|
|
217
|
+
if BrainzLab.configuration.reflex_effectively_enabled?
|
|
218
|
+
BrainzLab::Reflex.add_breadcrumb(
|
|
219
|
+
"Cable broadcast: #{broadcasting} (#{duration}ms)",
|
|
220
|
+
category: 'cable.broadcast',
|
|
221
|
+
level: :info,
|
|
222
|
+
data: {
|
|
223
|
+
broadcasting: broadcasting,
|
|
224
|
+
coder: coder&.to_s,
|
|
225
|
+
duration_ms: duration
|
|
226
|
+
}.compact
|
|
227
|
+
)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Add Pulse span
|
|
231
|
+
record_broadcast_span(event, broadcasting, duration, coder)
|
|
232
|
+
rescue StandardError => e
|
|
233
|
+
BrainzLab.debug_log("ActionCable broadcast instrumentation failed: #{e.message}")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# ============================================
|
|
237
|
+
# Span Recording Helpers
|
|
238
|
+
# ============================================
|
|
239
|
+
def record_action_span(event, channel_class, action, duration, data)
|
|
240
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
241
|
+
|
|
242
|
+
tracer = BrainzLab::Pulse.tracer
|
|
243
|
+
return unless tracer.current_trace
|
|
244
|
+
|
|
245
|
+
span_data = {
|
|
246
|
+
span_id: SecureRandom.uuid,
|
|
247
|
+
name: "cable.action.#{action}",
|
|
248
|
+
kind: 'websocket',
|
|
249
|
+
started_at: event.time,
|
|
250
|
+
ended_at: event.end,
|
|
251
|
+
duration_ms: duration,
|
|
252
|
+
error: false,
|
|
253
|
+
data: {
|
|
254
|
+
'cable.channel' => channel_class,
|
|
255
|
+
'cable.action' => action
|
|
256
|
+
}.compact
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
tracer.current_spans << span_data
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def record_transmit_span(event, channel_class, duration, via)
|
|
263
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
264
|
+
|
|
265
|
+
tracer = BrainzLab::Pulse.tracer
|
|
266
|
+
return unless tracer.current_trace
|
|
267
|
+
|
|
268
|
+
span_data = {
|
|
269
|
+
span_id: SecureRandom.uuid,
|
|
270
|
+
name: 'cable.transmit',
|
|
271
|
+
kind: 'websocket',
|
|
272
|
+
started_at: event.time,
|
|
273
|
+
ended_at: event.end,
|
|
274
|
+
duration_ms: duration,
|
|
275
|
+
error: false,
|
|
276
|
+
data: {
|
|
277
|
+
'cable.channel' => channel_class,
|
|
278
|
+
'cable.via' => via
|
|
279
|
+
}.compact
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
tracer.current_spans << span_data
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def record_subscription_span(event, channel_class, status, duration)
|
|
286
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
287
|
+
|
|
288
|
+
tracer = BrainzLab::Pulse.tracer
|
|
289
|
+
return unless tracer.current_trace
|
|
290
|
+
|
|
291
|
+
span_data = {
|
|
292
|
+
span_id: SecureRandom.uuid,
|
|
293
|
+
name: 'cable.subscribe',
|
|
294
|
+
kind: 'websocket',
|
|
295
|
+
started_at: event.time,
|
|
296
|
+
ended_at: event.end,
|
|
297
|
+
duration_ms: duration,
|
|
298
|
+
error: status == 'rejected',
|
|
299
|
+
data: {
|
|
300
|
+
'cable.channel' => channel_class,
|
|
301
|
+
'cable.subscription_status' => status
|
|
302
|
+
}.compact
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
tracer.current_spans << span_data
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def record_broadcast_span(event, broadcasting, duration, coder)
|
|
309
|
+
return unless BrainzLab.configuration.pulse_effectively_enabled?
|
|
310
|
+
|
|
311
|
+
tracer = BrainzLab::Pulse.tracer
|
|
312
|
+
return unless tracer.current_trace
|
|
313
|
+
|
|
314
|
+
span_data = {
|
|
315
|
+
span_id: SecureRandom.uuid,
|
|
316
|
+
name: 'cable.broadcast',
|
|
317
|
+
kind: 'websocket',
|
|
318
|
+
started_at: event.time,
|
|
319
|
+
ended_at: event.end,
|
|
320
|
+
duration_ms: duration,
|
|
321
|
+
error: false,
|
|
322
|
+
data: {
|
|
323
|
+
'cable.broadcasting' => broadcasting,
|
|
324
|
+
'cable.coder' => coder&.to_s
|
|
325
|
+
}.compact
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
tracer.current_spans << span_data
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# ============================================
|
|
332
|
+
# Logging Helpers
|
|
333
|
+
# ============================================
|
|
334
|
+
def log_slow_action(channel_class, action, duration)
|
|
335
|
+
return unless BrainzLab.configuration.recall_effectively_enabled?
|
|
336
|
+
|
|
337
|
+
level = duration >= VERY_SLOW_ACTION_THRESHOLD ? :error : :warn
|
|
338
|
+
|
|
339
|
+
BrainzLab::Recall.send(
|
|
340
|
+
level,
|
|
341
|
+
"Slow ActionCable action: #{channel_class}##{action} (#{duration}ms)",
|
|
342
|
+
channel: channel_class,
|
|
343
|
+
action: action,
|
|
344
|
+
duration_ms: duration,
|
|
345
|
+
threshold_exceeded: duration >= VERY_SLOW_ACTION_THRESHOLD ? 'critical' : 'warning'
|
|
346
|
+
)
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|