statsig 1.24.6 → 1.25.0
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/lib/evaluator.rb +7 -7
- data/lib/network.rb +8 -0
- data/lib/spec_store.rb +12 -15
- data/lib/statsig_logger.rb +5 -4
- data/lib/statsig_options.rb +18 -2
- data/lib/ua_parser.rb +57 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 267f2a16a3bb05a6b046d493bfe98f00b7c083f387eba7862641801ec0579b2b
|
4
|
+
data.tar.gz: a20de08fe3b12bcba40795ec1ff53ce5d3c2c27aca3ab41d72541a49e730414c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7afa3f47ea19f3d759a648f12bd98c8e56c1c757f2c86bc72859ace8ca081e205af90f315cd26c08598fed408a8b4163b452e2312066120d5ead9644f1028ec
|
7
|
+
data.tar.gz: d671a37cf7ad21212d71ad90c8fddab13110641a278c475c6f4cec3ff922c0d6b6bceaa1367b902933db481be56601af2ab203c03768a65e9dd959fb900a2438
|
data/lib/evaluator.rb
CHANGED
@@ -6,7 +6,7 @@ require 'evaluation_helpers'
|
|
6
6
|
require 'client_initialize_helpers'
|
7
7
|
require 'spec_store'
|
8
8
|
require 'time'
|
9
|
-
require '
|
9
|
+
require 'ua_parser'
|
10
10
|
require 'evaluation_details'
|
11
11
|
require 'user_agent_parser/operating_system'
|
12
12
|
|
@@ -19,8 +19,8 @@ module Statsig
|
|
19
19
|
|
20
20
|
def initialize(network, options, error_callback, init_diagnostics = nil)
|
21
21
|
@spec_store = Statsig::SpecStore.new(network, options, error_callback, init_diagnostics)
|
22
|
-
|
23
|
-
CountryLookup.
|
22
|
+
UAParser.initialize_async
|
23
|
+
CountryLookup.initialize_async
|
24
24
|
|
25
25
|
@gate_overrides = {}
|
26
26
|
@config_overrides = {}
|
@@ -449,16 +449,16 @@ module Statsig
|
|
449
449
|
|
450
450
|
case field.downcase
|
451
451
|
when 'os_name', 'osname'
|
452
|
-
os =
|
452
|
+
os = UAParser.parse_os(ua)
|
453
453
|
return os&.family
|
454
454
|
when 'os_version', 'osversion'
|
455
|
-
os =
|
455
|
+
os = UAParser.parse_os(ua)
|
456
456
|
return os&.version unless os&.version.nil?
|
457
457
|
when 'browser_name', 'browsername'
|
458
|
-
parsed =
|
458
|
+
parsed = UAParser.parse_ua(ua)
|
459
459
|
return parsed.family
|
460
460
|
when 'browser_version', 'browserversion'
|
461
|
-
parsed =
|
461
|
+
parsed = UAParser.parse_ua(ua)
|
462
462
|
return parsed.version.to_s
|
463
463
|
else
|
464
464
|
nil
|
data/lib/network.rb
CHANGED
@@ -33,6 +33,7 @@ module Statsig
|
|
33
33
|
@local_mode = options.local_mode
|
34
34
|
@timeout = options.network_timeout
|
35
35
|
@backoff_multiplier = backoff_mult
|
36
|
+
@post_logs_retry_backoff = options.post_logs_retry_backoff
|
36
37
|
@post_logs_retry_limit = options.post_logs_retry_limit
|
37
38
|
@session_id = SecureRandom.uuid
|
38
39
|
end
|
@@ -59,6 +60,13 @@ module Statsig
|
|
59
60
|
http = http.timeout(@timeout)
|
60
61
|
end
|
61
62
|
backoff_adjusted = backoff > 10 ? backoff += Random.rand(10) : backoff # to deter overlap
|
63
|
+
if @post_logs_retry_backoff
|
64
|
+
if @post_logs_retry_backoff.is_a? Integer
|
65
|
+
backoff_adjusted = @post_logs_retry_backoff
|
66
|
+
else
|
67
|
+
backoff_adjusted = @post_logs_retry_backoff.call(retries)
|
68
|
+
end
|
69
|
+
end
|
62
70
|
begin
|
63
71
|
res = http.post(@api + endpoint, body: body)
|
64
72
|
rescue StandardError => e
|
data/lib/spec_store.rb
CHANGED
@@ -32,6 +32,7 @@ module Statsig
|
|
32
32
|
|
33
33
|
@id_list_thread_pool = Concurrent::FixedThreadPool.new(
|
34
34
|
options.idlist_threadpool_size,
|
35
|
+
name: 'statsig-idlist',
|
35
36
|
max_queue: 100,
|
36
37
|
fallback_policy: :discard,
|
37
38
|
)
|
@@ -309,6 +310,16 @@ module Statsig
|
|
309
310
|
|
310
311
|
init_diagnostics&.mark("get_id_lists", "start", "process", new_id_lists.length)
|
311
312
|
|
313
|
+
delete_lists = []
|
314
|
+
local_id_lists.each do |list_name, list|
|
315
|
+
unless new_id_lists.key? list_name
|
316
|
+
delete_lists.push list_name
|
317
|
+
end
|
318
|
+
end
|
319
|
+
delete_lists.each do |list_name|
|
320
|
+
local_id_lists.delete list_name
|
321
|
+
end
|
322
|
+
|
312
323
|
new_id_lists.each do |list_name, list|
|
313
324
|
new_list = IDList.new(list)
|
314
325
|
local_list = get_id_list(list_name)
|
@@ -346,21 +357,7 @@ module Statsig
|
|
346
357
|
end
|
347
358
|
|
348
359
|
result = Concurrent::Promise.all?(*tasks).execute.wait(@id_lists_sync_interval)
|
349
|
-
|
350
|
-
init_diagnostics&.mark("get_id_lists", "end", "process", false)
|
351
|
-
return # timed out
|
352
|
-
end
|
353
|
-
|
354
|
-
delete_lists = []
|
355
|
-
local_id_lists.each do |list_name, list|
|
356
|
-
unless new_id_lists.key? list_name
|
357
|
-
delete_lists.push list_name
|
358
|
-
end
|
359
|
-
end
|
360
|
-
delete_lists.each do |list_name|
|
361
|
-
local_id_lists.delete list_name
|
362
|
-
end
|
363
|
-
init_diagnostics&.mark("get_id_lists", "end", "process", true)
|
360
|
+
init_diagnostics&.mark("get_id_lists", "end", "process", result.state == :fulfilled)
|
364
361
|
end
|
365
362
|
|
366
363
|
def get_single_id_list_from_adapter(list)
|
data/lib/statsig_logger.rb
CHANGED
@@ -15,10 +15,11 @@ module Statsig
|
|
15
15
|
@options = options
|
16
16
|
|
17
17
|
@logging_pool = Concurrent::ThreadPoolExecutor.new(
|
18
|
-
|
19
|
-
|
18
|
+
name: 'statsig-logger',
|
19
|
+
min_threads: @options.logger_threadpool_size,
|
20
|
+
max_threads: @options.logger_threadpool_size,
|
20
21
|
# max jobs pending before we start dropping
|
21
|
-
max_queue:
|
22
|
+
max_queue: 100,
|
22
23
|
fallback_policy: :discard
|
23
24
|
)
|
24
25
|
|
@@ -106,7 +107,7 @@ module Statsig
|
|
106
107
|
Thread.new do
|
107
108
|
loop do
|
108
109
|
sleep @options.logging_interval_seconds
|
109
|
-
|
110
|
+
flush_async
|
110
111
|
@interval += 1
|
111
112
|
@deduper.clear if @interval % 2 == 0
|
112
113
|
end
|
data/lib/statsig_options.rb
CHANGED
@@ -64,6 +64,11 @@ class StatsigOptions
|
|
64
64
|
# default: 3
|
65
65
|
attr_accessor :idlist_threadpool_size
|
66
66
|
|
67
|
+
sig { returns(Integer) }
|
68
|
+
# The number of threads allocated to posting event logs.
|
69
|
+
# default: 3
|
70
|
+
attr_accessor :logger_threadpool_size
|
71
|
+
|
67
72
|
sig { returns(T::Boolean) }
|
68
73
|
# Should diagnostics be logged. These include performance metrics for initialize.
|
69
74
|
# default: false
|
@@ -83,6 +88,11 @@ class StatsigOptions
|
|
83
88
|
# Number of times to retry sending a batch of failed log events
|
84
89
|
attr_accessor :post_logs_retry_limit
|
85
90
|
|
91
|
+
sig { returns(T.any(Method, Proc, Integer, NilClass)) }
|
92
|
+
# The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
|
93
|
+
# which overrides the default backoff time between retries
|
94
|
+
attr_accessor :post_logs_retry_backoff
|
95
|
+
|
86
96
|
sig do
|
87
97
|
params(
|
88
98
|
environment: T.any(T::Hash[String, String], NilClass),
|
@@ -96,10 +106,12 @@ class StatsigOptions
|
|
96
106
|
rules_updated_callback: T.any(Method, Proc, NilClass),
|
97
107
|
data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
|
98
108
|
idlist_threadpool_size: Integer,
|
109
|
+
logger_threadpool_size: Integer,
|
99
110
|
disable_diagnostics_logging: T::Boolean,
|
100
111
|
disable_sorbet_logging_handlers: T::Boolean,
|
101
112
|
network_timeout: T.any(Integer, NilClass),
|
102
|
-
post_logs_retry_limit: Integer
|
113
|
+
post_logs_retry_limit: Integer,
|
114
|
+
post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass)
|
103
115
|
).void
|
104
116
|
end
|
105
117
|
|
@@ -115,10 +127,12 @@ class StatsigOptions
|
|
115
127
|
rules_updated_callback: nil,
|
116
128
|
data_store: nil,
|
117
129
|
idlist_threadpool_size: 3,
|
130
|
+
logger_threadpool_size: 3,
|
118
131
|
disable_diagnostics_logging: false,
|
119
132
|
disable_sorbet_logging_handlers: false,
|
120
133
|
network_timeout: nil,
|
121
|
-
post_logs_retry_limit: 3
|
134
|
+
post_logs_retry_limit: 3,
|
135
|
+
post_logs_retry_backoff: nil)
|
122
136
|
@environment = environment.is_a?(Hash) ? environment : nil
|
123
137
|
@api_url_base = api_url_base
|
124
138
|
@rulesets_sync_interval = rulesets_sync_interval
|
@@ -130,9 +144,11 @@ class StatsigOptions
|
|
130
144
|
@rules_updated_callback = rules_updated_callback
|
131
145
|
@data_store = data_store
|
132
146
|
@idlist_threadpool_size = idlist_threadpool_size
|
147
|
+
@logger_threadpool_size = logger_threadpool_size
|
133
148
|
@disable_diagnostics_logging = disable_diagnostics_logging
|
134
149
|
@disable_sorbet_logging_handlers = disable_sorbet_logging_handlers
|
135
150
|
@network_timeout = network_timeout
|
136
151
|
@post_logs_retry_limit = post_logs_retry_limit
|
152
|
+
@post_logs_retry_backoff = post_logs_retry_backoff
|
137
153
|
end
|
138
154
|
end
|
data/lib/ua_parser.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'user_agent_parser'
|
2
|
+
|
3
|
+
module UAParser
|
4
|
+
class Parser
|
5
|
+
def initialize
|
6
|
+
@ua_parser = UserAgentParser::Parser.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_os(*args)
|
10
|
+
@ua_parser.parse_os(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_ua(*args)
|
14
|
+
@ua_parser.parse_ua(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_device(*args)
|
18
|
+
@ua_parser.parse_device(*args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.initialize
|
23
|
+
if !@initialize_bg_thread.nil? && @initialize_bg_thread.alive?
|
24
|
+
@initialize_bg_thread.kill.join
|
25
|
+
end
|
26
|
+
@parser = Parser.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.initialize_async
|
30
|
+
if !@initialize_bg_thread.nil? && @initialize_bg_thread.alive?
|
31
|
+
@initialize_bg_thread.kill.join
|
32
|
+
end
|
33
|
+
@initialize_bg_thread = Thread.new { @parser = Parser.new }
|
34
|
+
@initialize_bg_thread
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_os(*args)
|
38
|
+
if @parser.nil?
|
39
|
+
initialize
|
40
|
+
end
|
41
|
+
@parser.parse_os(*args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.parse_ua(*args)
|
45
|
+
if @parser.nil?
|
46
|
+
initialize
|
47
|
+
end
|
48
|
+
@parser.parse_ua(*args)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.parse_device(*args)
|
52
|
+
if @parser.nil?
|
53
|
+
initialize
|
54
|
+
end
|
55
|
+
@parser.parse_device(*args)
|
56
|
+
end
|
57
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -230,16 +230,16 @@ dependencies:
|
|
230
230
|
name: ip3country
|
231
231
|
requirement: !ruby/object:Gem::Requirement
|
232
232
|
requirements:
|
233
|
-
- -
|
233
|
+
- - "~>"
|
234
234
|
- !ruby/object:Gem::Version
|
235
|
-
version: 0.
|
235
|
+
version: 0.2.1
|
236
236
|
type: :runtime
|
237
237
|
prerelease: false
|
238
238
|
version_requirements: !ruby/object:Gem::Requirement
|
239
239
|
requirements:
|
240
|
-
- -
|
240
|
+
- - "~>"
|
241
241
|
- !ruby/object:Gem::Version
|
242
|
-
version: 0.
|
242
|
+
version: 0.2.1
|
243
243
|
- !ruby/object:Gem::Dependency
|
244
244
|
name: sorbet-runtime
|
245
245
|
requirement: !ruby/object:Gem::Requirement
|
@@ -294,6 +294,7 @@ files:
|
|
294
294
|
- lib/statsig_logger.rb
|
295
295
|
- lib/statsig_options.rb
|
296
296
|
- lib/statsig_user.rb
|
297
|
+
- lib/ua_parser.rb
|
297
298
|
homepage: https://rubygems.org/gems/statsig
|
298
299
|
licenses:
|
299
300
|
- ISC
|