NAME

Log::Message::JSON - structured messages that stringify to JSON

SYNOPSIS

package My::Application::Module;

use Log::Log4perl;
use Log::Message::JSON qw{logmsg};

sub do_something {
  my ($self, $foo, $bar, @rest) = @_;

  my $logger = Log::Log4perl->get_logger();

  $logger->info(logmsg message => "do_something entered",
                       foo => $foo, bar => $bar, rest => \@rest);

  # ...
}

# in flat-file logs entry would look like:
# Dec 28 00:24:52 example.net My-Application[1587]: {"message":"do_something entered","foo":"value of foo","bar":"value of bar","rest":["value","of","rest"]}

DESCRIPTION

Good logging requires today a lot more than in Good Ol' Times[tm]. Each log entry should have a structure and be machine-parseable. On the other hand, there are lot of logging libraries that don't quite support structured logs and only process flat strings.

Log::Log4perl(3) architecture allows both, flat strings and structured entries. It's up to appender module whether it accepts one or another form. Unfortunately, this makes application developer to decide in advance, which appenders could be in use and defeats much of Log::Log4perl's flexibility.

Log::Message::JSON is an attempt to solve this problem. Developer can create a message that has an internal structure (i.e. is a hash(ref)), and at the same time it can be used as a simple string, instantly serializing to single-line JSON. This way the developer don't need to decide on appenders in advance. Moreover, flat string logfiles are easier to parse, especially if entries have this form.

Of course, you don't need Log::Log4perl to use this module. It could be used wherever a hashref needs to be sensibly stringified while preserving its all hash-like features.

API

The preferred way is the short way. Object-oriented API is described here mainly for reference.

Short Way

logmsg(...)
logmess(...)
msg(...)
json(...)

These are plain functions. They all are exported (but none by default, you need to specifically ask for them), they all do the same and they all accept the same arguments. They are provided for your convenience. Choose the one that don't clash with your methods (but please, make your life easier in future and choose one for whole application).

These functions accept either a reference to a hash or a list of key => value pairs. The latter form preserves keys order, so I believe it's more useful. Also, in the latter form you may skip the first key name; the value will be stored under message key in such case.

Returned value is an object created with new() method (see "Object-Oriented API"), so it's a reference to a hash (blessed, but still hashref, with all its consequences).

Usage example:

use Log::Message::JSON qw{logmsg};
use Log::Log4perl;

my $msg1 = logmsg { key1 => 1, key2 => 2 };
my $msg2 = logmsg foo => 1, bar => 2, text => "some text";
my $msg3 = logmsg "my log message", host => hostname();

my $logger = Log::Log4perl->get_logger();
$logger->info($msg1);
$logger->debug($msg2);
$logger->warn($msg3);

print $msg1;
printf "%s => %s\n", $_, $msg2->{$_} for keys %$msg2;

Object-Oriented API

new(key => value, ...)
new({ key => value, ... })

Constructor.

This method creates a new hash reference. The underlying hash is tied to Tie::IxHash(3) and filled with arguments. Because of overloaded stringification operator, reference is blessed with Log::Message::JSON package.

If the first call form (list of pairs) was used, the order of key/value pairs is preserved. If the number of elements is odd, the first element is believed to be value of message key.

If the second call form (hashref) was used, key/value pairs are sorted using cmp operator, unless the referred hash was tied to Tie::IxHash(3).

to_json()

JSON encoding method. This method returns a JSON string that contains no tabs nor newlines. Just a single line of text.

Log::Log4perl NOTES

You might be tempted to use custom message output filter to stringify the message. It would look like this:

my $logger = Log::Log4perl->get_logger();
$logger->info({ filter => \&dumper, value => $mydata });

This won't work too well: the filter gets called before appender module, so the appender gets a string instead of a structured message. The better way would be:

my $logger = Log::Log4perl->get_logger();
$logger->info(logmsg $mydata);

Log::Log4perl only processes filter and value when the object is a plain, unblessed hash, so you may safely use these two key names.

AUTHOR

Stanislaw Klekot, <cpan at jarowit.net>

LICENSE AND COPYRIGHT

Copyright 2012 Stanislaw Klekot.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

SEE ALSO

Log::Log4perl(3), Log::Log4perl::Appender::Fluent(3), Tie::IxHash(3), Log::Message::Structured(3).