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


version 0.102


Default: log to STDOUT, log level info, prefix each line with level name unless it is info:

  use Log::Any::Adapter 'Daemontools';

Default to log level notice, and write to STDERR:

  use Log::Any::Adapter 'Daemontools', -init => { level => 'notice', out => \*STDERR };

Process @ARGV -v/-q and $ENV{DEBUG} to adjust the log level

  use Log::Any::Adapter 'Daemontools', -init => { argv => 1, env => 1 };

Custom output formatting:

  use Log::Any::Adapter 'Daemontools', -init => { format => '"$level: $_ (at $file on line $line)"' };

Change log level on the fly:

  my $cfg= Log::Any::Adapter::Daemontools->global_config;
  $SIG{USR1}= sub { $cfg->log_level_adjust(1); };
  $SIG{USR2}= sub { $cfg->log_level_adjust(-1); };
  # Those signal handlers can also be installed by the config:
  use Log::Any::Adapter 'Daemontools', -init => { signals => ['USR1','USR2'] };

Create alternate configurations separate from the global config:

  my $cfg2= Log::Any::Adapter::Daemontools->new_config(log_level => 'notice');
    { category => qr/^Noisy::Package::Hierarchy.*/ },
    config => $cfg2

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


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 format.

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 replaces that with a simple

  -init => { argv => 'consume', env => 1 };

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 a format option to easily add caller info and/or category where the message originated, and allows full customization with coderefs.

Enable autoflush on output handle

I often forget to $|= 1 , and then wonder why my log messages don't match what the program is currently doing. This module turns on autoflush if output is a file handle. (but if output is a coderef or other object, it's still up to you)


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.



  my $cfg= Log::Any::Adapter::Daemontools->global_config;

Returns the default config instance used by any adapter where you didn't specify one.


  my $cfg= Log::Any::Adapter::Daemontools->new_config( %attributes )

Returns a new instance of a config object appropriate for use with this adapter, but currently always an instance of Log::Any::Adapter::Daemontools::Config. See that package for available attributes.

  Log::Any::Adapter->set( 'Daemontools', config => $cfg );

This method is preferred over calling ->new on the Log::Any::Adapter::Daemontools::Config package directly, in case some day I decide to play subclassing tricks with the Config objects.



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


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


  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 verbose 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.

DO NOT pass un-sanitized user input to -init, because the 'format' attribute is processed as perl code.


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

See Log::Any::Adapter


Michael Conrad <>


This software is copyright (c) 2019 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.