sc4ry 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- @@config = config
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
- def Circuits.register(options = {})
28
- raise ":circuit is mandatory" unless options[:circuit]
29
- name = options[:circuit]
30
- override = (options[:config].class == Hash)? options[:config] : {}
31
- config = @@config.merge override
32
- @@circuits_store.put key: name, value: config
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
- def Circuits.get(options)
41
- @@circuits_store.get key: options[:circuit]
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
- def Circuits.run(options = {}, &block)
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 = (options[:circuit])? options[:circuit] : circuits_list.first
49
- raise "Circuit #{circuit_name} not found" unless circuits_list.include? circuit_name
50
- circuit = Circuits.get circuit: circuit_name
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 circuit.include? :status then
53
- if circuit[:status][:general] == :open then
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 - circuit[:values].last[:end_time]) < circuit[:check_delay])
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(circuit)
227
+ controller = Sc4ry::RunController.new(circuit_to_run)
60
228
  Circuits.control circuit: circuit_name, values: controller.run(block: block)
61
229
  end
62
- Sc4ry::Helpers.log level: :info, message: "Circuit #{circuit_name} : status #{circuit[:status]}"
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
- def Circuits.control(options={})
68
- data = @@circuits_store.get key: options[:circuit]
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 options[:values]
248
+ data[:values].push values
74
249
  worst_status = []
75
250
  ['failure','overtime','timeout'].each do |control|
76
- if options[:values][control.to_sym] == true then
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 Sc4ry::Exceptions::CircuitBreaked if data[:status][:general] == :open and data[:raise_on_opening]
97
- Sc4ry::Helpers.notify circuit: options[:circuit], config: data
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: options[:circuit], value: data
276
+ @@circuits_store.put key: circuit, value: data
100
277
  end
101
278
  end
102
279
  end
@@ -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
@@ -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
- require_relative 'notifiers/init'
25
- require_relative 'exporters/init'
34
+
@@ -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
- def Helpers.log(options)
6
- Sc4ry::Logger.current = options[:target] if options[:target]
7
- Sc4ry::Logger.get.send options[:level], "Sc4ry : #{options[:message]}"
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
- class Logger
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
- def Logger.list_avaible
9
- return @@loggers
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
- def Logger.current
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
- def Logger.get
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
- def Logger.current=(sym)
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
- def Logger.register(options = {})
26
- @@loggers[options[:name]] = options[:instance]
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