From: Bill Date: 2004-10-15T13:59:32+09:00 Subject: Re: Ruby programming styles and new program? Here's the (nearly last) refactoring: (text should word wrap at 80, but the news program wants to wrap earlier---) #!/usr/bin/ruby -w ######################################################### # # log_CID.rb # # Ruby CID logging script # # Logs all activity at a modem set to decipher CID # (Caller ID) information. Archives the daily logs as well. # ########################################################## require 'zip/zip' require 'serialport/serialport.so' require 'yaml' # name of config file (YAML format) config_yaml = 'log_CID.yml' ################################# # script local classes class ModemCIDMonitor attr_reader :port_err_count, :config, :log_blank_lines attr :debug, :port_err_count def initialize(config_hash, logger) @port_err_count = config_hash['port_err_count'] || 0 @port_name = config_hash['port_name'] || 'COM1:' @port = SerialPort.new(@port_name) @MAX_PORT_ERRORS = config_hash['MAX_PORT_ERRORS'] || 100 @debug = config_hash['DEBUG'] || false @log_blank_lines = config_hash['log_blank_lines'] || false @logger = logger @port.read_timeout = 0 @port_err_count = 0 @modem_init_string = config_hash['modem_init_string'] || "AT+VCID=1\r\n" @port.puts(@modem_init_string) end def log(txt) print txt if debug @logger.log_text(txt) end def run print "Starting run with port ", @port_name, " and logging to dir ", @logger.archive_dir, "\n" loop do @port.each_line do | text | # log text unless it is just spaces next unless text =~ /\S/ or log_blank_lines # squeeze double \r, etc to just \n text.sub!(/[\r\n]+/, "\n") log(text) end msg = "#{Time.now.to_s}: dropped out of system call, restarting loop.\n" log(msg) if debug @port_err_count += 1 if(@port_err_count > MAX_PORT_ERRORS) errmsg = "Too many port errors...ending run\n" log(errmsg) return errmsg end end end end class CID_Config attr_reader :config_file, :as_hash def initialize(config_file) @config_file = config_file @as_hash = YAML::load( File.open(@config_file)) end end class DailyLogWithArchive attr_reader :archive_dir, :base_log_name, :archive_zip_filename, :archive_days_secs, :archive_days_interval attr :debug def initialize(config_hash) @archive_dir = config_hash['archive_dir'] || './' @base_log_name = config_hash['base_log_name'] || 'CID' @debug = config_hash['DEBUG'] || false @archive_days_interval = config_hash['archive_days_interval'] || 1 @archive_zip_filename = config_hash['archive_zip_filename'] || 'CID_archive.zip' @last_archive_day = -1 @archive_days_secs = 60 * 60 * 24 * 7 @archive_days_secs = 60 * 60 * 24 * config_hash['days_before_archive'] if (config_hash['days_before_archive']) end def current_fname "#{archive_dir}/#{base_log_name}#{Time.now.strftime("%Y%m%d")}.log" end def archive_old_to_zip time = Time.now wd = Dir.getwd Dir.chdir(@archive_dir) dir = Dir.open(@archive_dir) moved = dir.inject(0) do | move_count, logfile | next unless logfile next unless logfile =~ /^#{base_log_name}/ next unless time > File.stat(logfile).mtime + @archive_days_secs if(move_to_archive(logfile)) log_text("LOGGER: Archiving file " + logfile + "\n") if @debug next move_count + 1 else next move_count end end dir.close Dir.chdir(wd) return moved end def move_to_archive(fname) Zip::ZipFile.open(@archive_zip_filename, 1) { | zfile | return nil if zfile.exist?(fname) zfile.add(fname, fname) } File.delete(fname) end def log_text(txt) wd = Dir.getwd Dir.chdir(@archive_dir) logfile = File.new(current_fname, "a") logfile.print(txt) logfile.close # check if we should do periodic archiving (up to daily) time = Time.now yday = time.yday if(yday != @last_archive_day and (yday >= @last_archive_day + @archive_days_interval or yday == 0) ) archive_old_to_zip @last_archive_day = yday end Dir.chdir(wd) end end ############################### # begin main program # get config from YAML text file config = CID_Config.new(config_yaml) # set up the logging class logger = DailyLogWithArchive.new(config.as_hash) # set up modem monitor monitor = ModemCIDMonitor.new(config.as_hash, logger) # run -- no return from this unless abort on port timeouts or errors errmsg = monitor.run print errmsg return 0 ================================================= log_CID.yml file: ############################################ # # log_CID YAML config file. # # name of archive file--daily logs are moved to this archive archive_zip_filename: CID_Data.zip # modem initialization string. # need to set to log verbose caller ID information (+VCID=1 or #CID=1, etc) # also need to set to NOT answer, just monitor line (usually the default) modem_init_string: AT+VCID=1\r\n # directory to keep log files archive_dir: c:/USR/log_CID # base log name for daily log files # daily log file name is this, plus YYYYMMDD date, plus .log extension # eg. CID20041004.log base_log_name: CID # the comm port having the CID-capable modem port_name: 'COM3:' # days that a daily log file is kept prior to archiving the file days_before_archive: 7 # maximum port read errors allowed before aborting run MAX_PORT_ERRORS: 3000 # whether to log whitespace-only lines log_blank_lines: false # debug on or off? DEBUG: true # # end YAML config file. # #####################################################