fiksu-af 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.gitignore +24 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +22 -0
  5. data/LICENSE +30 -0
  6. data/README.md +175 -0
  7. data/Rakefile +42 -0
  8. data/examples/af_script_with_options.rb +73 -0
  9. data/examples/af_side_component.rb +16 -0
  10. data/examples/my_application.rb +8 -0
  11. data/fiksu-af.gemspec +27 -0
  12. data/lib/fiksu-af/application/component.rb +95 -0
  13. data/lib/fiksu-af/application.rb +361 -0
  14. data/lib/fiksu-af/deprecated.rb +15 -0
  15. data/lib/fiksu-af/get_options.rb +68 -0
  16. data/lib/fiksu-af/logging/configurator.rb +152 -0
  17. data/lib/fiksu-af/logging.rb +13 -0
  18. data/lib/fiksu-af/option_parser/columnizer.rb +36 -0
  19. data/lib/fiksu-af/option_parser/dsl.rb +290 -0
  20. data/lib/fiksu-af/option_parser/get_options.rb +65 -0
  21. data/lib/fiksu-af/option_parser/helper.rb +80 -0
  22. data/lib/fiksu-af/option_parser/instance_variable_setter.rb +117 -0
  23. data/lib/fiksu-af/option_parser/interface.rb +63 -0
  24. data/lib/fiksu-af/option_parser/option.rb +40 -0
  25. data/lib/fiksu-af/option_parser/option_check.rb +66 -0
  26. data/lib/fiksu-af/option_parser/option_finder.rb +82 -0
  27. data/lib/fiksu-af/option_parser/option_group.rb +37 -0
  28. data/lib/fiksu-af/option_parser/option_select.rb +68 -0
  29. data/lib/fiksu-af/option_parser/option_store.rb +89 -0
  30. data/lib/fiksu-af/option_parser/option_type.rb +59 -0
  31. data/lib/fiksu-af/option_parser.rb +145 -0
  32. data/lib/fiksu-af/q_thread/base.rb +20 -0
  33. data/lib/fiksu-af/q_thread/interface.rb +23 -0
  34. data/lib/fiksu-af/q_thread/message.rb +14 -0
  35. data/lib/fiksu-af/q_thread/message_handler.rb +30 -0
  36. data/lib/fiksu-af/tcp_command/client.rb +49 -0
  37. data/lib/fiksu-af/tcp_command/server.rb +119 -0
  38. data/lib/fiksu-af/thread_pool.rb +102 -0
  39. data/lib/fiksu-af/version.rb +4 -0
  40. data/lib/fiksu-af.rb +12 -0
  41. data/logging/af.yml +32 -0
  42. data/spec/dummy/.rspec +1 -0
  43. data/spec/dummy/README.rdoc +261 -0
  44. data/spec/dummy/Rakefile +7 -0
  45. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  46. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  47. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  48. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  49. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  50. data/spec/dummy/config/application.rb +59 -0
  51. data/spec/dummy/config/boot.rb +10 -0
  52. data/spec/dummy/config/database-sample.yml +32 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +31 -0
  55. data/spec/dummy/config/environments/production.rb +67 -0
  56. data/spec/dummy/config/environments/test.rb +35 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/inflections.rb +15 -0
  59. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  60. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  61. data/spec/dummy/config/initializers/session_store.rb +8 -0
  62. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  63. data/spec/dummy/config/locales/en.yml +5 -0
  64. data/spec/dummy/config/routes.rb +58 -0
  65. data/spec/dummy/config.ru +4 -0
  66. data/spec/dummy/public/404.html +26 -0
  67. data/spec/dummy/public/422.html +26 -0
  68. data/spec/dummy/public/500.html +25 -0
  69. data/spec/dummy/public/favicon.ico +0 -0
  70. data/spec/dummy/script/rails +6 -0
  71. data/spec/dummy/spec/spec_helper.rb +32 -0
  72. data/spec/lib/af/application_spec.rb +60 -0
  73. data/spec/lib/af/get_options_spec.rb +24 -0
  74. data/spec/lib/af/option_parser/option_check_spec.rb +50 -0
  75. data/spec/lib/af/option_parser/option_select_spec.rb +51 -0
  76. data/spec/spec_helper.rb +33 -0
  77. metadata +288 -0
@@ -0,0 +1,361 @@
1
+ require 'pg_advisory_locker'
2
+ require 'pg_application_name'
3
+
4
+ module Af
5
+ # Abstract superclass for implementing command line applications.
6
+ #
7
+ # Provides:
8
+ # * Command line option parsing.
9
+ # * Logging with Log4r.
10
+ # * Pre and post option processes hooks.
11
+ # * Proxy support access to application frame functionality from other classes
12
+ #
13
+ # Subclasses must implement:
14
+ # * work
15
+ #
16
+ # Subclasses can implement:
17
+ # * pre_work
18
+ #
19
+ class Application
20
+ include Af::OptionParser
21
+ include Af::Logging
22
+ include Af::Deprecated
23
+
24
+ #-----------------------------
25
+ # *** Command Line Options ***
26
+ #+++++++++++++++++++++++++++++
27
+
28
+ # A number of default command line switches and switch groups available to all
29
+ # subclasses.
30
+
31
+ opt_group :basic, "basic options", :priority => 0, :description => <<-DESCRIPTION
32
+ These are the standard options offered to all Af commands.
33
+ DESCRIPTION
34
+
35
+ opt_group :basic do
36
+ opt '?', "show this help (--?? for all)", :short => '?', :var => nil do
37
+ Helper.new(::Af::Application.singleton.af_opt_class_path).help(::Af::Application.singleton.usage)
38
+ exit 0
39
+ end
40
+ opt '??', "show help for all commands", :hidden => true, :var => nil do
41
+ Helper.new(::Af::Application.singleton.af_opt_class_path).help(::Af::Application.singleton.usage, true)
42
+ exit 0
43
+ end
44
+ opt :daemon, "run as daemon", :short => :d
45
+ end
46
+
47
+ opt_group :advanced, "advanced options", :priority => 100, :hidden => true, :description => <<-DESCRIPTION
48
+ These are advanced options offered to this programs.
49
+ DESCRIPTION
50
+
51
+ opt_group :debugging, "debugging options", :priority => 1000, :hidden => true, :description => <<-DESCRIPTION
52
+ These are options associated with debugging the internal workings of the Af::Application sysyem and ruby
53
+ in general.
54
+ DESCRIPTION
55
+
56
+ opt_group :debugging do
57
+ opt :gc_profiler, "enable the gc profiler"
58
+ opt :gc_profiler_interval_minutes, "number of minutes between dumping gc information", :default => 60, :argument_note => "MINUTES"
59
+ end
60
+
61
+ opt_group :logging, "logger options", :priority => 100, :hidden => true, :description => <<-DESCRIPTION
62
+ These are options associated with logging whose core is Log4r.
63
+ Logging files should be in yaml format and should probably define a logger for 'Af' and 'Process'.
64
+ DESCRIPTION
65
+
66
+ opt_group :logging, :target_container => Af::Logging::Configurator do
67
+ opt :log_configuration_files, "a list of yaml files for log4r to use as configurations", :type => :strings, :default => ["af.yml"]
68
+ opt :log_configuration_search_path, "directories to search for log4r files", :type => :strings, :default => ["."]
69
+ opt :log_configuration_section_names, "section names in yaml files for log4r configurations", :type => :strings,
70
+ :default => ["log4r_config"], :env => 'LOG_CONFIGURATION_SECTION_NAMES'
71
+ opt :log_dump_configuration, "show the log4r configuration"
72
+ opt :log_levels, "set log levels", :type => :hash
73
+ opt :log_stdout, "set logfile for stdout (when daemonized)", :type => :string
74
+ opt :log_stderr, "set logfile for stderr (when daemonized)", :type => :string
75
+ opt :log_console, "force logging to console"
76
+ opt :log_ignore_configuration, "ignore logging configuration files", :default => false
77
+ end
78
+
79
+ #-------------------
80
+ # *** Attributes ***
81
+ #+++++++++++++++++++
82
+
83
+ attr_accessor :has_errors
84
+
85
+ @@singleton = nil
86
+
87
+ #----------------------
88
+ # *** Class Methods ***
89
+ #++++++++++++++++++++++
90
+
91
+ # Instantiate and run the application.
92
+ #
93
+ # *Arguments*
94
+ # - arguments - ????
95
+ def self.run(*arguments)
96
+ application = self.new._run(*arguments)
97
+ application._work
98
+ end
99
+
100
+ # Return the single allowable instance of this class.
101
+ #
102
+ # *Arguments*
103
+ # * safe - defaults to false, instantiates instance if it doesn't exist
104
+ def self.singleton(safe = false)
105
+ if @@singleton.nil?
106
+ if safe
107
+ @@singleton = new
108
+ else
109
+ fail("Application @@singleton not initialized! Maybe you are using a Proxy before creating an instance? or use SafeProxy")
110
+ end
111
+ end
112
+ return @@singleton
113
+ end
114
+
115
+ # Run this application with the provided arguments that must adhere to
116
+ # configured command line switches. It rewrites ARGV with these values.
117
+ #
118
+ # *Example*
119
+ # instance._run("-v", "--file", "foo.log")
120
+ #
121
+ # *Arguments*
122
+ # * arguments - list of command line option strings
123
+ #
124
+ def self._run(*arguments)
125
+ # this ARGV hack is here for test specs to add script arguments
126
+ ARGV[0..-1] = arguments if arguments.length > 0
127
+ self.new._run
128
+ end
129
+
130
+ #-------------------------
131
+ # *** Instance Methods ***
132
+ #+++++++++++++++++++++++++
133
+
134
+ # Run the application, fetching and parsing options from the command
135
+ # line.
136
+ #
137
+ # *Arguments*
138
+ # * usage - string describing usage (optional)
139
+ # * options - hash of options, containing ???
140
+ def _run
141
+ process_command_line_options(af_opt_class_path)
142
+ post_command_line_parsing
143
+ pre_work
144
+ return self
145
+ end
146
+
147
+ # Execute the actual work of the application upon execution.
148
+ #
149
+ # This method is used to wrap the actual run code with
150
+ # whatever specific code we are looking to maintain the
151
+ # execution context.
152
+ #
153
+ # one can imagine overlaoding this function with something
154
+ # call initiates a profiler or debugger
155
+ def _work
156
+ begin
157
+ work
158
+ rescue SystemExit => se
159
+ # we do nothing here
160
+ if se.status != 0
161
+ logger.error "exit called with error: #{se.message}"
162
+ logger.warn se
163
+ exit se.status
164
+ end
165
+ rescue Exception => e
166
+ # catching Exception cause some programs and libraries suck
167
+ logger.error "fatal error durring work: #{e.message}"
168
+ logger.warn e
169
+ @has_errors = true
170
+ end
171
+
172
+ if @gc_profiler
173
+ logger("GC::Profiler").info GC::Profiler.result
174
+ end
175
+
176
+ exit @has_errors ? 1 : 0
177
+ end
178
+
179
+ # Accessor for the af name set on the instance's class.
180
+ def af_name
181
+ return self.class.name
182
+ end
183
+
184
+ # override if you wish to include other class's opt/opt_group
185
+ def af_opt_class_path
186
+ return [self.class]
187
+ end
188
+
189
+ protected
190
+
191
+ def initialize
192
+ super
193
+ # sort of a singleton -- if forced to it really means "last instantiated and current"
194
+ @@singleton = self
195
+ set_connection_application_name(startup_database_application_name)
196
+ $stdout.sync = true
197
+ $stderr.sync = true
198
+ opt :log_configuration_search_path, :default => [".", Rails.root + "config/logging"]
199
+ opt :log_configuration_files, :default => ["af.yml", "#{af_name}.yml"]
200
+ opt :log_stdout, :default => Rails.root + "log/runner.log"
201
+ opt :log_stderr, :default => Rails.root + "log/runner-errors.log"
202
+ end
203
+
204
+ # Set the application name on the ActiveRecord connection. It is
205
+ # truncated to 64 characters.
206
+ #
207
+ # *Arguments*
208
+ # * name - application name to set on the connection
209
+ def set_connection_application_name(name)
210
+ ActiveRecord::ConnectionAdapters::ConnectionPool.initialize_connection_application_name(name[0...63])
211
+ end
212
+
213
+ # Application name consisting of process PID and af name.
214
+ def startup_database_application_name
215
+ return "//pid=#{Process.pid}/#{af_name}"
216
+ end
217
+
218
+ # Accessor for the application name set on the ActiveRecord database connection.
219
+ def database_application_name
220
+ return self.class.startup_database_application_name
221
+ end
222
+
223
+ # Work performed by this application. MUST be implemented by subclasses.
224
+ def work
225
+ raise NotImplemented.new("#{self.class.name}#work must be implemented to use the Application framework")
226
+ end
227
+
228
+ def post_command_line_parsing
229
+ # Iterate through all option_checks and option_selects in the class hierarchy.
230
+ # Create instance variables and accessor methods for each.
231
+ option_finder = OptionFinder.new(af_opt_class_path)
232
+
233
+ option_checks = option_finder.all_option_checks
234
+ option_selects = option_finder.all_option_selects
235
+
236
+ begin
237
+ option_checks.each do |option_check|
238
+ option_check.validate
239
+ end
240
+
241
+ option_selects.each do |option_select|
242
+ option_select.validate
243
+ end
244
+ rescue GetoptLong::Error, Error => e
245
+ opt_error e.message
246
+ end
247
+ end
248
+
249
+ # Overload to do any operations that need to be handled before work is called.
250
+ # Call exit if needed. Always call super.
251
+ def pre_work
252
+ logging_configurator.configurate
253
+
254
+ if @gc_profiler
255
+ logger("GC::Profiler").info "Enabling GC:Profilier"
256
+ logger("GC::Profiler").info "Signal USR1 will dump results"
257
+ logger("GC::Profiler").info "Will dump every #{@gc_profiler_interval_minutes} minutes"
258
+ GC::Profiler.enable
259
+ @last_gc_profiler_dump = Time.zone.now
260
+ Signal.trap("USR1") do
261
+ logger("GC::Profiler").info GC::Profiler.result
262
+ end
263
+ end
264
+
265
+ if @daemon
266
+ $stdout.reopen(Af::Logging::Configurator.log_stdout, "a")
267
+ $stderr.reopen(Af::Logging::Configurator.log_stderr, "a")
268
+ $stdout.sync = true
269
+ $stderr.sync = true
270
+ logger.info "Daemonizing"
271
+ pid = fork
272
+ if pid
273
+ exit 0
274
+ else
275
+ logger.info "forked"
276
+ Process.setsid
277
+ trap 'SIGHUP', 'IGNORE'
278
+ cleanup_after_fork
279
+ end
280
+ end
281
+ end
282
+
283
+ def cleanup_after_fork
284
+ ActiveRecord::Base.connection.reconnect!
285
+ end
286
+
287
+ # Returns a list of OS signals.
288
+ def signal_list
289
+ return Signal.list.keys
290
+ end
291
+
292
+ # Utility method to wrap code in a protective sheen
293
+ # use with "signal_list"
294
+ def protect_from_signals
295
+ # we are indiscriminate with the signals we block -- too bad ruby doesn't have some
296
+ # reasonable signal management system
297
+ signals = Hash[signal_list.map {|signal| [signal, Signal.trap(signal, "IGNORE")] }]
298
+ begin
299
+ yield
300
+ ensure
301
+ signals.each {|signal, saved_value| Signal.trap(signal, saved_value)}
302
+ end
303
+ end
304
+
305
+ # call this every once in a while
306
+ def periodic_application_checkpoint
307
+ if @gc_profiler
308
+ if (Time.zone.now - @last_gc_profiler_dump) > @gc_profiler_interval_minutes.minutes
309
+ @last_gc_profiler_dump = Time.zone.now
310
+ logger("GC::Profiler").info GC::Profiler.result
311
+ end
312
+ end
313
+ end
314
+
315
+ # Proxy's are used by dependant classes to reach back to the Application frame for
316
+ # some functionality.
317
+ #
318
+ # consider a model that wishes to use the logging functionality of Af:
319
+ #
320
+ # class Foo < ActiveRecord::Base
321
+ # include ::Af::Application::SafeProxy
322
+ #
323
+ # after_create :do_something_after_create
324
+ #
325
+ # def foo_logger
326
+ # return af_logger(self.class.name)
327
+ # end
328
+ #
329
+ # private
330
+ # def do_something_after_create
331
+ # foo_logger.info "created: #{self.inspect}"
332
+ # end
333
+ # end
334
+ #
335
+ # The difference between Proxy and SafeProxy is simply that
336
+ # SafeProxy can be used in classes that may not be in an Af::Application
337
+ # run (ie, models that are shared with a Rails web app where Af::Application
338
+ # is never instantiated)
339
+ #
340
+ module Proxy
341
+ def af_logger(logger_name = (af_name || "Unknown"))
342
+ return ::Af::Application.singleton.logger(logger_name)
343
+ end
344
+
345
+ def af_name
346
+ return ::Af::Application.singleton.af_name
347
+ end
348
+ end
349
+
350
+ module SafeProxy
351
+ def af_logger(logger_name = (af_name || "Unknown"))
352
+ return ::Af::Application.singleton(true).logger(logger_name)
353
+ end
354
+
355
+ def af_name
356
+ return ::Af::Application.singleton(true).af_name
357
+ end
358
+ end
359
+
360
+ end
361
+ end
@@ -0,0 +1,15 @@
1
+ module Af
2
+ module Deprecated
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ def update_opts(*x)
8
+ puts "don't use update_opts -- use #opt (#{caller.first})"
9
+ self.class.opt *x
10
+ end
11
+
12
+ module ClassMethods
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,68 @@
1
+ require 'getoptlong'
2
+
3
+ module Af
4
+
5
+ # Subclasses Getoptlong from the Ruby standard library.
6
+ # Docs: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/getoptlong/rdoc/GetoptLong.html.
7
+ # Source: https://github.com/ruby/ruby/blob/trunk/lib/getoptlong.rb.
8
+ class GetOptions < GetoptLong
9
+
10
+ # Local constants which map to superclass argument types.
11
+ ARGUMENT_FLAGS = [
12
+ NO_ARGUMENT = GetoptLong::NO_ARGUMENT,
13
+ REQUIRED_ARGUMENT = GetoptLong::REQUIRED_ARGUMENT,
14
+ OPTIONAL_ARGUMENT = GetoptLong::OPTIONAL_ARGUMENT
15
+ ]
16
+
17
+ # Instantiate a new long command line option parser with a hash of switches.
18
+ #
19
+ # *Arguments*
20
+ # * switches - optional hash of command line switches, with long switch as
21
+ # key to a set of options:
22
+ # :short => <optional short switch>
23
+ # :argument => <constant arg type>
24
+ # :environment_variable => <how do these work???>
25
+ # :note => <arg description>
26
+ def initialize(switches = {})
27
+ environment_variables = {} # switches that are set in the ENV
28
+ getopt_options = []
29
+
30
+ # Iterate through all of the switches.
31
+ switches.each do |long_switch, parameters|
32
+
33
+ # Set aside
34
+ if parameters[:environment_variable].present?
35
+ environment_variables[parameters[:environment_variable]] = long_switch
36
+ end
37
+
38
+ # Convert hash into array, in format expected by Getoptlong#new.
39
+ # Example: ['--foo', '-f', 'bar']
40
+ options = []
41
+ options << long_switch
42
+ if (parameters[:short])
43
+ options << parameters[:short]
44
+ end
45
+ options << parameters[:argument]
46
+ getopt_options << options
47
+ end
48
+
49
+ # Add enviroment variables to the front of ARGV.
50
+ argv_additions = []
51
+ for environment_variable_name,value in environment_variables do
52
+ if ENV[environment_variable_name]
53
+ argv_additions << value
54
+ argv_additions << ENV[environment_variable_name] unless ENV[environment_variable_name].empty?
55
+ end
56
+ end
57
+ for arg in ARGV do
58
+ argv_additions << arg
59
+ end
60
+
61
+ # Rewrite ARGV with environment variable with the new list.
62
+ argv_additions.each_with_index { |v,i| ARGV[i] = v }
63
+
64
+ super(*getopt_options)
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,152 @@
1
+ require 'log4r'
2
+ require 'log4r/configurator'
3
+ require 'log4r/yamlconfigurator'
4
+ require 'log4r/outputter/consoleoutputters'
5
+ require 'log4r_remote_syslog_outputter'
6
+ require 'reasonable_log4r'
7
+
8
+ module Af::Logging
9
+ class Configurator
10
+ @@singleton = nil
11
+
12
+ # Return the single allowable instance of this class, if the class has been instantiated
13
+ def self.singleton
14
+ return @@singleton ||= new
15
+ end
16
+
17
+ def initialize
18
+ @@singleton = self
19
+ Log4r::Configurator.custom_levels(:DEBUG, :DEBUG_FINE, :DEBUG_MEDIUM, :DEBUG_GROSS, :DETAIL, :INFO, :WARN, :ALARM, :ERROR, :FATAL)
20
+ end
21
+
22
+ # Parse and return the provided log level, which can be an integer,
23
+ # string integer or string constant. Returns all loging levels if value
24
+ # cannot be parsed.
25
+ #
26
+ # *Arguments*
27
+ # * logger_level - log level to be parsed
28
+ def parse_log_level(logger_level)
29
+ if logger_level.is_a? Integer
30
+ logger_level_value = logger_level
31
+ elsif logger_level.is_a? String
32
+ if logger_level[0] =~ /[0-9]/
33
+ logger_level_value = logger_level.to_i
34
+ else
35
+ logger_level_value = logger_level.constantize rescue nil
36
+ logger_level_value = "Log4r::#{logger_level.upcase}".constantize rescue nil unless logger_level_value
37
+ end
38
+ else
39
+ logger_level_value = Log4r::ALL
40
+ end
41
+ return logger_level_value
42
+ end
43
+
44
+ # Returns the logger with the provided name, instantiating it if needed.
45
+ #
46
+ # *Arguments*
47
+ # * logger_name - logger to return, defaults to ":default"
48
+ def logger(logger_name = :default)
49
+ # Coerce the logger_name if needed.
50
+ logger_name = ::Af::Application.singleton.af_name if logger_name == :default
51
+ # Check with Log4r to see if there is a logger by this name.
52
+ # If Log4r doesn't have a logger by this name, make one with Af defaults.
53
+ return Log4r::Logger[logger_name] || Log4r::Logger.new(logger_name)
54
+ end
55
+
56
+ # Load the provided yaml Log4r configuration files.
57
+ #
58
+ # *Arguments*
59
+ # * files - array of file names with full paths (??)
60
+ # * yaml_sections - ???
61
+ def logging_load_configuration_files(files, yaml_sections)
62
+ begin
63
+ Log4r::YamlConfigurator.load_yaml_files(files, yaml_sections)
64
+ rescue StandardError => e
65
+ puts "error while parsing log configuration files: #{e.message}"
66
+ puts "continuing without your configuration"
67
+ puts e.backtrace.join("\n")
68
+ return false
69
+ end
70
+ return true
71
+ end
72
+
73
+ # Load all of the Log4r yaml configuration files.
74
+ def logging_load_configuration
75
+ files = []
76
+ @@log_configuration_files.each do |configuration_file|
77
+ @@log_configuration_search_path.each do |path|
78
+ pathname = Pathname.new(path) + configuration_file
79
+ files << pathname.to_s if pathname.file?
80
+ end
81
+ end
82
+ logging_load_configuration_files(files, @@log_configuration_section_names)
83
+ end
84
+
85
+ # TODO AK: What is purpose of this method?
86
+ def logging_configuration_looks_bogus
87
+ return Log4r::LNAMES.length == 1
88
+ end
89
+
90
+ # Parses and sets the provided logger levels.
91
+ #
92
+ # *Argument*
93
+ # * logger_info - value indicating default log level, or JSON string
94
+ # of logger names to logger levels, i.e. "{'foo' => 'INFO'}.
95
+ def parse_and_set_logger_levels(logger_info)
96
+ log_level_hash = JSON.parse(logger_info) rescue {:default => parse_log_level(logger_info)}
97
+ set_logger_levels(log_level_hash)
98
+ end
99
+
100
+ # Sets the logger levels the provided hash. It supports the following formats for
101
+ # logger levels: 1, "1", "INFO", "Log4r::INFO".
102
+ #
103
+ # *Arguments*
104
+ # * log_level_hash - hash of logger names to logger levels,
105
+ # i.e. { :foo => 'INFO' }
106
+ def set_logger_levels(log_level_hash)
107
+ log_level_hash.each do |logger_name, logger_level|
108
+ logger_name = :default if logger_name == "default"
109
+ logger_level_value = parse_log_level(logger_level)
110
+ l = logger(logger_name)
111
+ l.level = logger_level_value
112
+ end
113
+ end
114
+
115
+ def configurate
116
+ if @@log_console || @@log_ignore_configuration
117
+ Log4r::Logger.root.outputters << Log4r::Outputter.stdout
118
+ else
119
+ logging_load_configuration
120
+ if logging_configuration_looks_bogus
121
+ Log4r::Logger.root.outputters << Log4r::Outputter.stdout
122
+ end
123
+ end
124
+
125
+ if @@log_levels
126
+ set_logger_levels(@@log_levels)
127
+ end
128
+
129
+ if @@log_dump_configuration
130
+ puts "Log configuration search path:"
131
+ puts " " + @@log_configuration_search_path.join("\n ")
132
+ puts "Log configuration files:"
133
+ puts " " + @@log_configuration_files.join("\n ")
134
+ puts "Logging Names: #{Log4r::LNAMES.join(', ')}"
135
+ puts "Yaml section names:"
136
+ puts " " + @@log_configuration_section_names.join("\n ")
137
+ loggers = []
138
+ Log4r::Logger.each do |logger_name, logger|
139
+ loggers << logger_name
140
+ end
141
+ puts "Loggers:"
142
+ puts "global: #{Log4r::LNAMES[Log4r::Logger.global.level]}"
143
+ puts "root: #{Log4r::LNAMES[Log4r::Logger['root'].level]} [#{Log4r::Logger['root'].outputters.map{|o| o.name}.join(', ')}]"
144
+ loggers.sort.reject{|logger_name| ["root", "global"].include? logger_name}.each do |logger_name|
145
+ puts "#{' ' * logger_name.split('::').length}#{logger_name}: #{Log4r::LNAMES[Log4r::Logger[logger_name].level]} [#{Log4r::Logger[logger_name].outputters.map{|o| o.name}.join(', ')}]"
146
+ end
147
+ exit 0
148
+ end
149
+ end
150
+
151
+ end
152
+ end
@@ -0,0 +1,13 @@
1
+ module Af::Logging
2
+ def self.included(base)
3
+ Configurator.singleton
4
+ end
5
+
6
+ def logger(logger_name = :default)
7
+ return Configurator.singleton.logger(logger_name)
8
+ end
9
+
10
+ def logging_configurator
11
+ return Configurator.singleton
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ module ::Af::OptionParser
2
+ class Columnizer
3
+ # Convert an array into a single string, where each item consumes a static
4
+ # number of characters. Long fields are truncated and small ones are padded.
5
+ #
6
+ # *Arguments*
7
+ # * fields - array of objects that respond to "to_s"
8
+ # * sized - character count for each field in the new string????
9
+ def columnized_row(fields, sized)
10
+ r = []
11
+ fields.each_with_index do |f, i|
12
+ r << sprintf("%0-#{sized[i]}s", f.to_s.gsub(/\\n\\r/, '').slice(0, sized[i]))
13
+ end
14
+ return r.join(' ')
15
+ end
16
+
17
+ # Converts an array of arrays into a single array of columnized strings.
18
+ #
19
+ # *Arguments*
20
+ # * rows - arrays to convert
21
+ # * options - hash of options, includes:
22
+ # :max_width => <integer max width of columns>
23
+ def columnized(rows, options = {})
24
+ sized = {}
25
+ rows.each do |row|
26
+ row.each_index do |i|
27
+ value = row[i]
28
+ sized[i] = [sized[i].to_i, value.to_s.length].max
29
+ sized[i] = [options[:max_width], sized[i].to_i].min if options[:max_width]
30
+ end
31
+ end
32
+
33
+ return rows.map { |row| " " + columnized_row(row, sized).rstrip }
34
+ end
35
+ end
36
+ end