Class: MobileMetrics::Log

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

Constant Summary collapse

@@in_progress_timers =
{}
@@log_file =
nil
@@env_values =
nil
@@verbose =
false
@@upload_location =
nil

Class Method Summary collapse

Class Method Details

.end_timer_metric(name:) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/mobile_metrics.rb', line 158

def self.end_timer_metric(name:)
  if !@@in_progress_timers.has_key?(name)
    print "WARNING: #{name} does not have a running timer, the end_timer_metric call has no effect"
    return
  end

  # Calculate delta
  start = @@in_progress_timers[name]
  now = monotonic_timestamp
  delta_in_ms = ((now - start) * 1000).to_i

  # remove existing timer
  @@in_progress_timers.delete(name)

  # log to file
  overrides = {name: METRIC_TIMER, data: {name: name, duration: delta_in_ms }}
  log_partial_metric(overrides)
end

.log_counter_metric(name:, count:) ⇒ Object



135
136
137
138
# File 'lib/mobile_metrics.rb', line 135

def self.log_counter_metric(name:, count:)
  overrides = { name: METRIC_COUNTER, data: {name: name, count: count.to_i } }
  log_partial_metric(overrides)
end

.log_fileObject



231
232
233
# File 'lib/mobile_metrics.rb', line 231

def self.log_file
  @@log_file
end

.log_ratio_metric(name:, ratio:) ⇒ Object

Public Logging Methods



130
131
132
133
# File 'lib/mobile_metrics.rb', line 130

def self.log_ratio_metric(name:, ratio:)
  overrides = { name: METRIC_RATIO, data: { name: name, ratio: ratio.to_f } }
  log_partial_metric(overrides)
end

.log_size_metric(name:, sizeInBytes:, filename:, artifactUrl:) ⇒ Object



140
141
142
143
# File 'lib/mobile_metrics.rb', line 140

def self.log_size_metric(name:, sizeInBytes:, filename:, artifactUrl:)
  overrides = { name: METRIC_SIZE, data: { name: name, filename: filename, size: sizeInBytes, artifactUrl: artifactUrl } }
  log_partial_metric(overrides)
end

.log_timer(name:, delta_in_ms:) ⇒ Object



145
146
147
148
# File 'lib/mobile_metrics.rb', line 145

def self.log_timer(name:, delta_in_ms:)
  overrides = {name: METRIC_TIMER, data: {name: name, duration: delta_in_ms }}
  log_partial_metric(overrides)
end

.log_unit_test_count_from_file(junit_file:, fail_build_on_file_not_found: false) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/mobile_metrics.rb', line 184

def self.log_unit_test_count_from_file(junit_file:, fail_build_on_file_not_found: false)
  if !File.exist?(junit_file)
    print "WARN: JUnit file #{junit_file} does not exist on disk"
    exit 16 if fail_build_on_file_not_found
    return if !fail_build_on_file_not_found
  end

  parser = MobileMetrics::JunitParser.new
  parser.parse(junit_file)
  unit_test_count = parser.tests.count

  # Only log values > 0 to avoid any parser issues.
  if unit_test_count == 0
    print 'WARN: Parsed unit test count is zero, avoiding logging.'
  else
    self.log_counter_metric(name: 'unit_tests_count', count: unit_test_count)
  end
end

.remove_all_log_filesObject



253
254
255
# File 'lib/mobile_metrics.rb', line 253

def self.remove_all_log_files
  FileUtils.rm_rf(LOGGING_DIR)
end

.resetObject

Tears down logging instance, removes any intermediate log files. Does not finalize or upload any in-progress logs. To use the logger again, you’ll have to call set_default_values before any other methods.



242
243
244
245
246
247
248
249
250
251
# File 'lib/mobile_metrics.rb', line 242

def self.reset
  if @@log_file
    remove_log_file
  end
  @@log_file = nil
  @@env_values = nil
  @@in_progress_timers = {}
  @@verbose = false
  @@upload_location = nil
end

.set_default_values(project:, level: "info", platform: "iOS", buildUrl: ENV['BUILD_URL'], gitUrl: ENV['GIT_URL'], gitBranch: ENV['BRANCH'], gitSha: ENV['SHA'], buildType: UNKNOWN, brand: UNKNOWN, verbose: false, upload_location: nil) ⇒ Object

Named params, with ability to override / leave out stuff we don’t care about.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/mobile_metrics.rb', line 36

def self.set_default_values(
  # Required params
  project:,
  # These params either aren't required, or have sensible defaults.
  level: "info",
  platform: "iOS",
  buildUrl: ENV['BUILD_URL'],
  gitUrl: ENV['GIT_URL'],
  gitBranch: ENV['BRANCH'],
  gitSha: ENV['SHA'],
  # no sensible defaults for these, we'll strip them later
  buildType: UNKNOWN,
  brand: UNKNOWN,
  # Controls log levels within this class
  verbose: false,
  # Upload location for logs
  upload_location: nil
  )

  #TODO: May be able to support overridding these at some point in the future.
  # It won't be threadsafe, but our builds aren't parallelized at the build script level anyway.
  if @@env_values
    print 'Can only override default values once! Aborting!'
    return
  end

  if project.nil?
    print 'Project value for logging MUST be non-nil, failing build.'
    exit 14
    return
  end

  @@verbose = verbose

  # Upload location
  @@upload_location = (upload_location || ENV[UPLOAD_ENV_VAR])
  if @@upload_location.nil?
    print 'Upload location value for logging MUST not be nil, exiting.'
    exit 15
    return
  end

  # Create the logging dir + filename
  FileUtils.mkdir_p(LOGGING_DIR)
  filename = "metrics_#{project}_#{build_number}.log"
  @@log_file = Pathname.new(LOGGING_DIR) + filename
  print @@log_file if @@verbose

  # Populate our env values
  @@env_values = {}

  # Required
  @@env_values[:project] = project
  # Optional
  @@env_values[:level] = level
  @@env_values[:platform] = platform
  @@env_values[:gitUrl] = gitUrl
  @@env_values[:gitBranch] = gitBranch
  @@env_values[:gitSha] = gitSha
  @@env_values[:buildUrl] = buildUrl

  #TODO: Should any of these be required? 
  @@env_values[:buildType] = buildType if buildType != UNKNOWN
  @@env_values[:brand] = brand if brand != UNKNOWN
end

.start_timer_metric(name:) ⇒ Object



150
151
152
153
154
155
156
# File 'lib/mobile_metrics.rb', line 150

def self.start_timer_metric(name:)
  if @@in_progress_timers.has_key?(name)
    print "WARNING: #{name} already has a running timer, refusing to start a new timer"
    return
  end
  @@in_progress_timers[name] = monotonic_timestamp
end

.time(name:, &_block) ⇒ Object

Block based timer. This is the recommended way to timer operations.



178
179
180
181
182
# File 'lib/mobile_metrics.rb', line 178

def self.time(name:, &_block)
  self.start_timer_metric(name: name)
  yield
  self.end_timer_metric(name: name)
end

.upload_locationObject



235
236
237
# File 'lib/mobile_metrics.rb', line 235

def self.upload_location
  @@upload_location
end

.upload_logsObject



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/mobile_metrics.rb', line 203

def self.upload_logs
  # Already called upload logs before, second time is a no-op
  if @@log_file.nil? || !@@log_file.file?
    print 'WARN: Log file is empty or doesn\'t exist. Was upload_logs called previously?'
    return
  end

  # Skip uploads for local dev machines
  if !should_upload_logs
    print 'Detected local machine, refusing to upload build metrics. Removing intermediate log file'
    remove_log_file
    return
  end

  # Warn for any open timers
  if @@in_progress_timers.size > 0
    @@in_progress_timers.each { |k, _v|
      print "WARN: Timer not closed when upload_logs was called: #{k}"
    }
  end

  # Upload
  upload_log_file

  # Remove log file
  remove_log_file
end