sc4ry 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|