splitclient-rb 3.1.0.pre.rc9 → 3.1.0.pre.rc10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|