Group
Extension

Log-ger-Manual/lib/Log/ger/Manual/ForLogAny.pod

package Log::ger::Manual::ForLogAny;

# AUTHORITY
# DATE
our $DIST = 'Log-ger-Manual'; # DIST
# VERSION

1;
# ABSTRACT: Log::ger for Log::Any users

__END__

=pod

=encoding UTF-8

=head1 NAME

Log::ger::Manual::ForLogAny - Log::ger for Log::Any users

=head1 VERSION

version 0.040.000

=head1 WHY LOG::ANY

Log::Any is one of the first logging libraries on CPAN which promotes separation
of producers and consumers. This means, instead of having to configure logging
output in your module like this:

 package MyLib;
 use Log::SomeLib;

 my $log = Log::SomeLib->new(
     output => ...,
     level => ...,
 );

 sub mymethod {
     $log->warn("blah ...");
 }

you just log:

 package MyLibrary;
 use Log::Any '$log';

 sub mymethod {
     $log->warn("blah ...");
 }

and the configuration of outputs and levels is done on the application side.

I loved Log::Any and was a happy user for a long time, but the increasing
startup overhead annoyed me enough to start the Log::ger project (see this FAQ
entry for more details: L<Log::ger::Manual::FAQ/"Why was Log::ger created?">).

=head1 WHY LOG::GER OVER LOG::ANY

Log::ger can be used in procedural style in addition to OO style. Aside from
preference, this gives the benefit of being able to optimize away unneeded
logging statements to avoid runtime overhead (see L<Log::ger::Plugin::OptAway>).
A procedural wrapper for Log::Any could also be written to accomplish the same,
but this is native in Log::ger.

Log::ger has a smaller startup overhead compared to Log::Any. Log::Any used to
be very light also (startup overhead under 1ms) until version 0.15.

Log::ger gives you customizable levels and routine names.

Log::ger allows you to log in a custom format, e.g. using block a la
L<Log::Contextual>, raw data structure as JSON, etc.

=head1 MIGRATING

To ease migrating, L<Log::ger::Like::LogAny> is provided. You can change this
line in your code:

 use Log::Any;

into:

 use Log::ger::Like::LogAny;

and this:

 my $log = Log::Any->get_logger;

into:

 my $log = Log::Any::Like::LogAny->get_logger;

and this:

 use Log::Any '$log';

into:

 use Log::ger::Like::LogAny '$log';

=head1 FAQ

=head2 In my application, I have some modules using Log::Any and some using Log::ger. I want to consume logs using Log::Any, how do I do that?

Install L<Log::ger::Output::LogAny> then in your application:

 use Log::ger::Output 'LogAny';

This will send logs produced via Log::ger to Log::Any.

=head2 In my application, I have some modules using Log::Any and some using Log::ger. I want to consume logs using Log::ger, how do I do that?

Install L<Log::Any::Adapter::LogGer> then in your application:

 use Log::Any::Adapter 'LogGer';

This will send logs produced via Log::Any to Log::ger.

=head2 How to set an output "lexically", like with the 'lexically' option in Log::Any::Adapter?

In Log::Any, this is a way to set an adapter temporarily:

 {
     Log::Any::Adapter->set({lexically => \my $lex}, 'Name', ...);
     ...
 } # when $lex goes out of scope, the adapter setting is removed

One way to do this in Log::ger:

 my $saved = Log::ger::Util::save_hooks('create_outputter');
 Log::ger::Output->set('Name', ...);
 ...
 Log::ger::Util::restore_hooks('create_outputter', $saved);

A nicer interface may be provided in the future.

=head2 How to log structured data?

In Log::Any, you log additional data via an additional structured data after the
message:

 $log->info("message", {additional=>1, data=>2});

or even just log structured data:

 $log->info({message=>"msg", {additional=>1, data=>2}, ['more', 'data']);

You must use an adapter that can handle structured data, i.e. one that defines
C<structured> method. This method will then receive the level, category, and the
arguments as-is. Whereas an adapter that cannot handle structured data will get
a single string where the structured is dumped and joined with a single space:

 "message {additional=>1,data=>2}"
 {message=>"msg",additional=>1,data=>2} ['more','data']"

Note that you must use the "non-f" variant of the logging methods. You cannot do
this:

 $log->infof("message", {additional=>1, data=>2});

as the first argument will be treated as sprintf format and the rest are
arguments for sprintf.

In Log::ger, you can use the L<None|Log::ger::Format::None> formatter. This
means your arguments will not be formatted and sent as-is to the output module:

 use Log::ger::Format 'None';
 log_info("message", {additional=>1, data=>2});
 log_info({message=>'msg', additional=>1, data=>2}, ['more','data']);

You can then choose an output module that can handle structured data.

=head2 What about contextual logging?

Contextual logging is attaching additional information along with your message.

In Log::Any this is done by adding keys to C<< $log->context >> which is a
hashref:

 $log->context->{progname} = "myapp";
 $log->info("Starting program");

 if (my $errmsg = error_condition()) {
     local $log->context->{file} = $path;
     $log->error("Can't process file: $errmsg");
 }

The adapter must be able to handle structured data. The context will be passed
to the adapter's C<structured> method as if it were an additional argument to
the logging function:

 ("Starting program", {progname=>"myapp"})
 ("Can't process file: some error msg", {progname=>"myapp", file=>"/some/path"})

If the adapter cannot handle structured data, the context
hashref will be dumped to string:

 "Starting program {progname=>"myapp"}"
 "Can't process file: some error msg {progname=>'myapp',file=>'/some/path'}"

In Log::ger this is currently not yet implemented as I haven't decided how to
best implement it.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2022, 2020, 2019, 2018, 2017 by perlancar <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


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.