posthog-ruby 3.9.1 → 3.10.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 +73 -26
- data/lib/posthog/field_parser.rb +12 -7
- data/lib/posthog/flag_definition_cache.rb +0 -2
- 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: caf866cb91c9fb07b894b6af005decf79644ddc3c2a7c2f84dc3dd59ac9350b1
|
|
4
|
+
data.tar.gz: 6aace1e7809b8f2c6f8529086aaaf8cceb44d5f47b515222d0eeb0e757a66617
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec98d033a36bd7069b001e957fd5a395d54225f505717c45322faa8ce157d00a8fdb1275b5ac4f098e3c51e78a8b2b13a11a94d76be7d50be9b87ab469da3285
|
|
7
|
+
data.tar.gz: c0122abe71ac22a9075236b167c4a136c156f8af6853252f0caf18e4c7f41f8ccdd4b2132481d1138a6ec44793efef8d14ed35c3b7aa5769f45b20babd1ebae9
|
data/lib/posthog/client.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'time'
|
|
4
|
+
require 'json'
|
|
4
5
|
require 'securerandom'
|
|
5
6
|
|
|
6
7
|
require 'posthog/defaults'
|
|
@@ -51,7 +52,7 @@ module PostHog
|
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
# @param opts [Hash] Client configuration.
|
|
54
|
-
# @option opts [String] :api_key Your project's API key.
|
|
55
|
+
# @option opts [String, nil] :api_key Your project's API key. Missing or blank values disable the client.
|
|
55
56
|
# @option opts [String, nil] :personal_api_key Your personal API key. Required for local feature flag evaluation.
|
|
56
57
|
# @option opts [String] :host Fully qualified hostname of the PostHog server. Defaults to `https://us.i.posthog.com`.
|
|
57
58
|
# @option opts [Integer] :max_queue_size Maximum number of calls to remain queued. Defaults to 10_000.
|
|
@@ -71,7 +72,10 @@ module PostHog
|
|
|
71
72
|
# @option opts [Boolean] :skip_ssl_verification +true+ to disable SSL certificate verification for requests.
|
|
72
73
|
# Intended only for local development or custom deployments.
|
|
73
74
|
# @option opts [Object] :flag_definition_cache_provider An object implementing the {FlagDefinitionCacheProvider}
|
|
74
|
-
# interface for distributed flag definition caching.
|
|
75
|
+
# interface for distributed flag definition caching.
|
|
76
|
+
# @option opts [Boolean] :is_server +true+ to stamp captured events with `$is_server => true` so PostHog
|
|
77
|
+
# attributes them as server-side. Defaults to +true+. Set to +false+ when running posthog-ruby as a
|
|
78
|
+
# client/CLI so the device OS is attributed normally and `$is_server` is omitted.
|
|
75
79
|
def initialize(opts = {})
|
|
76
80
|
symbolize_keys!(opts)
|
|
77
81
|
|
|
@@ -81,11 +85,12 @@ module PostHog
|
|
|
81
85
|
|
|
82
86
|
@queue = Queue.new
|
|
83
87
|
@api_key = opts[:api_key]
|
|
88
|
+
@disabled = @api_key.nil? || @api_key.empty?
|
|
84
89
|
@max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
|
|
85
90
|
@worker_mutex = Mutex.new
|
|
86
|
-
@sync_mode = opts[:sync_mode] == true && !opts[:test_mode]
|
|
91
|
+
@sync_mode = opts[:sync_mode] == true && !opts[:test_mode] && !@disabled
|
|
87
92
|
@on_error = opts[:on_error] || proc { |status, error| }
|
|
88
|
-
@worker = if opts[:test_mode]
|
|
93
|
+
@worker = if opts[:test_mode] || @disabled
|
|
89
94
|
NoopWorker.new(@queue)
|
|
90
95
|
elsif @sync_mode
|
|
91
96
|
nil
|
|
@@ -104,11 +109,12 @@ module PostHog
|
|
|
104
109
|
@feature_flags_poller = nil
|
|
105
110
|
@personal_api_key = opts[:personal_api_key]
|
|
106
111
|
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
if @disabled && !opts[:silence_disabled_client_error]
|
|
113
|
+
logger.error('api_key is missing or empty after trimming whitespace; check your project API key')
|
|
114
|
+
end
|
|
109
115
|
|
|
110
116
|
# Warn when multiple clients are created with the same API key (can cause dropped events)
|
|
111
|
-
unless opts[:test_mode] || opts[:disable_singleton_warning]
|
|
117
|
+
unless @disabled || opts[:test_mode] || opts[:disable_singleton_warning]
|
|
112
118
|
previous_count = self.class._increment_instance_count(@api_key)
|
|
113
119
|
if previous_count >= 1
|
|
114
120
|
logger.warn(
|
|
@@ -120,22 +126,25 @@ module PostHog
|
|
|
120
126
|
end
|
|
121
127
|
end
|
|
122
128
|
|
|
123
|
-
@
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
unless @disabled
|
|
130
|
+
@feature_flags_poller =
|
|
131
|
+
FeatureFlagsPoller.new(
|
|
132
|
+
opts[:feature_flags_polling_interval],
|
|
133
|
+
opts[:personal_api_key],
|
|
134
|
+
@api_key,
|
|
135
|
+
opts[:host],
|
|
136
|
+
opts[:feature_flag_request_timeout_seconds] || Defaults::FeatureFlags::FLAG_REQUEST_TIMEOUT_SECONDS,
|
|
137
|
+
opts[:on_error],
|
|
138
|
+
flag_definition_cache_provider: opts[:flag_definition_cache_provider]
|
|
139
|
+
)
|
|
140
|
+
end
|
|
133
141
|
|
|
134
142
|
@distinct_id_has_sent_flag_calls = SizeLimitedHash.new(Defaults::MAX_HASH_SIZE) do |hash, key|
|
|
135
143
|
hash[key] = []
|
|
136
144
|
end
|
|
137
145
|
|
|
138
146
|
@before_send = opts[:before_send]
|
|
147
|
+
@is_server = opts.fetch(:is_server, true) != false
|
|
139
148
|
@deprecation_emitted_for = Concurrent::Set.new
|
|
140
149
|
end
|
|
141
150
|
|
|
@@ -197,6 +206,8 @@ module PostHog
|
|
|
197
206
|
# @return [Boolean] Whether the event was queued or sent.
|
|
198
207
|
# @macro common_attrs
|
|
199
208
|
def capture(attrs)
|
|
209
|
+
return false if @disabled
|
|
210
|
+
|
|
200
211
|
symbolize_keys! attrs
|
|
201
212
|
enrich_capture_attrs_with_context(attrs)
|
|
202
213
|
|
|
@@ -225,7 +236,7 @@ module PostHog
|
|
|
225
236
|
end
|
|
226
237
|
|
|
227
238
|
send_feature_flags_param = attrs[:send_feature_flags]
|
|
228
|
-
if send_feature_flags_param
|
|
239
|
+
if send_feature_flags_param && !@disabled
|
|
229
240
|
_emit_deprecation(
|
|
230
241
|
:capture_send_feature_flags,
|
|
231
242
|
'`send_feature_flags` on `capture` is deprecated and will be removed in a future major ' \
|
|
@@ -265,6 +276,7 @@ module PostHog
|
|
|
265
276
|
attrs[:feature_variants] = feature_variants if feature_variants
|
|
266
277
|
end
|
|
267
278
|
|
|
279
|
+
attrs[:is_server] = @is_server
|
|
268
280
|
enqueue(FieldParser.parse_for_capture(attrs))
|
|
269
281
|
end
|
|
270
282
|
|
|
@@ -279,6 +291,8 @@ module PostHog
|
|
|
279
291
|
# same `$feature/<key>` and `$active_feature_flags` properties as the snapshot.
|
|
280
292
|
# @return [Boolean, nil] Whether the exception event was queued or sent, or nil if the input could not be parsed.
|
|
281
293
|
def capture_exception(exception, distinct_id = nil, additional_properties = {}, flags: nil)
|
|
294
|
+
return false if @disabled
|
|
295
|
+
|
|
282
296
|
exception_info = ExceptionCapture.build_parsed_exception(exception)
|
|
283
297
|
|
|
284
298
|
return if exception_info.nil?
|
|
@@ -305,7 +319,10 @@ module PostHog
|
|
|
305
319
|
# @return [Boolean] Whether the identify event was queued or sent.
|
|
306
320
|
# @macro common_attrs
|
|
307
321
|
def identify(attrs)
|
|
322
|
+
return false if @disabled
|
|
323
|
+
|
|
308
324
|
symbolize_keys! attrs
|
|
325
|
+
attrs[:is_server] = @is_server
|
|
309
326
|
enqueue(FieldParser.parse_for_identify(attrs))
|
|
310
327
|
end
|
|
311
328
|
|
|
@@ -320,7 +337,10 @@ module PostHog
|
|
|
320
337
|
# @return [Boolean] Whether the group identify event was queued or sent.
|
|
321
338
|
# @macro common_attrs
|
|
322
339
|
def group_identify(attrs)
|
|
340
|
+
return false if @disabled
|
|
341
|
+
|
|
323
342
|
symbolize_keys! attrs
|
|
343
|
+
attrs[:is_server] = @is_server
|
|
324
344
|
enqueue(FieldParser.parse_for_group_identify(attrs))
|
|
325
345
|
end
|
|
326
346
|
|
|
@@ -332,7 +352,10 @@ module PostHog
|
|
|
332
352
|
# @return [Boolean] Whether the alias event was queued or sent.
|
|
333
353
|
# @macro common_attrs
|
|
334
354
|
def alias(attrs)
|
|
355
|
+
return false if @disabled
|
|
356
|
+
|
|
335
357
|
symbolize_keys! attrs
|
|
358
|
+
attrs[:is_server] = @is_server
|
|
336
359
|
enqueue(FieldParser.parse_for_alias(attrs))
|
|
337
360
|
end
|
|
338
361
|
|
|
@@ -387,6 +410,8 @@ module PostHog
|
|
|
387
410
|
# @param flag_key [String, Symbol] The unique flag key of the remote config feature flag.
|
|
388
411
|
# @return [Hash] The parsed remote config payload response.
|
|
389
412
|
def get_remote_config_payload(flag_key)
|
|
413
|
+
return nil if @disabled
|
|
414
|
+
|
|
390
415
|
@feature_flags_poller.get_remote_config_payload(flag_key.to_s)
|
|
391
416
|
end
|
|
392
417
|
|
|
@@ -464,6 +489,8 @@ module PostHog
|
|
|
464
489
|
'`flags.get_flag_payload(key)` instead — this consolidates flag evaluation into a single ' \
|
|
465
490
|
'`/flags` request per incoming request.'
|
|
466
491
|
)
|
|
492
|
+
return nil if @disabled
|
|
493
|
+
|
|
467
494
|
_get_feature_flag_result(
|
|
468
495
|
key, distinct_id,
|
|
469
496
|
groups: groups, person_properties: person_properties, group_properties: group_properties,
|
|
@@ -506,6 +533,8 @@ module PostHog
|
|
|
506
533
|
return FeatureFlagEvaluations.new(host: host, distinct_id: '', flags: {})
|
|
507
534
|
end
|
|
508
535
|
|
|
536
|
+
return FeatureFlagEvaluations.new(host: host, distinct_id: distinct_id, flags: {}, groups: groups) if @disabled
|
|
537
|
+
|
|
509
538
|
person_properties, group_properties = add_local_person_and_group_properties(
|
|
510
539
|
distinct_id, groups, person_properties, group_properties
|
|
511
540
|
)
|
|
@@ -619,6 +648,8 @@ module PostHog
|
|
|
619
648
|
group_properties: {},
|
|
620
649
|
only_evaluate_locally: false
|
|
621
650
|
)
|
|
651
|
+
return {} if @disabled
|
|
652
|
+
|
|
622
653
|
person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups,
|
|
623
654
|
person_properties, group_properties)
|
|
624
655
|
@feature_flags_poller.get_all_flags(distinct_id, groups, person_properties, group_properties,
|
|
@@ -656,6 +687,8 @@ module PostHog
|
|
|
656
687
|
'instead — this consolidates flag evaluation into a single `/flags` request per ' \
|
|
657
688
|
'incoming request.'
|
|
658
689
|
)
|
|
690
|
+
return nil if @disabled
|
|
691
|
+
|
|
659
692
|
key = key.to_s
|
|
660
693
|
person_properties, group_properties = add_local_person_and_group_properties(distinct_id, groups,
|
|
661
694
|
person_properties, group_properties)
|
|
@@ -682,6 +715,8 @@ module PostHog
|
|
|
682
715
|
group_properties: {},
|
|
683
716
|
only_evaluate_locally: false
|
|
684
717
|
)
|
|
718
|
+
return { featureFlags: {}, featureFlagPayloads: {} } if @disabled
|
|
719
|
+
|
|
685
720
|
person_properties, group_properties = add_local_person_and_group_properties(
|
|
686
721
|
distinct_id, groups, person_properties, group_properties
|
|
687
722
|
)
|
|
@@ -699,6 +734,8 @@ module PostHog
|
|
|
699
734
|
#
|
|
700
735
|
# @return [void]
|
|
701
736
|
def reload_feature_flags
|
|
737
|
+
return if @disabled
|
|
738
|
+
|
|
702
739
|
unless @personal_api_key
|
|
703
740
|
logger.error(
|
|
704
741
|
'You need to specify a personal_api_key to locally evaluate feature flags'
|
|
@@ -712,8 +749,8 @@ module PostHog
|
|
|
712
749
|
#
|
|
713
750
|
# @return [void]
|
|
714
751
|
def shutdown
|
|
715
|
-
self.class._decrement_instance_count(@api_key)
|
|
716
|
-
@feature_flags_poller
|
|
752
|
+
self.class._decrement_instance_count(@api_key) unless @disabled
|
|
753
|
+
@feature_flags_poller&.shutdown_poller
|
|
717
754
|
flush
|
|
718
755
|
if @sync_mode
|
|
719
756
|
@sync_lock.synchronize { @transport&.shutdown }
|
|
@@ -760,11 +797,22 @@ module PostHog
|
|
|
760
797
|
# Shared by the legacy single-flag path ({#get_feature_flag_result}) and the
|
|
761
798
|
# snapshot's access-recording. Owns dedup-key construction, the
|
|
762
799
|
# per-distinct_id sent-flags cache, and the `$feature_flag_called` capture call.
|
|
800
|
+
# Group context is included in the dedup key so group-scoped flags fire a
|
|
801
|
+
# separate event for each group a user is evaluated under.
|
|
763
802
|
def _capture_feature_flag_called_if_needed(
|
|
764
803
|
distinct_id: nil, key: nil, response: nil, properties: nil,
|
|
765
804
|
groups: nil, disable_geoip: nil
|
|
766
805
|
)
|
|
767
|
-
|
|
806
|
+
response_repr = response.nil? ? '::null::' : response
|
|
807
|
+
groups_repr =
|
|
808
|
+
if groups && !groups.empty?
|
|
809
|
+
# Canonicalize so two equal hashes with keys inserted in a different
|
|
810
|
+
# order produce the same dedup key.
|
|
811
|
+
"_#{groups.sort.to_json}"
|
|
812
|
+
else
|
|
813
|
+
''
|
|
814
|
+
end
|
|
815
|
+
reported_key = "#{key}_#{response_repr}#{groups_repr}"
|
|
768
816
|
return if @distinct_id_has_sent_flag_calls[distinct_id].include?(reported_key)
|
|
769
817
|
|
|
770
818
|
msg = {
|
|
@@ -798,6 +846,8 @@ module PostHog
|
|
|
798
846
|
only_evaluate_locally: false,
|
|
799
847
|
send_feature_flag_events: true
|
|
800
848
|
)
|
|
849
|
+
return nil if @disabled
|
|
850
|
+
|
|
801
851
|
key = key.to_s
|
|
802
852
|
person_properties, group_properties = add_local_person_and_group_properties(
|
|
803
853
|
distinct_id, groups, person_properties, group_properties
|
|
@@ -863,6 +913,8 @@ module PostHog
|
|
|
863
913
|
#
|
|
864
914
|
# returns Boolean of whether the item was added to the queue.
|
|
865
915
|
def enqueue(action)
|
|
916
|
+
return false if @disabled
|
|
917
|
+
|
|
866
918
|
action = process_before_send(action)
|
|
867
919
|
return false if action.nil? || action.empty?
|
|
868
920
|
|
|
@@ -889,11 +941,6 @@ module PostHog
|
|
|
889
941
|
end
|
|
890
942
|
end
|
|
891
943
|
|
|
892
|
-
# private: Checks that the api_key is properly initialized
|
|
893
|
-
def check_api_key!
|
|
894
|
-
raise ArgumentError, 'API key must be initialized' if @api_key.nil?
|
|
895
|
-
end
|
|
896
|
-
|
|
897
944
|
def normalize_string_option(value, blank_as_nil: false)
|
|
898
945
|
return value unless value.is_a?(String)
|
|
899
946
|
|
data/lib/posthog/field_parser.rb
CHANGED
|
@@ -89,11 +89,11 @@ module PostHog
|
|
|
89
89
|
common.merge(
|
|
90
90
|
{
|
|
91
91
|
event: '$groupidentify',
|
|
92
|
-
properties: {
|
|
92
|
+
properties: (common[:properties] || {}).merge(
|
|
93
93
|
'$group_type': group_type,
|
|
94
94
|
'$group_key': group_key,
|
|
95
|
-
'$group_set': properties
|
|
96
|
-
|
|
95
|
+
'$group_set': properties
|
|
96
|
+
)
|
|
97
97
|
}
|
|
98
98
|
)
|
|
99
99
|
end
|
|
@@ -141,16 +141,21 @@ module PostHog
|
|
|
141
141
|
check_timestamp! timestamp
|
|
142
142
|
check_presence! distinct_id, 'distinct_id'
|
|
143
143
|
|
|
144
|
+
is_server = fields.fetch(:is_server, true) != false
|
|
145
|
+
|
|
146
|
+
properties = {
|
|
147
|
+
'$lib' => 'posthog-ruby',
|
|
148
|
+
'$lib_version' => PostHog::VERSION.to_s
|
|
149
|
+
}
|
|
150
|
+
properties['$is_server'] = true if is_server
|
|
151
|
+
|
|
144
152
|
parsed = {
|
|
145
153
|
timestamp: datetime_in_iso8601(timestamp),
|
|
146
154
|
library: 'posthog-ruby',
|
|
147
155
|
library_version: PostHog::VERSION.to_s,
|
|
148
156
|
messageId: message_id,
|
|
149
157
|
distinct_id: distinct_id,
|
|
150
|
-
properties:
|
|
151
|
-
'$lib' => 'posthog-ruby',
|
|
152
|
-
'$lib_version' => PostHog::VERSION.to_s
|
|
153
|
-
}
|
|
158
|
+
properties: properties
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
if send_feature_flags && fields[:feature_variants]
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module PostHog
|
|
4
4
|
# Interface for external caching of feature flag definitions.
|
|
5
5
|
#
|
|
6
|
-
# EXPERIMENTAL: This API may change in future minor version bumps.
|
|
7
|
-
#
|
|
8
6
|
# Enables multi-worker environments (Kubernetes, load-balanced servers,
|
|
9
7
|
# serverless functions) to share flag definitions via an external cache,
|
|
10
8
|
# reducing redundant API calls.
|
data/lib/posthog/version.rb
CHANGED