MooseX::Role::Loggable improvements (version 0.110)
I've released a new version of MooseX::Role::Loggable: 0.110. It provides some improvements and basically a more steady version of it.
Here's a description of what it is, what the improvements are, and some of the considerations in doing them.
What is MooseX::Role::Loggable?
It's a Moo/Moose role (works with both) that allows you to provide comfortable and strong logging capabilities to your objects. It uses Log::Dispatchouli to allow you to connect to various logging outputs. You can work with files, stdout, stderr, and Syslog. It has levels, facilities, identity, debugging mode, muted logging, fatal logging, and control over the path and name of the log files (if that's what you chose to use).
Along with methods (such as log and log_debug), it provides attributes with sane defaults to allow your application to work without doing any additional work. For example, you get a debug flag and the log_debug method will only output something if the flag is on.
Changes introduced:
Other than documentation improvements, I've introduced two major changes: setting the logger_ident attribute automatically and deprecating the log_fields method.
The identifier:
The logger_ident attribute is the application's identifying string for the logging. The default was set incorrectly to the name of the role, instead of the name of your class. Now it is set correctly to whatever your application's class name is.
If your have an application called MyApp::Worker, and it uses the role, the ident will be set to MyApp::Worker. This makes all logging instinctively clear for you in all your logs.
Of course, you can always set it to whatever you want by overriding the attribute in your class.
The logger fields:
Sometimes you have object MyApp, which uses the logger role, and you want to create another object (say, MyApp::Worker) which needs to have the exact same logging capabilities. The method log_fields was added in order to provide all the configuration for the child object. That wasn't very smart.
Instead of passing the attributes, you can simply pass the logger (Log::Dispatchouli) object, available in the logger attribute, as such:
MyApp::Worker->new( logger => $self->logger );
However, this created a problem. You see, MooseX::Role::Loggable provides attributes which are then used to create the logger object automatically. They have their own defaults as well. If you provide a logger yourself, you're ignoring the attributes, and the attributes no longer reflect the object you have passed. That's the problem.
MyApp might have the debug flag set to on. If it passes the logger to MyApp::Worker, it will have a debug-mode logger, but MyApp::Worker's debug flag attribute will be set to the default, which is off. The logging will work, yes, but probing your secondary object (like checking its debug flag) will be incompatible with what the logger actually has.
$worker->logger->{'debug'} == 1; # true $worker->debug == 1; # false, uses default value: 0
The way to fix it was to check whether a logger was passed to the object and if so, change the values of the attributes in the object to match the ones defined in the logger object that was passed. I used the BUILDARGS method for that.
Another tricky corner is making sure that you still allow the user to provide a logger and to override something in that logger. For example, a user might want to pass the logger, but enable debugging, which isn't on:
$self->debug == 0; # true
# pass the logger, but also turn debugging on
MyApp::Worker->new( logger => $self->logger, debug => 1 );
This sacrifices the immutability of the logger somewhat (and I'm a *big* fan of immutability) but I think that's a plausible usage case, so I'm allowing it.
If you're already using the log_fields methods, you should stop. It will still work now (passing on the logger attribute for you), but it's deprecated and will emit a warning both in your terminal and in your logs. Why both? Because I have no idea which is active, and I want to make sure you don't miss it, because will remove it later on.
Leave a comment