LogSimple

LogSimple - a Ruby logging library. LogSimple logs messages differently according to their level. For instance an ‘error’ message will go to syslog, but a ‘critical’ message will get emailed to the administrator. Log levels, and the behaviour associated with a given level, can be defined dynamically by the user. Behaviours include ‘formatters’ (to modify the message) and ‘outputters’ (to output the message), and while a certain number of predefined behaviours are provided as part of the library, users can create new ones.

Copyright © 2006 Netuxo

Author : Netuxo (www.netuxo.co.uk) ; contact anselm at netuxo dot co dot uk

Licence : GPL V2 (See LICENSE)

Sponsor : War Resisters’ International (www.wri-irg.org)

Ruby Forge project page : rubyforge.org/projects/logsimple/

Similar projects : Logger, which is part of the Ruby standard library and Log4r, inspired by the Apache Log4j

Overview

Outputters

Log levels are defined dynamically. Each level can be given any number of behaviours to apply when logging at that level. For instance :

  require 'logsimple.rb'
  include LogSimple

  Log.add_behaviour :debug, :log_stdout
  Log.debug "message"

The line with the call to "add_behaviour" creates the log level "debug" (if it didn’t already exist) and associates the behaviour "log_stdout". The following line logs the message "message" at the level debug - so it gets logged to stdout.

Further behaviours can be added :

  Log.add_behaviour :debug, :log_syslog
  Log.debug "second message"

Now "second message" will be logged to stdout and then to syslog.

Behaviours can also have parameters associated, for instance :

  Log.add_behaviour :info, :log_file
  Log.info "hello", {:filename => "mylog.txt"}

Will log the message "hello" to the file "mylog.txt". Behaviours can be given default parameters to avoid specifying them every time :

  Log.add_parameters :log_file, {:filename => "mylog.txt"}
  Log.info "another hello"

Will log "another hello" to the file "mylog.txt". In this case the default parameter applies to the behaviour ’:log_file’, so changing the parameter will affect any log level that uses this behaviour. It is also possible to set a parameter for only a specific log level :

  Log.add_parameters :log_file, {:filename => "mylog.txt"}
  Log.add_level_parameters :info, :log_file, {:filename => "theotherlog.txt"}
  Log.add_behaviour :info,  :log_file
  Log.add_behaviour :debug, :log_file
  Log.info  "info"
  Log.debug "debug"

Here the message "debug" goes to the generic file - mylog.txt - while the "info" message goes to theotherlog.txt

Formatters

Some behaviours are used to modifiy the message. For instance :

  Log.add_behaviour :error, :append_time, :log_stdout
  Log.error "error"

The logged message will have the current time appended to it. Behaviours are called in the order they are defined. So :

 Log.add_behaviour :error, :log_stdout, :append_time, :log_file

Will cause errors to first be logged to stdout (without the time) then to a file, with the time.

Default behaviours, and default log levels

The following behaviours are defined by default :

  • :null, which does not perform any action. The message is still sent to observers.
  • :log_stderr, to log to stderr
  • :log_stdout, to log to stdout
  • :log_file, to log to a file. Requires the :file_name parameter to be set.
  • :log_syslog, to log to syslog (when available). Will use the optional parameters :name and :level. :name represents the application name (will use $0 if not set) and :level represents the syslog error level. If not given, will log at syslog level ‘err’. The options are debug, info, notice, warning, err, alert, emerg and crit
  • :log_email to send an email with the log (SMTP only). Requires :smtp_server, :smtp_username, :smtp_password, :from and :to (may be an array) parameters to be set. If the optional parameter :subject is set, then it is used for subject instead of $0 ; if the optional parameter :smtp_port is set then it is used for port instead of 25 ; if the optional parameter :smtp_helo is set then it is used for HELO message ; if the optional parameter :smpt_authtype is set, then it is used to determine the type of authentification (:plain, :login or :cram_md5). :plain is used by default.
  • :log_exec, to call an executable with the log. Requires :executable parameter to be set
  • :raise, to raise an exception. Will use the optional :class_name parameter to raise the execption (otherwise, raises a RuntimeError exception)
  • :exit, to terminate execution imediately
  • :append_level Appends the log level at the begining of the message
  • :append_time Appends the date/time at the begining of the message

By default, the following two log levels are created :

  • :warning, for recovarable errors. Default behaviour is to append the level and log to stderr
  • :error, for unrecovarable errors. Default behaviour is to append the level and log to stderr and raise.

Adding your own behaviours

Any behaviour can be added at run time ; provided there is a class instance function do_#{behaviour} that takes the message string and a hash of parameters as parameters :

  def Log.do_puts(message, p)
    puts "Via puts : " + message
  end

  Log.add_behaviour :debug, :puts
  Log.debug "bug"

Will output "Via puts : bug". Behaviours that modify the message (such as :append_level) are defined by a class instance function mod_#{behaviour} that takes the output level, the message string and a hash of parameters and returns the modified string. For instance :

 def Log.mod_append_prog(level, message, p)
   "[" + $0.to_s + "] " + message
 end

Will cause the program name to be appended at the begining of the message.

Observers

Observers can be added as Proc objects. Those are called with the content of the message before each message gets called :

 last_log = nil
 Log.add_observer {|m| last_log = m}

Streams

It is possible to obtain stream objects linked to a particular log level which support the "<<" operator. This is usefull to pass the logger as a generic stream to external classes. For instance:

  o = Log.get_stream(:error)
  o << "message"

The last line has the same effect as Log.error "message". Note that parameters cannot be passed to stream objects. An extra string can be provided to a stream that gets appended at the begining of every message :

 o1 = Log.get_stream(:error, "[Module A] ")
 o2 = Log.get_stream(:error, "[Module B] ")
 o1 << "one"
 o2 << "two"

Will log ’[Module A] one’ and ’[Module B] two’ to the error log.