NAME
Log::ger::Manual::FAQ - FAQ on Log::ger
VERSION
version 0.028.006
GENERAL
Why am I not seeing the logs?
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.
Why am I getting error "Undefined subroutine &main::log_warn called at ..."?
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()
.
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.
How to use OO style?
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'});
}
How to create multiple loggers?
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});
How to log Perl warning/die message? (How to trap warn/die? How to override warn/die?)
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;
How to log stdout output? (How to trap print? How to override print?)
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.
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.
How to log stderr output?
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.
OUTPUT
How to switch output?
Just issue another Log::ger::Output->set()
which will replace previous output plugin.
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
How to send logs to several outputs?
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).
How to send trace/debug messages to screen, but warnings/errors to file?
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'],
},
},
);
How to send trace/debug messages to a file, but warnings/errors to another file?
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'],
},
],
],
);
How to filter by category?
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',
},
},
...
},
);
OUTPUT: FILE
How to have different applications log to the same file?
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.
LEVEL
How to use custom levels?
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.
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
.
Or, you can write your own Log::ger::Level::Like::
module.
CATEGORY
How to log under a different category than the current package?
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'");
How to direct log messages under a certain category to a separate output?
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:
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' },
},
],
},
);
FORMAT & LAYOUT
How to do sprintf-style formatting?
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 ...");
Why doesn't Log::ger log multiple arguments?
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.
How to use deferred calculation of arguments?
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);
}
How to dump data structures?
The default formatter already dumps data structures:
log_warn("Format %s %s", "blah ...", {data=>'structure'});
How to log raw data structure?
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.
How to do custom formatting?
For example, a la Log::Contextual:
log_warn { 'The number of stuffs is: ' . $obj->stuffs_count };
See Log::ger::Format::Block for an example.
How to add timestamps (and other stuffs)?
Use a layouter, e.g. Log::ger::Layout::Pattern.
How to use microsecond in timestamps?
TODO
How to redact sensitive information?
TODO
How to customize layout per output?
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.:
use Log::ger::Output Composite => (
outputs => {
Screen => {
layout => [Pattern => {format => '[%r] %m'}],
},
File => {
path => '/path/to/logfile',
layout => [Pattern => {format => '[%d] [PID %P] %m'}],
},
},
);
How to split multiline log message in a layout?
For example, with the [%r] %m
layout, you want a multiline log message "line1\nline2\nline3"
to be laid out not as:
[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.
TARGETS
How to customize format/layout, output, plugin on a per-target basis?
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).
SEE ALSO
AUTHOR
perlancar <perlancar@cpan.org>
COPYRIGHT AND LICENSE
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.