configcat 5.0.2 → 6.0.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.
- checksums.yaml +4 -4
- data/lib/configcat/configcache.rb +19 -4
- data/lib/configcat/configcatclient.rb +263 -107
- data/lib/configcat/configcatlogger.rb +24 -0
- data/lib/configcat/configcatoptions.rb +153 -0
- data/lib/configcat/configentry.rb +40 -0
- data/lib/configcat/configfetcher.rb +98 -40
- data/lib/configcat/configservice.rb +212 -0
- data/lib/configcat/evaluationdetails.rb +23 -0
- data/lib/configcat/interfaces.rb +4 -59
- data/lib/configcat/localdictionarydatasource.rb +14 -4
- data/lib/configcat/localfiledatasource.rb +22 -11
- data/lib/configcat/overridedatasource.rb +8 -2
- data/lib/configcat/pollingmode.rb +62 -0
- data/lib/configcat/refreshresult.rb +3 -0
- data/lib/configcat/rolloutevaluator.rb +32 -37
- data/lib/configcat/user.rb +18 -39
- data/lib/configcat/utils.rb +10 -0
- data/lib/configcat/version.rb +1 -1
- data/lib/configcat.rb +128 -136
- metadata +24 -5
- data/lib/configcat/autopollingcachepolicy.rb +0 -99
- data/lib/configcat/lazyloadingcachepolicy.rb +0 -69
- data/lib/configcat/manualpollingcachepolicy.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce490d2a3a5e6bc5762305dbd0740f2658b5e316a514306a7ab2061ccafe4382
|
4
|
+
data.tar.gz: c4ed8386bb8644fa723f82a677f64fe60c7dab44aa03eacceeec965231402d82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f80a0a78a5d0023de47a59eafc4fbb18ba40cbab7302bd260cd54b6b383113039a1a087b74cf72657e49bfcc1af84afd9d76d220c9696807f600dd4c393d1a4
|
7
|
+
data.tar.gz: 134cf29821feeb9f23debde30ede59545a45da81c8d8a0100a4684d01909c84f67c48d5029ca5734a618d226e55411f35fc6f412710b668b6b62f1ca15f82635
|
@@ -1,17 +1,32 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
2
|
|
3
3
|
module ConfigCat
|
4
|
+
class NullConfigCache < ConfigCache
|
5
|
+
def initialize
|
6
|
+
@value = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(key)
|
10
|
+
return nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def set(key, value)
|
14
|
+
# do nothing
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
4
18
|
class InMemoryConfigCache < ConfigCache
|
5
|
-
|
6
|
-
|
19
|
+
attr_reader :value
|
20
|
+
def initialize
|
21
|
+
@value = {}
|
7
22
|
end
|
8
23
|
|
9
24
|
def get(key)
|
10
|
-
return @
|
25
|
+
return @value.fetch(key, nil)
|
11
26
|
end
|
12
27
|
|
13
28
|
def set(key, value)
|
14
|
-
@
|
29
|
+
@value[key] = value
|
15
30
|
end
|
16
31
|
end
|
17
32
|
end
|
@@ -1,114 +1,182 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
2
|
require 'configcat/configcache'
|
3
|
+
require 'configcat/configcatoptions'
|
3
4
|
require 'configcat/configfetcher'
|
4
|
-
require 'configcat/autopollingcachepolicy'
|
5
|
-
require 'configcat/manualpollingcachepolicy'
|
6
|
-
require 'configcat/lazyloadingcachepolicy'
|
7
5
|
require 'configcat/rolloutevaluator'
|
8
|
-
require 'configcat/
|
6
|
+
require 'configcat/utils'
|
7
|
+
require 'configcat/configcatlogger'
|
8
|
+
require 'configcat/overridedatasource'
|
9
|
+
require 'configcat/configservice'
|
10
|
+
require 'configcat/evaluationdetails'
|
9
11
|
|
10
12
|
|
11
13
|
module ConfigCat
|
12
14
|
KeyValue = Struct.new(:key, :value)
|
13
15
|
class ConfigCatClient
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
attr_reader :log, :hooks
|
17
|
+
|
18
|
+
@@lock = Mutex.new
|
19
|
+
@@instances = {}
|
20
|
+
|
21
|
+
# Creates a new or gets an already existing `ConfigCatClient` for the given `sdk_key`.
|
22
|
+
#
|
23
|
+
# :param sdk_key [String] ConfigCat SDK Key to access your configuration.
|
24
|
+
# :param options [ConfigCatOptions] Configuration for `ConfigCatClient`.
|
25
|
+
# :return [ConfigCatClient] the `ConfigCatClient` instance.
|
26
|
+
def self.get(sdk_key, options = nil)
|
27
|
+
@@lock.synchronize do
|
28
|
+
client = @@instances[sdk_key]
|
29
|
+
if client
|
30
|
+
if options
|
31
|
+
client.log.warn("Client for sdk_key `#{sdk_key}` is already created and will be reused; " +
|
32
|
+
"options passed are being ignored.")
|
33
|
+
end
|
34
|
+
return client
|
35
|
+
end
|
36
|
+
|
37
|
+
options ||= ConfigCatOptions.new
|
38
|
+
client = ConfigCatClient.new(sdk_key, options)
|
39
|
+
@@instances[sdk_key] = client
|
40
|
+
return client
|
33
41
|
end
|
42
|
+
end
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
# Closes all ConfigCatClient instances.
|
45
|
+
def self.close_all
|
46
|
+
@@lock.synchronize do
|
47
|
+
@@instances.each do |key, value|
|
48
|
+
value.send(:_close_resources)
|
49
|
+
end
|
50
|
+
@@instances.clear
|
41
51
|
end
|
52
|
+
end
|
42
53
|
|
43
|
-
|
44
|
-
@
|
54
|
+
private def initialize(sdk_key, options = ConfigCatOptions.new)
|
55
|
+
@hooks = options.hooks || Hooks.new
|
56
|
+
@log = ConfigCatLogger.new(@hooks)
|
45
57
|
|
46
|
-
if
|
47
|
-
|
58
|
+
if sdk_key === nil
|
59
|
+
raise ConfigCatClientException, "SDK Key is required."
|
60
|
+
end
|
61
|
+
|
62
|
+
@_sdk_key = sdk_key
|
63
|
+
@_default_user = options.default_user
|
64
|
+
@_rollout_evaluator = RolloutEvaluator.new(@log)
|
65
|
+
if options.flag_overrides
|
66
|
+
@_override_data_source = options.flag_overrides.create_data_source(@log)
|
48
67
|
else
|
49
|
-
@
|
68
|
+
@_override_data_source = nil
|
50
69
|
end
|
51
70
|
|
52
|
-
|
71
|
+
config_cache = options.config_cache.nil? ? NullConfigCache.new : options.config_cache
|
72
|
+
|
73
|
+
if @_override_data_source && @_override_data_source.get_behaviour() == OverrideBehaviour::LOCAL_ONLY
|
53
74
|
@_config_fetcher = nil
|
54
|
-
@
|
55
|
-
elsif poll_interval_seconds > 0
|
56
|
-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "a", base_url: base_url,
|
57
|
-
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
|
58
|
-
open_timeout: open_timeout, read_timeout: read_timeout,
|
59
|
-
data_governance: data_governance)
|
60
|
-
@_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
|
61
|
-
elsif cache_time_to_live_seconds > 0
|
62
|
-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url: base_url,
|
63
|
-
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
|
64
|
-
open_timeout: open_timeout, read_timeout: read_timeout,
|
65
|
-
data_governance: data_governance)
|
66
|
-
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
|
75
|
+
@_config_service = nil
|
67
76
|
else
|
68
|
-
@_config_fetcher =
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
77
|
+
@_config_fetcher = ConfigFetcher.new(@_sdk_key,
|
78
|
+
@log,
|
79
|
+
options.polling_mode.identifier,
|
80
|
+
base_url: options.base_url,
|
81
|
+
proxy_address: options.proxy_address,
|
82
|
+
proxy_port: options.proxy_port,
|
83
|
+
proxy_user: options.proxy_user,
|
84
|
+
proxy_pass: options.proxy_pass,
|
85
|
+
open_timeout: options.open_timeout_seconds,
|
86
|
+
read_timeout: options.read_timeout_seconds,
|
87
|
+
data_governance: options.data_governance)
|
88
|
+
|
89
|
+
@_config_service = ConfigService.new(@sdk_key,
|
90
|
+
options.polling_mode,
|
91
|
+
@hooks,
|
92
|
+
@_config_fetcher,
|
93
|
+
@log,
|
94
|
+
config_cache,
|
95
|
+
options.offline)
|
73
96
|
end
|
74
97
|
end
|
75
98
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
99
|
+
# Gets the value of a feature flag or setting identified by the given `key`.
|
100
|
+
#
|
101
|
+
# :param key [String] the identifier of the feature flag or setting.
|
102
|
+
# :param default_value in case of any failure, this value will be returned.
|
103
|
+
# :param user [User] the user object to identify the caller.
|
104
|
+
# :return the value.
|
105
|
+
def get_value(key, default_value, user = nil)
|
106
|
+
settings, fetch_time = _get_settings()
|
107
|
+
if settings.nil?
|
108
|
+
message = "Evaluating get_value('%s') failed. Cache is empty. " \
|
109
|
+
"Returning default_value in your get_value call: [%s]." % [key, default_value.to_s]
|
110
|
+
@log.error(message)
|
111
|
+
@hooks.invoke_on_flag_evaluated(EvaluationDetails.from_error(key, default_value, error: message))
|
81
112
|
return default_value
|
82
113
|
end
|
83
|
-
|
84
|
-
return value
|
114
|
+
details = _evaluate(key, user, default_value, nil, settings, fetch_time)
|
115
|
+
return details.value
|
85
116
|
end
|
86
117
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
118
|
+
# Gets the value and evaluation details of a feature flag or setting identified by the given `key`.
|
119
|
+
#
|
120
|
+
# :param key [String] the identifier of the feature flag or setting.
|
121
|
+
# :param default_value in case of any failure, this value will be returned.
|
122
|
+
# :param user [User] the user object to identify the caller.
|
123
|
+
# :return [EvaluationDetails] the evaluation details.
|
124
|
+
def get_value_details(key, default_value, user = nil)
|
125
|
+
settings, fetch_time = _get_settings()
|
126
|
+
if settings.nil?
|
127
|
+
message = "Evaluating get_value_details('%s') failed. Cache is empty. " \
|
128
|
+
"Returning default_value in your get_value_details call: [%s]." % [key, default_value.to_s]
|
129
|
+
@log.error(message)
|
130
|
+
@hooks.invoke_on_flag_evaluated(EvaluationDetails.from_error(key, default_value, error: message))
|
131
|
+
return default_value
|
91
132
|
end
|
92
|
-
|
93
|
-
|
133
|
+
details = _evaluate(key, user, default_value, nil, settings, fetch_time)
|
134
|
+
return details
|
135
|
+
end
|
136
|
+
|
137
|
+
# Gets all setting keys.
|
138
|
+
#
|
139
|
+
# :return list of keys.
|
140
|
+
def get_all_keys
|
141
|
+
settings, _ = _get_settings()
|
142
|
+
if settings === nil
|
94
143
|
return []
|
95
144
|
end
|
96
|
-
return
|
145
|
+
return settings.keys
|
97
146
|
end
|
98
147
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
148
|
+
# Gets the Variation ID (analytics) of a feature flag or setting based on it's key.
|
149
|
+
#
|
150
|
+
# :param key [String] the identifier of the feature flag or setting.
|
151
|
+
# :param default_variation_id in case of any failure, this value will be returned.
|
152
|
+
# :param user [User] the user object to identify the caller.
|
153
|
+
# :return the variation ID.
|
154
|
+
def get_variation_id(key, default_variation_id, user = nil)
|
155
|
+
@log.warn("get_variation_id is deprecated and will be removed in a future major version. "\
|
156
|
+
"Please use [get_value_details] instead.")
|
157
|
+
|
158
|
+
settings, fetch_time = _get_settings()
|
159
|
+
if settings === nil
|
160
|
+
message = "Evaluating get_variation_id('%s') failed. Cache is empty. "\
|
161
|
+
"Returning default_variation_id in your get_variation_id call: [%s]." %
|
162
|
+
[key, default_variation_id.to_s]
|
163
|
+
@log.error(message)
|
164
|
+
@hooks.invoke_on_flag_evaluated(EvaluationDetails.from_error(key, nil, error: message,
|
165
|
+
variation_id: default_variation_id))
|
105
166
|
return default_variation_id
|
106
167
|
end
|
107
|
-
|
108
|
-
return variation_id
|
168
|
+
details = _evaluate(key, user, nil, default_variation_id, settings, fetch_time)
|
169
|
+
return details.variation_id
|
109
170
|
end
|
110
171
|
|
111
|
-
|
172
|
+
# Gets the Variation IDs (analytics) of all feature flags or settings.
|
173
|
+
#
|
174
|
+
# :param user [User] the user object to identify the caller.
|
175
|
+
# :return list of variation IDs
|
176
|
+
def get_all_variation_ids(user = nil)
|
177
|
+
@log.warn("get_all_variation_ids is deprecated and will be removed in a future major version. "\
|
178
|
+
"Please use [get_value_details] instead.")
|
179
|
+
|
112
180
|
keys = get_all_keys()
|
113
181
|
variation_ids = []
|
114
182
|
for key in keys
|
@@ -120,20 +188,18 @@ module ConfigCat
|
|
120
188
|
return variation_ids
|
121
189
|
end
|
122
190
|
|
191
|
+
# Gets the key of a setting, and it's value identified by the given Variation ID (analytics)
|
192
|
+
#
|
193
|
+
# :param variation_id [String] variation ID
|
194
|
+
# :return key and value
|
123
195
|
def get_key_and_value(variation_id)
|
124
|
-
|
125
|
-
if
|
126
|
-
|
127
|
-
return nil
|
128
|
-
end
|
129
|
-
|
130
|
-
feature_flags = config.fetch(FEATURE_FLAGS, nil)
|
131
|
-
if feature_flags === nil
|
132
|
-
ConfigCat.logger.warn("Evaluating get_key_and_value('%s') failed. Cache is empty. Returning None." % variation_id)
|
196
|
+
settings, _ = _get_settings()
|
197
|
+
if settings === nil
|
198
|
+
@log.warn("Evaluating get_key_and_value('%s') failed. Cache is empty. Returning nil." % variation_id)
|
133
199
|
return nil
|
134
200
|
end
|
135
201
|
|
136
|
-
for key, value in
|
202
|
+
for key, value in settings
|
137
203
|
if variation_id == value.fetch(VARIATION_ID, nil)
|
138
204
|
return KeyValue.new(key, value[VALUE])
|
139
205
|
end
|
@@ -152,9 +218,15 @@ module ConfigCat
|
|
152
218
|
end
|
153
219
|
end
|
154
220
|
end
|
221
|
+
|
222
|
+
@log.error("Could not find the setting for the given variation_id: " + variation_id)
|
155
223
|
end
|
156
224
|
|
157
|
-
|
225
|
+
# Evaluates and returns the values of all feature flags and settings.
|
226
|
+
#
|
227
|
+
# :param user [User] the user object to identify the caller.
|
228
|
+
# :return dictionary of values
|
229
|
+
def get_all_values(user = nil)
|
158
230
|
keys = get_all_keys()
|
159
231
|
all_values = {}
|
160
232
|
for key in keys
|
@@ -166,47 +238,131 @@ module ConfigCat
|
|
166
238
|
return all_values
|
167
239
|
end
|
168
240
|
|
169
|
-
|
170
|
-
|
241
|
+
# Gets the values along with evaluation details of all feature flags and settings.
|
242
|
+
#
|
243
|
+
# :param user [User] the user object to identify the caller.
|
244
|
+
# :return list of all evaluation details
|
245
|
+
def get_all_value_details(user = nil)
|
246
|
+
settings, fetch_time = _get_settings()
|
247
|
+
if settings.nil?
|
248
|
+
@log.error("Evaluating get_all_value_details() failed. Cache is empty. Returning empty list.")
|
249
|
+
return []
|
250
|
+
end
|
251
|
+
|
252
|
+
details_result = []
|
253
|
+
for key in settings.keys
|
254
|
+
details = _evaluate(key, user, nil, nil, settings, fetch_time)
|
255
|
+
details_result.push(details)
|
256
|
+
end
|
257
|
+
|
258
|
+
return details_result
|
259
|
+
end
|
260
|
+
|
261
|
+
# Initiates a force refresh on the cached configuration.
|
262
|
+
#
|
263
|
+
# :return [RefreshResult]
|
264
|
+
def force_refresh
|
265
|
+
return @_config_service.refresh if @_config_service
|
266
|
+
|
267
|
+
return RefreshResult(false,
|
268
|
+
"The SDK uses the LocalOnly flag override behavior which prevents making HTTP requests.")
|
269
|
+
end
|
270
|
+
|
271
|
+
# Sets the default user.
|
272
|
+
#
|
273
|
+
# :param user [User] the user object to identify the caller.
|
274
|
+
def set_default_user(user)
|
275
|
+
@_default_user = user
|
276
|
+
end
|
277
|
+
|
278
|
+
# Sets the default user to nil.
|
279
|
+
def clear_default_user
|
280
|
+
@_default_user = nil
|
171
281
|
end
|
172
282
|
|
173
|
-
|
174
|
-
|
175
|
-
@
|
176
|
-
|
283
|
+
# Configures the SDK to allow HTTP requests.
|
284
|
+
def set_online
|
285
|
+
@_config_service.set_online if @_config_service
|
286
|
+
@log.debug('Switched to ONLINE mode.')
|
287
|
+
end
|
288
|
+
|
289
|
+
# Configures the SDK to not initiate HTTP requests and work only from its cache.
|
290
|
+
def set_offline
|
291
|
+
@_config_service.set_offline if @_config_service
|
292
|
+
@log.debug('Switched to OFFLINE mode.')
|
293
|
+
end
|
294
|
+
|
295
|
+
# Returns true when the SDK is configured not to initiate HTTP requests, otherwise false.
|
296
|
+
def offline?
|
297
|
+
return @_config_service ? @_config_service.offline? : true
|
298
|
+
end
|
299
|
+
|
300
|
+
# Closes the underlying resources.
|
301
|
+
def close
|
302
|
+
@@lock.synchronize do
|
303
|
+
_close_resources
|
304
|
+
@@instances.delete(@_sdk_key)
|
305
|
+
end
|
177
306
|
end
|
178
307
|
|
179
308
|
private
|
180
309
|
|
181
|
-
def
|
310
|
+
def _close_resources
|
311
|
+
@_config_service.close if @_config_service
|
312
|
+
@_config_fetcher.close if @_config_fetcher
|
313
|
+
@hooks.clear
|
314
|
+
end
|
315
|
+
|
316
|
+
def _get_settings
|
182
317
|
if !@_override_data_source.nil?
|
183
318
|
behaviour = @_override_data_source.get_behaviour()
|
184
319
|
if behaviour == OverrideBehaviour::LOCAL_ONLY
|
185
|
-
return @_override_data_source.get_overrides()
|
320
|
+
return @_override_data_source.get_overrides(), Utils::DISTANT_PAST
|
186
321
|
elsif behaviour == OverrideBehaviour::REMOTE_OVER_LOCAL
|
187
|
-
remote_settings = @
|
322
|
+
remote_settings, fetch_time = @_config_service.get_settings()
|
188
323
|
local_settings = @_override_data_source.get_overrides()
|
324
|
+
remote_settings ||= {}
|
325
|
+
local_settings ||= {}
|
189
326
|
result = local_settings.clone()
|
190
|
-
|
191
|
-
|
192
|
-
end
|
193
|
-
return result
|
327
|
+
result.update(remote_settings)
|
328
|
+
return result, fetch_time
|
194
329
|
elsif behaviour == OverrideBehaviour::LOCAL_OVER_REMOTE
|
195
|
-
remote_settings = @
|
330
|
+
remote_settings, fetch_time = @_config_service.get_settings()
|
196
331
|
local_settings = @_override_data_source.get_overrides()
|
332
|
+
remote_settings ||= {}
|
333
|
+
local_settings ||= {}
|
197
334
|
result = remote_settings.clone()
|
198
|
-
|
199
|
-
|
200
|
-
end
|
201
|
-
return result
|
335
|
+
result.update(local_settings)
|
336
|
+
return result, fetch_time
|
202
337
|
end
|
203
338
|
end
|
204
|
-
return @
|
339
|
+
return @_config_service.get_settings()
|
205
340
|
end
|
206
341
|
|
207
|
-
def _get_cache_key
|
342
|
+
def _get_cache_key
|
208
343
|
return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
|
209
344
|
end
|
210
345
|
|
346
|
+
def _evaluate(key, user, default_value, default_variation_id, settings, fetch_time)
|
347
|
+
user = user || @_default_user
|
348
|
+
value, variation_id, rule, percentage_rule, error = @_rollout_evaluator.evaluate(
|
349
|
+
key: key,
|
350
|
+
user: user,
|
351
|
+
default_value: default_value,
|
352
|
+
default_variation_id: default_variation_id,
|
353
|
+
settings: settings)
|
354
|
+
|
355
|
+
details = EvaluationDetails.new(key: key,
|
356
|
+
value: value,
|
357
|
+
variation_id: variation_id,
|
358
|
+
fetch_time: !fetch_time.nil? ? Time.at(fetch_time).utc : nil,
|
359
|
+
user: user,
|
360
|
+
is_default_value: error.nil? || error.empty? ? false : true,
|
361
|
+
error: error,
|
362
|
+
matched_evaluation_rule: rule,
|
363
|
+
matched_evaluation_percentage_rule: percentage_rule)
|
364
|
+
@hooks.invoke_on_flag_evaluated(details)
|
365
|
+
return details
|
366
|
+
end
|
211
367
|
end
|
212
368
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ConfigCat
|
2
|
+
class ConfigCatLogger
|
3
|
+
def initialize(hooks)
|
4
|
+
@hooks = hooks
|
5
|
+
end
|
6
|
+
|
7
|
+
def debug(message)
|
8
|
+
ConfigCat.logger.debug(message)
|
9
|
+
end
|
10
|
+
|
11
|
+
def info(message)
|
12
|
+
ConfigCat.logger.info(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def warn(message)
|
16
|
+
ConfigCat.logger.warn(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
def error(message)
|
20
|
+
@hooks.invoke_on_error(message)
|
21
|
+
ConfigCat.logger.error(message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|