I need a new name for my module!

So I wrote a library to handle some logging tasks for me. None of the ones on CPAN really did what I wanted. After I finished up I said to myself, "hey, I think this is worthy of CPAN." I had some friends review it and they agreed.

I checked CPAN before choosing my name, but I only checked the categorized directory of registered names. Today I discovered that an existing library with the same name has already been released. This really showed me the importance of registering your namespace.

I would like any suggestions as to what to call my library. I've thought about it with the old name so much that I can't seem to concieve of any other.

I was going to call it Log::Simple. It provides an OO wrapper around a file handle and provides the ability to tie a callback to the handle that will pre-process any writes.

Full source is available behind the cut.

package Log::Simple; use strict; use Carp; use Symbol; use Fcntl; use IO::File; use vars qw( $VERSION ); $VERSION = '1.00'; my $standard_format = sub { my $message = shift; chomp $message; # Clean up any accidental double lines. return scalar localtime(time) . ": $message\n"; }; sub new { my $class = shift; my $file = shift || croak 'Must supply a filename'; my $format = shift; my $self = { LOGFILE => IO::File->new(), file => $file, 'format' => '', 'status' => 'closed', mode => 'append', }; $self->{LOGFILE}->autoflush(1); bless $self, $class; # Set format to default if no format is provided. $format = defined $format ? $format : 'standard'; $self->format($format) or $self->format('standard'); return $self; } sub open { my $self=shift; my $mode= shift || $self->mode() || 'append'; my $format = shift; $self->mode($mode); $self->format($format); $self->_setStatus('opening'); # Assemble mode my $fcntl_mode = O_WRONLY | O_CREAT; if ($self->mode eq 'append') { $fcntl_mode |= O_APPEND; } elsif ($self->mode eq 'overwrite') { $fcntl_mode |= O_TRUNC; } else { my $badmode = $self->mode; croak "Illegal mode: cannot open logfile in mode $badmode" } # Open IO::File object. $self->{LOGFILE}->open($self->{file}, $fcntl_mode) or croak "Unable to open logfile $self->{file}: $!"; $self->_setStatus('open'); } sub close { my $self = shift; carp('Cannot close a logfile that is not open'), return 0 unless $self->status eq 'open'; $self->_setStatus('closing'); close $self->{LOGFILE} or croak "Unable to close logfile: $!"; $self->_setStatus('closed'); return 'closed'; } sub exit { my $self = shift; my $error_code = shift; my ($message) = @_; $self->entry("Script terminating - $error_code", @_); $self->entry( @_ ); $!=$error_code; croak "$message"; } sub entry { my $self = shift; my $message = shift; my $format = shift; carp "Format '$format' is not a code reference or string literal ' +standard'." if ( ( $format ) && ( ref($format) ne 'CODE' ) && ( $format ne 'standard' ) ); $format = $standard_format if $format eq 'standard'; $format = $self->{'format'} unless ref($format) eq 'CODE'; carp "Cannot log entry unless log status is 'open'" if $self->status ne 'open'; my $string = $format->($message); print {$self->{LOGFILE}} $string; return $string; } sub status { my $self = shift; return $self->{status}; } sub mode { my $self = shift; my $mode = shift; my %mode; @mode{qw(overwrite append)} = (1) x 2; if ($mode) { if (exists $mode{$mode}) { if ($self->status eq 'closed') { $self->{mode} = $mode; } elsif ($self->{mode} ne $mode) { carp "Can only set mode when logfile is closed"; } } else { carp "Illegal mode $mode, mode remains set to $self->{mode}"; return 0; } } return $self->{mode}; } sub format { my $self = shift; my $format = shift || ''; if ($format eq 'standard') { $self->{'format'} = $standard_format; } elsif ($format) { unless ( ref $format eq 'CODE' ) { croak "Format must be a code reference or 'standard'"; return 0; } $self->{'format'} = $format; } return $self->{'format'}; } sub _setStatus { my $self = shift; my $status = shift; my %status; @status{qw(open closed opening closing)} = (1) x 4; croak "Illegal logfile status $status" unless exists $status{$stat +us}; $self->{'status'} = $status; } 1; __END__ =head1 NAME Log::Simple - A simple, object oriented logfile management library. =head1 SYNOPSIS use Log::Simple; my $logfile = '/var/log/perl/mylog'; # Basic usage my $log = Log::Simple->new( $logfile ); $log->open(); $log->entry("Stuff happened"); $log->exit(23, "Bad stuff happened and I am shutting down"); $log->close(); # Advanced functionality my $errors = Log::Simple->new( $logfile, sub { return "OOPS: $_[0]\n +" } ); $log->entry($hash_ref, sub { Dumper @_ }); $log->exit(5, "Bad stuff happened and I am shutting down", 'standard +' }); my $status = $log->status(); my $mode = $log->mode('overwrite'); my $format = $log->format( sub { my $message = shift; return "\t$message\n"; } ); =head1 DESCRIPTION Log::Simple is intended to simplify aspects of managing a logfile. It + uses object oriented interface that is both simple and flexible. Th +is module will not pollute your namespace, it does not export anythin +g. =head2 METHODS =head3 new =over =item $log_obj = new( $path, [$format] ) This method is the class' constructor. You must provide a filename fo +r the logfile; while it is best to use a fully qualified name, any na +me acceptable to C<open> will do. It is also possible to pass in a s +ubroutine reference to set the default format routine. The default f +ormat routine will be used to process the message parameters to all c +alls to C<entry> and C<exit>. See L<"format"> for more information o +n format routines. =back =head3 open =over =item open( [$mode, $format] ) Opens a filehandle to the logfile and sets the status to b<open>. The + method has two optional arguments, C<$mode> and C<$format>. C<$mode +> can be either B<append> or B<overwrite>, it controls whether the fi +lehandle will append to or overwrite the file it opens. C<$format> p +rovides another opportunity to set the default format routine, see L< +"new"> and L<"format"> for more information. This method will die if + it cannot open the filehandle, if this is not acceptable, you will n +eed to use C<eval {}> to trap the exception. =back =head3 close =over =item close() Closes an open logfile and sets the status to b<closed>. This method +will die if it cannot close the filehandle, if this is not acceptable +, you will need to use C<eval {}> to trap the exception. =back =head3 entry =over =item entry( $message, [$format] ) Writes C<$message> to the logfile, after passing it through the format + routine. If the optional C<$format> argument is sent, the routine p +rovided will be used. Otherwise the default format routine will be u +sed. C<$message> is usually a string, but can be just about anything +, depending on the format routine that will process it. See L<"forma +t"> for more information on format routines. =back =head3 exit =over =item exit( $status_code, $message, [$format] ) Calls C<entry($message, $format)>, then sets C<$!> to C<$status_code> +(which must be numeric) and terminates the script. See L<"entry"> for + more information. =back =head3 status =over =item $string = status() Returns the current status of the logfile object. Should only return +B<closed> or B<open>. If an untrapped error has occurred, it may ret +urn a status of B<opening> or B<closing>. =back =head3 mode =over =item $string = entry( [$mode] ) Gets or sets the mode of the logfile object. Allowed modes are B<appe +nd> and B<overwrite>. The mode can only be changed when the object's + status is B<closed>. Returns the mode as a string, or 0 on a failed + attempt to set the mode. =back =head3 format =over =item $code_ref = format( [$format] ) Gets or sets the object's default format routine. Returns a reference + to the default format routine, or B<0> on a failed attempt to set th +e format routine. Can take either the string B<standard> or a code r +eference as an argument. If $format is B<standard>, then the standar +d formatter that is built into the module will be used. =over =item Format Routines Format routines are used to process all messages that are logged. Thi +s feature is what makes this module particularly flexible. A format +routine takes one argument, usually a string, and returns a list suit +able for C<print> to process. # Example Format Routines # Standard Default Routine $log->format( sub { my $message = shift; chomp $message; # Clean up any accidental double lines. return scalar time . ": $message\n"; } ); # Do nothing $log->format( sub { return @_ } ); # Using Data::Dumper to look inside a few variables $log->entry( [$hash_ref, $array_ref], sub { Dumper @_ } ); # Use a closure to generate line numbers { my $counter = 1; $log->format( sub { my $message = shift; chomp $message; return sprintf( "%-3.3d - $message\n", $counter++ ); } } =back =back =head1 BUGS No known bugs exist. Tainting and better validation of file names sho +uld be put in place before this library should handle untrusted input +. Of particular concern is the C<path> argument to the contstructor, + as this is passed to the I<open> builtin. =head1 AUTHOR Mark Swayne, E<lt>mark.swayne -at- chater.netE<gt> Copyright 2002, Mark Swayne Copyright 2005, Zydax, LLC. =head1 LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut


TGI says moo

Replies are listed 'Best First'.
Re: Module Renaming Suggestions
by brian_d_foy (Abbot) on Jul 01, 2005 at 18:39 UTC

    I think Simple is a poor name for any module since it doesn't say anything about what it does. I'm guilty of the same thing, but I note that in Regrettable module names. I recommend you find the special, stand-out functional feature that makes your module different from all the other logging modules and get that into the name somehow.

    You can also discuss module names on the module-authors and modules lists (both @perl.org).

    --
    brian d foy <brian@stonehenge.com>

      In many ways I agree with what you have to say. But I can see some arguments in favor of "Simple".

      There seems to be a non-official standard usage of Simple, eg XML::Simple and Test::Simple. Simple has a specific meaning that a primary goal of the library is to be very easy to use.

      A tool with a very specific function is easier to name than one that is generalized. Adding any specific qualifier or descrptive dilutes the generalized name. Sometimes Simple may be appropriate.

      A very generalized tool that aims to solve the major problems in a given domain, while minimizing the learning curve probably should be called Foo::Simple.

      Whether Simple was appropriate in my case is a moot point, since the name's already take. With the above in mind, I think I'll focus on how my library is different from other offerings and what the specific goals of the system are.

      But, for now, I'm still drawing a blank.


      TGI says moo

        Any use of Simple is not a standard: it's just what people do instead of choosing a good name. Don't follow what other people do.

        Every peice of software should have as its goal that it will be easy to use. That your goal is also that doesn't really mean anything.

        Furthermore, any simplification always happens in some direction. To make things simple, you loose out on something else. Simply tagging "Simple" onto the end of a name doesn't tell the user in which direction you simplified things or which things they can't do anymore.

        As I mentioned before, the modules list (@perl.org) is a good place to discuss names (as well as watch other discussions for your naming edification).

        Good luck :)

        --
        brian d foy <brian@stonehenge.com>
Re: Module Renaming Suggestions
by gam3 (Curate) on Jul 01, 2005 at 18:42 UTC

    How about Log::OO::File?

    As that seems to be the only interface.

    -- gam3
    A picture is worth a thousand words, but takes 200K.
Re: Module Renaming Suggestions
by cees (Curate) on Jul 01, 2005 at 21:46 UTC

    I find it interesting that Log::Message::Simple just made it onto CPAN today. Looks like your not the only one with a Simple log module.

      There are lots of logging modules. They are either very complex and super featureful or are stripped down and address one problem. I originally wrote my module because I wanted something simple and flexible.

      To get that flexibility I decided to use callbacks to handle formatting. That way if you want simple content wrapping you can have it, or if you want to process complex data structures, you can do that too.

      I've used this module in several projects and it works nicely in both modes. Noting I've looked at seems to be quite as flexible. With other solutions I always wind up having to put a bunch of formatting code all over my programs.

      $loglevel = 2; # should be set by getopt sub loglevel { my $data = shift; return $data->[1] <= $loglevel ? Dumper $data->[0] : ""; } # ... Insert some code here. $log->format(\&loglevel); $log->entry( [$some_ref, 1] ); $log->entry("We always log this!", 'standard' ); # Sticks a time and +date stamp in front of text.


      TGI says moo

        If that is the major feature of your module (and the main difference from other logging modules), how about a name like Log::Formatted?

        In fact, I think your module is more complicated than it needs to be since you definitely want to control formatting, so *::Simple just isn't right. In the odd case that *::Simple would be appropriate, it wouldn't be for a module that requires extra work of setting up callbacks or denoting formats. A truly simple module would do that for you.

        --
        brian d foy <brian@stonehenge.com>
[OT] Re: Module Renaming Suggestions
by trammell (Priest) on Jul 02, 2005 at 15:01 UTC
    I think this module is too complicated to be called "Simple":
    • wouldn't it be even simpler if new() called open()? No sense in having a simple logging object that's in no condition to log anything.
    • I'm also not grokking why you need an exit() method. Sounds like functionality unrelated to logging.
    • for that matter, you can simplify further by making the object have exactly one state: OK. Just croak() if you can't open the logfile, and close the log by DESTROYing the object.

    Update: I guess I'd say a truly simple log object would have exactly three methods: new, print, and DESTROY. Log::Trivial?

      I included an exit method so that I could easily log a message and exit with a specified error code and the same time. In an early project with this module, I found that I was regularly logging some message and then croaking with the same message. This made for an ugly mess and much duplicated code. To fix this, I added the exit method.

      While I can see your point about automatically opening the file, something about it bothers me. I could make it possible to control open and close in a call to the constructor. But, since I chose not to use named parameters in the method calls, at that puts a real constraint on how many parameters each method can take without becoming cumbersome. I'd have to add two parameters to new. I hate functions and methods with long parameter lists, so I have say I can't agree to this one. I also feel like there is a built-in expectation that you have to open a file to use it. This module is intended to be a rather thin wrapper around a file handle. Of course it would be a simple matter to subclass and add this feature if one desired it.

      Your points about auto-opening the handle and what it means to be simple really do emphasize brian_d_foy's point about good naming.

      Your point about closing on a DESTROY is well taken. I've mostly used this on windows systems, which don't choke up if you fail to close a filehandle. But it could be used on other systems that might have that failing. I really should add a DESTROY method.


      TGI says moo

Re: Module Renaming Suggestions
by bass_warrior (Beadle) on Jul 01, 2005 at 18:42 UTC
    Log::RealEasy