statsig 1.24.6 → 1.25.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|