debian-mirror-gitlab/lib/gitlab/metrics/subscribers/action_cable.rb
2023-06-20 00:43:36 +05:30

112 lines
3.8 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Metrics
module Subscribers
class ActionCable < ActiveSupport::Subscriber
include Gitlab::Utils::StrongMemoize
BROADCASTING_GRAPHQL_EVENT = 'graphql-event'
BROADCASTING_GRAPHQL_SUBSCRIPTION = 'graphql-subscription'
BROADCASTING_OTHER = 'other'
attach_to :action_cable
SINGLE_CLIENT_TRANSMISSION = :action_cable_single_client_transmissions_total
TRANSMIT_SUBSCRIPTION_CONFIRMATION = :action_cable_subscription_confirmations_total
TRANSMIT_SUBSCRIPTION_REJECTION = :action_cable_subscription_rejections_total
BROADCAST = :action_cable_broadcasts_total
DATA_TRANSMITTED_BYTES = :action_cable_transmitted_bytes
def transmit_subscription_confirmation(event)
confirm_subscription_counter.increment
end
def transmit_subscription_rejection(event)
reject_subscription_counter.increment
end
def transmit(event)
transmit_counter.increment
if event.payload.present?
channel = event.payload[:channel_class]
operation = operation_name_from(event.payload)
data_size = Gitlab::Json.generate(event.payload[:data]).bytesize
transmitted_bytes_histogram.observe({ channel: channel, operation: operation }, data_size)
end
end
def broadcast(event)
broadcast_counter.increment({ broadcasting: broadcasting_from(event.payload) })
end
private
# Since broadcastings can have high dimensionality when they carry IDs, we need to
# collapse them. If it's not a well-know broadcast, we report it as "other".
def broadcasting_from(payload)
broadcasting = payload[:broadcasting]
if broadcasting.start_with?(BROADCASTING_GRAPHQL_EVENT)
# Take at most two levels of topic namespacing.
broadcasting.split(':').reject(&:empty?).take(2).join(':') # rubocop: disable CodeReuse/ActiveRecord
elsif broadcasting.start_with?(BROADCASTING_GRAPHQL_SUBSCRIPTION)
BROADCASTING_GRAPHQL_SUBSCRIPTION
else
BROADCASTING_OTHER
end
end
# When possible tries to query operation name
def operation_name_from(payload)
data = payload.dig(:data, 'result', 'data') || {}
data.each_key.first
end
def transmit_counter
strong_memoize("transmission_counter") do
::Gitlab::Metrics.counter(
SINGLE_CLIENT_TRANSMISSION,
'The number of ActionCable messages transmitted to any client in any channel'
)
end
end
def broadcast_counter
strong_memoize("broadcast_counter") do
::Gitlab::Metrics.counter(
BROADCAST,
'The number of ActionCable broadcasts emitted'
)
end
end
def confirm_subscription_counter
strong_memoize("confirm_subscription_counter") do
::Gitlab::Metrics.counter(
TRANSMIT_SUBSCRIPTION_CONFIRMATION,
'The number of ActionCable subscriptions from clients confirmed'
)
end
end
def reject_subscription_counter
strong_memoize("reject_subscription_counter") do
::Gitlab::Metrics.counter(
TRANSMIT_SUBSCRIPTION_REJECTION,
'The number of ActionCable subscriptions from clients rejected'
)
end
end
def transmitted_bytes_histogram
strong_memoize("transmitted_bytes_histogram") do
::Gitlab::Metrics.histogram(DATA_TRANSMITTED_BYTES, 'Message size, in bytes, transmitted over action cable')
end
end
end
end
end
end