Documentation

NAME

Lumberjack - A simple logging framework.

SYNOPSIS

use Lumberjack;

# Output to $*ERR by default - in colour!
Lumberjack.dispatchers.append: Lumberjack::Dispatcher::Console.new(:colour);

class MyClass does Lumberjack::Logger {
    method start() {
       self.log-info("Starting ...");
       ...
   }

   method do-stuff() {
      self.log-debug("Doing stuff ...");
      ...
      if $something-went-wrong {
         self.log-error("Something went wrong");
      }
   }
   method stop() {
       ...
       self.log-info("Stopped.");
   }
}

MyClass.log-level = Lumberjack::Debug;

DESCRIPTION

This is more of a sketch for a logging framework, or perhaps even a logging framework framework. It provides the minimum interface that classes can consume a role to provide themselves logging facilities and set a class wide logging level and have the messages delivered to dispatchers which can do what they want with the messages and specify the levels of messages that they want to handle.

It doesn't mandate any particular configuration format as the setup is entirely programmatic, I foresee that people providing their own higher level configuration driven things on top of this.

I'm sure this doesn't yet have all the features to support all the requirements people, but it is released with the basic interface complete so it can actually be used.

The approach taken reflects a patten that I have found useful in large object oriented programmes, where having the logging methods on a class means that you have the means to make log messages wherever you have an instance of the class without having to obtain a separate logger object.

There are a couple of simple log dispatchers included which should get you started, but I would envisage that more useful ones may be provided as separate modules, though they are sufficiently simple to implement you can provide your own as required.

METHODS

The main Lumberjack class operates as if all the methods and attributes are 'static', that is to say they are wrapped under the hood to be invoked against a single instance that is created the first time it is needed.

method log

method log(Message $message)

This injects the Lumberjack::Message into the dispatch mechanism, it is typically called by the methods provided by the role Lumberjack::Logger though you may call this directly if you wish to create your own message and/or dispatch the message outside of any particular class.

all-messages

This is a Supply that reflects all of the messages that traverse the system, before they are filtered for dispatch. In normal usage this is used internally to feed the dispatch mechanism, but can be tapped to provide a feed for an external logging mechanism for instance.

fatal-messages

This is a Supply derived from all-messages that only has the messages at level Fatal.

error-messages

This is a Supply derived from all-messages that only has the messages at level Error.

warn-messages

This is a Supply derived from all-messages that only has the messages at level Warn.

info-messages

This is a Supply derived from all-messages that only has the messages at level Info.

debug-messages

This is a Supply derived from all-messages that only has the messages at level Debug.

trace-messages

This is a Supply derived from all-messages that only has the messages at level Trace.

filtered-messages

This is a Supply that is filtered to be only those that will be candidates for dispatch. To be a candidate the level of the message must be equal to or of higher "severity" (lower numerical value,) than the log-level of the class the message is for, or (if the class is unknown,) the default-level. This is tapped internally to feed the dispatchers, but you could tap this yourself if you want to send the filtered messages to an alternative logging system.

default-level

This is the default level that is used to filter the messages when the class of the message is unknown (or has no level set.) It may also be used to set a default on new messages when the level isn't supplied (but this is almost certainly not what you want to do.) The default is Info.

dispatchers

This is an Array of objects that have the role Lumberjack::Dispatcher role. These should be object instances and not names or type objects. The rationale behind making them objects rather than types is so that multiple dispatchers of the same type can be used with a different configuration each handling messages for different log levels or for different classes. An example might be a dispatcher that writes to a file, where an instance might log Debug messages to a debug.log and a separate instance logs the Error messages to an error.log.

sub format-message

sub format-message(Str $format, Message $message, :&date-formatter = &default-date-formatter, Int :$callframes) returns Str is export(:FORMAT)

This is a utility subroutine that is only exported when the :FORMAT import adverb is applied to the use of Lumberjack It provides a simple formatting of the messages with sprintf like directives supplied in $format. $callframes indicates the number of frames to be skipped in the backtrace to find the frame we are interested in. &date-formatter is a subroutine that accepts a DateTime and returns a formatted string (the default is RFC2822-like.) The Format directives are:

%D

The formatted date, using the provided date-formatter or the default.

%P

The Process ID of this process.

%C

The class name of the the class from the Message.

%L

The logging level of the message.

%M

The text of the message.

%N

The program name.

%N

The current file, derived from the backtrace (thus $callframes may need adjustment)

%l

The line number in the current file, derived from the backtrace.

%S

The current subroutine or method name, derived from the backtrace.

Lumberjack::Message

Objects of this class represent the messages that are passing through the logger, in the simplest case where one is using the methods provided by the role Lumberjack::Logger then these objects will be created for you with sensible defaults. You are free to create them yourself if you want other values than the defaults or you can sub-class to provide different attributes if you have different requirements and the dispatchers that you are using would make use of them.

The messages themselves contain the information required to determine whether they will becomes candidates for dispatch and select which dispatchers (if any,) they will be sent to.

The messages can be smart matched against items of the enum Lumberjack::Level.

class

This is the type object of the class that the message is for and will be populated by the logging methods of the Lumberjack::Logger role. If it is populated it will be used in two ways. firstly if it is a Lumberjack::Logger the log-level "class method" will be used to determine whether the message should be dispatched, that is if the level of the message is of a higher or equal "severity" than the log-level it will be dispatched, secondly it will be used to select which dispatchers it will be handed to by smart matching against the classes of the dispatcher.

level

This is the Lumberjack::Level representing the level or severity of the message, it will be checked against the log-level of class if available, or the default-level to determine whether the message should be a candidate for dispatch. If this is not provided to the constructor for the message object then it will be set to the default-level which is probably not what you want. The helpers in Lumberjack::Logger take care of that for you however.

backtrace

This is a list of Backtrace::Frame object that represents the execution context when the log message is constructed, it can be used by the dispatcher to provide information about the call site. It will be populated for you when the message is created, however if you are sending a message, for example, about a caught exception you can supply a backtrace that came from elsewhere (though you may need to adjust the frames that the dispatcher examines accordingly.)

message

This is the only required field of the message that there is no default for, and represents the free text payload of the log message.

when

This is the DateTime when the Message was created, a dispatcher is free to use this in generating a log entry.

Lumberjack::Dispatcher

This is role that must be consumed by your dispatcher classes, it defines the interface for dispatch and for the selection of the the messages that is will handle. The actual dispatchers should be instances of your classes and can have any configuration required for them to work.

There are two simple dispatcher classes provided in the module and others might be found in the module ecosystem.

Whilst you are free to implement the dispatcher however you wish you should bear in mind that if you require a BUILD method and wish to populate the levels and classes attributes then you have to provide for them in your signaturem such as:

    submethod BUILD(:$my-parameter, :$!classes, :$!levels) {
        ...
    }

This is unfortunately necessary because a default BUILD for the role won't be called if a class provides one.

method log

method log(Message $message)

This is stubbed in the role and must be provided by a composing class. It is provided with the selected messages and is entirely free to do whatever it wants to implement.

levels

The value of this attribute is smart matched against the level attribute of a message to determine whether this dispatcher should receive it, it can be a single value of Lumberjack::Level, an any Junction of one or more of those values, a subroutine that will take a level as an argument an return a Bool or any other object that will smart match against a level. The default is Any.

classes

The value of this attribute is smart matched against the class attribute of a message to determine (along with the matching of level,) whether this dispatcher should receive it. It can be a class type object, a Junction of one or more type objects, a subroutine that will take the type object as an argument and return a Bool or anything else that could conceivably smart match a class type object.

Lumberjack::Logger

This is role that provides a convenient interface to the logging functionality that can be consumed by any class. The advantage of using the role rather than accessing the log method of Lumberjack directly is that you don't need to worry about constructing the message and so forth.

method log-level

method log-level() returns Level is rw

This is a "class method" (that is setting the value will apply to all instances of the class,) it is the value that is compared to the level of a message to determine whether the message that should be dispatched (contingent of course on there being a suitable dispatcher that would accept it.) Two special values of Lumberjack::Level are provided which may be used here as well as the standard values: All which will cause all messages to be dispatched, and Off which will cause no messages to be dispatched whatever the severity.

method log

multi method log(Message $message)
multi method log(Level $level, Str $message)

This method sends a message to be considered for dispatch. They may be suitable if, for example, the level of the method needs to be calculated or the message is actually being sent on behalf of some other object or process. For most cases however the level specific helpers will probably be more convenient.

method log-trace

method log-trace(Str() $message)

This will send a message at level Trace with the the supplied message. It will be sent for dispatch if the applicable log-level is All or Trace.

method log-trace

method log-debug(Str() $message)

This will send a message at level Debug with the supplied message it will be sent for dispatch if the applicable log-level is DebugΒΈ Trace or All.

method log-info

method log-info(Str() $message)

This will send a message at level Info with the supplied message. It will be sent for dispatch if the applicable log-level is Info, Debug, Trace or All.

method log-warn

method log-warn(Str() $message)

This will send a message at level Warn with the supplied message. It will be sent for dispatch at levels Warn, Info, Debug, Trace or All.

method log-error

method log-error(Str() $message)

This will send a message at level Error with the supplied message. It will be sent for dispatch at all applicable levels except Fatal or Off.

method log-fatal

method log-fatal(Str() $message)

This will send a message at level Fatal with the supplied message. It will always be sent for dispatch except if the applicable level is Off. Despite its name the behaviour does not differ from the other levels, if you wish to actually exit the program you should do this in your own code.

Lumberjack::Level

This is an enumeration who's values represent the dispatch levels for logging messages. The naming is vaguely related to those used by syslog and are suggestive of the frequency and "severity" of the messages (and thus the kind of use they may have,) but don't imply any particular behaviour, any specific or particular interpretation is the responsibility of the consumer of the messages. A dispatcher implementation is of course free to interpret them as it wishes.

The two "pseudo-levels" All and Off should never be present in a message but can be used to indicate "get all messages" or "get no messages" respectively.

The descriptions below are typical or suggested but not mandate uses of the levels.

Listed in decreasing "severity" (which is increasing numeric value,):

Off

No messages will be sent.

Fatal

The most severe and hopefully least frequent messages. This does not imply any specific behaviour despite its name.

Error

Messages that should probably receive attention from a human.

Warn

Events that are unexpected or unwanted but not serious enough to merit immediate attention.

Info

This is the default level and should probably be used for all expected messages that can occur during normal operation.

Debug

Possibly verbose and detailed messages that will only be of use to developers.

Trace

The most high frequency messages.

All

All messages will be sent.

Lumberjack::Dispatcher::Console

This is a simple dispatcher implementation that will output directly to the supplied STDIO handle (by default $*ERR,) Output can be coloured to reflect the log level of the messages displayed (and you can if wish alter the colours you use.) As well as the configuration attributes described below you can set classes and levels as described for Lumberjack::Dispatcher/

colour

A boolean "adverb" indicating whether display should be coloured or not. The default is False (Output is not coloured,)

handle

This is an IO::Handle to which output will be made, the default is the STDERR handle $*ERR, but you can use $*OUT or some other handle opened to a sufficiently display-like device.

format

This is a format string for the output of the messages, the directives are described for the subroutine format-message above. The default is "%D [%L] %C %S : %M" which outputs:

<date> [<Level>] <class> <method> : <message>

If you supply your own format you probably at least want to use "%M" to output the text of the message.

callframes

This is the number of callframes back from the top where the details of the actual callsite of the logging call that you are interesed in and is used to find the execution context of the logging message. The default is 4 which works well for using the Lumberjack::Logger helper methods, but if you are creating your own Message objects and find that the subroutine name, line number and file or wrong then you may want to adjust this.

colours

This is colour map from the log-level of the message to a colour expressed as an integer in the range 0x10 .. 0xE7 (from the ANSI 256 colour set,) the default is roughly what I would expect ranging from Bluish for the least serious messages to Reddish for the most serious. You are free to supply your own as a hash keyed on the log level. If you do so you should supply all of them.

Lumberjack::Dispatcher::File

This is a very simple dispatcher implementation that outputs to a file, it always appends to the end of the file and offers no facilities for rotation, truncation or any other things you might expect from a more sophisticated log appender, it is anticipated that anything with more features would emerge in the modules ecosystem.

As well as the configuration attributes below, the classes and levels of Lumberjack::Dispatcher can be provided when creating the instance.

file

This should be the path to the file which will have the log messages written to, an exception will be thrown if it can't be opened or if it isn't writeable. The file will be opened in append mode. If this isn't provided then handle must be.

handle

This can be provided as an alternative to file and should be an IO::Handle opened for writing that will be used to write the log messages, if this is provided it will be preferred to file but if neither is provided then an exception will be thrown.

format

This is a format string for the output of the messages, the directives are described for the subroutine format-message above. The default is "%D [%L] %C %S : %M" which outputs:

<date> [<Level>] <class> <method> : <message>

If you supply your own format you probably at least want to use "%M" to output the text of the message.

callframes

This is the number of callframes back from the top where the details of the actual callsite of the logging call that you are interesed in and is used to find the execution context of the logging message. The default is 4 which works well for using the Lumberjack::Logger helper methods, but if you are creating your own Message objects and find that the subroutine name, line number and file or wrong then you may want to adjust this.

Lumberjack v0.1.4

A simple logging framework.

Authors

  • Jonathan Stowe

License

Artistic-2.0

Dependencies

DateTime::Format

Test Dependencies

Provides

  • Lumberjack

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.