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

# AUTHORITY
# DATE
our $DIST = 'Log-ger-Manual'; # DIST
# 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.029.000

=head1 GENERAL/ETC

=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;

or (for loading in runtime):

 require Log::ger;
 Log::ger->import;

and not:

 use Log::ger ();

nor:

 require Log::ger;

In other words, the importing is necessary 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 Why am I getting "String found where operator expected at ..., near "log_warn "foo""? Why do I need to put parentheses after the log_* statements?

You need to do:

 use Log::ger;

or:

 BEGIN {
     require Log::ger;
     Log::ger->import;
 }

instead of just:

 require Log::ger;
 Log::ger->import;

In other words, the import() needs to happen during compile-time to give perl
hints that the logger statements (C<log_*>) are subroutines.

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

Examples of real code that produce logs to multiple loggers:
L<WWW::PAUSE::Simple>, L<Finance::Bank::ID::Base>.

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

See L<Log::ger::Manual::Tutorial::481_Output_Composite> for a more detailed
example.

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

=head2 How to log different things to different files (with different levels)?

An application might have more than one kind of logs. A common thing is for an
application to have two kinds of logs: an error log and an access log (like in
Apache or Squid). You can use Log::ger for both kinds of log and have them
easily configurable.

To produce different kinds of logs, you can log to multiple loggers with
different category. Let's say for the error log you use the default logger with
default procedural style, and for the access log you use another logger with OO
style and a specific category.

 use Log::ger;
 my $access_log = Log::ger->get_logger('access');
 log_warn "goes to error log";
 $access_log->info("goes to access log");

Or you can use OO style for both:

 use Log::ger (); # don't export log_* procedural routines
 my $error_log  = Log::ger->get_logger('error');
 my $access_log = Log::ger->get_logger('access');

 $error_log->warn("goes to error log");
 $access_log->info("goes to access log");

See L<Log::ger::Manual::Tutorial::481_Output_Composite> for a more detailed
example.

=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 THE PROJECT

=head2 Why was Log::ger created?

I was a happy user of L<Log::Any> from 2009-2014. Log::Any 0.15 is very
lightweight and I was happily peppering 'use Log::Any' to many of my modules.
Then Log::Any 1.00 was released on Christmas day 2014. David Golden took over
Log::Any's maintenance from its original creator Jonathan Swartz, and decided to
add Log::Any::Proxy while bringing in some other modules like L<Data::Dumper>,
L<base>, L<Carp>. Those modules are core modules and not particularly huge
themselves, but the result is that startup overhead of the 'use Log::Any'
statement increased from ~1-2ms (0.15) to ~10ms (1.00). To me this means
Log::Any is no longer a tiny little module I can sneak in the use of to just
about any other module without care. At that time, I was also developing a CLI
framework and was interested in doing tab completion using Perl scripts, so
startup overhead is a very important issue for me.

Since then, I planned to write my own replacement of Log::Any. Aside from
improving the startup overhead situation, I also wanted a logging library that
uses procedural style instead of OO. One of the reasons for that, aside from
obvious preference, was that so I can optimize away the logging statements if
unneeded (like how asserts work). Another wishlist I had for a logging library
is the ease of setting and re-setting levels, outputs, etc during runtime.

A long vacation in Jun-Jul 2017 gave me the opportunity to finally write
Log::ger.

By the way, the startup overhead of Log::Any (1.708 at the time of this writing)
is better now. But it will probably never be as lightweight as Log::Any 0.15
again, or as lightweight as Log::ger.

My blog post in 2017, which introduces Log::ger and explains basically the same
thing as above:
L<https://perlancar.wordpress.com/2017/07/13/introducing-logger/>

=head1 SEE ALSO

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2020, 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
