Changes for version 0.36 - 2026-10-03
- Enhancements
- Structured fields: every logging method accepts a hashref of fields after the message, e.g. $log->info('login', { user_id => 42 }). They are kept as data in the history, array and CODE-ref backends, as a nested "fields" object in format => 'json', and as journal fields in journald; other backends get them appended as logfmt key=value text.
- The Log::Any adapter implements structured(), so a trailing hashref and the Log::Any context reach Log::Abstraction as fields.
- New critical(), alert() and emergency() methods, logged at their own levels (syslog crit/alert/emerg, journald PRIORITY 2/1/0). They behave like error(): croak_on_error, or having no backend, croaks. An object logger without the method, such as Log::Log4perl, is called with fatal(), or error() if it has no fatal().
- New is_trace, is_info, is_notice, is_warn, is_error, is_critical, is_alert and is_emergency methods alongside is_debug. The Log::Any adapter's detection methods now call them.
- New timestamp options: timestamp_format (a strftime pattern, or 'iso8601'/'rfc3339'), utc, and timestamp_precision (0-9 digits of fractional seconds, from Time::HiRes). Patterns may also use %N, %3N etc., and %z/%:z, which now give a numeric offset on every platform. They apply to %timestamp% and the JSON timestamp. The time is now read once per message, so all backends show the same time. Time::HiRes and Time::Local (both core) are new dependencies.
- File rotation for the path backends: rotate_size (bytes, or with K/M/G), rotate_interval (hourly, daily, weekly, monthly) and rotate_keep (default 5). Files are rotated to FILE.1, FILE.2 ... before the write that is due. Since the file is opened for every message, logrotate's default rename-and-create works without copytruncate or SIGHUP; this is now documented and tested.
- Every backend can have its own 'level' and 'format'. syslog, journald and sendmail take them as keys; file, fd and array (in a logger hash or at the top level) may be given as a hash, e.g. file => { file => $path, level => 'info', format => 'json' }. A format replaces the message for array, syslog, journald and email. Invalid values croak in new().
- Incompatible Changes
- The Log::Any adapter no longer collapses critical, alert and emergency into error; they go to the new methods, so backends now see the levels 'critical', 'alert' and 'emergency' (CODE callbacks testing for 'error' miss them, and syslog priorities change), and is_critical, is_alert and is_emergency have their own thresholds.
- A hashref as the last of two or more arguments to a logging method is now taken as structured fields. It used to be joined into the message as "HASH(0x...)".
- When a call has structured fields, an object logger (such as the default Log::Log4perl) is passed them as an extra " key=value ..." argument after the message.
- Log::Abstraction no longer imports Carp, POSIX, Scalar::Util, Sys::Syslog or Email::Sender::Simple functions, so they can no longer be called as methods on a logger ($log->carp, $log->syslog, $log->strftime ...). Code mocking Log::Abstraction::openlog or ::setlogsock should mock Sys::Syslog::openlog/setlogsock instead.
- 'level' and 'format' in the journald hash are now that backend's level and format; they were sent to the journal as LEVEL and FORMAT fields.
- Bug Fixes
- A top-level 'fd' now counts as a backend in new(), as 'file' and 'array' do: Log::Abstraction->new(fd => $fh) no longer also sets up Log::Log4perl and sends every message there too.
- The release dates in this file are now in ISO-8601 (W3CDTF) form, as CPAN::Changes expects.
- t/journald.t no longer hangs if a journald send fails: its receiver now reads with MSG_DONTWAIT, so the test fails instead. This was the hang in RT#181461.
Documentation
Modules
Logging Abstraction Layer
Log::Any adapter backed by Log::Abstraction