posthog-ruby 3.17.0 → 3.19.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/posthog/client.rb +27 -8
- data/lib/posthog/feature_flag.rb +4 -1
- data/lib/posthog/feature_flag_evaluations.rb +2 -1
- data/lib/posthog/feature_flags.rb +21 -9
- data/lib/posthog/flag_definition_cache.rb +1 -1
- 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: b23e0da0723e7582825d0888d8c6ffd9b3ad0a77e5eec513a40ab3de1faaa306
|
|
4
|
+
data.tar.gz: 1fc203c912147dc865cb342213ef8ccd3604e4d84f0b0005932c559aa30c8017
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8409ba6d5fb0801643cbd6556a1dabf41441ff522b85d612601ac8547482c5eb139ac68f21250f2f240654f08c03b3ca6cdc0409f57f1c6af9cdd880c677805f
|
|
7
|
+
data.tar.gz: c7a146c293985480777e6f5139588ca0d897170b8fe15412e9d60561711cb57bec53e70225b8b209916a50835f249b9816bece364be754a56e6f1118454feb52
|
data/lib/posthog/client.rb
CHANGED
|
@@ -53,7 +53,11 @@ module PostHog
|
|
|
53
53
|
|
|
54
54
|
# @param opts [Hash] Client configuration.
|
|
55
55
|
# @option opts [String, nil] :api_key Your project's API key. Missing or blank values disable the client.
|
|
56
|
-
# @option opts [String, nil] :
|
|
56
|
+
# @option opts [String, nil] :secret_key The credential used for local feature flag evaluation and remote
|
|
57
|
+
# config. Accepts either a Personal API Key (`phx_...`) or a Project Secret API Key (`phs_...`). Required
|
|
58
|
+
# for local feature flag evaluation.
|
|
59
|
+
# @option opts [String, nil] :personal_api_key
|
|
60
|
+
# @deprecated Use +:secret_key+ instead. Retained as an alias; when both are supplied, +:secret_key+ wins.
|
|
57
61
|
# @option opts [String] :host Fully qualified hostname of the PostHog server. Defaults to `https://us.i.posthog.com`.
|
|
58
62
|
# @option opts [Integer] :max_queue_size Maximum number of calls to remain queued. Defaults to 10_000.
|
|
59
63
|
# @option opts [Integer] :batch_size Maximum number of events to send in one async batch.
|
|
@@ -88,9 +92,18 @@ module PostHog
|
|
|
88
92
|
symbolize_keys!(opts)
|
|
89
93
|
|
|
90
94
|
opts[:api_key] = normalize_string_option(opts[:api_key])
|
|
95
|
+
opts[:secret_key] = normalize_string_option(opts[:secret_key], blank_as_nil: true)
|
|
91
96
|
opts[:personal_api_key] = normalize_string_option(opts[:personal_api_key], blank_as_nil: true)
|
|
92
97
|
opts[:host] = normalize_host_option(opts[:host])
|
|
93
98
|
|
|
99
|
+
if opts[:secret_key].nil? && !opts[:personal_api_key].nil?
|
|
100
|
+
logger.warn(
|
|
101
|
+
'The :personal_api_key option is deprecated; use :secret_key instead. It accepts either a ' \
|
|
102
|
+
'Personal API Key (phx_...) or a Project Secret API Key (phs_...).'
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
secret_key = opts[:secret_key] || opts[:personal_api_key]
|
|
106
|
+
|
|
94
107
|
@queue = Queue.new
|
|
95
108
|
@queue_mutex = Mutex.new
|
|
96
109
|
@api_key = opts[:api_key]
|
|
@@ -119,7 +132,8 @@ module PostHog
|
|
|
119
132
|
end
|
|
120
133
|
@worker_thread = nil
|
|
121
134
|
@feature_flags_poller = nil
|
|
122
|
-
@
|
|
135
|
+
@secret_key = secret_key
|
|
136
|
+
@personal_api_key = secret_key
|
|
123
137
|
|
|
124
138
|
if @disabled && !opts[:silence_disabled_client_error]
|
|
125
139
|
logger.error('api_key is missing or empty after trimming whitespace; check your project API key')
|
|
@@ -142,7 +156,7 @@ module PostHog
|
|
|
142
156
|
@feature_flags_poller =
|
|
143
157
|
FeatureFlagsPoller.new(
|
|
144
158
|
opts[:feature_flags_polling_interval],
|
|
145
|
-
|
|
159
|
+
secret_key,
|
|
146
160
|
@api_key,
|
|
147
161
|
opts[:host],
|
|
148
162
|
opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
|
|
@@ -595,7 +609,8 @@ module PostHog
|
|
|
595
609
|
id: definition[:id],
|
|
596
610
|
version: nil,
|
|
597
611
|
reason: FeatureFlagEvaluations::EVALUATED_LOCALLY_REASON,
|
|
598
|
-
locally_evaluated: true
|
|
612
|
+
locally_evaluated: true,
|
|
613
|
+
has_experiment: definition[:has_experiment]
|
|
599
614
|
)
|
|
600
615
|
locally_evaluated_keys << key.to_s
|
|
601
616
|
end
|
|
@@ -635,7 +650,8 @@ module PostHog
|
|
|
635
650
|
id: metadata ? metadata.id : nil,
|
|
636
651
|
version: metadata ? metadata.version : nil,
|
|
637
652
|
reason: reason ? (reason.description || reason.code) : nil,
|
|
638
|
-
locally_evaluated: false
|
|
653
|
+
locally_evaluated: false,
|
|
654
|
+
has_experiment: metadata&.has_experiment
|
|
639
655
|
)
|
|
640
656
|
end
|
|
641
657
|
rescue StandardError => e
|
|
@@ -752,6 +768,7 @@ module PostHog
|
|
|
752
768
|
# Remove internal information
|
|
753
769
|
response.delete(:requestId)
|
|
754
770
|
response.delete(:evaluatedAt)
|
|
771
|
+
response.delete(:flagDetails)
|
|
755
772
|
response
|
|
756
773
|
end
|
|
757
774
|
|
|
@@ -761,9 +778,9 @@ module PostHog
|
|
|
761
778
|
def reload_feature_flags
|
|
762
779
|
return if @disabled
|
|
763
780
|
|
|
764
|
-
unless @
|
|
781
|
+
unless @secret_key
|
|
765
782
|
logger.error(
|
|
766
|
-
'You need to specify a
|
|
783
|
+
'You need to specify a secret_key to locally evaluate feature flags'
|
|
767
784
|
)
|
|
768
785
|
return
|
|
769
786
|
end
|
|
@@ -907,7 +924,8 @@ module PostHog
|
|
|
907
924
|
person_properties, group_properties = add_local_person_and_group_properties(
|
|
908
925
|
groups, person_properties, group_properties
|
|
909
926
|
)
|
|
910
|
-
feature_flag_response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload
|
|
927
|
+
feature_flag_response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload,
|
|
928
|
+
has_experiment =
|
|
911
929
|
@feature_flags_poller.get_feature_flag(
|
|
912
930
|
key, distinct_id, groups, person_properties, group_properties, only_evaluate_locally
|
|
913
931
|
)
|
|
@@ -917,6 +935,7 @@ module PostHog
|
|
|
917
935
|
'$feature_flag_response' => feature_flag_response,
|
|
918
936
|
'locally_evaluated' => flag_was_locally_evaluated
|
|
919
937
|
}
|
|
938
|
+
properties['$feature_flag_has_experiment'] = has_experiment unless has_experiment.nil?
|
|
920
939
|
properties['$feature_flag_request_id'] = request_id if request_id
|
|
921
940
|
properties['$feature_flag_evaluated_at'] = evaluated_at if evaluated_at
|
|
922
941
|
properties['$feature_flag_error'] = feature_flag_error if feature_flag_error
|
data/lib/posthog/feature_flag.rb
CHANGED
|
@@ -68,7 +68,7 @@ module PostHog
|
|
|
68
68
|
#
|
|
69
69
|
# @api private
|
|
70
70
|
class FeatureFlagMetadata
|
|
71
|
-
attr_reader :id, :version, :payload, :description
|
|
71
|
+
attr_reader :id, :version, :payload, :description, :has_experiment
|
|
72
72
|
|
|
73
73
|
# @param json [Hash] Raw metadata returned by /flags.
|
|
74
74
|
def initialize(json)
|
|
@@ -77,6 +77,9 @@ module PostHog
|
|
|
77
77
|
@version = json['version']
|
|
78
78
|
@payload = json['payload']
|
|
79
79
|
@description = json['description']
|
|
80
|
+
# Whether the flag is linked to an experiment. nil when the server
|
|
81
|
+
# (an older deployment) does not report the field.
|
|
82
|
+
@has_experiment = json['has_experiment']
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
end
|
|
@@ -13,7 +13,7 @@ module PostHog
|
|
|
13
13
|
EVALUATED_LOCALLY_REASON = 'Evaluated locally'
|
|
14
14
|
|
|
15
15
|
EvaluatedFlagRecord = Struct.new(
|
|
16
|
-
:key, :enabled, :variant, :payload, :id, :version, :reason, :locally_evaluated,
|
|
16
|
+
:key, :enabled, :variant, :payload, :id, :version, :reason, :locally_evaluated, :has_experiment,
|
|
17
17
|
keyword_init: true
|
|
18
18
|
)
|
|
19
19
|
|
|
@@ -169,6 +169,7 @@ module PostHog
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
if flag
|
|
172
|
+
properties['$feature_flag_has_experiment'] = flag.has_experiment unless flag.has_experiment.nil?
|
|
172
173
|
properties['$feature_flag_payload'] = flag.payload unless flag.payload.nil?
|
|
173
174
|
properties['$feature_flag_id'] = flag.id if flag.id
|
|
174
175
|
properties['$feature_flag_version'] = flag.version if flag.version
|
|
@@ -30,7 +30,8 @@ module PostHog
|
|
|
30
30
|
include PostHog::Utils
|
|
31
31
|
|
|
32
32
|
# @param polling_interval [Integer, nil] Seconds between local feature flag definition polls.
|
|
33
|
-
# @param
|
|
33
|
+
# @param secret_key [String, nil] Credential used to fetch local evaluation definitions. Accepts either a
|
|
34
|
+
# Personal API Key (`phx_...`) or a Project Secret API Key (`phs_...`).
|
|
34
35
|
# @param project_api_key [String] Project API key.
|
|
35
36
|
# @param host [String] PostHog API host URL.
|
|
36
37
|
# @param feature_flag_request_timeout_seconds [Integer] Timeout for feature flag requests.
|
|
@@ -41,7 +42,7 @@ module PostHog
|
|
|
41
42
|
# Set to 0 to disable retrying.
|
|
42
43
|
def initialize(
|
|
43
44
|
polling_interval,
|
|
44
|
-
|
|
45
|
+
secret_key,
|
|
45
46
|
project_api_key,
|
|
46
47
|
host,
|
|
47
48
|
feature_flag_request_timeout_seconds,
|
|
@@ -50,7 +51,7 @@ module PostHog
|
|
|
50
51
|
feature_flag_request_max_retries: nil
|
|
51
52
|
)
|
|
52
53
|
@polling_interval = polling_interval || 30
|
|
53
|
-
@
|
|
54
|
+
@secret_key = secret_key
|
|
54
55
|
@project_api_key = project_api_key
|
|
55
56
|
@host = host
|
|
56
57
|
@feature_flags = Concurrent::Array.new
|
|
@@ -74,9 +75,9 @@ module PostHog
|
|
|
74
75
|
execution_interval: polling_interval
|
|
75
76
|
) { _load_feature_flags }
|
|
76
77
|
|
|
77
|
-
# If no
|
|
78
|
-
if @
|
|
79
|
-
logger.info 'No
|
|
78
|
+
# If no secret_key, disable local evaluation & thus polling for definitions
|
|
79
|
+
if @secret_key.nil?
|
|
80
|
+
logger.info 'No secret_key provided, disabling local evaluation'
|
|
80
81
|
@loaded_flags_successfully_once.make_true
|
|
81
82
|
else
|
|
82
83
|
# load once before timer
|
|
@@ -220,6 +221,11 @@ module PostHog
|
|
|
220
221
|
end
|
|
221
222
|
|
|
222
223
|
flag_was_locally_evaluated = !response.nil?
|
|
224
|
+
# Whether the flag is linked to an experiment, as reported by the server.
|
|
225
|
+
# Locally-evaluated flags carry it in the stored definition; remotely
|
|
226
|
+
# evaluated flags carry it in the response metadata. nil when the server
|
|
227
|
+
# (an older deployment) does not report it.
|
|
228
|
+
has_experiment = feature_flag[:has_experiment] if flag_was_locally_evaluated
|
|
223
229
|
|
|
224
230
|
request_id = nil
|
|
225
231
|
evaluated_at = nil
|
|
@@ -252,6 +258,9 @@ module PostHog
|
|
|
252
258
|
payload = payloads[key]
|
|
253
259
|
feature_flag_error = errors.join(',') unless errors.empty?
|
|
254
260
|
|
|
261
|
+
flag_detail = flags_data[:flagDetails]&.[](key.to_sym)
|
|
262
|
+
has_experiment = flag_detail&.metadata&.has_experiment
|
|
263
|
+
|
|
255
264
|
logger.debug "Successfully computed flag remotely: #{key} -> #{response}"
|
|
256
265
|
rescue Timeout::Error => e
|
|
257
266
|
@on_error.call(-1, "Timeout while fetching flags remotely: #{e}")
|
|
@@ -265,7 +274,7 @@ module PostHog
|
|
|
265
274
|
end
|
|
266
275
|
end
|
|
267
276
|
|
|
268
|
-
[response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload]
|
|
277
|
+
[response, flag_was_locally_evaluated, request_id, evaluated_at, feature_flag_error, payload, has_experiment]
|
|
269
278
|
end
|
|
270
279
|
|
|
271
280
|
def get_all_flags(
|
|
@@ -323,10 +332,12 @@ module PostHog
|
|
|
323
332
|
errors_while_computing = false
|
|
324
333
|
quota_limited = nil
|
|
325
334
|
status_code = nil
|
|
335
|
+
flag_details = nil
|
|
326
336
|
|
|
327
337
|
if fallback_to_server && !only_evaluate_locally
|
|
328
338
|
begin
|
|
329
339
|
flags_and_payloads = get_flags(distinct_id, groups, person_properties, group_properties)
|
|
340
|
+
flag_details = flags_and_payloads[:flags]
|
|
330
341
|
errors_while_computing = flags_and_payloads[:errorsWhileComputingFlags] || false
|
|
331
342
|
quota_limited = flags_and_payloads[:quotaLimited]
|
|
332
343
|
status_code = flags_and_payloads[:status]
|
|
@@ -367,6 +378,7 @@ module PostHog
|
|
|
367
378
|
{
|
|
368
379
|
featureFlags: flags,
|
|
369
380
|
featureFlagPayloads: payloads,
|
|
381
|
+
flagDetails: flag_details,
|
|
370
382
|
requestId: request_id,
|
|
371
383
|
evaluatedAt: evaluated_at,
|
|
372
384
|
errorsWhileComputingFlags: errors_while_computing,
|
|
@@ -1227,7 +1239,7 @@ module PostHog
|
|
|
1227
1239
|
uri = URI("#{@host}/flags/definitions")
|
|
1228
1240
|
uri.query = URI.encode_www_form([['token', @project_api_key], %w[send_cohorts true]])
|
|
1229
1241
|
req = Net::HTTP::Get.new(uri)
|
|
1230
|
-
req['Authorization'] = "Bearer #{@
|
|
1242
|
+
req['Authorization'] = "Bearer #{@secret_key}"
|
|
1231
1243
|
req['If-None-Match'] = etag if etag
|
|
1232
1244
|
|
|
1233
1245
|
_request(uri, req, nil, include_etag: true)
|
|
@@ -1253,7 +1265,7 @@ module PostHog
|
|
|
1253
1265
|
uri.query = URI.encode_www_form([['token', @project_api_key]])
|
|
1254
1266
|
req = Net::HTTP::Get.new(uri)
|
|
1255
1267
|
req['Content-Type'] = 'application/json'
|
|
1256
|
-
req['Authorization'] = "Bearer #{@
|
|
1268
|
+
req['Authorization'] = "Bearer #{@secret_key}"
|
|
1257
1269
|
|
|
1258
1270
|
_request(uri, req, @feature_flag_request_timeout_seconds)
|
|
1259
1271
|
end
|
|
@@ -52,7 +52,7 @@ module PostHog
|
|
|
52
52
|
# cache = RedisFlagCache.new(redis, service_key: 'my-service')
|
|
53
53
|
# client = PostHog::Client.new(
|
|
54
54
|
# api_key: '<project_api_key>',
|
|
55
|
-
#
|
|
55
|
+
# secret_key: '<secret_key>',
|
|
56
56
|
# flag_definition_cache_provider: cache
|
|
57
57
|
# )
|
|
58
58
|
#
|
data/lib/posthog/version.rb
CHANGED