{Logging, Messaging, Notification, Auditing, ...} frameworks

They're all the same, in many respects.

In my module code, I want to be as flexible as possible. I want to be as detached from implementation details as possible.

I just want to generate a log message (or a notification, or an audit entry). I don't want to care where it ends up, how it is sent, how it is filtered/categorized, who the recipient(s) is/are, what medium(s) is/are used, etc. Let whoever uses the module configure it all.

And I don't want to reinvent the wheel, I want to use an existing framework. A logging framework seems to be a sensible choice. Let's use Log::Any for example. This is a snippet from a module for a file-manager-type web app:

my (@success, @failed);
for (@files) {
    unlink $_;
    if ($!) { push @failed, $_ } else { push @success, $_ }
$log->info("Done deleting files. Files deleted: %s. Files not deleted: %s", \@success, @failed);

The message can end up:

  • in a system-wide log-file;
  • discarded (if configured level of output is less than INFO);
  • in a per-user log file;
  • in a notification email to user (should the user configure it);
  • in a notification email to sysadmin (should the admin configure it);
  • into audit table in database (if the application is using a database);
  • in the console (if this module is also used in a command-line based app);
  • as a desktop notification (if this module is also used in a desktop app);
  • in an internal web-based forum;

However, some of those outputs usually need some additional metadata. In email and desktop notification we usually need separate subject and body. In the audit table in database we need to fill in who (the logged in user). In web applications we usually need to log the remote IP address (or even User-Agent string). In desktop notification or forum sometimes we would like to be able to update the message instead of creating a new one.

Instead of in the logging output module (the appender and formatter, in Log4perl-speak), sometimes I *do* care and need to specify this in my module.

Logging APIs usually do not allow us to do so. Output/appender modules are only given the message as a string.

So I intend to cheat by embedding a JSON-/YAML-encoded metadata in front of the message, e.g.:

$log->info("\x00{subject: 'Progress of copying $foo to $bar', id: xasd8f7d}\x00Copying $foo to $bar. 0%");
for (1..100) {
    $log->info("\x00{id: xasd8f7d}\x00$_%");
    sleep 1;

The presence of \x00 signify that until the next \x00 there will be additional metadata in the form of YAML (or JSON). This way, my desktop notification and web-based forum output module knows that the 2nd-101st message is an update and thus can adjust accordingly.

It should, and I don't have to reinvent any framework or wrapper. But it feels so hackish and ugly.


Well, this is ugly and hackish, and does not really make sense to use it that way.

You should rather write your own wrapper for Log::Any (just looked at Log::Any::Adapter now, probably works with Log::Dispatch or Log::Log4perl the same way). Then use your adapter and accept a hash or enumerated array where the fields have the according semantics.

So either $mymaillog->info( [qw(my@email.com his@email.com)], "ImportantSubject", "mybody") and you are set.

Still I don't thing that a logging framework should be used for non-logging tasks. Just use the according module for the specific purpose.

Just my 0.02€

Leave a comment

About Steven Haryanto

user-pic A programmer (mostly Perl 5 nowadays).