splitclient-rb 3.1.0.pre.rc9 → 3.1.0.pre.rc10
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/cache/adapters/redis_adapter.rb +10 -0
- data/lib/cache/repositories/impressions/memory_repository.rb +6 -0
- data/lib/cache/repositories/impressions/redis_repository.rb +12 -0
- data/lib/cache/repositories/impressions_repository.rb +1 -1
- data/lib/cache/repositories/metrics/memory_repository.rb +123 -0
- data/lib/cache/repositories/metrics/redis_repository.rb +92 -0
- data/lib/cache/repositories/metrics_repository.rb +21 -0
- data/lib/engine/metrics/binary_search_latency_tracker.rb +8 -2
- data/lib/engine/metrics/metrics.rb +11 -86
- data/lib/engine/parser/split_adapter.rb +16 -31
- data/lib/splitclient-rb.rb +3 -0
- data/lib/splitclient-rb/split_config.rb +14 -0
- data/lib/splitclient-rb/split_factory.rb +17 -9
- data/lib/splitclient-rb/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37a7aea4e576c0285c8fe0b52407263314b3dbe1
|
4
|
+
data.tar.gz: 0dfcf521a72a8eeac66bf8a1e2a4bcb45ab7b6be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01234be503798df68a17b5ac3182736a446cfe4c35fdad405a719e33d748adc1158f312e591601082fd52a7cec543ae5b76de09b1aa383db16152d162095cd37
|
7
|
+
data.tar.gz: 8baf6f0b69c26309421282d9c331abb94eae269be202742fd308cf7df8941ff07fd5f1c0c3d85ade401e84025305ae2715f085de57c3d0aca8ec0142a10d3466
|
@@ -6,6 +6,8 @@ module SplitIoClient
|
|
6
6
|
module Adapters
|
7
7
|
# Redis adapter used to provide interface to Redis
|
8
8
|
class RedisAdapter
|
9
|
+
attr_reader :redis
|
10
|
+
|
9
11
|
def initialize(redis_url)
|
10
12
|
connection = redis_url.is_a?(Hash) ? redis_url : { url: redis_url }
|
11
13
|
|
@@ -58,6 +60,10 @@ module SplitIoClient
|
|
58
60
|
Hash[keys.zip(@redis.mget(keys))]
|
59
61
|
end
|
60
62
|
|
63
|
+
def append_to_string(key, val)
|
64
|
+
@redis.append(key, val)
|
65
|
+
end
|
66
|
+
|
61
67
|
# Bool
|
62
68
|
def set_bool(key, val)
|
63
69
|
@redis.set(key, val.to_s)
|
@@ -111,6 +117,10 @@ module SplitIoClient
|
|
111
117
|
|
112
118
|
@redis.del(key)
|
113
119
|
end
|
120
|
+
|
121
|
+
def inc(key, inc = 1)
|
122
|
+
@redis.incrby(key, inc)
|
123
|
+
end
|
114
124
|
end
|
115
125
|
end
|
116
126
|
end
|
@@ -18,6 +18,12 @@ module SplitIoClient
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
def add_bulk(key, treatments, time)
|
22
|
+
treatments.each do |split_name, treatment|
|
23
|
+
add(split_name, 'key_name' => key, 'treatment' => treatment, 'time' => time)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
21
27
|
# Get everything from the queue and leave it empty
|
22
28
|
def clear
|
23
29
|
@adapter.clear
|
@@ -3,6 +3,8 @@ module SplitIoClient
|
|
3
3
|
module Repositories
|
4
4
|
module Impressions
|
5
5
|
class RedisRepository < Repository
|
6
|
+
IMPRESSIONS_SLICE = 1000
|
7
|
+
|
6
8
|
def initialize(adapter, config)
|
7
9
|
@adapter = adapter
|
8
10
|
@config = config
|
@@ -15,6 +17,16 @@ module SplitIoClient
|
|
15
17
|
)
|
16
18
|
end
|
17
19
|
|
20
|
+
def add_bulk(key, treatments, time)
|
21
|
+
@adapter.redis.pipelined do
|
22
|
+
treatments.each_slice(IMPRESSIONS_SLICE) do |treatments_slice|
|
23
|
+
treatments_slice.each do |split_name, treatment|
|
24
|
+
add(split_name, 'key_name' => key, 'treatment' => treatment, 'time' => time)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
18
30
|
# Get random impressions from redis in batches of size @config.impressions_queue_size,
|
19
31
|
# delete fetched impressions afterwards
|
20
32
|
def clear
|
@@ -4,7 +4,7 @@ module SplitIoClient
|
|
4
4
|
# Repository which forwards impressions interface to the selected adapter
|
5
5
|
class ImpressionsRepository < Repository
|
6
6
|
extend Forwardable
|
7
|
-
def_delegators :@adapter, :add, :clear, :empty?
|
7
|
+
def_delegators :@adapter, :add, :add_bulk, :clear, :empty?
|
8
8
|
|
9
9
|
def initialize(adapter, config)
|
10
10
|
@adapter = case adapter.class.to_s
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Cache
|
3
|
+
module Repositories
|
4
|
+
module Metrics
|
5
|
+
class MemoryRepository
|
6
|
+
def initialize(_ = nil, adapter, config)
|
7
|
+
@counts = []
|
8
|
+
@latencies = []
|
9
|
+
@gauges = []
|
10
|
+
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_count(counter, delta)
|
15
|
+
counter_hash = @counts.find { |c| c[:name] == counter }
|
16
|
+
if counter_hash.nil?
|
17
|
+
counter_delta = SumAndCount.new
|
18
|
+
counter_delta.add_delta(delta)
|
19
|
+
@counts << { name: counter, delta: counter_delta }
|
20
|
+
else
|
21
|
+
counter_hash[:delta].add_delta(delta)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_latency(operation, time_in_ms, binary_search)
|
26
|
+
operation_hash = @latencies.find { |l| l[:operation] == operation }
|
27
|
+
if operation_hash.nil?
|
28
|
+
latencies_for_op = (operation == 'sdk.get_treatment') ? binary_search.add_latency_millis(time_in_ms) : [time_in_ms]
|
29
|
+
@latencies << { operation: operation, latencies: latencies_for_op }
|
30
|
+
else
|
31
|
+
latencies_for_op = (operation == 'sdk.get_treatment') ? binary_search.add_latency_millis(time_in_ms) : operation_hash[:latencies].push(time_in_ms)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_gauge(gauge, value)
|
36
|
+
gauge_hash = @gauges.find { |g| g[:name] == gauge }
|
37
|
+
if gauge_hash.nil?
|
38
|
+
gauge_value = ValueAndCount.new
|
39
|
+
gauge_value.set_value(value)
|
40
|
+
@gauges << { name: gauge, value: gauge_value }
|
41
|
+
else
|
42
|
+
gauge_hash[:value].set_value(value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def counts
|
47
|
+
@counts.each_with_object({}) do |count, memo|
|
48
|
+
memo[count[:name]] = count[:delta].sum
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def latencies
|
53
|
+
@latencies.each_with_object({}) do |latency, memo|
|
54
|
+
memo[latency[:operation]] = latency[:latencies]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def gauges
|
59
|
+
# TODO
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear_counts
|
63
|
+
@counts = []
|
64
|
+
end
|
65
|
+
|
66
|
+
def clear_latencies
|
67
|
+
@latencies = []
|
68
|
+
end
|
69
|
+
|
70
|
+
def clear_gauges
|
71
|
+
@gauges = []
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# small class to act as DTO for counts
|
76
|
+
#
|
77
|
+
class SumAndCount
|
78
|
+
attr_reader :count
|
79
|
+
attr_reader :sum
|
80
|
+
|
81
|
+
def initialize
|
82
|
+
@count = 0
|
83
|
+
@sum = 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_delta(delta)
|
87
|
+
@count += 1
|
88
|
+
@sum += delta
|
89
|
+
end
|
90
|
+
|
91
|
+
def clear
|
92
|
+
@count = 0
|
93
|
+
@sum = 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# small class to act as DTO for gauges
|
99
|
+
#
|
100
|
+
class ValueAndCount
|
101
|
+
attr_reader :count
|
102
|
+
attr_reader :value
|
103
|
+
|
104
|
+
def initialize
|
105
|
+
@count = 0
|
106
|
+
@value = 0
|
107
|
+
end
|
108
|
+
|
109
|
+
def set_value(value)
|
110
|
+
@count += 1
|
111
|
+
@value = value
|
112
|
+
end
|
113
|
+
|
114
|
+
def clear
|
115
|
+
@count = 0
|
116
|
+
@value = 0
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Cache
|
3
|
+
module Repositories
|
4
|
+
module Metrics
|
5
|
+
class RedisRepository < Repository
|
6
|
+
def initialize(adapter = nil, config)
|
7
|
+
@config = config
|
8
|
+
@adapter = adapter
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_count(counter, delta)
|
12
|
+
prefixed_name = namespace_key("count.#{counter}")
|
13
|
+
counts = @adapter.find_strings_by_prefix(prefixed_name)
|
14
|
+
|
15
|
+
@adapter.inc(prefixed_name, delta)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_latency(operation, time_in_ms, binary_search)
|
19
|
+
prefixed_name = namespace_key("latency.#{operation}")
|
20
|
+
latencies = @adapter.find_strings_by_prefix(prefixed_name)
|
21
|
+
|
22
|
+
if operation == 'sdk.get_treatment'
|
23
|
+
@adapter.inc("#{prefixed_name}.#{binary_search.add_latency_millis(time_in_ms, true)}")
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
@adapter.append_to_string(prefixed_name, "#{time_in_ms},")
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_gauge(gauge, value)
|
31
|
+
# TODO
|
32
|
+
end
|
33
|
+
|
34
|
+
def counts
|
35
|
+
keys = @adapter.find_strings_by_prefix(namespace_key('count'))
|
36
|
+
|
37
|
+
return [] if keys.empty?
|
38
|
+
|
39
|
+
@adapter.multiple_strings(keys).map do |name, data|
|
40
|
+
[name.gsub(namespace_key('count.'), ''), data]
|
41
|
+
end.to_h
|
42
|
+
end
|
43
|
+
|
44
|
+
def latencies
|
45
|
+
collected_latencies = {}
|
46
|
+
latencies_array = Array.new(BinarySearchLatencyTracker::BUCKETS.length, 0)
|
47
|
+
keys = @adapter.find_strings_by_prefix(namespace_key('latency'))
|
48
|
+
|
49
|
+
return [] if keys.empty?
|
50
|
+
|
51
|
+
found_latencies = @adapter.multiple_strings(keys).map do |name, data|
|
52
|
+
[name.gsub(namespace_key('latency.'), ''), data]
|
53
|
+
end.to_h
|
54
|
+
|
55
|
+
found_latencies.each do |key, value|
|
56
|
+
if key.start_with?('sdk.get_treatment')
|
57
|
+
index = key.gsub('sdk.get_treatment.', '').to_i
|
58
|
+
latencies_array[index] = value.to_i
|
59
|
+
|
60
|
+
next
|
61
|
+
end
|
62
|
+
|
63
|
+
collected_latencies[key] = value.split(',').map(&:to_f)
|
64
|
+
end
|
65
|
+
|
66
|
+
collected_latencies['sdk.get_treatment'] = latencies_array
|
67
|
+
|
68
|
+
collected_latencies
|
69
|
+
end
|
70
|
+
|
71
|
+
def gauges
|
72
|
+
# TODO
|
73
|
+
end
|
74
|
+
|
75
|
+
def clear_counts
|
76
|
+
keys = @adapter.find_strings_by_prefix(namespace_key('count'))
|
77
|
+
@adapter.delete(keys)
|
78
|
+
end
|
79
|
+
|
80
|
+
def clear_latencies
|
81
|
+
keys = @adapter.find_strings_by_prefix(namespace_key('latency'))
|
82
|
+
@adapter.delete(keys)
|
83
|
+
end
|
84
|
+
|
85
|
+
def clear_gauges
|
86
|
+
# TODO
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Cache
|
3
|
+
module Repositories
|
4
|
+
# Repository which forwards impressions interface to the selected adapter
|
5
|
+
class MetricsRepository < Repository
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@adapter, :add_count, :add_latency, :add_gauge, :counts, :latencies, :gauges,
|
8
|
+
:clear_counts, :clear_latencies, :clear_gauges
|
9
|
+
|
10
|
+
def initialize(adapter, config)
|
11
|
+
@adapter = case adapter.class.to_s
|
12
|
+
when 'SplitIoClient::Cache::Adapters::MemoryAdapter'
|
13
|
+
Repositories::Metrics::MemoryRepository.new(adapter, config)
|
14
|
+
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
15
|
+
Repositories::Metrics::RedisRepository.new(adapter, config)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -52,16 +52,22 @@ module SplitIoClient
|
|
52
52
|
# Increment the internal counter for the bucket this latency falls into.
|
53
53
|
# @param millis
|
54
54
|
#
|
55
|
-
def add_latency_millis(millis)
|
55
|
+
def add_latency_millis(millis, return_index = false)
|
56
56
|
index = find_bucket_index(millis * 1000)
|
57
|
+
|
58
|
+
return index if return_index
|
59
|
+
|
57
60
|
@latencies[index] += 1
|
58
61
|
@latencies
|
59
62
|
end
|
60
63
|
|
61
64
|
# Increment the internal counter for the bucket this latency falls into.
|
62
65
|
# @param micros
|
63
|
-
def add_latency_micros(micros)
|
66
|
+
def add_latency_micros(micros, return_index = false)
|
64
67
|
index = find_bucket_index(micros)
|
68
|
+
|
69
|
+
return index if return_index
|
70
|
+
|
65
71
|
@latencies[index] += 1
|
66
72
|
@latencies
|
67
73
|
end
|
@@ -32,12 +32,13 @@ module SplitIoClient
|
|
32
32
|
# @return [int] queue size
|
33
33
|
attr_accessor :queue_size
|
34
34
|
|
35
|
-
def initialize(queue_size)
|
36
|
-
@latencies = []
|
37
|
-
@counts = []
|
38
|
-
@gauges = []
|
35
|
+
def initialize(queue_size, config, repository)
|
39
36
|
@queue_size = queue_size
|
40
37
|
@binary_search = SplitIoClient::BinarySearchLatencyTracker.new
|
38
|
+
|
39
|
+
@config = config
|
40
|
+
|
41
|
+
@repository = repository
|
41
42
|
end
|
42
43
|
|
43
44
|
#
|
@@ -48,18 +49,9 @@ module SplitIoClient
|
|
48
49
|
#
|
49
50
|
# @return void
|
50
51
|
def count(counter, delta)
|
51
|
-
return if delta <= 0
|
52
|
+
return if (delta <= 0) || counter.nil? || counter.strip.empty?
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
counter_hash = @counts.find { |c| c[:name] == counter }
|
56
|
-
if counter_hash.nil?
|
57
|
-
counter_delta = SumAndCount.new
|
58
|
-
counter_delta.add_delta(delta)
|
59
|
-
@counts << {name: counter, delta: counter_delta}
|
60
|
-
else
|
61
|
-
counter_hash[:delta].add_delta(delta)
|
62
|
-
end
|
54
|
+
@repository.add_count(counter, delta)
|
63
55
|
end
|
64
56
|
|
65
57
|
#
|
@@ -70,18 +62,9 @@ module SplitIoClient
|
|
70
62
|
#
|
71
63
|
# @return void
|
72
64
|
def time(operation, time_in_ms)
|
65
|
+
return if operation.nil? || operation.empty? || time_in_ms < 0
|
73
66
|
|
74
|
-
|
75
|
-
return;
|
76
|
-
end
|
77
|
-
|
78
|
-
operation_hash = @latencies.find { |l| l[:operation] == operation }
|
79
|
-
if operation_hash.nil?
|
80
|
-
latencies_for_op = (operation == 'sdk.get_treatment') ? @binary_search.add_latency_millis(time_in_ms) : [time_in_ms]
|
81
|
-
@latencies << {operation: operation, latencies: latencies_for_op}
|
82
|
-
else
|
83
|
-
latencies_for_op = (operation == 'sdk.get_treatment') ? @binary_search.add_latency_millis(time_in_ms) : operation_hash[:latencies].push(time_in_ms)
|
84
|
-
end
|
67
|
+
@repository.add_latency(operation, time_in_ms, @binary_search)
|
85
68
|
end
|
86
69
|
|
87
70
|
#
|
@@ -92,67 +75,9 @@ module SplitIoClient
|
|
92
75
|
#
|
93
76
|
# @return void
|
94
77
|
def gauge(gauge, value)
|
95
|
-
if gauge.nil? || gauge.empty?
|
96
|
-
return
|
97
|
-
end
|
78
|
+
return if gauge.nil? || gauge.empty?
|
98
79
|
|
99
|
-
|
100
|
-
if gauge_hash.nil?
|
101
|
-
gauge_value = ValueAndCount.new
|
102
|
-
gauge_value.set_value(value)
|
103
|
-
@gauges << {name: gauge, value: gauge_value}
|
104
|
-
else
|
105
|
-
gauge_hash[:value].set_value(value)
|
106
|
-
end
|
80
|
+
@repository.add_gauge(gauge, value)
|
107
81
|
end
|
108
|
-
|
109
82
|
end
|
110
|
-
|
111
|
-
#
|
112
|
-
# small class to act as DTO for counts
|
113
|
-
#
|
114
|
-
class SumAndCount
|
115
|
-
attr_reader :count
|
116
|
-
attr_reader :sum
|
117
|
-
|
118
|
-
def initialize
|
119
|
-
@count = 0
|
120
|
-
@sum = 0
|
121
|
-
end
|
122
|
-
|
123
|
-
def add_delta(delta)
|
124
|
-
@count++
|
125
|
-
@sum += delta
|
126
|
-
end
|
127
|
-
|
128
|
-
def clear
|
129
|
-
@count = 0
|
130
|
-
@sum = 0
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
#
|
135
|
-
# small class to act as DTO for gauges
|
136
|
-
#
|
137
|
-
class ValueAndCount
|
138
|
-
attr_reader :count
|
139
|
-
attr_reader :value
|
140
|
-
|
141
|
-
def initialize
|
142
|
-
@count = 0
|
143
|
-
@value = 0
|
144
|
-
end
|
145
|
-
|
146
|
-
def set_value(value)
|
147
|
-
@count += 1
|
148
|
-
@value = value
|
149
|
-
end
|
150
|
-
|
151
|
-
def clear
|
152
|
-
@count = 0
|
153
|
-
@value = 0
|
154
|
-
end
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
83
|
end
|
@@ -35,14 +35,16 @@ module SplitIoClient
|
|
35
35
|
# @param api_key [String] the API key for your split account
|
36
36
|
#
|
37
37
|
# @return [SplitIoClient] split.io client instance
|
38
|
-
def initialize(api_key, config, splits_repository, segments_repository, impressions_repository, sdk_blocker)
|
38
|
+
def initialize(api_key, config, splits_repository, segments_repository, impressions_repository, metrics_repository, sdk_blocker)
|
39
39
|
@api_key = api_key
|
40
40
|
@config = config
|
41
|
-
@metrics = Metrics.new(100)
|
42
41
|
|
43
42
|
@splits_repository = splits_repository
|
44
43
|
@segments_repository = segments_repository
|
45
44
|
@impressions_repository = impressions_repository
|
45
|
+
@metrics_repository = metrics_repository
|
46
|
+
|
47
|
+
@metrics = Metrics.new(100, @config, @metrics_repository)
|
46
48
|
|
47
49
|
@sdk_blocker = sdk_blocker
|
48
50
|
|
@@ -62,11 +64,12 @@ module SplitIoClient
|
|
62
64
|
metrics_sender
|
63
65
|
impressions_sender
|
64
66
|
when :consumer
|
65
|
-
|
67
|
+
# Do nothing in background
|
66
68
|
when :producer
|
67
69
|
split_store
|
68
70
|
segment_store
|
69
71
|
impressions_sender
|
72
|
+
metrics_sender
|
70
73
|
|
71
74
|
sleep unless ENV['SPLITCLIENT_ENV'] == 'test'
|
72
75
|
end
|
@@ -248,53 +251,35 @@ module SplitIoClient
|
|
248
251
|
#
|
249
252
|
# @return [void]
|
250
253
|
def post_metrics
|
251
|
-
if @
|
254
|
+
if @metrics_repository.latencies.empty?
|
252
255
|
@config.logger.debug('No latencies to report.') if @config.debug_enabled
|
253
256
|
else
|
254
|
-
@
|
255
|
-
metrics_time = {}
|
256
|
-
metrics_time = {name: l[:operation], latencies: l[:latencies]}
|
257
|
+
@metrics_repository.latencies.each do |name, latencies|
|
258
|
+
metrics_time = { name: name, latencies: latencies }
|
257
259
|
res = post_api('/metrics/time', metrics_time)
|
258
260
|
if res.status / 100 != 2
|
259
261
|
@config.logger.error("Unexpected status code while posting time metrics: #{res.status}")
|
260
262
|
else
|
261
|
-
@config.logger.debug("Metric time reported: #{metrics_time.size
|
263
|
+
@config.logger.debug("Metric time reported: #{metrics_time.size}") if @config.debug_enabled
|
262
264
|
end
|
263
265
|
end
|
264
266
|
end
|
265
|
-
@
|
267
|
+
@metrics_repository.clear_latencies
|
266
268
|
|
267
|
-
if @
|
269
|
+
if @metrics_repository.counts.empty?
|
268
270
|
@config.logger.debug('No counts to report.') if @config.debug_enabled
|
269
271
|
else
|
270
|
-
@
|
271
|
-
metrics_count = {}
|
272
|
-
metrics_count = {name: c[:name], delta: c[:delta].sum}
|
272
|
+
@metrics_repository.counts.each do |name, count|
|
273
|
+
metrics_count = { name: name, delta: count }
|
273
274
|
res = post_api('/metrics/counter', metrics_count)
|
274
275
|
if res.status / 100 != 2
|
275
276
|
@config.logger.error("Unexpected status code while posting count metrics: #{res.status}")
|
276
277
|
else
|
277
|
-
@config.logger.debug("Metric counts reported: #{metrics_count.size
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
@metrics.counts.clear
|
282
|
-
|
283
|
-
if @metrics.gauges.empty?
|
284
|
-
@config.logger.debug('No gauges to report.') if @config.debug_enabled
|
285
|
-
else
|
286
|
-
@metrics.gauges.each do |g|
|
287
|
-
metrics_gauge = {}
|
288
|
-
metrics_gauge = {name: g[:name], value: g[:gauge].value}
|
289
|
-
res = post_api('/metrics/gauge', metrics_gauge)
|
290
|
-
if res.status / 100 != 2
|
291
|
-
@config.logger.error("Unexpected status code while posting gauge metrics: #{res.status}")
|
292
|
-
else
|
293
|
-
@config.logger.debug("Metric gauge reported: #{metrics_gauge.size()}") if @config.debug_enabled
|
278
|
+
@config.logger.debug("Metric counts reported: #{metrics_count.size}") if @config.debug_enabled
|
294
279
|
end
|
295
280
|
end
|
296
281
|
end
|
297
|
-
@
|
282
|
+
@metrics_repository.clear_counts
|
298
283
|
end
|
299
284
|
|
300
285
|
private
|
data/lib/splitclient-rb.rb
CHANGED
@@ -15,6 +15,9 @@ require 'cache/repositories/splits_repository'
|
|
15
15
|
require 'cache/repositories/impressions_repository'
|
16
16
|
require 'cache/repositories/impressions/memory_repository'
|
17
17
|
require 'cache/repositories/impressions/redis_repository'
|
18
|
+
require 'cache/repositories/metrics_repository'
|
19
|
+
require 'cache/repositories/metrics/memory_repository'
|
20
|
+
require 'cache/repositories/metrics/redis_repository'
|
18
21
|
require 'cache/stores/sdk_blocker'
|
19
22
|
require 'cache/stores/segment_store'
|
20
23
|
require 'cache/stores/split_store'
|
@@ -44,6 +44,10 @@ module SplitIoClient
|
|
44
44
|
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :sized_queue_adapter, @redis_url, @impressions_queue_size
|
45
45
|
)
|
46
46
|
|
47
|
+
@metrics_adapter = SplitConfig.init_cache_adapter(
|
48
|
+
opts[:cache_adapter] || SplitConfig.default_cache_adapter, :map_adapter, @redis_url, false
|
49
|
+
)
|
50
|
+
|
47
51
|
@logger = opts[:logger] || SplitConfig.default_logger
|
48
52
|
@debug_enabled = opts[:debug_enabled] || SplitConfig.default_debug
|
49
53
|
@transport_debug_enabled = opts[:transport_debug_enabled] || SplitConfig.default_debug
|
@@ -89,6 +93,12 @@ module SplitIoClient
|
|
89
93
|
# @return [Object] Impressions adapter instance
|
90
94
|
attr_reader :impressions_adapter
|
91
95
|
|
96
|
+
#
|
97
|
+
# The cache adapter to store metrics in
|
98
|
+
#
|
99
|
+
# @return [Symbol] Metrics adapter
|
100
|
+
attr_reader :metrics_adapter
|
101
|
+
|
92
102
|
#
|
93
103
|
# The connection timeout for network connections in seconds.
|
94
104
|
#
|
@@ -179,6 +189,10 @@ module SplitIoClient
|
|
179
189
|
:memory
|
180
190
|
end
|
181
191
|
|
192
|
+
def self.default_metrics_adapter
|
193
|
+
:memory
|
194
|
+
end
|
195
|
+
|
182
196
|
#
|
183
197
|
# The default read timeout value
|
184
198
|
#
|
@@ -131,7 +131,7 @@ module SplitIoClient
|
|
131
131
|
# @param api_key [String] the API key for your split account
|
132
132
|
#
|
133
133
|
# @return [SplitIoClient] split.io client instance
|
134
|
-
def initialize(api_key, config = {}, adapter = nil, localhost_mode = false, splits_repository, segments_repository, impressions_repository)
|
134
|
+
def initialize(api_key, config = {}, adapter = nil, localhost_mode = false, splits_repository, segments_repository, impressions_repository, metrics_repository)
|
135
135
|
@localhost_mode = localhost_mode
|
136
136
|
@localhost_mode_features = []
|
137
137
|
|
@@ -140,6 +140,7 @@ module SplitIoClient
|
|
140
140
|
@splits_repository = splits_repository
|
141
141
|
@segments_repository = segments_repository
|
142
142
|
@impressions_repository = impressions_repository
|
143
|
+
@metrics_repository = metrics_repository
|
143
144
|
|
144
145
|
if api_key == LOCALHOST_MODE
|
145
146
|
@localhost_mode = true
|
@@ -150,17 +151,23 @@ module SplitIoClient
|
|
150
151
|
end
|
151
152
|
|
152
153
|
def get_treatments(key, split_names, attributes = nil)
|
153
|
-
|
154
154
|
# This localhost behavior must live in in localhost_spit_factory#client
|
155
155
|
if is_localhost_mode?
|
156
|
-
return split_names.each_with_object({}) do |
|
156
|
+
return split_names.each_with_object({}) do |name, memo|
|
157
157
|
memo.merge!(name => get_localhost_treatment(name))
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
-
|
162
|
-
|
161
|
+
bucketing_key, matching_key = keys_from_key(key)
|
162
|
+
bucketing_key = matching_key if bucketing_key.nil?
|
163
|
+
|
164
|
+
treatments = @splits_repository.get_splits(split_names).each_with_object({}) do |(name, data), memo|
|
165
|
+
memo.merge!(name => get_treatment(matching_key, name, attributes, data, false))
|
163
166
|
end
|
167
|
+
|
168
|
+
@impressions_repository.add_bulk(matching_key, treatments, (Time.now.to_f * 1000.0).to_i)
|
169
|
+
|
170
|
+
treatments
|
164
171
|
end
|
165
172
|
|
166
173
|
#
|
@@ -170,7 +177,7 @@ module SplitIoClient
|
|
170
177
|
# @param split_name [String/Array] name of the feature that is being validated or array of them
|
171
178
|
#
|
172
179
|
# @return [String/Hash] Treatment as String or Hash of treatments in case of array of features
|
173
|
-
def get_treatment(key, split_name, attributes = nil, split_data = nil)
|
180
|
+
def get_treatment(key, split_name, attributes = nil, split_data = nil, store_impressions = true)
|
174
181
|
bucketing_key, matching_key = keys_from_key(key)
|
175
182
|
bucketing_key = matching_key if bucketing_key.nil?
|
176
183
|
|
@@ -208,7 +215,7 @@ module SplitIoClient
|
|
208
215
|
|
209
216
|
begin
|
210
217
|
latency = (Time.now - start) * 1000.0
|
211
|
-
if @config.impressions_queue_size > 0
|
218
|
+
if @config.impressions_queue_size > 0 && store_impressions
|
212
219
|
# Disable impressions if @config.impressions_queue_size == -1
|
213
220
|
@impressions_repository.add(split_name, 'key_name' => matching_key, 'treatment' => result, 'time' => (Time.now.to_f * 1000.0).to_i)
|
214
221
|
end
|
@@ -288,9 +295,10 @@ module SplitIoClient
|
|
288
295
|
@splits_repository = SplitIoClient::Cache::Repositories::SplitsRepository.new(@cache_adapter)
|
289
296
|
@segments_repository = SplitIoClient::Cache::Repositories::SegmentsRepository.new(@cache_adapter)
|
290
297
|
@impressions_repository = SplitIoClient::Cache::Repositories::ImpressionsRepository.new(@config.impressions_adapter, @config)
|
298
|
+
@metrics_repository = SplitIoClient::Cache::Repositories::MetricsRepository.new(@config.metrics_adapter, @config)
|
291
299
|
@sdk_blocker = SplitIoClient::Cache::Stores::SDKBlocker.new(@config)
|
292
300
|
@adapter = api_key != 'localhost' \
|
293
|
-
? SplitAdapter.new(api_key, @config, @splits_repository, @segments_repository, @impressions_repository, @sdk_blocker)
|
301
|
+
? SplitAdapter.new(api_key, @config, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @sdk_blocker)
|
294
302
|
: nil
|
295
303
|
@localhost_mode = api_key == 'localhost'
|
296
304
|
|
@@ -317,7 +325,7 @@ module SplitIoClient
|
|
317
325
|
attr_reader :adapter
|
318
326
|
|
319
327
|
def init_client
|
320
|
-
SplitClient.new(@api_key, @config, @adapter, @localhost_mode, @splits_repository, @segments_repository, @impressions_repository)
|
328
|
+
SplitClient.new(@api_key, @config, @adapter, @localhost_mode, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository)
|
321
329
|
end
|
322
330
|
|
323
331
|
def init_manager
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: splitclient-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.0.pre.
|
4
|
+
version: 3.1.0.pre.rc10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Split Software
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -257,6 +257,9 @@ files:
|
|
257
257
|
- lib/cache/repositories/impressions/memory_repository.rb
|
258
258
|
- lib/cache/repositories/impressions/redis_repository.rb
|
259
259
|
- lib/cache/repositories/impressions_repository.rb
|
260
|
+
- lib/cache/repositories/metrics/memory_repository.rb
|
261
|
+
- lib/cache/repositories/metrics/redis_repository.rb
|
262
|
+
- lib/cache/repositories/metrics_repository.rb
|
260
263
|
- lib/cache/repositories/repository.rb
|
261
264
|
- lib/cache/repositories/segments_repository.rb
|
262
265
|
- lib/cache/repositories/splits_repository.rb
|