posthog-ruby 1.0.0.pre → 1.2.1
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 +5 -5
- data/bin/posthog +57 -39
- data/lib/posthog/backoff_policy.rb +3 -6
- data/lib/posthog/client.rb +58 -6
- data/lib/posthog/defaults.rb +9 -7
- data/lib/posthog/feature_flags.rb +129 -0
- data/lib/posthog/field_parser.rb +37 -24
- data/lib/posthog/logging.rb +8 -8
- data/lib/posthog/message_batch.rb +2 -1
- data/lib/posthog/response.rb +1 -2
- data/lib/posthog/transport.rb +13 -17
- data/lib/posthog/utils.rb +11 -12
- data/lib/posthog/version.rb +1 -1
- data/lib/posthog/worker.rb +0 -1
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b1c78909b0d23aea369a70193696c779c04de90bf5c7725c2d3402c982ba2568
|
4
|
+
data.tar.gz: bf4c5400441cefdf1b9037b27e3b2bfd572317cd7309b30fc89ae56548a2c1c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d4c65100cf0971d2382ec47c29346fd88e2d1ceab61a82694a96ad60d28607edcc08a3f4023d13235e87350f4ac3e9ccace34d7c2138b70a850895c6fa2482c
|
7
|
+
data.tar.gz: 7054d04f4c9346e18c638370d39858b98dfd9653e5731bcd286556f686978d652ef414c37f040a11272030624d86858419eccab147a50c88c4ca0226916451e3
|
data/bin/posthog
CHANGED
@@ -11,32 +11,39 @@ program :version, '1.0.0'
|
|
11
11
|
program :description, 'PostHog API'
|
12
12
|
|
13
13
|
def json_hash(str)
|
14
|
-
if str
|
15
|
-
return JSON.parse(str)
|
16
|
-
end
|
14
|
+
return JSON.parse(str) if str
|
17
15
|
end
|
18
16
|
|
19
17
|
command :capture do |c|
|
20
18
|
c.description = 'capture an event'
|
21
19
|
|
22
20
|
c.option '--api-key=<string>', String, 'The PostHog API Key'
|
23
|
-
c.option '--api-host=<url>',
|
24
|
-
|
21
|
+
c.option '--api-host=<url>',
|
22
|
+
String,
|
23
|
+
'The PostHog API URL host part (scheme+domain)'
|
24
|
+
c.option '--distinct-id=<distinct_id>',
|
25
|
+
String,
|
26
|
+
'The distinct id to send the event as'
|
25
27
|
c.option '--event=<event>', String, 'The event name to send with the event'
|
26
28
|
c.option '--properties=<properties>', 'The properties to send (JSON-encoded)'
|
27
29
|
|
28
30
|
c.action do |args, options|
|
29
|
-
posthog =
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
posthog =
|
32
|
+
PostHog::Client.new(
|
33
|
+
{
|
34
|
+
api_key: options.api_key,
|
35
|
+
api_host: options.api_host,
|
36
|
+
on_error: Proc.new { |status, msg| print msg }
|
37
|
+
}
|
38
|
+
)
|
39
|
+
|
40
|
+
posthog.capture(
|
41
|
+
{
|
42
|
+
distinct_id: options.distinct_id,
|
43
|
+
event: options.event,
|
44
|
+
properties: json_hash(options.properties)
|
45
|
+
}
|
46
|
+
)
|
40
47
|
|
41
48
|
posthog.flush
|
42
49
|
end
|
@@ -46,21 +53,30 @@ command :identify do |c|
|
|
46
53
|
c.description = 'identify the user'
|
47
54
|
|
48
55
|
c.option '--api-key=<api_key>', String, 'The PostHog API Key'
|
49
|
-
c.option '--api-host=<url>',
|
50
|
-
|
56
|
+
c.option '--api-host=<url>',
|
57
|
+
String,
|
58
|
+
'The PostHog API URL host part (scheme+domain)'
|
59
|
+
c.option '--distinct-id=<distinct_id>',
|
60
|
+
String,
|
61
|
+
'The distinct id to send the event as'
|
51
62
|
c.option '--properties=<properties>', 'The properties to send (JSON-encoded)'
|
52
63
|
|
53
64
|
c.action do |args, options|
|
54
|
-
posthog =
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
65
|
+
posthog =
|
66
|
+
PostHog::Client.new(
|
67
|
+
{
|
68
|
+
api_key: options.api_key,
|
69
|
+
api_host: options.api_host,
|
70
|
+
on_error: Proc.new { |status, msg| print msg }
|
71
|
+
}
|
72
|
+
)
|
73
|
+
|
74
|
+
posthog.identify(
|
75
|
+
{
|
76
|
+
distinct_id: options.distinct_id,
|
77
|
+
properties: json_hash(options.properties)
|
78
|
+
}
|
79
|
+
)
|
64
80
|
|
65
81
|
posthog.flush
|
66
82
|
end
|
@@ -70,21 +86,23 @@ command :alias do |c|
|
|
70
86
|
c.description = 'set an alias for a distinct id'
|
71
87
|
|
72
88
|
c.option '--api-key=<api_key>', String, 'The PostHog API Key'
|
73
|
-
c.option '--api-host=<url>',
|
89
|
+
c.option '--api-host=<url>',
|
90
|
+
String,
|
91
|
+
'The PostHog API URL host part (scheme+domain)'
|
74
92
|
c.option '--distinct-id=<distinct_id>', String, 'The distinct id'
|
75
93
|
c.option '--alias=<alias>', 'The alias to give to the distinct id'
|
76
94
|
|
77
95
|
c.action do |args, options|
|
78
|
-
posthog =
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
})
|
96
|
+
posthog =
|
97
|
+
PostHog::Client.new(
|
98
|
+
{
|
99
|
+
api_key: options.api_key,
|
100
|
+
api_host: options.api_host,
|
101
|
+
on_error: Proc.new { |status, msg| print msg }
|
102
|
+
}
|
103
|
+
)
|
104
|
+
|
105
|
+
posthog.alias({ distinct_id: options.distinct_id, alias: options.alias })
|
88
106
|
|
89
107
|
posthog.flush
|
90
108
|
end
|
@@ -15,7 +15,8 @@ class PostHog
|
|
15
15
|
@min_timeout_ms = opts[:min_timeout_ms] || MIN_TIMEOUT_MS
|
16
16
|
@max_timeout_ms = opts[:max_timeout_ms] || MAX_TIMEOUT_MS
|
17
17
|
@multiplier = opts[:multiplier] || MULTIPLIER
|
18
|
-
@randomization_factor =
|
18
|
+
@randomization_factor =
|
19
|
+
opts[:randomization_factor] || RANDOMIZATION_FACTOR
|
19
20
|
|
20
21
|
@attempts = 0
|
21
22
|
end
|
@@ -37,11 +38,7 @@ class PostHog
|
|
37
38
|
max_deviation = base * randomization_factor
|
38
39
|
deviation = random_number * max_deviation
|
39
40
|
|
40
|
-
|
41
|
-
base - deviation
|
42
|
-
else
|
43
|
-
base + deviation
|
44
|
-
end
|
41
|
+
random_number < 0.5 ? base - deviation : base + deviation
|
45
42
|
end
|
46
43
|
end
|
47
44
|
end
|
data/lib/posthog/client.rb
CHANGED
@@ -5,6 +5,7 @@ require 'posthog/defaults'
|
|
5
5
|
require 'posthog/logging'
|
6
6
|
require 'posthog/utils'
|
7
7
|
require 'posthog/worker'
|
8
|
+
require 'posthog/feature_flags'
|
8
9
|
|
9
10
|
class PostHog
|
10
11
|
class Client
|
@@ -25,9 +26,22 @@ class PostHog
|
|
25
26
|
@worker_mutex = Mutex.new
|
26
27
|
@worker = Worker.new(@queue, @api_key, opts)
|
27
28
|
@worker_thread = nil
|
29
|
+
@feature_flags_poller = nil
|
30
|
+
@personal_api_key = nil
|
28
31
|
|
29
32
|
check_api_key!
|
30
33
|
|
34
|
+
if opts[:personal_api_key].present?
|
35
|
+
@personal_api_key = opts[:personal_api_key]
|
36
|
+
@feature_flags_poller =
|
37
|
+
FeatureFlagsPoller.new(
|
38
|
+
opts[:feature_flags_polling_interval],
|
39
|
+
opts[:personal_api_key],
|
40
|
+
@api_key,
|
41
|
+
opts[:host]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
31
45
|
at_exit { @worker_thread && @worker_thread[:should_exit] = true }
|
32
46
|
end
|
33
47
|
|
@@ -87,6 +101,47 @@ class PostHog
|
|
87
101
|
@queue.length
|
88
102
|
end
|
89
103
|
|
104
|
+
def is_feature_enabled(flag_key, distinct_id, default_value = false)
|
105
|
+
unless @personal_api_key
|
106
|
+
logger.error(
|
107
|
+
'You need to specify a personal_api_key to use feature flags'
|
108
|
+
)
|
109
|
+
return
|
110
|
+
end
|
111
|
+
is_enabled =
|
112
|
+
@feature_flags_poller.is_feature_enabled(
|
113
|
+
flag_key,
|
114
|
+
distinct_id,
|
115
|
+
default_value
|
116
|
+
)
|
117
|
+
capture(
|
118
|
+
{
|
119
|
+
'distinct_id': distinct_id,
|
120
|
+
'event': '$feature_flag_called',
|
121
|
+
'properties': {
|
122
|
+
'$feature_flag': flag_key,
|
123
|
+
'$feature_flag_response': is_enabled
|
124
|
+
}
|
125
|
+
}
|
126
|
+
)
|
127
|
+
return is_enabled
|
128
|
+
end
|
129
|
+
|
130
|
+
def reload_feature_flags
|
131
|
+
unless @personal_api_key
|
132
|
+
logger.error(
|
133
|
+
'You need to specify a personal_api_key to use feature flags'
|
134
|
+
)
|
135
|
+
return
|
136
|
+
end
|
137
|
+
@feature_flags_poller.load_feature_flags(true)
|
138
|
+
end
|
139
|
+
|
140
|
+
def shutdown
|
141
|
+
@feature_flags_poller.shutdown_poller
|
142
|
+
flush
|
143
|
+
end
|
144
|
+
|
90
145
|
private
|
91
146
|
|
92
147
|
# private: Enqueues the action.
|
@@ -104,8 +159,8 @@ class PostHog
|
|
104
159
|
else
|
105
160
|
logger.warn(
|
106
161
|
'Queue is full, dropping events. The :max_queue_size ' \
|
107
|
-
|
108
|
-
|
162
|
+
'configuration parameter can be increased to prevent this from ' \
|
163
|
+
'happening.'
|
109
164
|
)
|
110
165
|
false
|
111
166
|
end
|
@@ -120,9 +175,7 @@ class PostHog
|
|
120
175
|
return if worker_running?
|
121
176
|
@worker_mutex.synchronize do
|
122
177
|
return if worker_running?
|
123
|
-
@worker_thread = Thread.new
|
124
|
-
@worker.run
|
125
|
-
end
|
178
|
+
@worker_thread = Thread.new { @worker.run }
|
126
179
|
end
|
127
180
|
end
|
128
181
|
|
@@ -131,4 +184,3 @@ class PostHog
|
|
131
184
|
end
|
132
185
|
end
|
133
186
|
end
|
134
|
-
|
data/lib/posthog/defaults.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
class PostHog
|
2
2
|
module Defaults
|
3
3
|
module Request
|
4
|
-
HOST = '
|
4
|
+
HOST = 'app.posthog.com'
|
5
5
|
PORT = 443
|
6
6
|
PATH = '/batch/'
|
7
7
|
SSL = true
|
8
|
-
HEADERS = {
|
9
|
-
|
10
|
-
|
8
|
+
HEADERS = {
|
9
|
+
'Accept' => 'application/json',
|
10
|
+
'Content-Type' => 'application/json',
|
11
|
+
'User-Agent' => "posthog-ruby/#{PostHog::VERSION}"
|
12
|
+
}
|
11
13
|
RETRIES = 10
|
12
14
|
end
|
13
15
|
|
14
16
|
module Queue
|
15
|
-
MAX_SIZE =
|
17
|
+
MAX_SIZE = 10_000
|
16
18
|
end
|
17
19
|
|
18
20
|
module Message
|
19
|
-
MAX_BYTES =
|
21
|
+
MAX_BYTES = 32_768 # 32Kb
|
20
22
|
end
|
21
23
|
|
22
24
|
module MessageBatch
|
@@ -26,7 +28,7 @@ class PostHog
|
|
26
28
|
|
27
29
|
module BackoffPolicy
|
28
30
|
MIN_TIMEOUT_MS = 100
|
29
|
-
MAX_TIMEOUT_MS =
|
31
|
+
MAX_TIMEOUT_MS = 10_000
|
30
32
|
MULTIPLIER = 1.5
|
31
33
|
RANDOMIZATION_FACTOR = 0.5
|
32
34
|
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
require 'posthog/version'
|
5
|
+
require 'posthog/logging'
|
6
|
+
require 'digest'
|
7
|
+
class PostHog
|
8
|
+
class FeatureFlagsPoller
|
9
|
+
include PostHog::Logging
|
10
|
+
|
11
|
+
def initialize(polling_interval, personal_api_key, project_api_key, host)
|
12
|
+
@polling_interval = polling_interval || 60 * 5
|
13
|
+
@personal_api_key = personal_api_key
|
14
|
+
@project_api_key = project_api_key
|
15
|
+
@host = host || 'app.posthog.com'
|
16
|
+
@feature_flags = Concurrent::Array.new
|
17
|
+
@loaded_flags_successfully_once = Concurrent::AtomicBoolean.new
|
18
|
+
|
19
|
+
@task =
|
20
|
+
Concurrent::TimerTask.new(
|
21
|
+
execution_interval: polling_interval,
|
22
|
+
timeout_interval: 15
|
23
|
+
) { _load_feature_flags }
|
24
|
+
|
25
|
+
# load once before timer
|
26
|
+
load_feature_flags
|
27
|
+
@task.execute
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_feature_enabled(key, distinct_id, default_result = false)
|
31
|
+
# make sure they're loaded on first run
|
32
|
+
load_feature_flags
|
33
|
+
|
34
|
+
return default_result unless @loaded_flags_successfully_once
|
35
|
+
|
36
|
+
feature_flag = nil
|
37
|
+
|
38
|
+
|
39
|
+
@feature_flags.each do |flag|
|
40
|
+
if key == flag['key']
|
41
|
+
feature_flag = flag
|
42
|
+
break
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
return default_result if !feature_flag
|
47
|
+
|
48
|
+
flag_rollout_pctg =
|
49
|
+
if feature_flag['rollout_percentage']
|
50
|
+
feature_flag['rollout_percentage']
|
51
|
+
else
|
52
|
+
100
|
53
|
+
end
|
54
|
+
if feature_flag['is_simple_flag']
|
55
|
+
return is_simple_flag_enabled(key, distinct_id, flag_rollout_pctg)
|
56
|
+
else
|
57
|
+
data = { 'distinct_id' => distinct_id }
|
58
|
+
res = _request('POST', 'decide', false, data)
|
59
|
+
return res['featureFlags'].include? key
|
60
|
+
end
|
61
|
+
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_simple_flag_enabled(key, distinct_id, rollout_percentage)
|
66
|
+
hash = Digest::SHA1.hexdigest "#{key}.#{distinct_id}"
|
67
|
+
return(
|
68
|
+
(Integer(hash[0..14], 16).to_f / 0xfffffffffffffff) <=
|
69
|
+
(rollout_percentage / 100)
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def load_feature_flags(force_reload = false)
|
74
|
+
if @loaded_flags_successfully_once.false? || force_reload
|
75
|
+
_load_feature_flags
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def shutdown_poller()
|
80
|
+
@task.shutdown
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def _load_feature_flags()
|
86
|
+
res = _request('GET', 'api/feature_flag', true)
|
87
|
+
@feature_flags.clear
|
88
|
+
@feature_flags = res['results'].filter { |flag| flag['active'] }
|
89
|
+
if @loaded_flags_successfully_once.false?
|
90
|
+
@loaded_flags_successfully_once.make_true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def _request(method, endpoint, use_personal_api_key = false, data = {})
|
95
|
+
uri = URI("https://#{@host}/#{endpoint}/?token=#{@project_api_key}")
|
96
|
+
req = nil
|
97
|
+
if use_personal_api_key
|
98
|
+
req = Net::HTTP::Get.new(uri)
|
99
|
+
req['Authorization'] = "Bearer #{@personal_api_key}"
|
100
|
+
else
|
101
|
+
req = Net::HTTP::Post.new(uri)
|
102
|
+
req['Content-Type'] = 'application/json'
|
103
|
+
data['token'] = @project_api_key
|
104
|
+
req.body = data.to_json
|
105
|
+
end
|
106
|
+
|
107
|
+
req['User-Agent'] = "posthog-ruby#{PostHog::VERSION}"
|
108
|
+
|
109
|
+
begin
|
110
|
+
res_body = nil
|
111
|
+
res =
|
112
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
113
|
+
res = http.request(req)
|
114
|
+
res_body = JSON.parse(res.body)
|
115
|
+
return res_body
|
116
|
+
end
|
117
|
+
rescue Timeout::Error,
|
118
|
+
Errno::EINVAL,
|
119
|
+
Errno::ECONNRESET,
|
120
|
+
EOFError,
|
121
|
+
Net::HTTPBadResponse,
|
122
|
+
Net::HTTPHeaderSyntaxError,
|
123
|
+
Net::ProtocolError => e
|
124
|
+
logger.debug("Unable to complete request to #{uri}")
|
125
|
+
throw e
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/posthog/field_parser.rb
CHANGED
@@ -18,11 +18,13 @@ class PostHog
|
|
18
18
|
|
19
19
|
isoify_dates! properties
|
20
20
|
|
21
|
-
common.merge(
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
common.merge(
|
22
|
+
{
|
23
|
+
type: 'capture',
|
24
|
+
event: event.to_s,
|
25
|
+
properties: properties.merge(common[:properties] || {})
|
26
|
+
}
|
27
|
+
)
|
26
28
|
end
|
27
29
|
|
28
30
|
# In addition to the common fields, identify accepts:
|
@@ -36,11 +38,14 @@ class PostHog
|
|
36
38
|
|
37
39
|
isoify_dates! properties
|
38
40
|
|
39
|
-
common.merge(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
common.merge(
|
42
|
+
{
|
43
|
+
type: 'identify',
|
44
|
+
event: '$identify',
|
45
|
+
'$set': properties,
|
46
|
+
properties: properties.merge(common[:properties] || {})
|
47
|
+
}
|
48
|
+
)
|
44
49
|
end
|
45
50
|
|
46
51
|
# In addition to the common fields, alias accepts:
|
@@ -54,15 +59,17 @@ class PostHog
|
|
54
59
|
alias_field = fields[:alias]
|
55
60
|
check_presence! alias_field, 'alias'
|
56
61
|
|
57
|
-
common.merge(
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
:
|
63
|
-
|
62
|
+
common.merge(
|
63
|
+
{
|
64
|
+
type: 'alias',
|
65
|
+
event: '$create_alias',
|
66
|
+
distinct_id: nil,
|
67
|
+
properties:
|
68
|
+
{ distinct_id: distinct_id, alias: alias_field }.merge(
|
69
|
+
common[:properties] || {}
|
70
|
+
)
|
64
71
|
}
|
65
|
-
|
72
|
+
)
|
66
73
|
end
|
67
74
|
|
68
75
|
private
|
@@ -81,17 +88,23 @@ class PostHog
|
|
81
88
|
check_presence! distinct_id, 'distinct_id'
|
82
89
|
|
83
90
|
parsed = {
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
91
|
+
timestamp: datetime_in_iso8601(timestamp),
|
92
|
+
library: 'posthog-ruby',
|
93
|
+
library_version: PostHog::VERSION.to_s,
|
94
|
+
messageId: message_id,
|
95
|
+
distinct_id: distinct_id,
|
96
|
+
properties: {
|
97
|
+
'$lib' => 'posthog-ruby',
|
98
|
+
'$lib_version' => PostHog::VERSION.to_s
|
99
|
+
}
|
89
100
|
}
|
90
101
|
parsed
|
91
102
|
end
|
92
103
|
|
93
104
|
def check_timestamp!(timestamp)
|
94
|
-
|
105
|
+
unless timestamp.is_a? Time
|
106
|
+
raise ArgumentError, 'Timestamp must be a Time'
|
107
|
+
end
|
95
108
|
end
|
96
109
|
|
97
110
|
# private: Ensures that a string is non-empty
|
data/lib/posthog/logging.rb
CHANGED
@@ -30,13 +30,14 @@ class PostHog
|
|
30
30
|
def logger
|
31
31
|
return @logger if @logger
|
32
32
|
|
33
|
-
base_logger =
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
base_logger =
|
34
|
+
if defined?(Rails)
|
35
|
+
Rails.logger
|
36
|
+
else
|
37
|
+
logger = Logger.new STDOUT
|
38
|
+
logger.progname = 'PostHog'
|
39
|
+
logger
|
40
|
+
end
|
40
41
|
@logger = PrefixedLogger.new(base_logger, '[posthog-ruby]')
|
41
42
|
end
|
42
43
|
|
@@ -56,4 +57,3 @@ class PostHog
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
59
|
-
|
data/lib/posthog/response.rb
CHANGED
data/lib/posthog/transport.rb
CHANGED
@@ -26,8 +26,7 @@ class PostHog
|
|
26
26
|
@headers = options[:headers] || HEADERS
|
27
27
|
@path = options[:path] || PATH
|
28
28
|
@retries = options[:retries] || RETRIES
|
29
|
-
@backoff_policy =
|
30
|
-
options[:backoff_policy] || PostHog::BackoffPolicy.new
|
29
|
+
@backoff_policy = options[:backoff_policy] || PostHog::BackoffPolicy.new
|
31
30
|
|
32
31
|
http = Net::HTTP.new(options[:host], options[:port])
|
33
32
|
http.use_ssl = options[:ssl]
|
@@ -43,15 +42,16 @@ class PostHog
|
|
43
42
|
def send(api_key, batch)
|
44
43
|
logger.debug("Sending request for #{batch.length} items")
|
45
44
|
|
46
|
-
last_response, exception =
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
last_response, exception =
|
46
|
+
retry_with_backoff(@retries) do
|
47
|
+
status_code, body = send_request(api_key, batch)
|
48
|
+
error = JSON.parse(body)['error']
|
49
|
+
should_retry = should_retry_request?(status_code, body)
|
50
|
+
logger.debug("Response status code: #{status_code}")
|
51
|
+
logger.debug("Response error: #{error}") if error
|
52
52
|
|
53
|
-
|
54
|
-
|
53
|
+
[Response.new(status_code, error), should_retry]
|
54
|
+
end
|
55
55
|
|
56
56
|
if exception
|
57
57
|
logger.error(exception.message)
|
@@ -95,7 +95,7 @@ class PostHog
|
|
95
95
|
|
96
96
|
begin
|
97
97
|
result, should_retry = yield
|
98
|
-
return
|
98
|
+
return result, nil unless should_retry
|
99
99
|
rescue StandardError => e
|
100
100
|
should_retry = true
|
101
101
|
caught_exception = e
|
@@ -112,16 +112,13 @@ class PostHog
|
|
112
112
|
|
113
113
|
# Sends a request for the batch, returns [status_code, body]
|
114
114
|
def send_request(api_key, batch)
|
115
|
-
payload = JSON.generate(
|
116
|
-
api_key: api_key,
|
117
|
-
batch: batch
|
118
|
-
)
|
115
|
+
payload = JSON.generate(api_key: api_key, batch: batch)
|
119
116
|
|
120
117
|
request = Net::HTTP::Post.new(@path, @headers)
|
121
118
|
|
122
119
|
if self.class.stub
|
123
120
|
logger.debug "stubbed request to #{@path}: " \
|
124
|
-
|
121
|
+
"api key = #{api_key}, batch = #{JSON.generate(batch)}"
|
125
122
|
|
126
123
|
[200, '{}']
|
127
124
|
else
|
@@ -140,4 +137,3 @@ class PostHog
|
|
140
137
|
end
|
141
138
|
end
|
142
139
|
end
|
143
|
-
|
data/lib/posthog/utils.rb
CHANGED
@@ -7,9 +7,7 @@ class PostHog
|
|
7
7
|
# public: Return a new hash with keys converted from strings to symbols
|
8
8
|
#
|
9
9
|
def symbolize_keys(hash)
|
10
|
-
hash.each_with_object({})
|
11
|
-
memo[k.to_sym] = v
|
12
|
-
end
|
10
|
+
hash.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v }
|
13
11
|
end
|
14
12
|
|
15
13
|
# public: Convert hash keys from strings to symbols in place
|
@@ -21,9 +19,7 @@ class PostHog
|
|
21
19
|
# public: Return a new hash with keys as strings
|
22
20
|
#
|
23
21
|
def stringify_keys(hash)
|
24
|
-
hash.each_with_object({})
|
25
|
-
memo[k.to_s] = v
|
26
|
-
end
|
22
|
+
hash.each_with_object({}) { |(k, v), memo| memo[k.to_s] = v }
|
27
23
|
end
|
28
24
|
|
29
25
|
# public: Returns a new hash with all the date values in the into iso8601
|
@@ -64,9 +60,8 @@ class PostHog
|
|
64
60
|
end
|
65
61
|
|
66
62
|
def time_in_iso8601(time, fraction_digits = 3)
|
67
|
-
fraction =
|
68
|
-
|
69
|
-
end
|
63
|
+
fraction =
|
64
|
+
(('.%06i' % time.usec)[0, fraction_digits + 1] if fraction_digits > 0)
|
70
65
|
|
71
66
|
"#{time.strftime('%Y-%m-%dT%H:%M:%S')}#{fraction}#{formatted_offset(time, true, 'Z')}"
|
72
67
|
end
|
@@ -76,15 +71,19 @@ class PostHog
|
|
76
71
|
end
|
77
72
|
|
78
73
|
def formatted_offset(time, colon = true, alternate_utc_string = nil)
|
79
|
-
time.utc? && alternate_utc_string ||
|
74
|
+
time.utc? && alternate_utc_string ||
|
75
|
+
seconds_to_utc_offset(time.utc_offset, colon)
|
80
76
|
end
|
81
77
|
|
82
78
|
def seconds_to_utc_offset(seconds, colon = true)
|
83
|
-
(colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON) % [
|
79
|
+
(colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON) % [
|
80
|
+
(seconds < 0 ? '-' : '+'),
|
81
|
+
(seconds.abs / 3600),
|
82
|
+
((seconds.abs % 3600) / 60)
|
83
|
+
]
|
84
84
|
end
|
85
85
|
|
86
86
|
UTC_OFFSET_WITH_COLON = '%s%02d:%02d'
|
87
87
|
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
data/lib/posthog/version.rb
CHANGED
data/lib/posthog/worker.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: posthog-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ''
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: commander
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,6 +149,7 @@ files:
|
|
135
149
|
- lib/posthog/backoff_policy.rb
|
136
150
|
- lib/posthog/client.rb
|
137
151
|
- lib/posthog/defaults.rb
|
152
|
+
- lib/posthog/feature_flags.rb
|
138
153
|
- lib/posthog/field_parser.rb
|
139
154
|
- lib/posthog/logging.rb
|
140
155
|
- lib/posthog/message_batch.rb
|
@@ -158,12 +173,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
158
173
|
version: '2.0'
|
159
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
175
|
requirements:
|
161
|
-
- - "
|
176
|
+
- - ">="
|
162
177
|
- !ruby/object:Gem::Version
|
163
|
-
version:
|
178
|
+
version: '0'
|
164
179
|
requirements: []
|
165
|
-
|
166
|
-
rubygems_version: 2.5.2.3
|
180
|
+
rubygems_version: 3.0.3
|
167
181
|
signing_key:
|
168
182
|
specification_version: 4
|
169
183
|
summary: PostHog library
|