sc4ry 0.1.6 → 0.2.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/.github/workflows/main.yml +27 -0
- data/.gitignore +1 -1
- data/Gemfile +4 -1
- data/README.md +69 -24
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/assets/images/sc4ry_workflow.png +0 -0
- data/lib/sc4ry/backends/memory.rb +35 -8
- data/lib/sc4ry/backends/redis.rb +21 -20
- data/lib/sc4ry/circuits.rb +217 -40
- data/lib/sc4ry/config.rb +91 -0
- data/lib/sc4ry/constants.rb +51 -0
- data/lib/sc4ry/dependencies.rb +12 -3
- data/lib/sc4ry/exceptions.rb +39 -0
- data/lib/sc4ry/helpers.rb +20 -6
- data/lib/sc4ry/logger.rb +45 -9
- data/lib/sc4ry/notifiers/init.rb +41 -14
- data/lib/sc4ry/notifiers/mattermost.rb +26 -18
- data/lib/sc4ry/notifiers/prometheus.rb +7 -1
- data/lib/sc4ry/run_controller.rb +22 -6
- data/lib/sc4ry/store.rb +74 -11
- data/lib/sc4ry/version.rb +7 -1
- data/sc4ry.gemspec +7 -3
- data/ultragreen_roodi_coding_convention.yml +25 -0
- metadata +96 -7
- data/assets/logo_sc4ry.png +0 -0
data/lib/sc4ry/circuits.rb
CHANGED
@@ -1,79 +1,254 @@
|
|
1
|
+
# Sc4ry Module
|
2
|
+
# @note namespace
|
1
3
|
module Sc4ry
|
4
|
+
|
5
|
+
# Circuits and default configuration management class
|
2
6
|
class Circuits
|
3
7
|
|
8
|
+
include Sc4ry::Constants
|
9
|
+
include Sc4ry::Exceptions
|
10
|
+
|
4
11
|
@@circuits_store = Sc4ry::Store.instance
|
12
|
+
@@circuits_notifiers = Sc4ry::Notifiers
|
13
|
+
@@circuits_loggers = Sc4ry::Loggers
|
14
|
+
@@config = DEFAULT_CONFIG
|
15
|
+
|
16
|
+
# @!group forwarders
|
17
|
+
|
18
|
+
# Class method how forward the Notifiers class factory/manager
|
19
|
+
# @return [Sc4ry::Notifiers]
|
20
|
+
def Circuits.notifiers
|
21
|
+
return @@circuits_notifiers
|
22
|
+
end
|
23
|
+
|
24
|
+
# Class method how forward a Store manager class singleton
|
25
|
+
# @return [Sc4ry::Store]
|
26
|
+
def Circuits.store
|
27
|
+
return @@circuits_store
|
28
|
+
end
|
29
|
+
|
30
|
+
# Class method how forward the Logger manager class factory/manager
|
31
|
+
# @return [Sc4ry::Store]
|
32
|
+
def Circuits.loggers
|
33
|
+
return @@circuits_loggers
|
34
|
+
end
|
35
|
+
|
5
36
|
|
6
|
-
@@config = { :max_failure_count => 5,
|
7
|
-
:timeout_value => 20,
|
8
|
-
:timeout => false,
|
9
|
-
:max_timeout_count => 5,
|
10
|
-
:max_time => 10,
|
11
|
-
:max_overtime_count => 3,
|
12
|
-
:check_delay => 30,
|
13
|
-
:notifiers => [],
|
14
|
-
:forward_unknown_exceptions => true,
|
15
|
-
:raise_on_opening => false,
|
16
|
-
:exceptions => [StandardError, RuntimeError]
|
17
|
-
}
|
18
37
|
|
38
|
+
# @!endgroup
|
39
|
+
|
40
|
+
|
41
|
+
# @!group Default Sc4ry configuration management
|
42
|
+
|
43
|
+
# Class method how return de default Sc4ry config
|
44
|
+
# @return [Hash]
|
19
45
|
def Circuits.default_config
|
20
46
|
return @@config
|
21
47
|
end
|
22
48
|
|
49
|
+
# class method how merge a differential hash to default config
|
50
|
+
# @param [Hash] diff the differential hash config
|
51
|
+
# @example usage
|
52
|
+
# include Sc4ry
|
53
|
+
# Circuits.merge_default_config diff: {max_time: 20, notifiers: [:mattermost]}
|
54
|
+
def Circuits.merge_default_config(diff:)
|
55
|
+
validator = Sc4ry::Config::Validator::new(definition: diff, from: @@config)
|
56
|
+
validator.validate!
|
57
|
+
@@config = validator.result
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# class method for specifiying config by block
|
62
|
+
# @yield [Sc4ry::Config::ConfigMapper]
|
63
|
+
# @example usage
|
64
|
+
# include Sc4ry
|
65
|
+
# Circuits.configure do |spec|
|
66
|
+
# spec.max_failure_count = 3
|
67
|
+
# end
|
68
|
+
def Circuits.configure(&bloc)
|
69
|
+
mapper = Sc4ry::Config::ConfigMapper::new(definition: @@config.dup)
|
70
|
+
yield(mapper)
|
71
|
+
validator = Sc4ry::Config::Validator::new(definition: mapper.config, from: @@config)
|
72
|
+
validator.validate!
|
73
|
+
@@config = validator.result
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# old default config setter
|
78
|
+
# @deprecated use {.merge_default_config} instead
|
79
|
+
# @param [Hash] config
|
23
80
|
def Circuits.default_config=(config)
|
24
|
-
|
81
|
+
Sc4ry::Helpers.log level: :warn, message: "DEPRECATED: Circuits.default_config= is deprecated please use Circuits.merge_default_config add: {<config_hash>}"
|
82
|
+
Circuits.merge_default_config(diff: config)
|
25
83
|
end
|
26
84
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
85
|
+
# @!endgroup
|
86
|
+
|
87
|
+
# @!group Circuits management
|
88
|
+
|
89
|
+
# class method for registering a new circuit, cloud work with a block
|
90
|
+
# @yield [Sc4ry::Config::ConfigMapper]
|
91
|
+
# @param [Symbol] circuit a circuit name
|
92
|
+
# @param [Hash] config a config override on default config for the circuit
|
93
|
+
# @example usage
|
94
|
+
# include Sc4ry
|
95
|
+
# Circuits.register circuit: :mycircuit, config: {raise_on_opening: true, timeout: true}
|
96
|
+
# # or
|
97
|
+
# Circuits.register circuit: :mycircuit do |spec|
|
98
|
+
# spec.raise_on_opening = true
|
99
|
+
# spec.timeout = true
|
100
|
+
# end
|
101
|
+
# @return [Hash] the full config of the circuit after merge on default
|
102
|
+
# @raise [Sc4ryGenericError] if use config keyword with a block
|
103
|
+
# @raise [Sc4ryGenericError] if circuit already exist in current store.
|
104
|
+
def Circuits.register(circuit:, config: {})
|
105
|
+
if config.size > 0 and block_given? then
|
106
|
+
raise Sc4ryGenericError, "config: keyword must not be defined when block is given"
|
107
|
+
end
|
108
|
+
if block_given? then
|
109
|
+
mapper = Sc4ry::Config::ConfigMapper::new(definition: @@config.dup)
|
110
|
+
yield(mapper)
|
111
|
+
validator = Sc4ry::Config::Validator::new(definition: mapper.config, from: @@config.dup)
|
112
|
+
else
|
113
|
+
validator = Sc4ry::Config::Validator::new(definition: config, from: @@config.dup )
|
114
|
+
end
|
115
|
+
validator.validate!
|
116
|
+
Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit} : registered"
|
117
|
+
raise Sc4ryGenericError, "Circuit: #{circuit} already exist in store" if @@circuits_store.exist? key: circuit
|
118
|
+
@@circuits_store.put key: circuit, value: validator.result
|
119
|
+
return validator.result
|
33
120
|
end
|
34
121
|
|
122
|
+
# class method how list all circuits in current store
|
123
|
+
# @example usage
|
124
|
+
# include Sc4ry
|
125
|
+
# circuits = Circuits.list
|
126
|
+
# @return [Array] the list of [Symbol] circuits name
|
35
127
|
def Circuits.list
|
36
128
|
return @@circuits_store.list
|
37
129
|
end
|
38
130
|
|
131
|
+
# class method how flush all circuits in current store
|
132
|
+
# @example usage
|
133
|
+
# include Sc4ry
|
134
|
+
# Circuits.flush
|
135
|
+
# @return [true,false]
|
136
|
+
def Circuits.flush
|
137
|
+
return @@circuits_store.flush
|
138
|
+
end
|
39
139
|
|
40
|
-
|
41
|
-
|
140
|
+
# class method for unregistering a circuit
|
141
|
+
# @param [Symbol] circuit a circuit name
|
142
|
+
# @example usage
|
143
|
+
# include Sc4ry
|
144
|
+
# Circuits.unregister circuit: :mycircuit
|
145
|
+
# @raise [Sc4ryGenericError] if circuit not found in current store.
|
146
|
+
# @return [true,false]
|
147
|
+
def Circuits.unregister(circuit:)
|
148
|
+
if Circuits.list.include? circuit then
|
149
|
+
@@circuits_store.del key: circuit
|
150
|
+
return true
|
151
|
+
else
|
152
|
+
raise Sc4ryGenericError, "Circuit #{circuit} not found"
|
153
|
+
return false
|
154
|
+
end
|
42
155
|
end
|
43
156
|
|
44
|
-
|
157
|
+
|
158
|
+
# class method for get a specific circuit by circuit name
|
159
|
+
# @param [Symbol] circuit a circuit name
|
160
|
+
# @example usage
|
161
|
+
# include Sc4ry
|
162
|
+
# Circuits.get circuit: :mycircuit
|
163
|
+
# @return [Hash] the circuit record in current store included values and status if the circuit have already run.
|
164
|
+
def Circuits.get(circuit:)
|
165
|
+
@@circuits_store.get key: circuit
|
166
|
+
end
|
167
|
+
|
168
|
+
# class method for update the config of a specific circuit by circuit name
|
169
|
+
# @param [Symbol] circuit a circuit name
|
170
|
+
# @param [Hash] config a config hash to merge on current config
|
171
|
+
# @example usage
|
172
|
+
# include Sc4ry
|
173
|
+
# Circuits.update_config circuit: :mycircuit, config: {}
|
174
|
+
# @note : <b>important</b> updating config will reset status and values !
|
175
|
+
# @return [Hash] new config for this circuit
|
176
|
+
def Circuits.update_config(circuit: , config: {forward_unknown_exceptions: false})
|
177
|
+
raise Sc4ryGenericError, "Circuit #{circuit} not found" unless Circuits.list.include? circuit
|
178
|
+
save = @@circuits_store.get key: circuit
|
179
|
+
save.delete_if {|key,val| [:status,:values].include? key}
|
180
|
+
Circuits.unregister(circuit: circuit)
|
181
|
+
save.merge! config
|
182
|
+
return Circuits.register circuit: circuit, config: save
|
183
|
+
end
|
184
|
+
|
185
|
+
# class method for get the status of a specific circuit by circuit name
|
186
|
+
# @param [Symbol] circuit a circuit name
|
187
|
+
# @example usage
|
188
|
+
# include Sc4ry
|
189
|
+
# Circuits.status circuit: :mycircuit
|
190
|
+
# @return [Symbol] status must in [:open,:half_open,:closed,:never_run]
|
191
|
+
def Circuits.status(circuit:)
|
192
|
+
data = @@circuits_store.get key: circuit
|
193
|
+
return (data.include? :status)? data[:status][:general] : :never_run
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
# class method for running circuit, need a block
|
198
|
+
# @yield [Proc]
|
199
|
+
# @param [Symbol] circuit a circuit name
|
200
|
+
# @example usage
|
201
|
+
# include Sc4ry
|
202
|
+
# Circuits.run circuit: :mycircuit do
|
203
|
+
# # [...] your code like a Restclient.get("URL")
|
204
|
+
# end
|
205
|
+
# # or
|
206
|
+
# Circuits.run do
|
207
|
+
# # [...] your code like a Restclient.get("URL")
|
208
|
+
# # running with the first define circuit (use only on a one circuit usage)
|
209
|
+
# end
|
210
|
+
# @return [Hash] a result like ":general=>:open, :failure_count=>X, :overtime_count=>X, :timeout_count=>X"
|
211
|
+
# @raise [Sc4ryGenericError] if circuit already not exit, block is missing or store empty
|
212
|
+
def Circuits.run(circuit: nil , &block)
|
45
213
|
circuits_list = Circuits.list
|
46
|
-
raise "No circuit block given" unless block_given?
|
47
|
-
raise "No circuits defined" if circuits_list.empty?
|
48
|
-
circuit_name = (
|
49
|
-
raise "Circuit #{circuit_name} not found" unless circuits_list.include? circuit_name
|
50
|
-
|
214
|
+
raise Sc4ryGenericError, "No circuit block given" unless block_given?
|
215
|
+
raise Sc4ryGenericError, "No circuits defined" if circuits_list.empty?
|
216
|
+
circuit_name = (circuit)? circuit : circuits_list.first
|
217
|
+
raise Sc4ryGenericError, "Circuit #{circuit_name} not found" unless circuits_list.include? circuit_name
|
218
|
+
circuit_to_run = Circuits.get circuit: circuit_name
|
51
219
|
skip = false
|
52
|
-
if
|
53
|
-
if
|
220
|
+
if circuit_to_run.include? :status then
|
221
|
+
if circuit_to_run[:status][:general] == :open then
|
54
222
|
@now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
55
|
-
skip = true if ((@now -
|
223
|
+
skip = true if ((@now - circuit_to_run[:values].last[:end_time]) < circuit_to_run[:check_delay])
|
56
224
|
end
|
57
225
|
end
|
58
226
|
unless skip
|
59
|
-
controller = Sc4ry::RunController.new(
|
227
|
+
controller = Sc4ry::RunController.new(circuit_to_run)
|
60
228
|
Circuits.control circuit: circuit_name, values: controller.run(block: block)
|
61
229
|
end
|
62
|
-
|
63
|
-
|
230
|
+
result = @@circuits_store.get key: circuit_name
|
231
|
+
Sc4ry::Helpers.log level: :debug, message: "Circuit #{circuit_name} : status #{result[:status]}"
|
232
|
+
return result
|
64
233
|
end
|
65
234
|
|
235
|
+
# @!endgroup
|
236
|
+
|
66
237
|
private
|
67
|
-
|
68
|
-
|
238
|
+
# the private class method to control circuits running status
|
239
|
+
# @param [Symbol] circuit the name the circuit to control
|
240
|
+
# @param [Hash] values the resut value of a run
|
241
|
+
# @return [Boolean]
|
242
|
+
def Circuits.control(circuit: , values: )
|
243
|
+
data = @@circuits_store.get key: circuit
|
69
244
|
data[:status] = {:general => :closed, :failure_count => 0, :overtime_count => 0, :timeout_count => 0} unless data.include? :status
|
70
245
|
data[:values] = Array::new unless data.include? :values
|
71
246
|
level = [data[:max_failure_count].to_i, data[:max_timeout_count].to_i, data[:max_overtime_count].to_i].max
|
72
247
|
data[:values].shift if data[:values].size > level
|
73
|
-
data[:values].push
|
248
|
+
data[:values].push values
|
74
249
|
worst_status = []
|
75
250
|
['failure','overtime','timeout'].each do |control|
|
76
|
-
if
|
251
|
+
if values[control.to_sym] == true then
|
77
252
|
data[:status]["#{control}_count".to_sym] += 1
|
78
253
|
else
|
79
254
|
data[:status]["#{control}_count".to_sym] = 0
|
@@ -93,10 +268,12 @@ module Sc4ry
|
|
93
268
|
data[:status][:general] = status if worst_status.include? status
|
94
269
|
end
|
95
270
|
if save != data[:status][:general] then
|
96
|
-
raise
|
97
|
-
Sc4ry::Helpers.
|
271
|
+
raise CircuitBreaked if data[:status][:general] == :open and data[:raise_on_opening]
|
272
|
+
Sc4ry::Helpers.log level: :error, message: "Circuit #{circuit} : breacking ! " if data[:status][:general] == :open
|
273
|
+
Sc4ry::Helpers.log level: :info, message: "Circuit #{circuit} : is now closed" if data[:status][:general] == :closed
|
274
|
+
Sc4ry::Helpers.notify circuit: circuit, config: data
|
98
275
|
end
|
99
|
-
@@circuits_store.put key:
|
276
|
+
@@circuits_store.put key: circuit, value: data
|
100
277
|
end
|
101
278
|
end
|
102
279
|
end
|
data/lib/sc4ry/config.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Sc4ry module
|
2
|
+
# @note namespace
|
3
|
+
module Sc4ry
|
4
|
+
# Sc4ry::Config module
|
5
|
+
# @note namespace
|
6
|
+
module Config
|
7
|
+
# Configuration validator for Sc4ry default and circuits configuration
|
8
|
+
# @private
|
9
|
+
class Validator
|
10
|
+
|
11
|
+
# accessor on Circuit definition given for validation
|
12
|
+
attr_reader :input
|
13
|
+
# accessor on circuit initial definition from default config or given in construction by from keyword
|
14
|
+
# @note altered by reference to final result mapping with {#validate!}
|
15
|
+
attr_reader :config
|
16
|
+
|
17
|
+
def result
|
18
|
+
@config
|
19
|
+
end
|
20
|
+
|
21
|
+
include Sc4ry::Constants
|
22
|
+
include Sc4ry::Exceptions
|
23
|
+
# Validator constructor
|
24
|
+
# @param [Hash] definition the config hash to merge and validate
|
25
|
+
# @param [Hash] from config hash merged on origin (default : the Sc4ry base config from Constants )
|
26
|
+
# @return [Validator] a new instance of Validator
|
27
|
+
def initialize(definition: , from: DEFAULT_CONFIG)
|
28
|
+
@config = from
|
29
|
+
@input = definition
|
30
|
+
end
|
31
|
+
|
32
|
+
# Validation method, alter by reference the config attribut
|
33
|
+
# @raise ConfigError if un unknown key is given in definition to merge.
|
34
|
+
def validate!
|
35
|
+
unknown_keys = @input.keys.difference @config.keys
|
36
|
+
raise ConfigError::new("Unknown keys in config set : #{unknown_keys.to_s}") unless unknown_keys.empty?
|
37
|
+
validate_formats
|
38
|
+
@config.merge! @input
|
39
|
+
format_exceptions
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
# Validation private sub method
|
44
|
+
# @raise ConfigError if proposed values haven't the good format and deeply in array
|
45
|
+
def validate_formats
|
46
|
+
@input.each do |spec,value|
|
47
|
+
raise ConfigError::new("#{spec} value #{DEFAULT_CONFIG_FORMATS[spec][:desc]}") unless DEFAULT_CONFIG_FORMATS[spec][:proc].call(value)
|
48
|
+
if DEFAULT_CONFIG_FORMATS[spec].include? :list then
|
49
|
+
value.each do |item|
|
50
|
+
raise ConfigError::new("#{spec} value must be in #{DEFAULT_CONFIG_FORMATS[spec][:list]}") unless DEFAULT_CONFIG_FORMATS[spec][:list].include? item
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# adapter for exception key in config String to Constant Class Name if need
|
57
|
+
# @note by reference
|
58
|
+
def format_exceptions
|
59
|
+
@config[:exceptions].map! {|item| item = (item.class == String)? Object.const_get(item) : item }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# Config Data mapper for block yielding methods for configuration
|
65
|
+
# @note work for/with {Sc4ry::Circuits.configure} and {Sc4ry::Circuits.register} when block given
|
66
|
+
class ConfigMapper
|
67
|
+
|
68
|
+
include Sc4ry::Constants
|
69
|
+
|
70
|
+
# config from given definition passed in constructor
|
71
|
+
attr_reader :config
|
72
|
+
|
73
|
+
# the mapping constructor from a given definition or the default From Sc4ry config (Constant)
|
74
|
+
# @param [Hash] definition a config hash
|
75
|
+
# @note creating dynamically accessors on config record given in definition
|
76
|
+
def initialize(definition: DEFAULT_CONFIG)
|
77
|
+
@config = definition
|
78
|
+
@config.each do |key,value|
|
79
|
+
self.define_singleton_method "#{key.to_s}=".to_sym do |val|
|
80
|
+
key = __method__.to_s.chop.to_sym
|
81
|
+
@config[key]=val
|
82
|
+
end
|
83
|
+
self.define_singleton_method key do
|
84
|
+
return @config[__method__]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Sc4ry module
|
2
|
+
# @note namespace
|
3
|
+
module Sc4ry
|
4
|
+
# Sc4ry::Constants module
|
5
|
+
# @note namespace
|
6
|
+
module Constants
|
7
|
+
|
8
|
+
# notifiers available in Sc4ry natively
|
9
|
+
CURRENT_NOTIFIERS = [:prometheus, :mattermost]
|
10
|
+
|
11
|
+
# the Sc4ry default config entries and values
|
12
|
+
DEFAULT_CONFIG = {
|
13
|
+
:max_failure_count => 5,
|
14
|
+
:timeout_value => 20,
|
15
|
+
:timeout => false,
|
16
|
+
:max_timeout_count => 5,
|
17
|
+
:max_time => 10,
|
18
|
+
:max_overtime_count => 3,
|
19
|
+
:check_delay => 30,
|
20
|
+
:notifiers => [],
|
21
|
+
:forward_unknown_exceptions => true,
|
22
|
+
:raise_on_opening => false,
|
23
|
+
:exceptions => [StandardError, RuntimeError]
|
24
|
+
}
|
25
|
+
|
26
|
+
# Default config supported entries with format and Proc checker for {Sc4ry::Config::Validator}
|
27
|
+
DEFAULT_CONFIG_FORMATS = {
|
28
|
+
:max_failure_count => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
29
|
+
:timeout_value => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
30
|
+
:timeout => {:proc => Proc::new {|item| [true,false].include? item}, :desc => "must be a Boolean"},
|
31
|
+
:max_timeout_count => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
32
|
+
:max_time => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
33
|
+
:max_overtime_count => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
34
|
+
:check_delay => {:proc => Proc::new {|item| item.class == Integer}, :desc => "must be an Integer"},
|
35
|
+
:notifiers => {
|
36
|
+
:proc => Proc::new {|item|
|
37
|
+
item.class == Array and item.select {|val| val.class == Symbol }.size == item.size
|
38
|
+
},
|
39
|
+
:desc => "must be an Array of Symbol",
|
40
|
+
:list => CURRENT_NOTIFIERS},
|
41
|
+
:forward_unknown_exceptions => {:proc => Proc::new {|item| [true,false].include? item}, :desc => "must be a Boolean"},
|
42
|
+
:raise_on_opening => {:proc => Proc::new {|item| [true,false].include? item}, :desc => "must be a Boolean"},
|
43
|
+
:exceptions => {
|
44
|
+
:proc => Proc::new {|item| item.class == Array and item.select {|val|
|
45
|
+
[Class,String].include? val.class}.size == item.size
|
46
|
+
},
|
47
|
+
:desc => "must be an Array of Exception(Class) or String"}
|
48
|
+
}
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/sc4ry/dependencies.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# rubygems depends
|
1
2
|
require 'rest-client'
|
2
3
|
require 'prometheus/client'
|
3
4
|
require 'prometheus/client/push'
|
5
|
+
require 'redis'
|
6
|
+
require 'version'
|
4
7
|
|
8
|
+
# Stdlibs depends
|
5
9
|
require 'logger'
|
6
10
|
require 'timeout'
|
7
11
|
require 'forwardable'
|
@@ -11,15 +15,20 @@ require 'openssl'
|
|
11
15
|
require 'net/http'
|
12
16
|
require 'uri'
|
13
17
|
require 'json'
|
18
|
+
require 'yaml'
|
14
19
|
|
15
20
|
|
16
|
-
|
21
|
+
# Sc4ry internal depends
|
17
22
|
require_relative 'helpers'
|
18
23
|
require_relative 'exceptions'
|
19
24
|
require_relative 'logger'
|
25
|
+
require_relative 'constants'
|
26
|
+
require_relative 'config'
|
27
|
+
require_relative 'notifiers/init'
|
28
|
+
require_relative 'exporters/init'
|
20
29
|
require_relative 'backends/init'
|
30
|
+
|
21
31
|
require_relative 'store'
|
22
32
|
require_relative 'run_controller'
|
23
33
|
require_relative 'circuits'
|
24
|
-
|
25
|
-
require_relative 'exporters/init'
|
34
|
+
|
data/lib/sc4ry/exceptions.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
+
# Sc4ry module
|
2
|
+
# @note namespace
|
1
3
|
module Sc4ry
|
4
|
+
|
5
|
+
# Sc4ry::Exceptions module
|
6
|
+
# @note namespace
|
2
7
|
module Exceptions
|
8
|
+
|
9
|
+
# Exception use in {Sc4ry::Circuits} when running circuit {Sc4ry::Circuits::run}
|
3
10
|
class CircuitBreaked < StandardError
|
4
11
|
def initialize(msg="Circuit just opened")
|
5
12
|
super(msg)
|
@@ -7,5 +14,37 @@ module Sc4ry
|
|
7
14
|
|
8
15
|
end
|
9
16
|
|
17
|
+
# Generic Exception use in {Sc4ry::Circuits}
|
18
|
+
class Sc4ryGenericError < StandardError
|
19
|
+
def initialize(msg="")
|
20
|
+
super(msg)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# Exception use in {Sc4ry::Store} or/and {Sc4ry::Backend} on data string issues
|
26
|
+
class Sc4ryBackendError < StandardError
|
27
|
+
def initialize(msg="")
|
28
|
+
super(msg)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# Exception use in {Sc4ry::Notifiers} on notification issues
|
34
|
+
class Sc4ryNotifierError < StandardError
|
35
|
+
def initialize(msg="")
|
36
|
+
super(msg)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# Exception use in {Sc4ry::Circuits} on config management issues
|
42
|
+
class ConfigError < StandardError
|
43
|
+
def initialize(msg="")
|
44
|
+
super(msg)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
10
49
|
end
|
11
50
|
end
|
data/lib/sc4ry/helpers.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
-
|
1
|
+
# Sc4ry module
|
2
|
+
# @note namespace
|
2
3
|
module Sc4ry
|
3
|
-
module Helpers
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# Sc4ry::Helpers module
|
6
|
+
# @note namespace
|
7
|
+
module Helpers
|
8
|
+
|
9
|
+
# class method (module) to help logging messages
|
10
|
+
# @param [Symbol] target a specific logger, restored old after
|
11
|
+
# @param [Symbol] level (default :info) a logging level (see Logger Stdlib)
|
12
|
+
# @param [String] message your message
|
13
|
+
# @return [Boolean]
|
14
|
+
def Helpers.log(target: nil, level: :info, message: )
|
15
|
+
save = Sc4ry::Loggers.current
|
16
|
+
Sc4ry::Loggers.current = target if target
|
17
|
+
Sc4ry::Loggers.get.send level, "Sc4ry : #{message}"
|
18
|
+
Sc4ry::Loggers.current = save
|
19
|
+
return true
|
8
20
|
end
|
9
21
|
|
10
22
|
# TCP/IP service checker
|
@@ -37,7 +49,9 @@ module Sc4ry
|
|
37
49
|
end
|
38
50
|
end
|
39
51
|
|
40
|
-
|
52
|
+
# class method (module) to help send notifiesby Sc4ry::Notifiers
|
53
|
+
# @param [Hash] options a Notifying structure
|
54
|
+
# @return [Boolean]
|
41
55
|
def Helpers.notify(options = {})
|
42
56
|
Sc4ry::Notifiers.list.each do |record|
|
43
57
|
notifier = Sc4ry::Notifiers.get name: record
|
data/lib/sc4ry/logger.rb
CHANGED
@@ -1,29 +1,65 @@
|
|
1
|
-
|
1
|
+
# Sc4ry module
|
2
|
+
# @note namespace
|
2
3
|
module Sc4ry
|
3
|
-
|
4
|
+
|
5
|
+
# Sc4ry loggers Factory/provider
|
6
|
+
# @note must be accessed by [Sc4ry::Circuits.loggers]
|
7
|
+
class Loggers
|
4
8
|
|
5
9
|
@@loggers = {:stdout => ::Logger.new(STDOUT)}
|
6
10
|
@@current = :stdout
|
7
11
|
|
8
|
-
|
9
|
-
|
12
|
+
# give the list of available loggers (initially internal Sc4ry logger )
|
13
|
+
# @return [Array] of [symbol] the list of defined loggers
|
14
|
+
# @note default :stdout => ::Logger(STDOUT) from Ruby Stdlib
|
15
|
+
# @example usage
|
16
|
+
# include Sc4ry
|
17
|
+
# Circuits.loggers.list_available.each {|logger| puts logger }
|
18
|
+
def Loggers.list_available
|
19
|
+
return @@loggers.keys
|
10
20
|
end
|
11
21
|
|
12
|
-
|
22
|
+
# return the current logger name (initially :stdtout )
|
23
|
+
# @return [symbol] the name of the logger
|
24
|
+
# @example usage
|
25
|
+
# include Sc4ry
|
26
|
+
# puts Circuits.loggers.current
|
27
|
+
def Loggers.current
|
13
28
|
return @@current
|
14
29
|
end
|
15
30
|
|
16
|
-
|
31
|
+
# return the current logger Object (initially internal Sc4ry Stdlib Logger on STDOUT )
|
32
|
+
# @return [symbol] the name of the logger
|
33
|
+
# @example usage
|
34
|
+
# include Sc4ry
|
35
|
+
# Circuits.loggers.get :stdout
|
36
|
+
def Loggers.get
|
17
37
|
return @@loggers[@@current]
|
18
38
|
end
|
19
39
|
|
20
|
-
|
40
|
+
# Set the current logger
|
41
|
+
# @param [Symbol] sym the name of the logger
|
42
|
+
# @return [symbol] the name of the logger updated
|
43
|
+
# @example usage
|
44
|
+
# include Sc4ry
|
45
|
+
# Circuits.loggers.current = :newlogger
|
46
|
+
def Loggers.current=(sym)
|
21
47
|
raise "Logger not define : #{sym}" unless @@loggers.keys.include? sym
|
22
48
|
@@current = sym
|
49
|
+
return @@current
|
23
50
|
end
|
24
51
|
|
25
|
-
|
26
|
-
|
52
|
+
# register un new logger
|
53
|
+
# @param [Symbol] name the name of the new logger
|
54
|
+
# @param [Object] instance the new logger object
|
55
|
+
# raise Sc4ry::Exceptions::Sc4ryGenericError if name is not a Symbol
|
56
|
+
# @example usage
|
57
|
+
# include Sc4ry
|
58
|
+
# Circuits.loggers.register name: :newlogger, instance: Logger::new('/path/to/my.log')
|
59
|
+
def Loggers.register(name: , instance: )
|
60
|
+
raise Sc4ry::Exceptions::Sc4ryGenericError, "name: keyword must be a Symbol" unless name.class == Symbol
|
61
|
+
@@loggers[name] = instance
|
62
|
+
return name
|
27
63
|
end
|
28
64
|
|
29
65
|
end
|