Class: Bolt::Analytics::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/analytics.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_id) ⇒ Client

Returns a new instance of Client.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/bolt/analytics.rb', line 106

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

Instance Attribute Details

#bundled_contentObject

Returns the value of attribute bundled_content.



104
105
106
# File 'lib/bolt/analytics.rb', line 104

def bundled_content
  @bundled_content
end

#user_idObject (readonly)

Returns the value of attribute user_id.



103
104
105
# File 'lib/bolt/analytics.rb', line 103

def user_id
  @user_id
end

Instance Method Details

#base_paramsObject

These parameters have terrible names. See this page for complete documentation: developers.google.com/analytics/devguides/collection/protocol/v1/parameters



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/bolt/analytics.rb', line 188

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

#compute_osObject



208
209
210
211
212
# File 'lib/bolt/analytics.rb', line 208

def compute_os
  require 'facter'
  os = Facter.value('os')
  "#{os['name']} #{os.dig('release', 'major')}"
end

#event(category, action, label: nil, value: nil, **kwargs) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/bolt/analytics.rb', line 154

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

#finishObject

If the user is running a very fast command, there may not be time for analytics submission to complete before the command is finished. In that case, we give a little buffer for any stragglers to finish up. 250ms strikes a balance between accomodating slower networks while not introducing a noticeable “hang”.



219
220
221
222
# File 'lib/bolt/analytics.rb', line 219

def finish
  @executor.shutdown
  @executor.wait_for_termination(0.25)
end

#plan_counts(plans_path) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
# File 'lib/bolt/analytics.rb', line 142

def plan_counts(plans_path)
  pp_count, yaml_count = if File.exist?(plans_path)
                           %w[pp yaml].map do |extension|
                             Find.find(plans_path.to_s).grep(/.*\.#{extension}/).length
                           end
                         else
                           [0, 0]
                         end

  { puppet_plan_count: pp_count, yaml_plan_count: yaml_count }
end

#report_bundled_content(mode, name) ⇒ Object



136
137
138
139
140
# File 'lib/bolt/analytics.rb', line 136

def report_bundled_content(mode, name)
  if bundled_content[mode.split.first]&.include?(name)
    event('Bundled Content', mode, label: name)
  end
end

#screen_view(screen, **kwargs) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/bolt/analytics.rb', line 121

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

#submit(params) ⇒ Object



176
177
178
179
180
181
182
183
184
# File 'lib/bolt/analytics.rb', line 176

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