splitclient-rb 4.5.1-java
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 +7 -0
- data/.gitignore +45 -0
- data/CHANGES.txt +147 -0
- data/Detailed-README.md +571 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/NEWS +75 -0
- data/README.md +43 -0
- data/Rakefile +24 -0
- data/exe/splitio +96 -0
- data/ext/murmurhash/MurmurHash3.java +162 -0
- data/lib/murmurhash/base.rb +58 -0
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/murmurhash/murmurhash_mri.rb +3 -0
- data/lib/splitclient-rb.rb +90 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +133 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +44 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +165 -0
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +30 -0
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +29 -0
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +41 -0
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +78 -0
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +21 -0
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +129 -0
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +98 -0
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +22 -0
- data/lib/splitclient-rb/cache/repositories/repository.rb +23 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +82 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +106 -0
- data/lib/splitclient-rb/cache/routers/impression_router.rb +52 -0
- data/lib/splitclient-rb/cache/senders/events_sender.rb +47 -0
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +73 -0
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +67 -0
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +49 -0
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +48 -0
- data/lib/splitclient-rb/cache/stores/segment_store.rb +82 -0
- data/lib/splitclient-rb/cache/stores/split_store.rb +97 -0
- data/lib/splitclient-rb/clients/localhost_split_client.rb +92 -0
- data/lib/splitclient-rb/clients/split_client.rb +214 -0
- data/lib/splitclient-rb/engine/api/client.rb +74 -0
- data/lib/splitclient-rb/engine/api/events.rb +48 -0
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +55 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +42 -0
- data/lib/splitclient-rb/engine/api/metrics.rb +61 -0
- data/lib/splitclient-rb/engine/api/segments.rb +62 -0
- data/lib/splitclient-rb/engine/api/splits.rb +60 -0
- data/lib/splitclient-rb/engine/evaluator/splitter.rb +123 -0
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +46 -0
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +56 -0
- data/lib/splitclient-rb/engine/matchers/combiners.rb +9 -0
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +86 -0
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +21 -0
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +19 -0
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +30 -0
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +27 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +54 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +19 -0
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +53 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +53 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +24 -0
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +60 -0
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +23 -0
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +45 -0
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +128 -0
- data/lib/splitclient-rb/engine/metrics/metrics.rb +83 -0
- data/lib/splitclient-rb/engine/models/label.rb +8 -0
- data/lib/splitclient-rb/engine/models/split.rb +17 -0
- data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +210 -0
- data/lib/splitclient-rb/engine/parser/evaluator.rb +118 -0
- data/lib/splitclient-rb/engine/parser/partition.rb +35 -0
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +88 -0
- data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +4 -0
- data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +4 -0
- data/lib/splitclient-rb/localhost_split_factory.rb +13 -0
- data/lib/splitclient-rb/localhost_utils.rb +36 -0
- data/lib/splitclient-rb/managers/localhost_split_manager.rb +45 -0
- data/lib/splitclient-rb/managers/split_manager.rb +77 -0
- data/lib/splitclient-rb/split_config.rb +391 -0
- data/lib/splitclient-rb/split_factory.rb +35 -0
- data/lib/splitclient-rb/split_factory_builder.rb +16 -0
- data/lib/splitclient-rb/utilitites.rb +41 -0
- data/lib/splitclient-rb/version.rb +3 -0
- data/splitclient-rb.gemspec +50 -0
- data/splitio.yml.example +7 -0
- data/tasks/benchmark_get_treatment.rake +43 -0
- data/tasks/irb.rake +4 -0
- data/tasks/rspec.rake +3 -0
- metadata +321 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'thread'
|
|
3
|
+
|
|
4
|
+
include SplitIoClient::Cache::Stores
|
|
5
|
+
include SplitIoClient::Cache::Senders
|
|
6
|
+
|
|
7
|
+
module SplitIoClient
|
|
8
|
+
#
|
|
9
|
+
# acts as an api adapater to connect to split endpoints
|
|
10
|
+
# uses a configuration object that can be modified when creating the client instance
|
|
11
|
+
# also, uses safe threads to execute fetches and post give the time execution values from the config
|
|
12
|
+
#
|
|
13
|
+
class SplitAdapter < NoMethodError
|
|
14
|
+
attr_reader :splits_repository, :segments_repository, :impressions_repository, :metrics
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# Creates a new split api adapter instance that consumes split api endpoints
|
|
18
|
+
#
|
|
19
|
+
# @param api_key [String] the API key for your split account
|
|
20
|
+
# @param config [SplitConfig] SplitConfig instance
|
|
21
|
+
# @param splits_repository [SplitsRepository] SplitsRepository instance to store splits in
|
|
22
|
+
# @param segments_repository [SegmentsRepository] SegmentsRepository instance to store segments in
|
|
23
|
+
# @param impressions_repository [ImpressionsRepository] ImpressionsRepository instance to store impressions in
|
|
24
|
+
# @param metrics_repository [MetricsRepository] SplitsRepository instance to store metrics in
|
|
25
|
+
# @param sdk_blocker [SDKBlocker] SDKBlocker instance which blocks splits_repository/segments_repository
|
|
26
|
+
#
|
|
27
|
+
# @return [SplitIoClient] split.io client instance
|
|
28
|
+
def initialize(api_key, config, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker)
|
|
29
|
+
@api_key = api_key
|
|
30
|
+
@config = config
|
|
31
|
+
@splits_repository = splits_repository
|
|
32
|
+
@segments_repository = segments_repository
|
|
33
|
+
@impressions_repository = impressions_repository
|
|
34
|
+
@metrics_repository = metrics_repository
|
|
35
|
+
@events_repository = events_repository
|
|
36
|
+
@metrics = Metrics.new(100, @config, @metrics_repository)
|
|
37
|
+
@sdk_blocker = sdk_blocker
|
|
38
|
+
|
|
39
|
+
start_based_on_mode(@config.mode)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def start_based_on_mode(mode)
|
|
43
|
+
case mode
|
|
44
|
+
when :standalone
|
|
45
|
+
split_store
|
|
46
|
+
segment_store
|
|
47
|
+
metrics_sender
|
|
48
|
+
impressions_sender
|
|
49
|
+
events_sender
|
|
50
|
+
when :consumer
|
|
51
|
+
# Do nothing in background
|
|
52
|
+
when :producer
|
|
53
|
+
split_store
|
|
54
|
+
segment_store
|
|
55
|
+
impressions_sender
|
|
56
|
+
metrics_sender
|
|
57
|
+
events_sender
|
|
58
|
+
|
|
59
|
+
sleep unless ENV['SPLITCLIENT_ENV'] == 'test'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Starts thread which loops constantly and stores splits in the splits_repository of choice
|
|
64
|
+
def split_store
|
|
65
|
+
SplitStore.new(@splits_repository, @config, @api_key, @metrics, @sdk_blocker).call
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Starts thread which loops constantly and stores segments in the segments_repository of choice
|
|
69
|
+
def segment_store
|
|
70
|
+
SegmentStore.new(@segments_repository, @config, @api_key, @metrics, @sdk_blocker).call
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Starts thread which loops constantly and sends impressions to the Split API
|
|
74
|
+
def impressions_sender
|
|
75
|
+
ImpressionsSender.new(@impressions_repository, @config, @api_key).call
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Starts thread which loops constantly and sends metrics to the Split API
|
|
79
|
+
def metrics_sender
|
|
80
|
+
MetricsSender.new(@metrics_repository, @config, @api_key).call
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Starts thread which loops constantly and sends events to the Split API
|
|
84
|
+
def events_sender
|
|
85
|
+
EventsSender.new(@events_repository, @config, @api_key).call
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
class LocalhostSplitFactory
|
|
3
|
+
attr_reader :client, :manager
|
|
4
|
+
|
|
5
|
+
def initialize(splits_file, reload_rate = nil)
|
|
6
|
+
@splits_file = splits_file
|
|
7
|
+
@reload_rate = reload_rate
|
|
8
|
+
|
|
9
|
+
@client = LocalhostSplitClient.new(@splits_file, @reload_rate)
|
|
10
|
+
@manager = LocalhostSplitManager.new(@splits_file, @reload_rate)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
module LocalhostUtils
|
|
3
|
+
#
|
|
4
|
+
# method to set localhost mode features by reading the given .splits
|
|
5
|
+
#
|
|
6
|
+
# @param splits_file [File] the .split file that contains the splits
|
|
7
|
+
# @param reload_rate [Integer] the number of seconds to reload splits_file
|
|
8
|
+
# @return nil
|
|
9
|
+
def load_localhost_mode_features(splits_file, reload_rate = nil)
|
|
10
|
+
return @localhost_mode_features unless File.exists?(splits_file)
|
|
11
|
+
|
|
12
|
+
store_features(splits_file)
|
|
13
|
+
|
|
14
|
+
return unless reload_rate
|
|
15
|
+
|
|
16
|
+
Thread.new do
|
|
17
|
+
loop do
|
|
18
|
+
@localhost_mode_features = []
|
|
19
|
+
store_features(splits_file)
|
|
20
|
+
|
|
21
|
+
sleep(SplitIoClient::Utilities.randomize_interval(reload_rate))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def store_features(splits_file)
|
|
27
|
+
File.open(splits_file).each do |line|
|
|
28
|
+
feature, treatment = line.strip.split(' ')
|
|
29
|
+
|
|
30
|
+
next if line.start_with?('#') || line.strip.empty?
|
|
31
|
+
|
|
32
|
+
@localhost_mode_features << { feature: feature, treatment: treatment }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
class LocalhostSplitManager
|
|
3
|
+
include SplitIoClient::LocalhostUtils
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Creates a new split manager instance that holds the splits from a given file
|
|
7
|
+
#
|
|
8
|
+
# @param splits_file [File] the .split file that contains the splits
|
|
9
|
+
# @param reload_rate [Integer] the number of seconds to reload splits_file
|
|
10
|
+
#
|
|
11
|
+
# @return [LocalhostSplitIoManager] split.io localhost manager instance
|
|
12
|
+
def initialize(splits_file, reload_rate = nil)
|
|
13
|
+
@localhost_mode = true
|
|
14
|
+
@localhost_mode_features = []
|
|
15
|
+
|
|
16
|
+
load_localhost_mode_features(splits_file, reload_rate)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
# method to get a split view
|
|
21
|
+
#
|
|
22
|
+
# @returns a split view
|
|
23
|
+
def split(split_name)
|
|
24
|
+
@localhost_mode_features.find { |x| x[:feature] == split_name }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# method to get the split list from the client
|
|
29
|
+
#
|
|
30
|
+
# @returns [object] array of splits
|
|
31
|
+
def splits
|
|
32
|
+
@localhost_mode_features
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# method to get the list of just split names. Ideal for ietrating and calling client.get_treatment
|
|
37
|
+
#
|
|
38
|
+
# @returns [object] array of split names (String)
|
|
39
|
+
def split_names
|
|
40
|
+
@localhost_mode_features.each_with_object([]) do |split, memo|
|
|
41
|
+
memo << split[:feature]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
class SplitManager
|
|
3
|
+
#
|
|
4
|
+
# Creates a new split manager instance that connects to split.io API.
|
|
5
|
+
#
|
|
6
|
+
# @param api_key [String] the API key for your split account
|
|
7
|
+
#
|
|
8
|
+
# @return [SplitIoManager] split.io client instance
|
|
9
|
+
def initialize(api_key, config = {}, adapter = nil, splits_repository = nil)
|
|
10
|
+
@localhost_mode_features = []
|
|
11
|
+
@config = config
|
|
12
|
+
@splits_repository = splits_repository
|
|
13
|
+
@adapter = adapter
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# method to get the split list from the client
|
|
18
|
+
#
|
|
19
|
+
# @returns [object] array of splits
|
|
20
|
+
def splits
|
|
21
|
+
return if @splits_repository.nil?
|
|
22
|
+
|
|
23
|
+
@splits_repository.splits.each_with_object([]) do |(name, split), memo|
|
|
24
|
+
split_view = build_split_view(name, split)
|
|
25
|
+
|
|
26
|
+
next if split_view[:name] == nil
|
|
27
|
+
|
|
28
|
+
memo << split_view unless Engine::Models::Split.archived?(split)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# method to get the list of just split names. Ideal for ietrating and calling client.get_treatment
|
|
34
|
+
#
|
|
35
|
+
# @returns [object] array of split names (String)
|
|
36
|
+
def split_names
|
|
37
|
+
return if @splits_repository.nil?
|
|
38
|
+
|
|
39
|
+
@splits_repository.split_names
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# method to get a split view
|
|
44
|
+
#
|
|
45
|
+
# @returns a split view
|
|
46
|
+
def split(split_name)
|
|
47
|
+
return unless @splits_repository
|
|
48
|
+
|
|
49
|
+
split = @splits_repository.get_split(split_name)
|
|
50
|
+
|
|
51
|
+
return if split.nil? || Engine::Models::Split.archived?(split)
|
|
52
|
+
|
|
53
|
+
build_split_view(split_name, split)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def build_split_view(name, split)
|
|
57
|
+
return {} unless split
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
treatments = split[:conditions]
|
|
61
|
+
.detect { |c| c[:conditionType] == 'ROLLOUT' }[:partitions]
|
|
62
|
+
.map { |partition| partition[:treatment] }
|
|
63
|
+
rescue StandardError
|
|
64
|
+
treatments = []
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
name: name,
|
|
70
|
+
traffic_type_name: split[:trafficTypeName],
|
|
71
|
+
killed: split[:killed],
|
|
72
|
+
treatments: treatments,
|
|
73
|
+
change_number: split[:changeNumber]
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'socket'
|
|
3
|
+
|
|
4
|
+
module SplitIoClient
|
|
5
|
+
#
|
|
6
|
+
# This class manages configuration options for the split client library.
|
|
7
|
+
# If not custom configuration is required the default configuration values will be used
|
|
8
|
+
#
|
|
9
|
+
class SplitConfig
|
|
10
|
+
#
|
|
11
|
+
# Constructor for creating custom split client config
|
|
12
|
+
#
|
|
13
|
+
# @param opts [Hash] optional hash with configuration options
|
|
14
|
+
# @option opts [String] :base_uri ("https://sdk.split.io/api/") The base URL for split API end points
|
|
15
|
+
# @option opts [String] :events_uri ("https://events.split.io/api/") The events URL for events end points
|
|
16
|
+
# @option opts [Int] :read_timeout (10) The read timeout for network connections in seconds.
|
|
17
|
+
# @option opts [Int] :connection_timeout (2) The connect timeout for network connections in seconds.
|
|
18
|
+
# @option opts [Int] :features_refresh_rate The SDK polls Split servers for changes to feature roll-out plans. This parameter controls this polling period in seconds.
|
|
19
|
+
# @option opts [Int] :segments_refresh_rate
|
|
20
|
+
# @option opts [Int] :metrics_refresh_rate
|
|
21
|
+
# @option opts [Int] :impressions_refresh_rate
|
|
22
|
+
# @option opts [Object] :logger a logger to user for messages from the client. Defaults to stdout
|
|
23
|
+
# @option opts [Boolean] :debug_enabled (false) The value for the debug flag
|
|
24
|
+
# @option opts [Int] :impressions_queue_size how big the impressions queue is before dropping impressions. -1 to disable it.
|
|
25
|
+
#
|
|
26
|
+
# @return [type] SplitConfig with configuration options
|
|
27
|
+
def initialize(opts = {})
|
|
28
|
+
@base_uri = (opts[:base_uri] || SplitConfig.default_base_uri).chomp('/')
|
|
29
|
+
@events_uri = (opts[:events_uri] || SplitConfig.default_events_uri).chomp('/')
|
|
30
|
+
@mode = opts[:mode] || SplitConfig.default_mode
|
|
31
|
+
@redis_url = opts[:redis_url] || SplitConfig.default_redis_url
|
|
32
|
+
@redis_namespace = opts[:redis_namespace] ? "#{opts[:redis_namespace]}.#{SplitConfig.default_redis_namespace}" : SplitConfig.default_redis_namespace
|
|
33
|
+
@cache_adapter = SplitConfig.init_cache_adapter(
|
|
34
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :map_adapter, @redis_url, false
|
|
35
|
+
)
|
|
36
|
+
@connection_timeout = opts[:connection_timeout] || SplitConfig.default_connection_timeout
|
|
37
|
+
@read_timeout = opts[:read_timeout] || SplitConfig.default_read_timeout
|
|
38
|
+
@features_refresh_rate = opts[:features_refresh_rate] || SplitConfig.default_features_refresh_rate
|
|
39
|
+
@segments_refresh_rate = opts[:segments_refresh_rate] || SplitConfig.default_segments_refresh_rate
|
|
40
|
+
@metrics_refresh_rate = opts[:metrics_refresh_rate] || SplitConfig.default_metrics_refresh_rate
|
|
41
|
+
|
|
42
|
+
@impressions_refresh_rate = opts[:impressions_refresh_rate] || SplitConfig.default_impressions_refresh_rate
|
|
43
|
+
@impressions_queue_size = opts[:impressions_queue_size] || SplitConfig.default_impressions_queue_size
|
|
44
|
+
@impressions_adapter = SplitConfig.init_cache_adapter(
|
|
45
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :queue_adapter, @redis_url, @impressions_queue_size
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@metrics_adapter = SplitConfig.init_cache_adapter(
|
|
49
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :map_adapter, @redis_url, false
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
@logger = opts[:logger] || SplitConfig.default_logger
|
|
53
|
+
@debug_enabled = opts[:debug_enabled] || SplitConfig.default_debug
|
|
54
|
+
@transport_debug_enabled = opts[:transport_debug_enabled] || SplitConfig.default_debug
|
|
55
|
+
@block_until_ready = opts[:ready] || opts[:block_until_ready] || 0
|
|
56
|
+
@machine_name = opts[:machine_name] || SplitConfig.machine_hostname
|
|
57
|
+
@machine_ip = opts[:machine_ip] || SplitConfig.machine_ip
|
|
58
|
+
|
|
59
|
+
@language = opts[:language] || 'ruby'
|
|
60
|
+
@version = opts[:version] || SplitIoClient::VERSION
|
|
61
|
+
|
|
62
|
+
@labels_enabled = opts[:labels_enabled].nil? ? SplitConfig.default_labels_logging : opts[:labels_enabled]
|
|
63
|
+
|
|
64
|
+
@impression_listener = opts[:impression_listener]
|
|
65
|
+
@impression_listener_refresh_rate = opts[:impression_listener_refresh_rate] || SplitConfig.default_impression_listener_refresh_rate
|
|
66
|
+
|
|
67
|
+
@threads = {}
|
|
68
|
+
|
|
69
|
+
@events_push_rate = opts[:events_push_rate] || SplitConfig.default_events_push_rate
|
|
70
|
+
@events_queue_size = opts[:events_queue_size] || SplitConfig.default_events_queue_size
|
|
71
|
+
@events_adapter = SplitConfig.init_cache_adapter(
|
|
72
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :queue_adapter, @redis_url, @events_queue_size
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
startup_log
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# The base URL for split API end points
|
|
80
|
+
#
|
|
81
|
+
# @return [String] The configured base URL for the split API end points
|
|
82
|
+
attr_reader :base_uri
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# The base URL for split events API end points
|
|
86
|
+
#
|
|
87
|
+
# @return [String] The configured URL for the events API end points
|
|
88
|
+
attr_reader :events_uri
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# The mode SDK will run
|
|
92
|
+
#
|
|
93
|
+
# @return [Symbol] One of the available SDK modes: standalone, consumer, producer
|
|
94
|
+
attr_reader :mode
|
|
95
|
+
|
|
96
|
+
# The read timeout for network connections in seconds.
|
|
97
|
+
#
|
|
98
|
+
# @return [Int] The timeout in seconds.
|
|
99
|
+
attr_reader :read_timeout
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# The cache adapter to store splits/segments in
|
|
103
|
+
#
|
|
104
|
+
# @return [Object] Cache adapter instance
|
|
105
|
+
attr_reader :cache_adapter
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# The cache adapter to store impressions in
|
|
109
|
+
#
|
|
110
|
+
# @return [Object] Impressions adapter instance
|
|
111
|
+
attr_reader :impressions_adapter
|
|
112
|
+
|
|
113
|
+
#
|
|
114
|
+
# The cache adapter to store metrics in
|
|
115
|
+
#
|
|
116
|
+
# @return [Symbol] Metrics adapter
|
|
117
|
+
attr_reader :metrics_adapter
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# The cache adapter to store events in
|
|
121
|
+
#
|
|
122
|
+
# @return [Object] Metrics adapter
|
|
123
|
+
attr_reader :events_adapter
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# The connection timeout for network connections in seconds.
|
|
127
|
+
#
|
|
128
|
+
# @return [Int] The connect timeout in seconds.
|
|
129
|
+
attr_reader :connection_timeout
|
|
130
|
+
|
|
131
|
+
#
|
|
132
|
+
# The configured logger. The client library uses the log to
|
|
133
|
+
# print warning and error messages.
|
|
134
|
+
#
|
|
135
|
+
# @return [Logger] The configured logger
|
|
136
|
+
attr_reader :logger
|
|
137
|
+
|
|
138
|
+
#
|
|
139
|
+
# The boolean that represents the state of the debug log level
|
|
140
|
+
#
|
|
141
|
+
# @return [Boolean] The value for the debug flag
|
|
142
|
+
attr_reader :debug_enabled
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# Enable to log the content retrieved from endpoints
|
|
146
|
+
#
|
|
147
|
+
# @return [Boolean] The value for the debug flag
|
|
148
|
+
attr_reader :transport_debug_enabled
|
|
149
|
+
|
|
150
|
+
#
|
|
151
|
+
# Enable logging labels and sending potentially sensitive information
|
|
152
|
+
#
|
|
153
|
+
# @return [Boolean] The value for the labels enabled flag
|
|
154
|
+
attr_reader :labels_enabled
|
|
155
|
+
|
|
156
|
+
#
|
|
157
|
+
# The number of seconds to wait for SDK readiness
|
|
158
|
+
# or false to disable waiting
|
|
159
|
+
# @return [Integer]/[FalseClass]
|
|
160
|
+
attr_reader :block_until_ready
|
|
161
|
+
|
|
162
|
+
attr_reader :machine_ip
|
|
163
|
+
attr_reader :machine_name
|
|
164
|
+
|
|
165
|
+
attr_reader :language
|
|
166
|
+
attr_reader :version
|
|
167
|
+
|
|
168
|
+
attr_reader :features_refresh_rate
|
|
169
|
+
attr_reader :segments_refresh_rate
|
|
170
|
+
attr_reader :metrics_refresh_rate
|
|
171
|
+
attr_reader :impressions_refresh_rate
|
|
172
|
+
|
|
173
|
+
attr_reader :impression_listener
|
|
174
|
+
attr_reader :impression_listener_refresh_rate
|
|
175
|
+
|
|
176
|
+
#
|
|
177
|
+
# How big the impressions queue is before dropping impressions. -1 to disable it.
|
|
178
|
+
#
|
|
179
|
+
# @return [Integer]
|
|
180
|
+
attr_reader :impressions_queue_size
|
|
181
|
+
|
|
182
|
+
attr_reader :redis_url
|
|
183
|
+
attr_reader :redis_namespace
|
|
184
|
+
|
|
185
|
+
attr_accessor :threads
|
|
186
|
+
|
|
187
|
+
#
|
|
188
|
+
# The schedule time for events flush after the first one
|
|
189
|
+
#
|
|
190
|
+
# @return [Integer]
|
|
191
|
+
attr_reader :events_push_rate
|
|
192
|
+
|
|
193
|
+
#
|
|
194
|
+
# The max size of the events queue
|
|
195
|
+
#
|
|
196
|
+
# @return [Integer]
|
|
197
|
+
attr_reader :events_queue_size
|
|
198
|
+
|
|
199
|
+
#
|
|
200
|
+
# The default split client configuration
|
|
201
|
+
#
|
|
202
|
+
# @return [Config] The default split client configuration.
|
|
203
|
+
def self.default
|
|
204
|
+
SplitConfig.new
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
#
|
|
208
|
+
# The default base uri for api calls
|
|
209
|
+
#
|
|
210
|
+
# @return [string] The default base uri
|
|
211
|
+
def self.default_base_uri
|
|
212
|
+
'https://sdk.split.io/api/'
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def self.default_events_uri
|
|
216
|
+
'https://events.split.io/api/'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def self.init_cache_adapter(adapter, data_structure, redis_url = nil, queue_size = nil)
|
|
220
|
+
case adapter
|
|
221
|
+
when :memory
|
|
222
|
+
SplitIoClient::Cache::Adapters::MemoryAdapter.new(map_memory_adapter(data_structure, queue_size))
|
|
223
|
+
when :redis
|
|
224
|
+
begin
|
|
225
|
+
require 'redis'
|
|
226
|
+
rescue LoadError
|
|
227
|
+
fail StandardError, 'To use Redis as a cache adapter you must include it in your Gemfile'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
SplitIoClient::Cache::Adapters::RedisAdapter.new(redis_url)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def self.map_memory_adapter(name, queue_size)
|
|
235
|
+
case name
|
|
236
|
+
when :map_adapter
|
|
237
|
+
SplitIoClient::Cache::Adapters::MemoryAdapters::MapAdapter.new
|
|
238
|
+
when :queue_adapter
|
|
239
|
+
SplitIoClient::Cache::Adapters::MemoryAdapters::QueueAdapter.new(queue_size)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def self.default_mode
|
|
244
|
+
:standalone
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# @return [LocalStore] configuration value for local cache store
|
|
248
|
+
def self.default_cache_adapter
|
|
249
|
+
:memory
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def self.default_metrics_adapter
|
|
253
|
+
:memory
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
#
|
|
257
|
+
# The default read timeout value
|
|
258
|
+
#
|
|
259
|
+
# @return [int]
|
|
260
|
+
def self.default_read_timeout
|
|
261
|
+
5
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
# The default connection timeout value
|
|
266
|
+
#
|
|
267
|
+
# @return [int]
|
|
268
|
+
def self.default_connection_timeout
|
|
269
|
+
5
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def self.default_features_refresh_rate
|
|
273
|
+
30
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def self.default_segments_refresh_rate
|
|
277
|
+
60
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def self.default_metrics_refresh_rate
|
|
281
|
+
60
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def self.default_impressions_refresh_rate
|
|
285
|
+
60
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def self.default_impression_listener_refresh_rate
|
|
289
|
+
0
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def self.default_impressions_queue_size
|
|
293
|
+
5000
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def self.default_events_push_rate
|
|
297
|
+
60
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def self.default_events_queue_size
|
|
301
|
+
500
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
#
|
|
305
|
+
# The default logger object
|
|
306
|
+
#
|
|
307
|
+
# @return [object]
|
|
308
|
+
def self.default_logger
|
|
309
|
+
(defined?(Rails) && Rails.logger) ? Rails.logger : Logger.new($stdout)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
#
|
|
313
|
+
# The default debug value
|
|
314
|
+
#
|
|
315
|
+
# @return [boolean]
|
|
316
|
+
def self.default_debug
|
|
317
|
+
false
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
#
|
|
321
|
+
# The default labels logging value
|
|
322
|
+
#
|
|
323
|
+
# @return [boolean]
|
|
324
|
+
def self.default_labels_logging
|
|
325
|
+
true
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def self.default_redis_url
|
|
329
|
+
'redis://127.0.0.1:6379/0'
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def self.default_redis_namespace
|
|
333
|
+
'SPLITIO'
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
#
|
|
337
|
+
# The default transport_debug_enabled value
|
|
338
|
+
#
|
|
339
|
+
# @return [boolean]
|
|
340
|
+
def self.transport_debug
|
|
341
|
+
false
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
#
|
|
345
|
+
# custom logger of exceptions
|
|
346
|
+
#
|
|
347
|
+
# @return [void]
|
|
348
|
+
def log_found_exception(caller, error)
|
|
349
|
+
message = ''
|
|
350
|
+
|
|
351
|
+
message << "[splitclient-rb] Unexpected exception in #{caller}: #{error.inspect} #{error}"
|
|
352
|
+
message << "\n\t#{error.backtrace.join("\n\t")}" if @debug_enabled
|
|
353
|
+
|
|
354
|
+
@logger.warn(message)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
#
|
|
358
|
+
# log which cache class was loaded and SDK mode
|
|
359
|
+
#
|
|
360
|
+
# @return [void]
|
|
361
|
+
def startup_log
|
|
362
|
+
return if ENV['SPLITCLIENT_ENV'] == 'test'
|
|
363
|
+
|
|
364
|
+
@logger.info("Loaded Ruby SDK v#{VERSION} in the #{@mode} mode")
|
|
365
|
+
@logger.info("Loaded cache class: #{@cache_adapter.class}")
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
#
|
|
369
|
+
# gets the hostname where the sdk gem is running
|
|
370
|
+
#
|
|
371
|
+
# @return [string]
|
|
372
|
+
def self.machine_hostname
|
|
373
|
+
Socket.gethostname
|
|
374
|
+
rescue
|
|
375
|
+
'localhost'.freeze
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
#
|
|
379
|
+
# gets the ip where the sdk gem is running
|
|
380
|
+
#
|
|
381
|
+
# @return [string]
|
|
382
|
+
def self.machine_ip
|
|
383
|
+
loopback_ip = Socket.ip_address_list.find { |ip| ip.ipv4_loopback? }
|
|
384
|
+
private_ip = Socket.ip_address_list.find { |ip| ip.ipv4_private? }
|
|
385
|
+
|
|
386
|
+
addr_info = private_ip || loopback_ip
|
|
387
|
+
|
|
388
|
+
addr_info.ip_address
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|