package Log::ger::Manual::Tutorial::49_WritingAnOutputPlugin;

# DATE
# VERSION

1;
# ABSTRACT: Writing an output plugin

__END__

=pod

=encoding UTF-8

=head1 NAME

Log::ger::Manual::Tutorial::49_WritingAnOutputPlugin - Writing an output plugin

=head1 VERSION

version 0.028.004

=head1 DESCRIPTION

A lot of output plugins have been written. Search CPAN for
C<Log::ger::Output::*> modules. If none suits your needs, there's still
L<Log::ger::Output::LogDispatchOutput> which can use a L<Log::Dispatch> output
module (of which there are many), or L<Log::ger::Output::Callback> which lets
you supply just a coderef to do the logging.

If you really want to write your own Log::ger output plugin, the following will
show you how. Let's say we want to log to some logging server using a client
library called C<Lancard>. Create C<Log::ger::Output::Lancard> as follows:

 # in lib/Log/ger/Output/Lancard.pm
 package Log::ger::Output::Lancard;

 use 5.010;
 use strict;
 use warnings;

 sub get_hooks {
     require Lancard::Client;
     my %conf = @_;

     $conf{host} or die "Please specify host";

     my $lancard = Lancard::Client->connect(
         host => $conf{host},
         port => $conf{port} // 12345,
     );

     return {
         create_log_routine => [
             __PACKAGE__, # key
             50,          # priority
             sub {        # hook
                 my %hook_args = @_;
                 my $logger = sub {
                     my ($ctx, $msg) = @_;
                     $lancard->log($msg);
                 };
                 [$logger];
             }
         },
     };
 }

 1;

The only subroutine you have to provide is C<get_hooks> to return the hooks that
this plugin wants to add. For output plugin, usually this is hook in the
C<create_log_routine> or, less often, C<create_logml_routine> phase. Our
C<get_hooks> should return a hashref with phase names as keys and hook records
as values. Hook record is C<< [$key, $priority, $hook] >> where C<$key> is
usually C<__PACKAGE__>, and C<$priority> is usually 50 unless you want to do
something tricky or advanced.

At this point, it will really help if you understand how hooks work by reading
L<Log::ger::Manual::Internals>. But, without reading the said documentation,
it's still possible to write an output plugin so let's continue right away if
you want to skip reading the internals documentation.

The actual hook coderef (C<$hook>) should return a logger routine, which is
another coderef (C<$logger> in the above code). Logger routine will receive C<<
($ctx, $msg) >> as argument where C<$msg> is the already-formatted message. You
typically just need to send C<$msg> (which is almost always a string) to some
output. In our example, we send the log message string to the logging server via
the client object C<$lancard>.

Note that a separate logger routine will be created for each logging level (and
for each target package that uses logging!), so you'd want to keep C<$logger>
small, like avoid instantiating your Lancard client C<$lancard> inside
C<$logger> as there will be multiple clients instantiated.

To use your newly written output plugin, do the usual:

 use Log::ger::Output Lancard => (host => '192.168.0.22');

or:

 use Log::ger::Output;
 Log::ger::Output->set(Lancard => (host => '192.168.0.22'));

=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
