splitclient-rb 6.3.0 → 8.11.0

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.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/pull_request_template.md +9 -0
  4. data/.github/workflows/ci.yml +90 -0
  5. data/.github/workflows/update-license-year.yml +45 -0
  6. data/.gitignore +4 -0
  7. data/.rubocop.yml +46 -3
  8. data/CHANGES.txt +158 -11
  9. data/CONTRIBUTORS-GUIDE.md +49 -0
  10. data/LICENSE +169 -13
  11. data/NOTICE.txt +5 -0
  12. data/README.md +67 -27
  13. data/Rakefile +1 -8
  14. data/ext/murmurhash/3_x64_128.c +117 -0
  15. data/ext/murmurhash/murmurhash.c +5 -1
  16. data/lib/murmurhash/murmurhash.jar +0 -0
  17. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
  18. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +4 -0
  19. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +7 -0
  20. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +12 -4
  21. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  22. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  23. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  24. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  25. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  26. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  27. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  28. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  29. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +26 -14
  30. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +9 -14
  31. data/lib/splitclient-rb/cache/repositories/events_repository.rb +31 -10
  32. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  33. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  34. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +22 -23
  35. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +15 -22
  36. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +6 -31
  37. data/lib/splitclient-rb/cache/repositories/repository.rb +6 -5
  38. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  39. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +46 -6
  40. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +232 -43
  41. data/lib/splitclient-rb/cache/routers/impression_router.rb +24 -22
  42. data/lib/splitclient-rb/cache/senders/events_sender.rb +12 -29
  43. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  44. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  45. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  46. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +27 -13
  47. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +11 -25
  48. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  49. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  50. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  51. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  52. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  53. data/lib/splitclient-rb/clients/split_client.rb +385 -138
  54. data/lib/splitclient-rb/constants.rb +16 -0
  55. data/lib/splitclient-rb/engine/api/client.rb +38 -43
  56. data/lib/splitclient-rb/engine/api/events.rb +19 -11
  57. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
  58. data/lib/splitclient-rb/engine/api/impressions.rb +49 -14
  59. data/lib/splitclient-rb/engine/api/segments.rb +31 -24
  60. data/lib/splitclient-rb/engine/api/splits.rb +108 -33
  61. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  62. data/lib/splitclient-rb/engine/auth_api_client.rb +96 -0
  63. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  64. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  65. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  66. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  67. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  68. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  69. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  70. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  71. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  72. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  73. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  74. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  75. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
  76. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
  77. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  78. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +10 -8
  79. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +2 -6
  80. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +1 -5
  81. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
  82. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +6 -5
  83. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
  84. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
  85. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
  86. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  87. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +1 -5
  88. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
  89. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  90. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  91. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
  92. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  93. data/lib/splitclient-rb/engine/matchers/matcher.rb +22 -0
  94. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
  95. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
  96. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +2 -6
  97. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  98. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  99. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  100. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
  101. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
  102. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
  103. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
  104. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
  105. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  106. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  107. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  108. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  109. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  110. data/lib/splitclient-rb/engine/models/label.rb +3 -0
  111. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  112. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  113. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  114. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  116. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  117. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  118. data/lib/splitclient-rb/engine/parser/condition.rb +81 -20
  119. data/lib/splitclient-rb/engine/parser/evaluator.rb +40 -51
  120. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  121. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  122. data/lib/splitclient-rb/engine/sync_manager.rb +180 -0
  123. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  124. data/lib/splitclient-rb/exceptions.rb +20 -1
  125. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  126. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  127. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  128. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  129. data/lib/splitclient-rb/helpers/util.rb +26 -0
  130. data/lib/splitclient-rb/managers/split_manager.rb +58 -20
  131. data/lib/splitclient-rb/spec.rb +9 -0
  132. data/lib/splitclient-rb/split_config.rb +336 -54
  133. data/lib/splitclient-rb/split_factory.rb +219 -33
  134. data/lib/splitclient-rb/split_factory_builder.rb +1 -22
  135. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  136. data/lib/splitclient-rb/split_logger.rb +9 -10
  137. data/lib/splitclient-rb/sse/event_source/client.rb +263 -0
  138. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  139. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  140. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  141. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  142. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  143. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  144. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  145. data/lib/splitclient-rb/sse/workers/splits_worker.rb +149 -0
  146. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  147. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  148. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  149. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  150. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  151. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  152. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  153. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  154. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  155. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  156. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  157. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  158. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  159. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  160. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  161. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  162. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  163. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  164. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  165. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  166. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  167. data/lib/splitclient-rb/utilitites.rb +8 -0
  168. data/lib/splitclient-rb/validators.rb +142 -38
  169. data/lib/splitclient-rb/version.rb +1 -1
  170. data/lib/splitclient-rb.rb +101 -16
  171. data/sonar-project.properties +6 -0
  172. data/splitclient-rb.gemspec +28 -23
  173. metadata +262 -82
  174. data/.travis.yml +0 -11
  175. data/Appraisals +0 -10
  176. data/Detailed-README.md +0 -588
  177. data/NEWS +0 -141
  178. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -127
  179. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -96
  180. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -21
  181. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -56
  182. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +0 -46
  183. data/lib/splitclient-rb/cache/stores/segment_store.rb +0 -81
  184. data/lib/splitclient-rb/cache/stores/split_store.rb +0 -102
  185. data/lib/splitclient-rb/clients/localhost_split_client.rb +0 -183
  186. data/lib/splitclient-rb/engine/api/faraday_adapter/patched_net_http_persistent.rb +0 -46
  187. data/lib/splitclient-rb/engine/api/metrics.rb +0 -60
  188. data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
  189. data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -81
  190. data/lib/splitclient-rb/localhost_split_factory.rb +0 -13
  191. data/lib/splitclient-rb/localhost_utils.rb +0 -59
  192. data/lib/splitclient-rb/managers/localhost_split_manager.rb +0 -60
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class MemorySynchronizer
6
+ def initialize(config,
7
+ telemtry_consumers,
8
+ repositories,
9
+ telemetry_api,
10
+ flag_sets,
11
+ flag_sets_invalid)
12
+ @config = config
13
+ @telemetry_init_consumer = telemtry_consumers[:init]
14
+ @telemetry_runtime_consumer = telemtry_consumers[:runtime]
15
+ @telemtry_evaluation_consumer = telemtry_consumers[:evaluation]
16
+ @splits_repository = repositories[:splits]
17
+ @segments_repository = repositories[:segments]
18
+ @telemetry_api = telemetry_api
19
+ @flag_sets = flag_sets
20
+ @flag_sets_invalid = flag_sets_invalid
21
+ end
22
+
23
+ def synchronize_stats
24
+ usage = Usage.new(@telemetry_runtime_consumer.last_synchronizations,
25
+ @telemtry_evaluation_consumer.pop_latencies,
26
+ @telemtry_evaluation_consumer.pop_exceptions,
27
+ @telemetry_runtime_consumer.pop_http_errors,
28
+ @telemetry_runtime_consumer.pop_http_latencies,
29
+ @telemetry_runtime_consumer.pop_token_refreshes,
30
+ @telemetry_runtime_consumer.pop_auth_rejections,
31
+ @telemetry_runtime_consumer.impressions_stats(Domain::Constants::IMPRESSIONS_QUEUED),
32
+ @telemetry_runtime_consumer.impressions_stats(Domain::Constants::IMPRESSIONS_DEDUPE),
33
+ @telemetry_runtime_consumer.impressions_stats(Domain::Constants::IMPRESSIONS_DROPPED),
34
+ @splits_repository.splits_count,
35
+ @segments_repository.segments_count,
36
+ @segments_repository.segment_keys_count,
37
+ @telemetry_runtime_consumer.session_length,
38
+ @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_QUEUED),
39
+ @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_DROPPED),
40
+ @telemetry_runtime_consumer.pop_streaming_events,
41
+ @telemetry_runtime_consumer.pop_tags,
42
+ @telemetry_runtime_consumer.pop_updates_from_sse)
43
+
44
+ @telemetry_api.record_stats(format_stats(usage))
45
+ rescue StandardError => e
46
+ @config.log_found_exception(__method__.to_s, e)
47
+ end
48
+
49
+ def synchronize_config(active_factories = nil, redundant_active_factories = nil, time_until_ready = nil)
50
+ rates = Rates.new(@config.features_refresh_rate,
51
+ @config.segments_refresh_rate,
52
+ @config.impressions_refresh_rate,
53
+ @config.events_push_rate,
54
+ @config.telemetry_refresh_rate)
55
+
56
+ url_overrides = UrlOverrides.new(@config.base_uri != SplitConfig.default_base_uri.chomp('/'),
57
+ @config.events_uri != SplitConfig.default_events_uri.chomp('/'),
58
+ @config.auth_service_url != SplitConfig.default_auth_service_url,
59
+ @config.streaming_service_url != SplitConfig.default_streaming_service_url,
60
+ @config.telemetry_service_url != SplitConfig.default_telemetry_service_url)
61
+
62
+ active_factories ||= SplitIoClient.split_factory_registry.active_factories
63
+ redundant_active_factories ||= SplitIoClient.split_factory_registry.redundant_active_factories
64
+ time_until_ready ||= ((Time.now.to_f - @config.sdk_start_time) * 1000.0).to_i
65
+
66
+ init_config = ConfigInit.new(mode,
67
+ 'memory',
68
+ active_factories,
69
+ redundant_active_factories,
70
+ @telemetry_runtime_consumer.pop_tags,
71
+ @flag_sets,
72
+ @flag_sets_invalid,
73
+ @config.streaming_enabled,
74
+ rates,
75
+ url_overrides,
76
+ @config.impressions_queue_size,
77
+ @config.events_queue_size,
78
+ impressions_mode,
79
+ !@config.impression_listener.nil?,
80
+ http_proxy_detected?,
81
+ time_until_ready,
82
+ @telemetry_init_consumer.bur_timeouts,
83
+ @telemetry_init_consumer.non_ready_usages)
84
+
85
+ @telemetry_api.record_init(fornat_init_config(init_config))
86
+ rescue StandardError => e
87
+ @config.log_found_exception(__method__.to_s, e)
88
+ end
89
+
90
+ private
91
+
92
+ def fornat_init_config(init)
93
+ {
94
+ oM: init.om,
95
+ sE: init.se,
96
+ st: init.st,
97
+ rR: {
98
+ sp: init.rr.sp,
99
+ se: init.rr.se,
100
+ im: init.rr.im,
101
+ ev: init.rr.ev,
102
+ te: init.rr.te
103
+ },
104
+ iQ: init.iq,
105
+ eQ: init.eq,
106
+ iM: init.im,
107
+ uO: {
108
+ s: init.uo.s,
109
+ e: init.uo.e,
110
+ a: init.uo.a,
111
+ st: init.uo.st,
112
+ t: init.uo.t
113
+ },
114
+ iL: init.il,
115
+ hP: init.hp,
116
+ aF: init.af,
117
+ rF: init.rf,
118
+ tR: init.tr,
119
+ bT: init.bt,
120
+ nR: init.nr,
121
+ t: init.t,
122
+ i: init.i,
123
+ fsT: init.fsT,
124
+ fsI: init.fsI
125
+ }
126
+ end
127
+
128
+ def format_stats(usage)
129
+ {
130
+ lS: usage.ls.to_h,
131
+ mL: {
132
+ t: usage.ml[Telemetry::Domain::Constants::TREATMENT],
133
+ ts: usage.ml[Telemetry::Domain::Constants::TREATMENTS],
134
+ tc: usage.ml[Telemetry::Domain::Constants::TREATMENT_WITH_CONFIG],
135
+ tcs: usage.ml[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG],
136
+ tf: usage.ml[Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SET],
137
+ tfs: usage.ml[Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SETS],
138
+ tcf: usage.ml[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET],
139
+ tcfs: usage.ml[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS],
140
+ tr: usage.ml[Telemetry::Domain::Constants::TRACK]
141
+ },
142
+ mE: {
143
+ t: usage.me[Telemetry::Domain::Constants::TREATMENT],
144
+ ts: usage.me[Telemetry::Domain::Constants::TREATMENTS],
145
+ tc: usage.me[Telemetry::Domain::Constants::TREATMENT_WITH_CONFIG],
146
+ tcs: usage.me[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG],
147
+ tf: usage.me[Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SET],
148
+ tfs: usage.me[Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SETS],
149
+ tcf: usage.me[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET],
150
+ tcfs: usage.me[Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS],
151
+ tr: usage.me[Telemetry::Domain::Constants::TRACK]
152
+ },
153
+ hE: {
154
+ sp: usage.he.sp,
155
+ se: usage.he.se,
156
+ im: usage.he.im,
157
+ ic: usage.he.ic,
158
+ ev: usage.he.ev,
159
+ te: usage.he.te,
160
+ to: usage.he.to
161
+ },
162
+ hL: {
163
+ sp: usage.hl.sp,
164
+ se: usage.hl.se,
165
+ im: usage.hl.im,
166
+ ic: usage.hl.ic,
167
+ ev: usage.hl.ev,
168
+ te: usage.hl.te,
169
+ to: usage.hl.to
170
+ },
171
+ tR: usage.tr,
172
+ aR: usage.ar,
173
+ iQ: usage.iq,
174
+ iDe: usage.ide,
175
+ iDr: usage.idr,
176
+ spC: usage.spc,
177
+ seC: usage.sec,
178
+ skC: usage.skc,
179
+ sL: usage.sl,
180
+ eQ: usage.eq,
181
+ eD: usage.ed,
182
+ sE: usage.se,
183
+ t: usage.t,
184
+ ufs: usage.ufs.to_h
185
+ }
186
+ end
187
+
188
+ def http_proxy_detected?
189
+ !ENV['HTTP_PROXY'].nil? || !ENV['HTTPS_PROXY'].nil?
190
+ end
191
+
192
+ def mode
193
+ case @config.mode
194
+ when :customer
195
+ 1
196
+ else
197
+ 0
198
+ end
199
+ end
200
+
201
+ def impressions_mode
202
+ case @config.impressions_mode
203
+ when :optimized
204
+ 0
205
+ when :debug
206
+ 1
207
+ else
208
+ 2
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class RedisEvaluationProducer
6
+ def initialize(config)
7
+ @config = config
8
+ @adapter = config.telemetry_adapter
9
+
10
+ @sdk_version = "#{@config.language}-#{@config.version}"
11
+ @name = @config.machine_name
12
+ @ip = @config.machine_ip
13
+ end
14
+
15
+ def record_latency(method, bucket)
16
+ @adapter.hincrby(latency_key, "#{@sdk_version}/#{@name}/#{@ip}/#{method}/#{bucket}", 1)
17
+ rescue StandardError => e
18
+ @config.log_found_exception(__method__.to_s, e)
19
+ end
20
+
21
+ def record_exception(method)
22
+ @adapter.hincrby(exception_key, "#{@sdk_version}/#{@name}/#{@ip}/#{method}", 1)
23
+ rescue StandardError => e
24
+ @config.log_found_exception(__method__.to_s, e)
25
+ end
26
+
27
+ private
28
+
29
+ def latency_key
30
+ "#{@config.redis_namespace}.telemetry.latencies"
31
+ end
32
+
33
+ def exception_key
34
+ "#{@config.redis_namespace}.telemetry.exceptions"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class RedisInitProducer
6
+ def initialize(config)
7
+ @config = config
8
+ @adapter = config.telemetry_adapter
9
+ end
10
+
11
+ def record_config(config_data)
12
+ return if config_data.nil?
13
+
14
+ data = { t: { oM: config_data.om, st: config_data.st, aF: config_data.af, rF: config_data.rf, t: config_data.t } }
15
+ field = "#{@config.language}-#{@config.version}/#{@config.machine_name}/#{@config.machine_ip}"
16
+
17
+ @adapter.add_to_map(config_key, field, data.to_json)
18
+ rescue StandardError => e
19
+ @config.log_found_exception(__method__.to_s, e)
20
+ end
21
+
22
+ def record_bur_timeout
23
+ # no-op
24
+ end
25
+
26
+ def record_non_ready_usages
27
+ # no-op
28
+ end
29
+
30
+ private
31
+
32
+ def config_key
33
+ "#{@config.redis_namespace}.telemetry.init"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class RedisSynchronizer
6
+ def initialize(config,
7
+ telemetry_init_producer)
8
+ @config = config
9
+ @telemetry_init_producer = telemetry_init_producer
10
+ end
11
+
12
+ def synchronize_stats
13
+ # No-op
14
+ end
15
+
16
+ def synchronize_config(active_factories = nil, redundant_active_factories = nil, tags = nil)
17
+ active_factories ||= SplitIoClient.split_factory_registry.active_factories
18
+ redundant_active_factories ||= SplitIoClient.split_factory_registry.redundant_active_factories
19
+
20
+ init_config = ConfigInit.new(@config.mode, 'redis', active_factories, redundant_active_factories, tags)
21
+ @telemetry_init_producer.record_config(init_config)
22
+ rescue StandardError => e
23
+ @config.log_found_exception(__method__.to_s, e)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class RuntimeConsumer
6
+ extend Forwardable
7
+ def_delegators :@runtime,
8
+ :pop_tags,
9
+ :impressions_stats,
10
+ :events_stats,
11
+ :last_synchronizations,
12
+ :pop_http_errors,
13
+ :pop_http_latencies,
14
+ :pop_auth_rejections,
15
+ :pop_token_refreshes,
16
+ :pop_streaming_events,
17
+ :session_length,
18
+ :pop_updates_from_sse
19
+
20
+ def initialize(config)
21
+ @runtime = SplitIoClient::Telemetry::MemoryRuntimeConsumer.new(config)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class RuntimeProducer
6
+ extend Forwardable
7
+ def_delegators :@runtime,
8
+ :add_tag,
9
+ :record_impressions_stats,
10
+ :record_events_stats,
11
+ :record_successful_sync,
12
+ :record_sync_error,
13
+ :record_sync_latency,
14
+ :record_auth_rejections,
15
+ :record_token_refreshes,
16
+ :record_streaming_event,
17
+ :record_session_length,
18
+ :record_updates_from_sse
19
+
20
+ def initialize(config)
21
+ @runtime = SplitIoClient::Telemetry::MemoryRuntimeProducer.new(config)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ module Storages
6
+ class Memory
7
+ attr_reader :latencies,
8
+ :exceptions,
9
+ :factory_counters,
10
+ :tags,
11
+ :impressions_data_records,
12
+ :events_data_records,
13
+ :last_synchronization,
14
+ :http_errors,
15
+ :http_latencies,
16
+ :auth_rejections,
17
+ :token_refreshes,
18
+ :streaming_events,
19
+ :session_length,
20
+ :updates_from_sse
21
+
22
+ def initialize
23
+ init_latencies
24
+ init_exceptions
25
+ init_factory_counters
26
+ init_impressions_data_records
27
+ init_events_data_records
28
+ init_last_synchronization
29
+ init_http_errors
30
+ init_http_latencies
31
+ init_auth_rejections
32
+ init_token_refreshes
33
+ init_streaming_events
34
+ init_session_length
35
+ init_tags
36
+ init_updates_from_sse
37
+ end
38
+
39
+ def init_latencies
40
+ @latencies = Concurrent::Array.new
41
+ treatment_with_config_by_flag_set_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET
42
+ treatment_with_config_by_flag_sets_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
43
+
44
+ array_size = BinarySearchLatencyTracker::BUCKETS.length
45
+ @latencies << { method: Domain::Constants::TREATMENT, latencies: Concurrent::Array.new(array_size, 0) }
46
+ @latencies << { method: Domain::Constants::TREATMENTS, latencies: Concurrent::Array.new(array_size, 0) }
47
+ @latencies << { method: Domain::Constants::TREATMENT_WITH_CONFIG, latencies: Concurrent::Array.new(array_size, 0) }
48
+ @latencies << { method: Domain::Constants::TREATMENTS_WITH_CONFIG, latencies: Concurrent::Array.new(array_size, 0) }
49
+ @latencies << { method: Domain::Constants::TREATMENTS_BY_FLAG_SET, latencies: Concurrent::Array.new(array_size, 0) }
50
+ @latencies << { method: Domain::Constants::TREATMENTS_BY_FLAG_SETS, latencies: Concurrent::Array.new(array_size, 0) }
51
+ @latencies << { method: treatment_with_config_by_flag_set_const, latencies: Concurrent::Array.new(array_size, 0) }
52
+ @latencies << { method: treatment_with_config_by_flag_sets_const, latencies: Concurrent::Array.new(array_size, 0) }
53
+ @latencies << { method: Domain::Constants::TRACK, latencies: Concurrent::Array.new(array_size, 0) }
54
+ end
55
+
56
+ def init_exceptions
57
+ @exceptions = Concurrent::Array.new
58
+ treatment_with_config_by_flag_set_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET
59
+ treatment_with_config_by_flag_sets_const = Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
60
+
61
+ @exceptions << { method: Domain::Constants::TREATMENT, exceptions: Concurrent::AtomicFixnum.new(0) }
62
+ @exceptions << { method: Domain::Constants::TREATMENTS, exceptions: Concurrent::AtomicFixnum.new(0) }
63
+ @exceptions << { method: Domain::Constants::TREATMENT_WITH_CONFIG, exceptions: Concurrent::AtomicFixnum.new(0) }
64
+ @exceptions << { method: Domain::Constants::TREATMENTS_WITH_CONFIG, exceptions: Concurrent::AtomicFixnum.new(0) }
65
+ @exceptions << { method: Domain::Constants::TREATMENTS_BY_FLAG_SET, exceptions: Concurrent::AtomicFixnum.new(0) }
66
+ @exceptions << { method: Domain::Constants::TREATMENTS_BY_FLAG_SETS, exceptions: Concurrent::AtomicFixnum.new(0) }
67
+ @exceptions << { method: treatment_with_config_by_flag_set_const, exceptions: Concurrent::AtomicFixnum.new(0) }
68
+ @exceptions << { method: treatment_with_config_by_flag_sets_const, exceptions: Concurrent::AtomicFixnum.new(0) }
69
+ @exceptions << { method: Domain::Constants::TRACK, exceptions: Concurrent::AtomicFixnum.new(0) }
70
+ end
71
+
72
+ def init_factory_counters
73
+ @factory_counters = Concurrent::Array.new
74
+
75
+ @factory_counters << { action: Domain::Constants::BUR_TIMEOUT, counts: Concurrent::AtomicFixnum.new(0) }
76
+ @factory_counters << { action: Domain::Constants::NON_READY_USAGES, counts: Concurrent::AtomicFixnum.new(0) }
77
+ end
78
+
79
+ def init_impressions_data_records
80
+ @impressions_data_records = Concurrent::Array.new
81
+
82
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_DEDUPE, value: Concurrent::AtomicFixnum.new(0) }
83
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_DROPPED, value: Concurrent::AtomicFixnum.new(0) }
84
+ @impressions_data_records << { type: Domain::Constants::IMPRESSIONS_QUEUED, value: Concurrent::AtomicFixnum.new(0) }
85
+ end
86
+
87
+ def init_events_data_records
88
+ @events_data_records = Concurrent::Array.new
89
+
90
+ @events_data_records << { type: Domain::Constants::EVENTS_DROPPED, value: Concurrent::AtomicFixnum.new(0) }
91
+ @events_data_records << { type: Domain::Constants::EVENTS_QUEUED, value: Concurrent::AtomicFixnum.new(0) }
92
+ end
93
+
94
+ def init_last_synchronization
95
+ @last_synchronization = Concurrent::Array.new
96
+
97
+ @last_synchronization << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
98
+ @last_synchronization << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
99
+ @last_synchronization << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
100
+ @last_synchronization << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::AtomicFixnum.new(0) }
101
+ @last_synchronization << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::AtomicFixnum.new(0) }
102
+ @last_synchronization << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::AtomicFixnum.new(0) }
103
+ @last_synchronization << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::AtomicFixnum.new(0) }
104
+ end
105
+
106
+ def init_tags
107
+ @tags = Concurrent::Array.new
108
+ end
109
+
110
+ def init_http_errors
111
+ @http_errors = Concurrent::Array.new
112
+
113
+ @http_errors << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::Hash.new }
114
+ @http_errors << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::Hash.new }
115
+ @http_errors << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::Hash.new }
116
+ @http_errors << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::Hash.new }
117
+ @http_errors << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::Hash.new }
118
+ @http_errors << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::Hash.new }
119
+ @http_errors << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::Hash.new }
120
+ end
121
+
122
+ def init_http_latencies
123
+ @http_latencies = Concurrent::Array.new
124
+
125
+ array_size = BinarySearchLatencyTracker::BUCKETS.length
126
+ @http_latencies << { type: Domain::Constants::SPLIT_SYNC, value: Concurrent::Array.new(array_size, 0) }
127
+ @http_latencies << { type: Domain::Constants::SEGMENT_SYNC, value: Concurrent::Array.new(array_size, 0) }
128
+ @http_latencies << { type: Domain::Constants::EVENT_SYNC, value: Concurrent::Array.new(array_size, 0) }
129
+ @http_latencies << { type: Domain::Constants::IMPRESSION_COUNT_SYNC, value: Concurrent::Array.new(array_size, 0) }
130
+ @http_latencies << { type: Domain::Constants::IMPRESSIONS_SYNC, value: Concurrent::Array.new(array_size, 0) }
131
+ @http_latencies << { type: Domain::Constants::TELEMETRY_SYNC, value: Concurrent::Array.new(array_size, 0) }
132
+ @http_latencies << { type: Domain::Constants::TOKEN_SYNC, value: Concurrent::Array.new(array_size, 0) }
133
+ end
134
+
135
+ def init_auth_rejections
136
+ @auth_rejections = Concurrent::AtomicFixnum.new(0)
137
+ end
138
+
139
+ def init_token_refreshes
140
+ @token_refreshes = Concurrent::AtomicFixnum.new(0)
141
+ end
142
+
143
+ def init_streaming_events
144
+ @streaming_events = Concurrent::Array.new
145
+ end
146
+
147
+ def init_session_length
148
+ @session_length = Concurrent::AtomicFixnum.new(0)
149
+ end
150
+
151
+ def init_updates_from_sse
152
+ @updates_from_sse = Concurrent::Hash.new
153
+
154
+ @updates_from_sse[Domain::Constants::SPLITS] = 0
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class SyncTask
6
+ def initialize(config, telemetry_synchronizer)
7
+ @config = config
8
+ @telemetry_synchronizer = telemetry_synchronizer
9
+ end
10
+
11
+ def call
12
+ stats_thread
13
+ end
14
+
15
+ private
16
+
17
+ def stats_thread
18
+ @config.threads[:telemetry_stats_sender] = Thread.new { telemetry_sync_task }
19
+ end
20
+
21
+ def telemetry_sync_task
22
+ @config.logger.info('Starting Telemetry Sync Task')
23
+
24
+ loop do
25
+ sleep(@config.telemetry_refresh_rate)
26
+
27
+ @telemetry_synchronizer.synchronize_stats
28
+ end
29
+ rescue SplitIoClient::SDKShutdownException
30
+ @telemetry_synchronizer.synchronize_stats
31
+
32
+ @config.logger.info('Posting Telemetry due to shutdown')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Telemetry
5
+ class Synchronizer
6
+ extend Forwardable
7
+ def_delegators :@synchronizer,
8
+ :synchronize_config,
9
+ :synchronize_stats
10
+
11
+ def initialize(config,
12
+ telemtry_consumers,
13
+ telemetry_init_producer,
14
+ repositories,
15
+ telemetry_api,
16
+ flag_sets,
17
+ flag_sets_invalid)
18
+ @synchronizer = case config.telemetry_adapter.class.to_s
19
+ when 'SplitIoClient::Cache::Adapters::RedisAdapter'
20
+ SplitIoClient::Telemetry::RedisSynchronizer.new(config,
21
+ telemetry_init_producer)
22
+ else
23
+ SplitIoClient::Telemetry::MemorySynchronizer.new(config,
24
+ telemtry_consumers,
25
+ repositories,
26
+ telemetry_api,
27
+ flag_sets,
28
+ flag_sets_invalid)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -37,5 +37,13 @@ module SplitIoClient
37
37
 
38
38
  interval * random_factor
39
39
  end
40
+
41
+ def split_bulk_to_send(items, divisions)
42
+ to_return = []
43
+ items.to_a.each_slice(divisions) {|bulk|
44
+ to_return.push(bulk.to_set)
45
+ }
46
+ to_return
47
+ end
40
48
  end
41
49
  end