7. Logging

7.1. Overview

Logging is a pretty common activity in many applications. Because it is so common, Needle provides a powerful framework for logging messages in a consistent manner.

Needle’s logging framework is built on top of the standard Ruby Logger library. However, it extends that library to add additional functionality, including customizable message formats and a centralized location for obtaining logger instances.

This centralized location is the LogFactory.

7.2. LogFactory

The LogFactory is available as a service, so that any component that needs a logger instance can gain easy access to one. The factory’s service name is :logs.

Accessing the LogFactory service [ruby]
factory = reg.logs

You obtain logger instances from the factory by passing a logger name to #get:

Getting a named logger instance [ruby]
logger = reg.logs.get "a logger name"

Subsequent calls to #get will return the same logger instance for the given logger name.

Loggers for Services

Typically, you’ll use this to assign a logger instance to a service when it is constructed. In that case, the name of the logger is the fully-qualified name of the service:

Getting a logger for a service [ruby]
1
2
3
reg.register( :foo ) do |c,p|
  Foo.new( c.logs.get( p.fullname ) )
end

As a convenience, if the value passed to #get responds to either fullname or name, the return value of that message will be used as the name. Thus, you can do the following:

Getting a logger for a service (simplified) [ruby]
1
2
3
reg.register( :foo ) do |c,p|
  Foo.new( c.logs.get( p ) )
end

As a further convenience, there is a :log_for service that is parameterized. Just pass the name of the log to retreive (or the service point instance) and it will return the log handle directly:

Getting a logger for a service (simplified further) [ruby]
1
2
3
reg.register( :foo ) do |c,p|
  Foo.new( c.log_for( p ) )
end

7.3. Configuration

You can configure the LogFactory when you create the registry by passing a hash as the :logs option to Registry.new. The hash may have the following properties:

:device Should refer to an IO or pseudo-IO object that will receive #write and #close messages.
:filename The name of the file to write log messages to.
:roll_age The number of days before the log should be rolled.
:roll_frequency Either ‘daily’, ‘weekly’, or ‘monthly’, indicating how often the log should be rolled.
:roll_size The maximum size that a log file may grow to before it is rolled.
:default_date_format A strftime-formatted string to use for formatting message dates and times.
:default_message_format A printf-styled format string to use when formatting messages. It’s format is reminiscent of Log4r, but differs in some options. See the API documentation for Needle::Logger for details.
:default_level One of :debug, :info, :warn, :error, or :fatal, indicating the default level of logging detail to use.
:levels Another hash of pattern/level or pattern/hash pairs, where the pattern is a string describing the logger name (or names) that it matches. If the corresponding value of a key is a symbol or a string, then it describes the logging level to use for loggers that match it. If the value is a hash, then it may contain :level, :date_format, or :message_format keys that apply to matching logs.

By default, the filename is ”./needle.log”, and the roll_size is one megabyte. The default level is :debug. If you wanted to specify a different filename and default level of :warn, you could do:

Configuring the loggers [ruby]
1
2
3
4
5
reg = Needle::Registry.new(
  :logs => {
    :filename => "./my-app.log",
    :default_level => :warn }
)

Alternatively, you can easily put the logging configuration in a YAML file and read it in, like so:

Configuring the loggers from a YAML file [ruby]
1
2
3
4
require 'yaml'
reg = Needle::Registry.new(
  :logs => YAML.load( File.read( "log-conf.yml" ) )
)