NAME

Log::Any::Adapter::Daemontools - Logging adapter suitable for use in a Daemontools-style logging chain

VERSION

version 0.090000_003

SYNOPSIS

# Log to STDOUT with log-level-name prefixes for all but 'info'
# Default log level is 'info'
use Log::Any::Adapter 'Daemontools';

# As above, but log level 'notice'
use Log::Any::Adapter 'Daemontools', init => { level => 'notice' };

# As above, but process @ARGV -v/-q and $ENV{DEBUG} to adjust the level
use Log::Any::Adapter 'Daemontools', init => { argv => 1, env => 1 };

# Direct edits to shared config
my $cfg= Log::Any::Adapter::Daemontools->global_config;
$cfg->log_level('debug');
$cfg->init( argv => 1, env => 1 );

# Change log level on the fly
$SIG{USR1}= sub { $cfg->log_level_adjust(1); };
$SIG{USR2}= sub { $cfg->log_level_adjust(-1); };

# Signal handlers can also be installed by the config:
$cfg->init( handle_signals => ['USR1','USR2'] );

# Create a second config independent of the global config
my $cfg2= Log::Any::Adapter::Daemontools->new_config;

# Multiple adapter configurations, tracking different config instances
Log::Any::Adapter->set({ category => qr/^Noisy::Package.*/ }, 'Daemontools', config => $cfg2 );
Log::Any::Adapter->set('Daemontools'); # config defaults to global_config
$cfg2->log_level('warn'); # lower log level for messages from Noisy::Package::*

# Like above, but limit the verbosity instead of creating a second config
Log::Any::Adapter->set({ category => qr/^Noisy::Package.*/ }, 'Daemontools', log_level_max => 'warn' );
Log::Any::Adapter->set('Daemontools'); # config defaults to global_config

See Log::Any::Adapter::Daemontools::Config for most of the details.

DESCRIPTION

The measure of good software is low learning curve, low complexity, few dependencies, high efficiency, and high flexibility. (choose two. haha)

In the daemontools way of thinking, a daemon writes all its logging output to STDOUT (or STDERR), which is a pipe to a logger process. Doing this instead of other logging alternatives keeps your program simple and allows you to capture errors generated by deeper libraries (like libc) which aren't aware of your logging API. If you want complicated logging you can keep those details in the logging process and not bloat each daemon you write.

This module aims to be the easiest, simplest, most efficent way to get Log::Any messages to a file handle while still being flexible enough for the needs of the typical unix daemon or utility script.

Problems solved by this module are:

Preserve log level

The downside of logging to a pipe is you don't get the log-level that you could have had with syslog or Log4perl. An simple way to preserve this information is to prefix each line with "error:" or etc, which can be re-parsed later (or by the logger process). See prefix.

Efficiently squelch log levels

Trace logging is a great thing, but the methods can get a bit "hot" and you don't want it to impact performance. Log::Any provides the syntax

$log->trace(...) if $log->is_trace

which is great as long as "is_trace" is super-efficient. This module does subclassing/caching tricks so that suppressed log levels are effectively sub is_trace { 0 } (although as of Log::Any 1.03 there is still another layer of method call from the Log::Any::Proxy, which is unfortunate)

Dynamically adjust log levels

Log::Any::Adapter allows you to replace the current adapters with new ones with a different configuration, which you can use to adjust log_level, but it isn't terribly efficient, and if you are also using the regex feature (where different categories get different loggers) it's even worse.

This module uses shared configurations on the back-end so you can alter the configuration in many ways without having to re-attach the adapters. (there is a small re-caching penalty, but it's done lazily)

--verbose / --quiet / $ENV{DEBUG}

My scripts usually end up with a chunk of boilerplate in the option processing to raise or lower the log level. This module provides an option to get you common UNIX behavior in as little as 7 characters :-) It's flexible enough to give you many other common varieties, or you can ignore it because it isn't enabled by default.

Display caller() or category, or custom formatting

And of course, you often want to see additional details about the message or perform some of your own tweaks. This module provides quick options to enable caller() info and/or category name where the message originated, and allows full customization with coderefs.

VERSION NOTICE

NOTE: Version 0.1 lost some of the features of version 0.002 when the internals of Log::Any changed in a way that made them impossible. I don't know if anyone was using them anyway, but pay close attention if you are upgrading. This new version adheres more closely to the specification for a logging adapter.

ATTRIBUTES

category

The category of the Log::Any logger attached to this adapter. Read-only.

config

The Log::Any::Adapter::Daemontools::Config object which this adapter is tracking. Read-only reference ( but the config can be altered ).

-init

Log::Any::Adapter 'Daemontools', -init => { ... };

Not actually an attribute! If you pass this to the Daemontools adapter, the first time an instance of the Adapter is created it will call ->init on the adapter's configuration. This allows you to squeeze things onto one line.

The more proper way to write the above example is:

use Log::Any::Adapter 'Daemontools';
Log::Any::Adapter::Daemontools->global_config->init( ... );

The implied init() call will happen exactly once per config object. (but you can call the init() method yourself as much as you like)

See "init" in Log::Any::Adapter::Daemontools::Config for the complete list of initialization options.

METHODS

Adapter instances support all the standard logging methods of Log::Any::Adapter

See Log::Any::Adapter

AUTHOR

Michael Conrad <mike@nrdvana.net>

COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.