posthog-ruby 3.23.5 → 3.23.7
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/posthog/client.rb +23 -7
- data/lib/posthog/feature_flags.rb +41 -22
- data/lib/posthog/field_parser.rb +2 -2
- data/lib/posthog/send_worker.rb +1 -0
- data/lib/posthog/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67be906751ad3545830e00ac558a3787ba935d08c5414b216b653b63a745a424
|
|
4
|
+
data.tar.gz: 589fa3335b009dc16e22224e4708d55079e9b236c5c6cdfdba6f996fdb191af3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d7c92afb919cfb24e8e3a9bcfd3605cb4fce07d784019f1dd80fd0c685bc4ddde18d5b0322091fe49ad0e474cedbcae3804baf624697be650eed0418a450cdd
|
|
7
|
+
data.tar.gz: c9bec9d494e68a63b594c6960dc5e9d30d32d918c68df1a7dd83ba3a047179ff87bf5756f5dd0434ffde305b14a392457cbac7762c84e8ea91ed9839fab09763
|
data/lib/posthog/client.rb
CHANGED
|
@@ -141,6 +141,9 @@ module PostHog
|
|
|
141
141
|
@api_key = opts[:api_key]
|
|
142
142
|
@disabled = @api_key.nil? || @api_key.empty?
|
|
143
143
|
@max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
|
|
144
|
+
@lib = opts[:_lib] || 'posthog-ruby'
|
|
145
|
+
@lib_version = (opts[:_lib_version] || PostHog::VERSION).to_s
|
|
146
|
+
@headers = Defaults::Request::HEADERS.merge('User-Agent' => "#{@lib}/#{@lib_version}")
|
|
144
147
|
@worker_mutex = Mutex.new
|
|
145
148
|
@shutdown_mutex = Mutex.new
|
|
146
149
|
@shutdown_condition = ConditionVariable.new
|
|
@@ -154,11 +157,12 @@ module PostHog
|
|
|
154
157
|
elsif @sync_mode
|
|
155
158
|
nil
|
|
156
159
|
else
|
|
157
|
-
SendWorker.new(@queue, @api_key, opts)
|
|
160
|
+
SendWorker.new(@queue, @api_key, opts.merge(headers: @headers))
|
|
158
161
|
end
|
|
159
162
|
if @sync_mode
|
|
160
163
|
@transport = Transport.new(
|
|
161
164
|
api_host: opts[:host],
|
|
165
|
+
headers: @headers,
|
|
162
166
|
skip_ssl_verification: opts[:skip_ssl_verification],
|
|
163
167
|
retries: opts.key?(:max_retries) ? opts[:max_retries].to_i + 1 : 3,
|
|
164
168
|
compress_request: opts[:compress_request]
|
|
@@ -187,6 +191,12 @@ module PostHog
|
|
|
187
191
|
end
|
|
188
192
|
end
|
|
189
193
|
|
|
194
|
+
# Initialize tracking before the poller can load definitions (including async loads).
|
|
195
|
+
@distinct_id_has_sent_flag_calls_mutex = Mutex.new
|
|
196
|
+
@distinct_id_has_sent_flag_calls = SizeLimitedHash.new(Defaults::MAX_HASH_SIZE) do |hash, key|
|
|
197
|
+
hash[key] = SizeLimitedArray.new(Defaults::MAX_HASH_SIZE)
|
|
198
|
+
end
|
|
199
|
+
|
|
190
200
|
unless @disabled
|
|
191
201
|
@feature_flags_poller =
|
|
192
202
|
FeatureFlagsPoller.new(
|
|
@@ -198,15 +208,13 @@ module PostHog
|
|
|
198
208
|
opts[:on_error],
|
|
199
209
|
flag_definition_cache_provider: opts[:flag_definition_cache_provider],
|
|
200
210
|
feature_flag_request_max_retries: opts[:feature_flag_request_max_retries],
|
|
201
|
-
async_load: opts[:feature_flags_async_load] == true
|
|
211
|
+
async_load: opts[:feature_flags_async_load] == true,
|
|
212
|
+
user_agent: @headers['User-Agent'],
|
|
213
|
+
flag_definitions_update_mutex: @distinct_id_has_sent_flag_calls_mutex,
|
|
214
|
+
on_flag_definitions_updated: -> { @distinct_id_has_sent_flag_calls.clear }
|
|
202
215
|
)
|
|
203
216
|
end
|
|
204
217
|
|
|
205
|
-
@distinct_id_has_sent_flag_calls_mutex = Mutex.new
|
|
206
|
-
@distinct_id_has_sent_flag_calls = SizeLimitedHash.new(Defaults::MAX_HASH_SIZE) do |hash, key|
|
|
207
|
-
hash[key] = SizeLimitedArray.new(Defaults::MAX_HASH_SIZE)
|
|
208
|
-
end
|
|
209
|
-
|
|
210
218
|
@before_send = opts[:before_send]
|
|
211
219
|
@is_server = opts.fetch(:is_server, true) != false
|
|
212
220
|
@deprecation_emitted_for = Concurrent::Set.new
|
|
@@ -362,6 +370,8 @@ module PostHog
|
|
|
362
370
|
end
|
|
363
371
|
|
|
364
372
|
attrs[:is_server] = @is_server
|
|
373
|
+
attrs[:lib] = @lib
|
|
374
|
+
attrs[:lib_version] = @lib_version
|
|
365
375
|
message = FieldParser.parse_for_capture(attrs)
|
|
366
376
|
# Minimal events are built from the allowlist after full assembly so
|
|
367
377
|
# context properties and parser-added metadata can never leak in.
|
|
@@ -417,6 +427,8 @@ module PostHog
|
|
|
417
427
|
|
|
418
428
|
symbolize_keys! attrs
|
|
419
429
|
attrs[:is_server] = @is_server
|
|
430
|
+
attrs[:lib] = @lib
|
|
431
|
+
attrs[:lib_version] = @lib_version
|
|
420
432
|
enqueue(FieldParser.parse_for_identify(attrs))
|
|
421
433
|
end
|
|
422
434
|
|
|
@@ -435,6 +447,8 @@ module PostHog
|
|
|
435
447
|
|
|
436
448
|
symbolize_keys! attrs
|
|
437
449
|
attrs[:is_server] = @is_server
|
|
450
|
+
attrs[:lib] = @lib
|
|
451
|
+
attrs[:lib_version] = @lib_version
|
|
438
452
|
enqueue(FieldParser.parse_for_group_identify(attrs))
|
|
439
453
|
end
|
|
440
454
|
|
|
@@ -450,6 +464,8 @@ module PostHog
|
|
|
450
464
|
|
|
451
465
|
symbolize_keys! attrs
|
|
452
466
|
attrs[:is_server] = @is_server
|
|
467
|
+
attrs[:lib] = @lib
|
|
468
|
+
attrs[:lib_version] = @lib_version
|
|
453
469
|
enqueue(FieldParser.parse_for_alias(attrs))
|
|
454
470
|
end
|
|
455
471
|
|
|
@@ -44,6 +44,10 @@ module PostHog
|
|
|
44
44
|
# @param async_load [Boolean] When true, flag definitions are fetched only on the poller thread: an
|
|
45
45
|
# immediate first tick at construction, then the regular polling cadence, which keeps retrying until a
|
|
46
46
|
# load succeeds.
|
|
47
|
+
# @param user_agent [String] User-Agent header sent with feature flag requests.
|
|
48
|
+
# @param flag_definitions_update_mutex [Mutex] Internal lock shared with flag-called deduplication.
|
|
49
|
+
# @param on_flag_definitions_updated [Proc, nil] Internal callback after definitions are applied or discarded,
|
|
50
|
+
# called while holding flag_definitions_update_mutex.
|
|
47
51
|
def initialize(
|
|
48
52
|
polling_interval,
|
|
49
53
|
secret_key,
|
|
@@ -53,7 +57,10 @@ module PostHog
|
|
|
53
57
|
on_error = nil,
|
|
54
58
|
flag_definition_cache_provider: nil,
|
|
55
59
|
feature_flag_request_max_retries: nil,
|
|
56
|
-
async_load: false
|
|
60
|
+
async_load: false,
|
|
61
|
+
user_agent: "posthog-ruby/#{PostHog::VERSION}",
|
|
62
|
+
on_flag_definitions_updated: nil,
|
|
63
|
+
flag_definitions_update_mutex: Mutex.new
|
|
57
64
|
)
|
|
58
65
|
@polling_interval = polling_interval || Defaults::FeatureFlags::POLLING_INTERVAL_SECONDS
|
|
59
66
|
@secret_key = secret_key
|
|
@@ -72,6 +79,9 @@ module PostHog
|
|
|
72
79
|
@flags_etag = Concurrent::AtomicReference.new(nil)
|
|
73
80
|
@flag_definitions_loaded_at = Concurrent::AtomicReference.new(nil)
|
|
74
81
|
@async_load = async_load
|
|
82
|
+
@user_agent = user_agent
|
|
83
|
+
@on_flag_definitions_updated = on_flag_definitions_updated
|
|
84
|
+
@flag_definitions_update_mutex = flag_definitions_update_mutex
|
|
75
85
|
# Server-controlled gate for minimal `$feature_flag_called` events, read
|
|
76
86
|
# from the top-level `minimal_flag_called_events` key of the local
|
|
77
87
|
# evaluation definitions payload. false when the server does not send it.
|
|
@@ -1218,14 +1228,18 @@ module PostHog
|
|
|
1218
1228
|
'[FEATURE FLAGS] Feature flags quota limit exceeded - unsetting all local flags. ' \
|
|
1219
1229
|
'Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts'
|
|
1220
1230
|
)
|
|
1221
|
-
@
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1231
|
+
@flag_definitions_update_mutex.synchronize do
|
|
1232
|
+
definitions_were_loaded = definitions_loaded?
|
|
1233
|
+
@feature_flags = Concurrent::Array.new
|
|
1234
|
+
@feature_flags_by_key = {}
|
|
1235
|
+
@group_type_mapping = Concurrent::Hash.new
|
|
1236
|
+
@cohorts = Concurrent::Hash.new
|
|
1237
|
+
@flag_definitions_loaded_at.value = nil
|
|
1238
|
+
@minimal_flag_called_events = false
|
|
1239
|
+
@loaded_flags_successfully_once.make_false
|
|
1240
|
+
@quota_limited.make_true
|
|
1241
|
+
@on_flag_definitions_updated&.call if definitions_were_loaded
|
|
1242
|
+
end
|
|
1229
1243
|
return
|
|
1230
1244
|
end
|
|
1231
1245
|
|
|
@@ -1262,21 +1276,26 @@ module PostHog
|
|
|
1262
1276
|
cohorts = get_by_symbol_or_string_key(data, 'cohorts') || {}
|
|
1263
1277
|
minimal_flag_called_events = get_by_symbol_or_string_key(data, 'minimal_flag_called_events')
|
|
1264
1278
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1279
|
+
new_flags = Concurrent::Array.new(flags.map { |f| deep_symbolize_keys(f) })
|
|
1267
1280
|
new_by_key = {}
|
|
1268
|
-
|
|
1281
|
+
new_flags.each do |flag|
|
|
1269
1282
|
new_by_key[flag[:key]] = flag unless flag[:key].nil?
|
|
1270
1283
|
end
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
@
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1284
|
+
new_group_type_mapping = Concurrent::Hash[deep_symbolize_keys(group_type_mapping)]
|
|
1285
|
+
new_cohorts = Concurrent::Hash[deep_symbolize_keys(cohorts)]
|
|
1286
|
+
|
|
1287
|
+
# A read of the new definitions must not record its event before the tracker reset.
|
|
1288
|
+
@flag_definitions_update_mutex.synchronize do
|
|
1289
|
+
@feature_flags = new_flags
|
|
1290
|
+
@feature_flags_by_key = new_by_key
|
|
1291
|
+
@group_type_mapping = new_group_type_mapping
|
|
1292
|
+
@cohorts = new_cohorts
|
|
1293
|
+
@minimal_flag_called_events = minimal_flag_called_events == true
|
|
1294
|
+
@flag_definitions_loaded_at.value = (Time.now.to_f * 1000).to_i
|
|
1295
|
+
@loaded_flags_successfully_once.make_true if @loaded_flags_successfully_once.false?
|
|
1296
|
+
@on_flag_definitions_updated&.call
|
|
1297
|
+
end
|
|
1298
|
+
logger.debug "Loaded #{new_flags.length} feature flags and #{new_cohorts.length} cohorts"
|
|
1280
1299
|
end
|
|
1281
1300
|
|
|
1282
1301
|
def _request_feature_flag_definitions(etag: nil)
|
|
@@ -1326,7 +1345,7 @@ module PostHog
|
|
|
1326
1345
|
RETRYABLE_FLAGS_REQUEST_STATUS_CODES = [502, 504].freeze
|
|
1327
1346
|
|
|
1328
1347
|
def _request(uri, request_object, timeout = nil, include_etag: false, retry_status_codes: [])
|
|
1329
|
-
request_object['User-Agent'] =
|
|
1348
|
+
request_object['User-Agent'] = @user_agent
|
|
1330
1349
|
request_timeout = timeout || 10
|
|
1331
1350
|
backoff_policy = nil
|
|
1332
1351
|
attempts = 0
|
data/lib/posthog/field_parser.rb
CHANGED
|
@@ -144,8 +144,8 @@ module PostHog
|
|
|
144
144
|
is_server = fields.fetch(:is_server, true) != false
|
|
145
145
|
|
|
146
146
|
properties = {
|
|
147
|
-
'$lib' => 'posthog-ruby',
|
|
148
|
-
'$lib_version' => PostHog::VERSION.to_s
|
|
147
|
+
'$lib' => fields.fetch(:lib, 'posthog-ruby'),
|
|
148
|
+
'$lib_version' => fields.fetch(:lib_version, PostHog::VERSION.to_s)
|
|
149
149
|
}
|
|
150
150
|
properties['$is_server'] = true if is_server
|
|
151
151
|
|
data/lib/posthog/send_worker.rb
CHANGED
data/lib/posthog/version.rb
CHANGED