package Log::ger::Manual::FAQ;

# DATE
# VERSION

1;
# ABSTRACT: FAQ on Log::ger

__END__

=pod

=encoding UTF-8

=head1 NAME

Log::ger::Manual::FAQ - FAQ on Log::ger

=head1 VERSION

version 0.028.004

=head1 GENERAL

=head2 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
C<info>, C<debug>, or C<trace>. By default, log level is set to C<warn>. You
need to increase log level first to show messages logged at higher level.

=head2 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
C<import()>.

This will not work either:

 require Log::ger;
 Log::ger::log_warn("blah");

because the logger routines (C<log_warn> et al) are not defined statically in
the C<Log::ger> package but constructed dynamically for each calling package.

=head2 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'});
 }

=head2 How to create multiple loggers?

For example, in L<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});

=head2 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 L<Log::ger::LogException> which shortens the above incantation to
just:

 use Log::ger::LogException;

=head2 How to log stdout output? (How to trap print? How to override print?)

Overriding the builtin C<print> is a bit complex as it is not overridable like
some other builtin functions (see e.g.:
L<https://www.perlmonks.org/?node_id=300471>,
L<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 L<Tie::STDOUT>:

 use Log::ger;
 use Tie::STDOUT
     print => sub {
         log_info join("", @_);
     };

If you are actually debugging with C<print()> instead of any logging framework,
take a look at L<Debug::Print>.

=head2 How to log stderr output?

You can use L<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 F</tmp/log>.

See also the FAQ on how to log warn/die.

=head1 OUTPUT

=head2 How to switch output?

Just issue another C<< 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

=head2 How to send logs to several outputs?

Use L<Log::ger::Output::Composite>, which can multiplex log message to multiple
outputs, including multiple outputs of the same type (e.g. two or more
L<File|Log::ger::Output::File>'s).

=head2 How to send trace/debug messages to screen, but warnings/errors to file?

Using L<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'],
         },
     },
 );

=head2 How to send trace/debug messages to a file, but warnings/errors to another file?

Using L<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'],
             },
         ],
     ],
 );

=head2 How to filter by category?

Using L<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',
             },
         },
         ...
     },
 );

=head1 OUTPUT: FILE

=head2 How to have different applications log to the same file?

You need to use a file output module which supports locking, e.g.
L<FileWriteRotate|Log::ger::Output::FileWriteRotate> or
L<File|Log::ger::Output::File> then enable locking so that on every log a lock
is acquired first.

One nice thing about the FileWriteRotate output module is that
L<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.

=head1 LEVEL

=head2 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 C<use Log::ger>. The above example
will create these logging routines: C<log_critical>, C<log_error>,
C<log_warning>, C<log_info>, C<log_extra>. The aliases won't get the logging
routines but C<Log::ger::Util::numeric_level> will recognize them.

ALternatively, you can use one of the available C<Log::ger::Level::Like::*>
(like L<Log::ger::Level::Like::LogAny>) which basically perform something like
the above so you can just say C<use Log::ger::Level::Like::LogAny>.

Or, you can write your own C<Log::ger::Level::Like::> module.

=head1 CATEGORY

=head2 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'");

=head2 How to direct log messages under a certain category to a separate output?

For example, you want category C<Foo> to go to a separate file C</tmp/foo.log>
while the rest go to C</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' },
             },
         ],
     },
 );

=head1 FORMAT & LAYOUT

=head2 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 ...");

=head2 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. L<Log::ger::Like::LogAny>.

=head2 How to use deferred calculation of arguments?

Use a formatter like L<Log::ger::Format::Block>, or
L<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);
 }

=head2 How to dump data structures?

The default formatter already dumps data structures:

 log_warn("Format %s %s", "blah ...", {data=>'structure'});

=head2 How to log raw data structure?

You can use a formatter like L<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 L<Log::ger::Layout::JSON> or
L<Log::ger::Layout::LTSV>. Or perhaps write your own output module that accepts
raw data structure instead of formatted string and send it somewhere.

=head2 How to do custom formatting?

For example, a la L<Log::Contextual>:

 log_warn { 'The number of stuffs is: ' . $obj->stuffs_count };

See L<Log::ger::Format::Block> for an example.

=head2 How to add timestamps (and other stuffs)?

Use a layouter, e.g. L<Log::ger::Layout::Pattern>.

=head2 How to use microsecond in timestamps?

TODO

=head2 How to redact sensitive information?

TODO

=head2 How to customize layout per output?

For example, you want to use C<[%r] %m> on the screen, but the more complete
C<[%d] [PID %P] %m> in log file. Use L<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'}],
         },
     },
 );

=head2 How to split multiline log message in a layout?

For example, with the C<[%r] %m> layout, you want a multiline log message
C<"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 L<Log::ger::Layout::Pattern::Multiline> instead of
L<Log::ger::Layout::Pattern> to accomplish this.

=head1 TARGETS

=head2 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 L<Log::ger::Format>), layout (using
L<Log::ger::Layout>), or output (using L<Log::ger::Output>).

=head1 SEE ALSO

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 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.

=cut
