mobile_metrics 0.0.5 → 0.0.6
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/Gemfile.lock +1 -1
- data/lib/mobile_metrics.rb +141 -122
- data/lib/mobile_metrics/junit.rb +6 -7
- data/lib/mobile_metrics/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3517102712246e11c22fe0bdf3484fbae5f6fd80d88895da29e7075de7c2a6fb
|
4
|
+
data.tar.gz: 151b0833679f05c680cfbe81c74641794b103056e1627af4ee1c16abad60e66f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e26d2c6e2ffc1f5b24b4e32edc0519bf575660296f4c711df8ae2158e41173da1b576de4fb96ecade1b305310f1fcd008f7f3d0caec1caca1776e8d3d159eb83
|
7
|
+
data.tar.gz: c38dde7199e4637cde07fbb14506a045761312ddf724258e1433714946fa4485c6dcebd22f5c00e2f553bc63646679e0273b5feff80aa566249d014a5f92cac2
|
data/Gemfile.lock
CHANGED
data/lib/mobile_metrics.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'mobile_metrics/version'
|
2
|
+
require 'mobile_metrics/junit'
|
3
3
|
|
4
4
|
require 'time'
|
5
5
|
require 'json'
|
@@ -8,18 +8,18 @@ require 'fileutils'
|
|
8
8
|
require 'pathname'
|
9
9
|
|
10
10
|
# Metric types
|
11
|
-
METRIC_TIMER = 'x.mobile_metric.timer'
|
12
|
-
METRIC_COUNTER = 'x.mobile_metric.counter'
|
13
|
-
METRIC_RATIO = 'x.mobile_metric.ratio'
|
14
|
-
METRIC_SIZE = 'x.mobile_metric.size'
|
11
|
+
METRIC_TIMER = 'x.mobile_metric.timer'.freeze
|
12
|
+
METRIC_COUNTER = 'x.mobile_metric.counter'.freeze
|
13
|
+
METRIC_RATIO = 'x.mobile_metric.ratio'.freeze
|
14
|
+
METRIC_SIZE = 'x.mobile_metric.size'.freeze
|
15
15
|
|
16
16
|
# Misc Constants
|
17
|
-
UNKNOWN = 'UNKNOWN'
|
18
|
-
LOG_PREFIX = 'CI-METRICS:'
|
19
|
-
LOGGING_DIR = '/tmp/cimetricslogs'
|
20
|
-
UPLOAD_ENV_VAR = 'MOBILE_METRICS_UPLOAD_LOCATION'
|
17
|
+
UNKNOWN = 'UNKNOWN'.freeze
|
18
|
+
LOG_PREFIX = 'CI-METRICS:'.freeze
|
19
|
+
LOGGING_DIR = '/tmp/cimetricslogs'.freeze
|
20
|
+
UPLOAD_ENV_VAR = 'MOBILE_METRICS_UPLOAD_LOCATION'.freeze
|
21
21
|
|
22
|
-
module MobileMetrics
|
22
|
+
module MobileMetrics
|
23
23
|
class Log
|
24
24
|
|
25
25
|
@@in_progress_timers = {}
|
@@ -27,63 +27,63 @@ module MobileMetrics
|
|
27
27
|
@@env_values = nil
|
28
28
|
@@verbose = false
|
29
29
|
@@upload_location = nil
|
30
|
-
|
30
|
+
|
31
31
|
#========================================
|
32
32
|
# Configuration
|
33
33
|
#=========================================
|
34
|
-
|
34
|
+
|
35
35
|
# Named params, with ability to override / leave out stuff we don't care about.
|
36
36
|
def self.set_default_values(
|
37
37
|
# Required params
|
38
38
|
project:,
|
39
39
|
# These params either aren't required, or have sensible defaults.
|
40
|
-
level: "info",
|
41
|
-
platform: "iOS",
|
42
|
-
buildUrl: ENV['BUILD_URL'],
|
43
|
-
gitUrl: ENV['GIT_URL'],
|
44
|
-
gitBranch: ENV['DOTCI_BRANCH'],
|
45
|
-
gitSha: ENV['DOTCI_SHA'],
|
40
|
+
level: "info",
|
41
|
+
platform: "iOS",
|
42
|
+
buildUrl: ENV['BUILD_URL'],
|
43
|
+
gitUrl: ENV['GIT_URL'],
|
44
|
+
gitBranch: ENV['DOTCI_BRANCH'],
|
45
|
+
gitSha: ENV['DOTCI_SHA'],
|
46
46
|
# no sensible defaults for these, we'll strip them later
|
47
|
-
buildType: UNKNOWN,
|
47
|
+
buildType: UNKNOWN,
|
48
48
|
brand: UNKNOWN,
|
49
49
|
# Controls log levels within this class
|
50
50
|
verbose: false,
|
51
51
|
# Upload location for logs
|
52
52
|
upload_location: nil
|
53
|
-
)
|
54
|
-
|
53
|
+
)
|
54
|
+
|
55
55
|
#TODO: May be able to support overridding these at some point in the future.
|
56
56
|
# It won't be threadsafe, but our builds aren't parallelized at the build script level anyway.
|
57
57
|
if @@env_values
|
58
58
|
print 'Can only override default values once! Aborting!'
|
59
59
|
return
|
60
60
|
end
|
61
|
-
|
62
|
-
if project.nil?
|
61
|
+
|
62
|
+
if project.nil?
|
63
63
|
print 'Project value for logging MUST be non-nil, failing build.'
|
64
64
|
exit 14
|
65
65
|
return
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
@@verbose = verbose
|
69
|
-
|
69
|
+
|
70
70
|
# Upload location
|
71
71
|
@@upload_location = (upload_location || ENV[UPLOAD_ENV_VAR])
|
72
|
-
if @@upload_location.nil?
|
72
|
+
if @@upload_location.nil?
|
73
73
|
print 'Upload location value for logging MUST not be nil, exiting.'
|
74
74
|
exit 15
|
75
75
|
return
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Create the logging dir + filename
|
79
79
|
FileUtils.mkdir_p(LOGGING_DIR)
|
80
80
|
filename = "metrics_#{project}_#{build_number}.log"
|
81
81
|
@@log_file = Pathname.new(LOGGING_DIR) + filename
|
82
82
|
print @@log_file if @@verbose
|
83
|
-
|
83
|
+
|
84
84
|
# Populate our env values
|
85
85
|
@@env_values = {}
|
86
|
-
|
86
|
+
|
87
87
|
# Required
|
88
88
|
@@env_values[:project] = project
|
89
89
|
# Optional
|
@@ -93,131 +93,150 @@ module MobileMetrics
|
|
93
93
|
@@env_values[:gitBranch] = gitBranch
|
94
94
|
@@env_values[:gitSha] = gitSha
|
95
95
|
@@env_values[:buildUrl] = buildUrl
|
96
|
-
|
96
|
+
|
97
97
|
#TODO: Should any of these be required?
|
98
98
|
@@env_values[:buildType] = buildType if buildType != UNKNOWN
|
99
99
|
@@env_values[:brand] = brand if brand != UNKNOWN
|
100
100
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
101
|
+
|
102
|
+
# =begin
|
103
|
+
# # Sample timer metric
|
104
|
+
# {
|
105
|
+
# "time": "<yyyy-MM-ddThh:mm:ss[.sss]Z>",
|
106
|
+
# "name": "x.mobile_metric.<metric_type>",
|
107
|
+
# "level": "info",
|
108
|
+
# "data": {
|
109
|
+
# "name": "<metric_name>",
|
110
|
+
# … // additional data per metric type
|
111
|
+
# }
|
112
|
+
# "context": {
|
113
|
+
# "platform": "<ios_or_android>",
|
114
|
+
# "project": "<project_name>",
|
115
|
+
# "gitUrl": "<git_url>",
|
116
|
+
# "gitBranch": "<git_branch>",
|
117
|
+
# "gitSha": "<git_sha>",
|
118
|
+
# "buildType": "<build_type>",
|
119
|
+
# "brand": "<brand>",
|
120
|
+
# "host": "<machine_dns_name_or_device_name>",
|
121
|
+
# "processId": "<process_id_or_build_number>"
|
122
|
+
# }
|
123
|
+
# }
|
124
|
+
# =end
|
125
125
|
|
126
126
|
#=========================================
|
127
127
|
# Public Logging Methods
|
128
128
|
#=========================================
|
129
|
-
|
129
|
+
|
130
130
|
def self.log_ratio_metric(name:, ratio:)
|
131
|
-
overrides = {name: METRIC_RATIO, data: {name: name, ratio: ratio.to_f }}
|
131
|
+
overrides = { name: METRIC_RATIO, data: { name: name, ratio: ratio.to_f } }
|
132
132
|
log_partial_metric(overrides)
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
def self.log_counter_metric(name:, count:)
|
136
|
-
overrides = {name: METRIC_COUNTER, data: {name: name, count: count.to_i }}
|
136
|
+
overrides = { name: METRIC_COUNTER, data: {name: name, count: count.to_i } }
|
137
137
|
log_partial_metric(overrides)
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
def self.log_size_metric(name:, sizeInBytes:, filename:, artifactUrl:)
|
141
|
-
overrides = {name: METRIC_SIZE, data: {name: name, filename: filename, size: sizeInBytes, artifactUrl: artifactUrl }}
|
141
|
+
overrides = { name: METRIC_SIZE, data: { name: name, filename: filename, size: sizeInBytes, artifactUrl: artifactUrl } }
|
142
142
|
log_partial_metric(overrides)
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
def self.start_timer_metric(name:)
|
146
|
-
if @@in_progress_timers.has_key?(name)
|
146
|
+
if @@in_progress_timers.has_key?(name)
|
147
147
|
print "WARNING: #{name} already has a running timer, refusing to start a new timer"
|
148
148
|
return
|
149
149
|
end
|
150
150
|
@@in_progress_timers[name] = monotonic_timestamp
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
def self.end_timer_metric(name:)
|
154
154
|
if !@@in_progress_timers.has_key?(name)
|
155
155
|
print "WARNING: #{name} does not have a running timer, the end_timer_metric call has no effect"
|
156
156
|
return
|
157
157
|
end
|
158
|
-
|
158
|
+
|
159
159
|
# Calculate delta
|
160
160
|
start = @@in_progress_timers[name]
|
161
161
|
now = monotonic_timestamp
|
162
162
|
delta_in_ms = ((now - start) * 1000).to_i
|
163
|
-
|
163
|
+
|
164
164
|
# remove existing timer
|
165
165
|
@@in_progress_timers.delete(name)
|
166
|
-
|
166
|
+
|
167
167
|
# log to file
|
168
168
|
overrides = {name: METRIC_TIMER, data: {name: name, duration: delta_in_ms }}
|
169
169
|
log_partial_metric(overrides)
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
# Block based timer. This is the recommended way to timer operations.
|
173
|
-
def self.time(name:, &
|
173
|
+
def self.time(name:, &_block)
|
174
174
|
self.start_timer_metric(name: name)
|
175
175
|
yield
|
176
176
|
self.end_timer_metric(name: name)
|
177
177
|
end
|
178
|
-
|
179
|
-
def self.
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
return
|
178
|
+
|
179
|
+
def self.log_unit_test_count_from_file(junit_file:, fail_build_on_file_not_found: false)
|
180
|
+
if !File.exist?(junit_file)
|
181
|
+
print "WARN: JUnit file #{junit_file} does not exist on disk"
|
182
|
+
exit 16 if fail_build_on_file_not_found
|
183
|
+
return if !fail_build_on_file_not_found
|
184
|
+
end
|
185
|
+
|
186
|
+
parser = MobileMetrics::JunitParser.new
|
187
|
+
parser.parse(junit_file)
|
188
|
+
unit_test_count = parser.tests.count
|
189
|
+
|
190
|
+
# Only log values > 0 to avoid any parser issues.
|
191
|
+
if unit_test_count == 0
|
192
|
+
print 'WARN: Parsed unit test count is zero, avoiding logging.'
|
193
|
+
else
|
194
|
+
self.log_counter_metric(name: 'unit_tests_count', count: unit_test_count)
|
184
195
|
end
|
185
|
-
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.upload_logs
|
199
|
+
# Already called upload logs before, second time is a no-op
|
200
|
+
if @@log_file.nil? || !@@log_file.file?
|
201
|
+
print 'WARN: Log file is empty or doesn\'t exist. Was upload_logs called previously?'
|
202
|
+
return
|
203
|
+
end
|
204
|
+
|
186
205
|
# Skip uploads for local dev machines
|
187
|
-
if !should_upload_logs
|
206
|
+
if !should_upload_logs
|
188
207
|
print 'Detected local machine, refusing to upload build metrics. Removing intermediate log file'
|
189
|
-
remove_log_file
|
208
|
+
remove_log_file
|
190
209
|
return
|
191
210
|
end
|
192
|
-
|
211
|
+
|
193
212
|
# Warn for any open timers
|
194
|
-
if @@in_progress_timers.size > 0
|
195
|
-
@@in_progress_timers.each { |k,
|
213
|
+
if @@in_progress_timers.size > 0
|
214
|
+
@@in_progress_timers.each { |k, _v|
|
196
215
|
print "WARN: Timer not closed when upload_logs was called: #{k}"
|
197
216
|
}
|
198
217
|
end
|
199
|
-
|
200
|
-
# Upload
|
201
|
-
upload_log_file
|
202
|
-
|
218
|
+
|
219
|
+
# Upload
|
220
|
+
upload_log_file
|
221
|
+
|
203
222
|
# Remove log file
|
204
|
-
remove_log_file
|
223
|
+
remove_log_file
|
205
224
|
end
|
206
|
-
|
207
|
-
def self.log_file
|
225
|
+
|
226
|
+
def self.log_file
|
208
227
|
@@log_file
|
209
228
|
end
|
210
|
-
|
211
|
-
def self.upload_location
|
229
|
+
|
230
|
+
def self.upload_location
|
212
231
|
@@upload_location
|
213
232
|
end
|
214
|
-
|
233
|
+
|
215
234
|
# Tears down logging instance, removes any intermediate log files.
|
216
235
|
# Does not finalize or upload any in-progress logs.
|
217
236
|
# To use the logger again, you'll have to call set_default_values before any other methods.
|
218
|
-
def self.reset
|
219
|
-
if @@log_file
|
220
|
-
remove_log_file
|
237
|
+
def self.reset
|
238
|
+
if @@log_file
|
239
|
+
remove_log_file
|
221
240
|
end
|
222
241
|
@@log_file = nil
|
223
242
|
@@env_values = nil
|
@@ -225,15 +244,15 @@ module MobileMetrics
|
|
225
244
|
@@verbose = false
|
226
245
|
@@upload_location = nil
|
227
246
|
end
|
228
|
-
|
229
|
-
def self.remove_all_log_files
|
230
|
-
FileUtils.rm_rf(LOGGING_DIR)
|
247
|
+
|
248
|
+
def self.remove_all_log_files
|
249
|
+
FileUtils.rm_rf(LOGGING_DIR)
|
231
250
|
end
|
232
|
-
|
251
|
+
|
233
252
|
private
|
234
253
|
|
235
254
|
# Creates a stubbed metric with common fields
|
236
|
-
def self.default_metric
|
255
|
+
def self.default_metric
|
237
256
|
if !@@env_values
|
238
257
|
print 'default_metric called before env_values initialized, aborting!'
|
239
258
|
exit 12
|
@@ -251,25 +270,25 @@ module MobileMetrics
|
|
251
270
|
buildUrl: @@env_values[:buildUrl],
|
252
271
|
host: hostname(),
|
253
272
|
processId: build_number()
|
254
|
-
}.select { |k,v| !v.nil? }
|
273
|
+
}.select { |k,v| !v.nil? }
|
255
274
|
{time: timestamp(), level:@@env_values[:level], context: context}
|
256
275
|
end
|
257
|
-
|
276
|
+
|
258
277
|
def self.append_to_log(value)
|
259
278
|
# Create the log file if it doesn't exist
|
260
279
|
if !@@log_file.file?
|
261
|
-
FileUtils.touch(@@log_file)
|
280
|
+
FileUtils.touch(@@log_file)
|
262
281
|
end
|
263
282
|
File.open(@@log_file, 'a+') { |f| f.puts(value + "\n") }
|
264
283
|
end
|
265
|
-
|
266
|
-
def self.remove_log_file
|
284
|
+
|
285
|
+
def self.remove_log_file
|
267
286
|
FileUtils.rm_rf(@@log_file)
|
268
287
|
end
|
269
|
-
|
270
|
-
def self.upload_log_file
|
288
|
+
|
289
|
+
def self.upload_log_file
|
271
290
|
destination = @@upload_location + "metrics_#{@@env_values[:project]}_#{build_number}.log"
|
272
|
-
verbose_flag = @@verbose ?
|
291
|
+
verbose_flag = @@verbose ? '-v' : ''
|
273
292
|
command = "scp #{verbose_flag} -o StrictHostKeyChecking=no #{@@log_file} #{destination}"
|
274
293
|
# This feels icky
|
275
294
|
print `#{command}`
|
@@ -279,17 +298,17 @@ module MobileMetrics
|
|
279
298
|
# Note: This format doesn't currently add milliseconds.
|
280
299
|
# Example: "2018-03-27T21:12:21Z"
|
281
300
|
# Note: DO NOT use this for benchmarking / measuring timers, see monotonic_timestamp instead.
|
282
|
-
def self.timestamp
|
301
|
+
def self.timestamp
|
283
302
|
Time.now.utc.iso8601.to_s
|
284
303
|
end
|
285
|
-
|
304
|
+
|
286
305
|
# Returns a floating point monotonic timestamp suitable for timers
|
287
306
|
# Monotonic means we won't ever go back for things like leap seconds
|
288
307
|
# Unit is a floating point in seconds.
|
289
|
-
def self.monotonic_timestamp
|
308
|
+
def self.monotonic_timestamp
|
290
309
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
291
310
|
end
|
292
|
-
|
311
|
+
|
293
312
|
# Each metric should call this method.
|
294
313
|
# This method handles merging the metric hash with the default hash,
|
295
314
|
# Generates the JSON with the keys in the right order, then appends to the log.
|
@@ -300,40 +319,40 @@ module MobileMetrics
|
|
300
319
|
metric = ordered_hash.to_json
|
301
320
|
append_to_log(metric)
|
302
321
|
end
|
303
|
-
|
322
|
+
|
304
323
|
# Util method for merging the default hash values and overrides recursively as we want them
|
305
324
|
def self.merge_hashes(default, overrides)
|
306
|
-
default.merge(overrides) { |key, oldval, newval|
|
307
|
-
if key == :data || key == :
|
325
|
+
default.merge(overrides) { |key, oldval, newval|
|
326
|
+
if key == :data || key == :context
|
308
327
|
oldval.merge(newval)
|
309
328
|
else
|
310
329
|
newval
|
311
330
|
end
|
312
331
|
}
|
313
332
|
end
|
314
|
-
|
333
|
+
|
315
334
|
# Returns the host name of the machine we are currently running on
|
316
|
-
def self.hostname
|
335
|
+
def self.hostname
|
317
336
|
ENV['NODE_NAME'] || 'local-dev'
|
318
337
|
end
|
319
|
-
|
320
|
-
def self.build_number
|
338
|
+
|
339
|
+
def self.build_number
|
321
340
|
ENV['BUILD_NUMBER']
|
322
341
|
end
|
323
|
-
|
342
|
+
|
324
343
|
# This method checks against a bunch of default environment variables available through DOTCI
|
325
344
|
# The intent is never to upload timing logs from a local machine, so we make it unlikely that these
|
326
345
|
# env variables are present on a dev's local machine
|
327
|
-
def self.should_upload_logs
|
346
|
+
def self.should_upload_logs
|
328
347
|
have_workspace = ENV['WORKSPACE'] && !ENV['WORKSPACE'].empty?
|
329
348
|
have_build_number = ENV['BUILD_NUMBER'] && !ENV['BUILD_NUMBER'].empty?
|
330
349
|
have_jenkins_url = ENV['JENKINS_URL'] && !ENV['JENKINS_URL'].empty?
|
331
350
|
have_ci_var = ENV['CI'] && !ENV['CI'].empty?
|
332
351
|
have_workspace && have_build_number && have_jenkins_url && have_ci_var
|
333
352
|
end
|
334
|
-
|
353
|
+
|
335
354
|
def self.print(val)
|
336
355
|
puts("#{LOG_PREFIX} #{val}")
|
337
356
|
end
|
338
357
|
end
|
339
|
-
end
|
358
|
+
end
|
data/lib/mobile_metrics/junit.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
|
2
2
|
module MobileMetrics
|
3
|
-
|
4
3
|
# Adapted from: https://github.com/orta/danger-junit/blob/master/lib/junit/plugin.rb
|
5
4
|
class JunitParser
|
6
5
|
# All the tests for introspection
|
@@ -55,23 +54,23 @@ module MobileMetrics
|
|
55
54
|
failed_suites = suite_root.nodes.select { |suite| suite[:failures].to_i > 0 || suite[:errors].to_i > 0 }
|
56
55
|
failed_tests = failed_suites.map(&:nodes).flatten.select { |node| node.kind_of?(Ox::Element) && node.value == 'testcase' }
|
57
56
|
|
58
|
-
@failures = failed_tests.select do |test|
|
57
|
+
@failures = failed_tests.select do |test|
|
59
58
|
test.nodes.count > 0
|
60
59
|
end.select do |test|
|
61
60
|
node = test.nodes.first
|
62
61
|
node.kind_of?(Ox::Element) && node.value == 'failure'
|
63
62
|
end
|
64
63
|
|
65
|
-
@errors = failed_tests.select do |test|
|
64
|
+
@errors = failed_tests.select do |test|
|
66
65
|
test.nodes.count > 0
|
67
|
-
end.select do |test|
|
66
|
+
end.select do |test|
|
68
67
|
node = test.nodes.first
|
69
68
|
node.kind_of?(Ox::Element) && node.value == 'error'
|
70
69
|
end
|
71
70
|
|
72
|
-
@skipped = tests.select do |test|
|
71
|
+
@skipped = tests.select do |test|
|
73
72
|
test.nodes.count > 0
|
74
|
-
end.select do |test|
|
73
|
+
end.select do |test|
|
75
74
|
node = test.nodes.first
|
76
75
|
node.kind_of?(Ox::Element) && node.value == 'skipped'
|
77
76
|
end
|
@@ -79,4 +78,4 @@ module MobileMetrics
|
|
79
78
|
@passes = tests - @failures - @errors - @skipped
|
80
79
|
end
|
81
80
|
end
|
82
|
-
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mobile_metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dbeard
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01
|
11
|
+
date: 2019-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ox
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
106
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.7.
|
107
|
+
rubygems_version: 2.7.9
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: Mobile logging format library
|