class Bolt::Analytics::Client
def base_params
These parameters have terrible names. See this page for complete documentation:
def base_params { v: PROTOCOL_VERSION, # Client ID cid: @user_id, # Tracking ID tid: TRACKING_ID, # Application Name an: APPLICATION_NAME, # Application Version av: Bolt::VERSION, # Anonymize IPs aip: true, # User locale ul: Locale.current.to_rfc, # Custom Dimension 1 (Operating System) cd1: @os } end
def compute_os
def compute_os require 'facter' os = Facter.value('os') "#{os['name']} #{os.dig('release', 'major')}" end
def event(category, action, label: nil, value: nil, **kwargs)
def event(category, action, label: nil, value: nil, **kwargs) custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k| CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'") end event_params = { # Type t: 'event', # Event Category ec: category, # Event Action ea: action }.merge(custom_dimensions) # Event Label event_params[:el] = label if label # Event Value event_params[:ev] = value if value submit(base_params.merge(event_params)) end
def finish
250ms strikes a balance between accomodating slower networks while not
that case, we give a little buffer for any stragglers to finish up.
analytics submission to complete before the command is finished. In
If the user is running a very fast command, there may not be time for
def finish @executor.shutdown @executor.wait_for_termination(0.25) end
def initialize(user_id)
def initialize(user_id) # lazy-load expensive gem code require 'concurrent/configuration' require 'concurrent/future' require 'httpclient' require 'locale' @logger = Bolt::Logger.logger(self) @http = HTTPClient.new @user_id = user_id @executor = Concurrent.global_io_executor @os = compute_os @bundled_content = {} end
def report_bundled_content(mode, name)
def report_bundled_content(mode, name) if bundled_content[mode.split.first]&.include?(name) event('Bundled Content', mode, label: name) end end
def screen_view(screen, **kwargs)
def screen_view(screen, **kwargs) custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k| CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'") end screen_view_params = { # Type t: 'screenview', # Screen Name cd: screen }.merge(custom_dimensions) submit(base_params.merge(screen_view_params)) end
def submit(params)
def submit(params) # Handle analytics submission in the background to avoid blocking the # app or polluting the log with errors Concurrent::Future.execute(executor: @executor) do @logger.trace "Submitting analytics: #{JSON.pretty_generate(params)}" @http.post(TRACKING_URL, params) @logger.trace "Completed analytics submission" end end