package Log::ger::Manual::Tutorial::481_Output_Composite;

our $DIST = 'Log-ger-Manual'; # DIST

# ABSTRACT: More on the Composite output



=encoding UTF-8

=head1 NAME

Log::ger::Manual::Tutorial::481_Output_Composite - More on the Composite output

=head1 VERSION

version 0.040.000


=head1 EXAMPLE 1: access log and error log

A very common thing to have in an application is two kids 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.

=head2 Producing

You have two choices. First, you use the default logger with default procedural
style for the error log, and another logger with OO style for the access log:

 use Log::ger;
 my $access_log = Log::ger->get_logger(category => '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(category => 'error');
 my $access_log = Log::ger->get_logger(category => 'access');

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

Or you can use procedural style for both using L<Log::ger::Plugin::Multisets>:

 use Log::ger::Plugin Multisets => (
     log_sub_prefixes => {
         # prefix  => init args
         log_      => {category=>'error' }, # or undef, to use the default init args (including category)
         access_   => {category=>'access'},
     is_sub_prefixes => {
         # prefix   => category
         is_        => {category=>'error' },
         access_is_ => {category=>'access'},
 use Log::ger;

 access_info "goes to access log";
 access_warn "goes to access log";
 log_warn    "goes to error log";
 log_debug   "goes to error log";

The example below will use the first choice.

Usually, for the access log you will need to log additional pieces of
information like the current user (and/or IP, and/or process ID, etc). A simple
format for the access log is JSON, where each JSON object (hash) is printed as a
single line and contains the necessary information pieces in hash keys. So let's
create a wrapper to supply this information in a more convenient manner:

 use Log::ger::Format 'None';

 sub access_log {
     my ($self, $action, $object, $note) = @_;
         time   => time(),
         user   => $self->user,
         ip     => $self->user_ip,
         pid    => $pid,

         action => $action,
         object => $object,
         note   => $note,

 sub handle_request {
     my $self = shift;
     if ($is_success) {
         $self->access_log($action => {file=>$file});
     } else {
         log_error ...;

=head2 Consuming

To display the logs, you can use Log::ger::Output::Composite, for example with
this configuration:

 use Log::ger::Output Composite => (
     outputs => {
         Screen => {
             category_level => {access=>'off'}, # we don't show access log to screen
         File => [
             # error log file
                 conf => {path=>'/path/to/app-error.log'},
                 category_level => {access=>'off'}, # we don't show access log to error log file
             # access log file
                 conf => {path=>'/path/to/app-access.log'},
                 level => 'off',
                 category_level => {access=>'info'}, # we only show access log to access log file

See also a real-world example in L<WWW::PAUSE::Simple> and L<App::pause>.

=head1 SEE ALSO

=head1 AUTHOR

perlancar <>


This software is copyright (c) 2022, 2020, 2019, 2018, 2017 by perlancar <>.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.