posthog-ruby 3.16.0 → 3.18.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 +19 -5
- data/lib/posthog/exception_capture.rb +71 -9
- data/lib/posthog/feature_flags.rb +9 -8
- 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: 75e17034bb60a9af9539cfe28137a91a71d83305e4d3dc7d1db3844870efac38
|
|
4
|
+
data.tar.gz: b511f71723032dff61fc998ae145d1e650eb6d90bdb4df84024e9335613aed71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d27932884831bba0abb8b90315c1c8c684ae821aa85a5f6df8b486339d53097022ee2d58303b913a46cb05cf576230bf1f45b2ffdbdf465c79fce4875239cfb9
|
|
7
|
+
data.tar.gz: 043c0f02fb14f744898e7910623757931021d03cb0fbcacc46a305ec2f4d753df81a1ed8482b72f6e9c7e8bc1c826c78b86e889491ceb4c112dfa1844b1cf82a
|
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,
|
|
@@ -761,9 +775,9 @@ module PostHog
|
|
|
761
775
|
def reload_feature_flags
|
|
762
776
|
return if @disabled
|
|
763
777
|
|
|
764
|
-
unless @
|
|
778
|
+
unless @secret_key
|
|
765
779
|
logger.error(
|
|
766
|
-
'You need to specify a
|
|
780
|
+
'You need to specify a secret_key to locally evaluate feature flags'
|
|
767
781
|
)
|
|
768
782
|
return
|
|
769
783
|
end
|
|
@@ -97,8 +97,10 @@ module PostHog
|
|
|
97
97
|
def self.build_stacktrace(backtrace)
|
|
98
98
|
return nil unless backtrace && !backtrace.empty?
|
|
99
99
|
|
|
100
|
+
root = project_root
|
|
101
|
+
roots = dependency_roots(root)
|
|
100
102
|
frames = backtrace.first(50).map do |line|
|
|
101
|
-
parse_backtrace_line(line)
|
|
103
|
+
parse_backtrace_line(line, project_root: root, dependency_roots: roots)
|
|
102
104
|
end.compact.reverse
|
|
103
105
|
|
|
104
106
|
{
|
|
@@ -108,8 +110,10 @@ module PostHog
|
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
# @param line [String]
|
|
113
|
+
# @param project_root [String, nil] Project root used to derive project-relative filenames.
|
|
114
|
+
# @param dependency_roots [Array<String>, nil] Cached gem and stdlib roots.
|
|
111
115
|
# @return [Hash, nil]
|
|
112
|
-
def self.parse_backtrace_line(line)
|
|
116
|
+
def self.parse_backtrace_line(line, project_root: self.project_root, dependency_roots: nil)
|
|
113
117
|
match = line.match(RUBY_INPUT_FORMAT)
|
|
114
118
|
return nil unless match
|
|
115
119
|
|
|
@@ -118,11 +122,11 @@ module PostHog
|
|
|
118
122
|
method_name = match[5]
|
|
119
123
|
|
|
120
124
|
frame = {
|
|
121
|
-
'filename' =>
|
|
125
|
+
'filename' => frame_filename(file, project_root),
|
|
122
126
|
'abs_path' => file,
|
|
123
127
|
'lineno' => lineno,
|
|
124
128
|
'function' => method_name,
|
|
125
|
-
'in_app' => !gem_path?(file),
|
|
129
|
+
'in_app' => !gem_path?(file, dependency_roots || self.dependency_roots(project_root)),
|
|
126
130
|
'platform' => 'ruby'
|
|
127
131
|
}
|
|
128
132
|
|
|
@@ -131,13 +135,71 @@ module PostHog
|
|
|
131
135
|
frame
|
|
132
136
|
end
|
|
133
137
|
|
|
138
|
+
# Root directory the application runs from, used to derive stable
|
|
139
|
+
# project-relative filenames from per-host deploy paths
|
|
140
|
+
# (e.g. `/app/releases/20240101/...`).
|
|
141
|
+
#
|
|
142
|
+
# @return [String]
|
|
143
|
+
def self.project_root
|
|
144
|
+
if defined?(::Rails) && ::Rails.respond_to?(:root) && ::Rails.root
|
|
145
|
+
::Rails.root.to_s
|
|
146
|
+
else
|
|
147
|
+
Dir.pwd
|
|
148
|
+
end
|
|
149
|
+
rescue StandardError
|
|
150
|
+
Dir.pwd
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Stable filename used for fingerprinting: the project-relative path when
|
|
154
|
+
# the file lives inside the project root, its basename otherwise. The raw
|
|
155
|
+
# absolute path is kept separately in `abs_path`.
|
|
156
|
+
#
|
|
157
|
+
# @param path [String]
|
|
158
|
+
# @param project_root [String, nil]
|
|
159
|
+
# @return [String]
|
|
160
|
+
def self.frame_filename(path, project_root)
|
|
161
|
+
if project_root && !project_root.empty? && path_within?(path, project_root)
|
|
162
|
+
relative = path[project_root.length..]
|
|
163
|
+
relative = relative[1..] while relative.start_with?(File::SEPARATOR)
|
|
164
|
+
return relative unless relative.empty?
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
File.basename(path)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Whether the path belongs to an installed gem or the Ruby standard library,
|
|
171
|
+
# based on gem install locations rather than path substrings.
|
|
172
|
+
#
|
|
173
|
+
# @param path [String]
|
|
174
|
+
# @param dependency_roots [Array<String>]
|
|
175
|
+
# @return [Boolean]
|
|
176
|
+
def self.gem_path?(path, dependency_roots = self.dependency_roots)
|
|
177
|
+
dependency_roots.any? { |root| path_within?(path, root) }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# @param project_root [String]
|
|
181
|
+
# @return [Array<String>] Directories containing installed gems and the Ruby stdlib.
|
|
182
|
+
def self.dependency_roots(project_root = self.project_root)
|
|
183
|
+
roots = []
|
|
184
|
+
if defined?(Gem)
|
|
185
|
+
roots.concat(Gem.path) if Gem.respond_to?(:path)
|
|
186
|
+
roots << Gem.default_dir if Gem.respond_to?(:default_dir)
|
|
187
|
+
roots.concat(Gem.loaded_specs.each_value.map(&:full_gem_path)) if Gem.respond_to?(:loaded_specs)
|
|
188
|
+
end
|
|
189
|
+
roots << RbConfig::CONFIG['rubylibprefix'] if defined?(RbConfig)
|
|
190
|
+
# The project itself can be a loaded spec (e.g. a gem developed in place,
|
|
191
|
+
# or a Rails engine); its frames are still application code.
|
|
192
|
+
roots.compact.reject(&:empty?).uniq - [project_root]
|
|
193
|
+
rescue StandardError
|
|
194
|
+
[]
|
|
195
|
+
end
|
|
196
|
+
|
|
134
197
|
# @param path [String]
|
|
198
|
+
# @param root [String]
|
|
135
199
|
# @return [Boolean]
|
|
136
|
-
def self.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
path.include?('/.rbenv/') ||
|
|
140
|
-
path.include?('/.rvm/')
|
|
200
|
+
def self.path_within?(path, root)
|
|
201
|
+
root = root.chomp(File::SEPARATOR)
|
|
202
|
+
path == root || path.start_with?("#{root}#{File::SEPARATOR}")
|
|
141
203
|
end
|
|
142
204
|
|
|
143
205
|
# @param frame [Hash]
|
|
@@ -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
|
|
@@ -1227,7 +1228,7 @@ module PostHog
|
|
|
1227
1228
|
uri = URI("#{@host}/flags/definitions")
|
|
1228
1229
|
uri.query = URI.encode_www_form([['token', @project_api_key], %w[send_cohorts true]])
|
|
1229
1230
|
req = Net::HTTP::Get.new(uri)
|
|
1230
|
-
req['Authorization'] = "Bearer #{@
|
|
1231
|
+
req['Authorization'] = "Bearer #{@secret_key}"
|
|
1231
1232
|
req['If-None-Match'] = etag if etag
|
|
1232
1233
|
|
|
1233
1234
|
_request(uri, req, nil, include_etag: true)
|
|
@@ -1253,7 +1254,7 @@ module PostHog
|
|
|
1253
1254
|
uri.query = URI.encode_www_form([['token', @project_api_key]])
|
|
1254
1255
|
req = Net::HTTP::Get.new(uri)
|
|
1255
1256
|
req['Content-Type'] = 'application/json'
|
|
1256
|
-
req['Authorization'] = "Bearer #{@
|
|
1257
|
+
req['Authorization'] = "Bearer #{@secret_key}"
|
|
1257
1258
|
|
|
1258
1259
|
_request(uri, req, @feature_flag_request_timeout_seconds)
|
|
1259
1260
|
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