Log::ger::Manual::FAQ - FAQ on Log::ger
version 0.028.005
By default log messages don't go anywhere (stealth/null logging). Only after you set up an output, the messages will go somewhere:
use Log::ger::Output 'Screen'; use Log::ger; log_warn("hey!");
One mistake might be that you write this instead:
use Log::ger::Output::Screen;
This does nothing; you need to do:
use Log::ger::Output 'Screen';
or:
use Log::ger::Output; Log::ger::Output->set('Screen');
Another reason why your logs are not showing might be that you use levels info, debug, or trace. By default, log level is set to warn. You need to increase log level first to show messages logged at higher level.
info
debug
trace
warn
You need to import Log::ger using:
use Log::ger;
and not:
require Log::ger; use Log::ger ();
because Log::ger sets up the logger routines to the calling package via import().
import()
This will not work either:
require Log::ger; Log::ger::log_warn("blah");
because the logger routines (log_warn et al) are not defined statically in the Log::ger package but constructed dynamically for each calling package.
log_warn
Log::ger
The default in Log::ger is to use procedural style:
use Log::ger; log_warn("blah"); if (log_is_debug()) { log_debug("Format: %s %s", "blah ...", {data=>'structure'}); }
However, you can also use objects:
use Log::ger (); # don't initialize and export logger subroutines my $log = Log::ger->get_logger; $log->warn("blah"); if ($log->is_debug) { $log->debug("Format: %s %s", "blah ...", {data=>'structure'}); }
For example, in Log::Any:
my $log = Log::Any->get_logger; my $log_dump = Log::Any->get_logger(category => "dump"); # to dump contents $log->debugf("Headers is: %s", $http_res->{headers}); $log_dump->debug($http_res->{content});
in Log::ger:
# instead of installing to package, we setup objects (or hashes) for the # secondary loggers my $log_dump = Log::ger->get_logger(category => "dump"); log_debug("Headers is: %s", $http_res->{headers}); $log_dump->debug($http_res->{content});
use Log::ger; $SIG{__WARN__} = sub { log_warn(join "", @_); warn @_; }; $SIG{__DIE__} = sub { log_fatal(join "", @_); die @_; }; warn "This is a warning"; # message will also be logged die "This is an error"; # message will also be logged before script dies
or you can use Log::ger::LogException which shortens the above incantation to just:
use Log::ger::LogException;
Overriding the builtin print is a bit complex as it is not overridable like some other builtin functions (see e.g.: https://www.perlmonks.org/?node_id=300471, https://www.perlmonks.org/?node_id=542712) although it's still doable via e.g. low-level manipulation or source filter trickery.
print
A simpler alternative is capturing output to the filehandle instead (STDERR, STDOUT), e.g. using Tie::STDOUT:
use Log::ger; use Tie::STDOUT print => sub { log_info join("", @_); };
If you are actually debugging with print() instead of any logging framework, take a look at Debug::Print.
print()
You can use Tie::STDERR:
use Log::ger; use Log::ger::Output File => (path => "/tmp/log"); use Tie::STDERR sub { log_warn(join "", @_) };
Now output to stderr will be logged to file /tmp/log.
See also the FAQ on how to log warn/die.
Just issue another Log::ger::Output->set() which will replace previous output plugin.
Log::ger::Output->set()
Log::ger::Output->set("Screen"); log_warn("foo!"); # goes to screen Log::ger::Output->set("SimpleFile", path=>"app.log"); log_warn("bar!"); # goes to file
Use Log::ger::Output::Composite, which can multiplex log message to multiple outputs, including multiple outputs of the same type (e.g. two or more File's).
Using Log::ger::Output::Composite's per-output level:
use Log::ger::Output 'Composite' => ( outputs => { Screen => { level => ['trace', 'debug'], }, File => { conf => { path=>'/path/to/file.log' }, level => ['warn', 'error'], }, }, );
Using Log::ger::Output::Composite's per-output level. Note that you can specify multiple outputs of the same kind (in this case, File):
use Log::ger::Output 'Composite' => ( outputs => { File => [ { conf => { path=>'file1.log' }, level => ['trace', 'debug'], }, { conf => { path=>'file2.log' }, level => ['warn', 'error'], }, ], ], );
Using Log::ger::Output::Composite's per-category level:
use Log::ger::Output 'Composite' => ( outputs => { Screen => {...}, File => {...}, }, category_level => { 'MyApp::SubModule1' => 'info', 'MyApp::SubModule2' => 'debug', ... }, );
or per-output, per-category level:
use Log::ger::Output 'Composite' => ( outputs => { Screen => { category_level => { 'MyApp::SubModule1' => 'info', 'MyApp::SubModule2' => 'debug', }, }, ... }, );
You need to use a file output module which supports locking, e.g. FileWriteRotate or File then enable locking so that on every log a lock is acquired first.
One nice thing about the FileWriteRotate output module is that File::Write::Rotate provides a buffer so when you temporarily fail writing (e.g. disk is momentarily full or lock momentarily cannot be acquired) log messages (up to a certain number of them) is kept at the memory buffer first.
One way:
use Log::ger (); BEGIN { our %Log::ger::Levels = ( critical => 1, error => 2, warning => 3, info => 4, extra => 5, ); our %Log::ger::Level_Aliases = ( warn => 3, verbose => 4, );
Do this before initializing any package with use Log::ger. The above example will create these logging routines: log_critical, log_error, log_warning, log_info, log_extra. The aliases won't get the logging routines but Log::ger::Util::numeric_level will recognize them.
use Log::ger
log_critical
log_error
log_warning
log_info
log_extra
Log::ger::Util::numeric_level
ALternatively, you can use one of the available Log::ger::Level::Like::* (like Log::ger::Level::Like::LogAny) which basically perform something like the above so you can just say use Log::ger::Level::Like::LogAny.
Log::ger::Level::Like::*
use Log::ger::Level::Like::LogAny
Or, you can write your own Log::ger::Level::Like:: module.
Log::ger::Level::Like::
Normally, using the procedural interface you are logging under the category of your package:
package My::App; use Log::ger; log_warn("this will be logged under category 'My::App'");
If you want to log under a different category, you can use the OO interface:
package My::App; use Log::ger; my $log_foo = Log::ger->get_logger(category => "Foo"); $log_foo->warn("this will be logged under category 'Foo'");
For example, you want category Foo to go to a separate file /tmp/foo.log while the rest go to /path/app.log, you can do something like this:
Foo
/tmp/foo.log
/path/app.log
use Log::ger::Output Composite => ( outputs => { File => [ { conf => {path=>'/path/app.log'}, category_level => { Foo => 'off' }, }, { conf => {path=>'/path/foo.log'}, level => 'off', category_level => { Foo => 'trace' }, }, ], }, );
By default, the Log::ger formatter already does sprintf-style formatting:
log_warn("Format %s %s", "blah ...", {data=>'structure'});
If there is only one argument, no formatting is done.
log_warn("blah ...");
Logging multiple arguments is not supported by the default formatter because by default Log::ger adopts sprintf style:
log_warn("blah ...", "more blah ...");
Either join the arguments first, use sprintf style, or use some of the other formatters that support this, e.g. Log::ger::Like::LogAny.
Use a formatter like Log::ger::Format::Block, or Log::ger::Format::Flogger, or develop your own formatter to do what you want.
You can also do this:
if (log_is_trace()) { log_trace("Format %s", $foo->something_that_is_expensive_to_calculate); }
The default formatter already dumps data structures:
You can use a formatter like Log::ger::Format::None which will prevent your log message from being stringified. To output this to destination, combine this with a layout plugin like Log::ger::Layout::JSON or Log::ger::Layout::LTSV. Or perhaps write your own output module that accepts raw data structure instead of formatted string and send it somewhere.
For example, a la Log::Contextual:
log_warn { 'The number of stuffs is: ' . $obj->stuffs_count };
See Log::ger::Format::Block for an example.
Use a layouter, e.g. Log::ger::Layout::Pattern.
TODO
For example, you want to use [%r] %m on the screen, but the more complete [%d] [PID %P] %m in log file. Use Log::ger::Output::Composite, e.g.:
[%r] %m
[%d] [PID %P] %m
use Log::ger::Output Composite => ( outputs => { Screen => { layout => [Pattern => {format => '[%r] %m'}], }, File => { path => '/path/to/logfile', layout => [Pattern => {format => '[%d] [PID %P] %m'}], }, }, );
For example, with the [%r] %m layout, you want a multiline log message "line1\nline2\nline3" to be laid out not as:
"line1\nline2\nline3"
[0.003] line1 line2 line3
but as:
[0.003] line1 [0.003] line2 [0.003] line3
You can use Log::ger::Layout::Pattern::Multiline instead of Log::ger::Layout::Pattern to accomplish this.
To use a plugin only for the current package:
package MyPackage; use Log::ger::Plugin; Log::ger::Plugin->set_for_current_package( 'PluginName', conf1 => ..., ...); use Log::ger;
Do the same thing for format (using Log::ger::Format), layout (using Log::ger::Layout), or output (using Log::ger::Output).
perlancar <perlancar@cpan.org>
This software is copyright (c) 2019, 2018, 2017 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Log::ger::Manual, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Log::ger::Manual
CPAN shell
perl -MCPAN -e shell install Log::ger::Manual
For more information on module installation, please visit the detailed CPAN module installation guide.