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.
@@ -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