posthog-rails 3.5.0 → 3.5.2
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/generators/posthog/install_generator.rb +31 -0
- data/lib/posthog/rails/active_job.rb +106 -0
- data/lib/posthog/rails/capture_exceptions.rb +131 -0
- data/lib/posthog/rails/configuration.rb +69 -0
- data/lib/posthog/rails/error_subscriber.rb +43 -0
- data/lib/posthog/rails/parameter_filter.rb +128 -0
- data/lib/posthog/rails/railtie.rb +186 -0
- data/lib/posthog/rails/rescued_exception_interceptor.rb +28 -0
- data/lib/posthog/rails.rb +46 -0
- data/lib/posthog-rails.rb +11 -0
- metadata +13 -25
- data/lib/posthog/backoff_policy.rb +0 -46
- data/lib/posthog/client.rb +0 -545
- data/lib/posthog/defaults.rb +0 -44
- data/lib/posthog/exception_capture.rb +0 -116
- data/lib/posthog/feature_flag.rb +0 -66
- data/lib/posthog/feature_flag_error.rb +0 -36
- data/lib/posthog/feature_flag_result.rb +0 -56
- data/lib/posthog/feature_flags.rb +0 -1004
- data/lib/posthog/field_parser.rb +0 -194
- data/lib/posthog/logging.rb +0 -70
- data/lib/posthog/message_batch.rb +0 -73
- data/lib/posthog/noop_worker.rb +0 -19
- data/lib/posthog/response.rb +0 -15
- data/lib/posthog/send_feature_flags_options.rb +0 -34
- data/lib/posthog/send_worker.rb +0 -70
- data/lib/posthog/transport.rb +0 -144
- data/lib/posthog/utils.rb +0 -145
- data/lib/posthog/version.rb +0 -5
- data/lib/posthog.rb +0 -14
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PostHog
|
|
4
|
+
module Rails
|
|
5
|
+
class Railtie < ::Rails::Railtie
|
|
6
|
+
# Add PostHog module methods for accessing Rails-specific client
|
|
7
|
+
initializer 'posthog.set_configs' do |_app|
|
|
8
|
+
PostHog.class_eval do
|
|
9
|
+
class << self
|
|
10
|
+
attr_accessor :client
|
|
11
|
+
|
|
12
|
+
# Methods explicitly delegated to the client
|
|
13
|
+
DELEGATED_METHODS = %i[
|
|
14
|
+
capture
|
|
15
|
+
capture_exception
|
|
16
|
+
identify
|
|
17
|
+
alias
|
|
18
|
+
group_identify
|
|
19
|
+
is_feature_enabled
|
|
20
|
+
get_feature_flag
|
|
21
|
+
get_all_flags
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
# Initialize PostHog client with a block configuration
|
|
25
|
+
def init(options = {})
|
|
26
|
+
# If block given, yield to configuration
|
|
27
|
+
if block_given?
|
|
28
|
+
config = PostHog::Rails::InitConfig.new(options)
|
|
29
|
+
yield config
|
|
30
|
+
options = config.to_client_options
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Create the PostHog client
|
|
34
|
+
@client = PostHog::Client.new(options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Define delegated methods using metaprogramming
|
|
38
|
+
DELEGATED_METHODS.each do |method_name|
|
|
39
|
+
define_method(method_name) do |*args, **kwargs, &block|
|
|
40
|
+
ensure_initialized!
|
|
41
|
+
client.public_send(method_name, *args, **kwargs, &block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialized?
|
|
46
|
+
!@client.nil?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Fallback for any client methods not explicitly defined
|
|
50
|
+
# rubocop:disable Lint/RedundantSafeNavigation
|
|
51
|
+
def method_missing(method_name, ...)
|
|
52
|
+
if client&.respond_to?(method_name)
|
|
53
|
+
ensure_initialized!
|
|
54
|
+
client.public_send(method_name, ...)
|
|
55
|
+
else
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
61
|
+
client&.respond_to?(method_name) || super
|
|
62
|
+
end
|
|
63
|
+
# rubocop:enable Lint/RedundantSafeNavigation
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def ensure_initialized!
|
|
68
|
+
return if initialized?
|
|
69
|
+
|
|
70
|
+
raise 'PostHog is not initialized. Call PostHog.init in an initializer.'
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Insert middleware for exception capturing
|
|
77
|
+
initializer 'posthog.insert_middlewares' do |app|
|
|
78
|
+
# Insert after DebugExceptions to catch rescued exceptions
|
|
79
|
+
insert_middleware_after(
|
|
80
|
+
app, ActionDispatch::DebugExceptions,
|
|
81
|
+
PostHog::Rails::RescuedExceptionInterceptor
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Insert after ShowExceptions to capture all exceptions
|
|
85
|
+
insert_middleware_after(
|
|
86
|
+
app, ActionDispatch::ShowExceptions,
|
|
87
|
+
PostHog::Rails::CaptureExceptions
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# After initialization, set up remaining integrations
|
|
92
|
+
config.after_initialize do |_app|
|
|
93
|
+
# Hook into ActiveJob only if enabled
|
|
94
|
+
if PostHog::Rails.config&.auto_instrument_active_job
|
|
95
|
+
ActiveSupport.on_load(:active_job) do
|
|
96
|
+
prepend PostHog::Rails::ActiveJobExtensions
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
next unless PostHog.initialized?
|
|
101
|
+
|
|
102
|
+
# Register with Rails error reporter (Rails 7.0+)
|
|
103
|
+
register_error_subscriber if rails_version_above_7?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Ensure PostHog shuts down gracefully (register only once)
|
|
107
|
+
config.after_initialize do
|
|
108
|
+
next if @posthog_at_exit_registered
|
|
109
|
+
|
|
110
|
+
@posthog_at_exit_registered = true
|
|
111
|
+
at_exit { PostHog.client&.shutdown if PostHog.initialized? }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.insert_middleware_after(app, target, middleware)
|
|
115
|
+
if app.config.middleware.include?(target)
|
|
116
|
+
app.config.middleware.insert_after(target, middleware)
|
|
117
|
+
else
|
|
118
|
+
# Fallback: append to stack if target middleware is missing (e.g., API-only apps)
|
|
119
|
+
app.config.middleware.use(middleware)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def self.register_error_subscriber
|
|
124
|
+
return unless PostHog::Rails.config&.auto_capture_exceptions
|
|
125
|
+
|
|
126
|
+
subscriber = PostHog::Rails::ErrorSubscriber.new
|
|
127
|
+
::Rails.error.subscribe(subscriber)
|
|
128
|
+
rescue StandardError => e
|
|
129
|
+
PostHog::Logging.logger.warn("Failed to register error subscriber: #{e.message}")
|
|
130
|
+
PostHog::Logging.logger.warn("Backtrace: #{e.backtrace&.first(5)&.join("\n")}")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.rails_version_above_7?
|
|
134
|
+
::Rails.version.to_f >= 7.0
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Configuration wrapper for the init block
|
|
139
|
+
class InitConfig
|
|
140
|
+
def initialize(base_options = {})
|
|
141
|
+
@base_options = base_options
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Core PostHog options
|
|
145
|
+
def api_key=(value)
|
|
146
|
+
@base_options[:api_key] = value
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def personal_api_key=(value)
|
|
150
|
+
@base_options[:personal_api_key] = value
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def host=(value)
|
|
154
|
+
@base_options[:host] = value
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def max_queue_size=(value)
|
|
158
|
+
@base_options[:max_queue_size] = value
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def test_mode=(value)
|
|
162
|
+
@base_options[:test_mode] = value
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def on_error=(value)
|
|
166
|
+
@base_options[:on_error] = value
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def feature_flags_polling_interval=(value)
|
|
170
|
+
@base_options[:feature_flags_polling_interval] = value
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def feature_flag_request_timeout_seconds=(value)
|
|
174
|
+
@base_options[:feature_flag_request_timeout_seconds] = value
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def before_send=(value)
|
|
178
|
+
@base_options[:before_send] = value
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def to_client_options
|
|
182
|
+
@base_options
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PostHog
|
|
4
|
+
module Rails
|
|
5
|
+
# Middleware that intercepts exceptions that are rescued by Rails
|
|
6
|
+
# This middleware runs before ShowExceptions and captures the exception
|
|
7
|
+
# so we can report it even if Rails rescues it
|
|
8
|
+
class RescuedExceptionInterceptor
|
|
9
|
+
def initialize(app)
|
|
10
|
+
@app = app
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(env)
|
|
14
|
+
@app.call(env)
|
|
15
|
+
rescue StandardError => e
|
|
16
|
+
# Store the exception so CaptureExceptions middleware can report it
|
|
17
|
+
env['posthog.rescued_exception'] = e if should_intercept?
|
|
18
|
+
raise e
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def should_intercept?
|
|
24
|
+
PostHog::Rails.config&.report_rescued_exceptions
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'posthog/rails/configuration'
|
|
4
|
+
require 'posthog/rails/capture_exceptions'
|
|
5
|
+
require 'posthog/rails/rescued_exception_interceptor'
|
|
6
|
+
require 'posthog/rails/active_job'
|
|
7
|
+
require 'posthog/rails/error_subscriber'
|
|
8
|
+
require 'posthog/rails/railtie'
|
|
9
|
+
|
|
10
|
+
module PostHog
|
|
11
|
+
module Rails
|
|
12
|
+
VERSION = PostHog::VERSION
|
|
13
|
+
|
|
14
|
+
# Thread-local key for tracking web request context
|
|
15
|
+
IN_WEB_REQUEST_KEY = :posthog_in_web_request
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def config
|
|
19
|
+
@config ||= Configuration.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_writer :config
|
|
23
|
+
|
|
24
|
+
def configure
|
|
25
|
+
yield config if block_given?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Mark that we're in a web request context
|
|
29
|
+
# CaptureExceptions middleware will handle exception capture
|
|
30
|
+
def enter_web_request
|
|
31
|
+
Thread.current[IN_WEB_REQUEST_KEY] = true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Clear web request context (called at end of request)
|
|
35
|
+
def exit_web_request
|
|
36
|
+
Thread.current[IN_WEB_REQUEST_KEY] = false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Check if we're currently in a web request context
|
|
40
|
+
# Used by ErrorSubscriber to avoid duplicate captures
|
|
41
|
+
def in_web_request?
|
|
42
|
+
Thread.current[IN_WEB_REQUEST_KEY] == true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
unless defined?(Rails)
|
|
4
|
+
raise LoadError, 'posthog-rails requires Rails. Use the posthog-ruby gem directly for non-Rails applications.'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Load core PostHog Ruby SDK
|
|
8
|
+
require 'posthog'
|
|
9
|
+
|
|
10
|
+
# Load Rails integration
|
|
11
|
+
require 'posthog/rails'
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: posthog-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.5.
|
|
4
|
+
version: 3.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- PostHog
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: railties
|
|
@@ -45,31 +44,21 @@ executables: []
|
|
|
45
44
|
extensions: []
|
|
46
45
|
extra_rdoc_files: []
|
|
47
46
|
files:
|
|
48
|
-
- lib/posthog.rb
|
|
49
|
-
- lib/posthog
|
|
50
|
-
- lib/posthog/
|
|
51
|
-
- lib/posthog/
|
|
52
|
-
- lib/posthog/
|
|
53
|
-
- lib/posthog/
|
|
54
|
-
- lib/posthog/
|
|
55
|
-
- lib/posthog/
|
|
56
|
-
- lib/posthog/
|
|
57
|
-
- lib/posthog/
|
|
58
|
-
- lib/posthog/logging.rb
|
|
59
|
-
- lib/posthog/message_batch.rb
|
|
60
|
-
- lib/posthog/noop_worker.rb
|
|
61
|
-
- lib/posthog/response.rb
|
|
62
|
-
- lib/posthog/send_feature_flags_options.rb
|
|
63
|
-
- lib/posthog/send_worker.rb
|
|
64
|
-
- lib/posthog/transport.rb
|
|
65
|
-
- lib/posthog/utils.rb
|
|
66
|
-
- lib/posthog/version.rb
|
|
47
|
+
- lib/generators/posthog/install_generator.rb
|
|
48
|
+
- lib/posthog-rails.rb
|
|
49
|
+
- lib/posthog/rails.rb
|
|
50
|
+
- lib/posthog/rails/active_job.rb
|
|
51
|
+
- lib/posthog/rails/capture_exceptions.rb
|
|
52
|
+
- lib/posthog/rails/configuration.rb
|
|
53
|
+
- lib/posthog/rails/error_subscriber.rb
|
|
54
|
+
- lib/posthog/rails/parameter_filter.rb
|
|
55
|
+
- lib/posthog/rails/railtie.rb
|
|
56
|
+
- lib/posthog/rails/rescued_exception_interceptor.rb
|
|
67
57
|
homepage: https://github.com/PostHog/posthog-ruby
|
|
68
58
|
licenses:
|
|
69
59
|
- MIT
|
|
70
60
|
metadata:
|
|
71
61
|
rubygems_mfa_required: 'true'
|
|
72
|
-
post_install_message:
|
|
73
62
|
rdoc_options: []
|
|
74
63
|
require_paths:
|
|
75
64
|
- lib
|
|
@@ -84,8 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
73
|
- !ruby/object:Gem::Version
|
|
85
74
|
version: '0'
|
|
86
75
|
requirements: []
|
|
87
|
-
rubygems_version:
|
|
88
|
-
signing_key:
|
|
76
|
+
rubygems_version: 4.0.3
|
|
89
77
|
specification_version: 4
|
|
90
78
|
summary: PostHog integration for Rails
|
|
91
79
|
test_files: []
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'posthog/defaults'
|
|
4
|
-
|
|
5
|
-
module PostHog
|
|
6
|
-
class BackoffPolicy
|
|
7
|
-
include PostHog::Defaults::BackoffPolicy
|
|
8
|
-
|
|
9
|
-
# @param [Hash] opts
|
|
10
|
-
# @option opts [Numeric] :min_timeout_ms The minimum backoff timeout
|
|
11
|
-
# @option opts [Numeric] :max_timeout_ms The maximum backoff timeout
|
|
12
|
-
# @option opts [Numeric] :multiplier The value to multiply the current
|
|
13
|
-
# interval with for each retry attempt
|
|
14
|
-
# @option opts [Numeric] :randomization_factor The randomization factor
|
|
15
|
-
# to use to create a range around the retry interval
|
|
16
|
-
def initialize(opts = {})
|
|
17
|
-
@min_timeout_ms = opts[:min_timeout_ms] || MIN_TIMEOUT_MS
|
|
18
|
-
@max_timeout_ms = opts[:max_timeout_ms] || MAX_TIMEOUT_MS
|
|
19
|
-
@multiplier = opts[:multiplier] || MULTIPLIER
|
|
20
|
-
@randomization_factor =
|
|
21
|
-
opts[:randomization_factor] || RANDOMIZATION_FACTOR
|
|
22
|
-
|
|
23
|
-
@attempts = 0
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# @return [Numeric] the next backoff interval, in milliseconds.
|
|
27
|
-
def next_interval
|
|
28
|
-
interval = @min_timeout_ms * (@multiplier**@attempts)
|
|
29
|
-
interval = add_jitter(interval, @randomization_factor)
|
|
30
|
-
|
|
31
|
-
@attempts += 1
|
|
32
|
-
|
|
33
|
-
[interval, @max_timeout_ms].min
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def add_jitter(base, randomization_factor)
|
|
39
|
-
random_number = rand
|
|
40
|
-
max_deviation = base * randomization_factor
|
|
41
|
-
deviation = random_number * max_deviation
|
|
42
|
-
|
|
43
|
-
random_number < 0.5 ? base - deviation : base + deviation
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|