File Coverage

blib/lib/Log/Any/Adapter/FileHandle.pm
Criterion Covered Total %
statement 40 41 97.5
branch 12 14 85.7
condition 6 6 100.0
subroutine 10 10 100.0
pod 0 1 0.0
total 68 72 94.4


line stmt bran cond sub pod time code
1             package Log::Any::Adapter::FileHandle;
2             $Log::Any::Adapter::FileHandle::VERSION = '0.010';
3             =head1 NAME
4              
5             Log::Any::Adapter::FileHandle - A basic Log::Any::Adapter to forward messages to a filehandle
6              
7             =head1 VERSION
8              
9             version 0.010
10              
11             =head1 SYNOPSIS
12              
13             use Log::Any qw($log);
14             use Log::Any::Adapter;
15              
16             # Send all logs to Log::Any::Adapter::FileHandle
17             Log::Any::Adapter->set('FileHandle');
18              
19             $log->info("Hello world");
20            
21             =head1 DESCRIPTION
22              
23             This module is a basic adapter that will simply forward log messages to a filehandle, or any object that
24             supports a 'print' method (L, L, Plack's $env->{psgi.errors} object, etc).
25              
26             I've created it so that my scripts running under damontools or runit can output
27             messages to locally defined logs. It does not timestamp messages, that responsbility is
28             delegated to the external log capture mechanism.
29              
30             You can override the default configuration by passing extra arguments to the
31             C set_adapter method:
32              
33             =over
34              
35             =item fh
36              
37             Pass in your IO::Handle-like object here. If this isn't specified, it will
38             default to opening STDERR. If the object supports an autoflush method,
39             autoflush will be enabled, unless no_autoflush is set.
40              
41             =item no_autoflush
42              
43             Disable automatically turning on autoflush on the fh object.
44              
45             =item format
46              
47             A sprintf string that controls the formatting of the message. It is supplied 2
48             arguments: the log level as supplied by Log::Any (usually all-lowercase), and
49             the message to be logged. The default is "[%s] %s\n". This value should
50             contain the log record terminator, such as a newline.
51              
52             =item escape
53              
54             one of 'none' (default), 'newline', or 'nonascii'. Controls how messages are
55             pre-filtered before passing them to a filehandle. This is handy if you want do
56             smoosh messages into a single line (for easier filtering + processing), or if
57             you want to filter non ascii characters for safe terminal printing.
58              
59             =back
60              
61              
62             =head1 COPYRIGHT AND LICENSE
63              
64             Copyright 2014 by Jason Jay Rodrigues
65              
66             Log::Any::Adapter::FileHandle is provided "as is" and without any express or
67             implied warranties, including, without limitation, the implied warranties of
68             merchantibility and fitness for a particular purpose.
69              
70             This program is free software; you can redistribute it and/or modify it under
71             the same terms as Perl itself.
72              
73             =cut
74              
75              
76 3     3   31006 use strict;
  3         5  
  3         162  
77 3     3   18 use warnings;
  3         6  
  3         118  
78 3     3   788 use Log::Any::Adapter::Util qw(make_method);
  3         9265  
  3         177  
79 3     3   20 use Scalar::Util qw(blessed);
  3         5  
  3         217  
80 3     3   15 use IO::Handle;
  3         4  
  3         130  
81 3     3   13 use base qw(Log::Any::Adapter::Base);
  3         4  
  3         1912  
82              
83             sub init {
84 11     11 0 5710 my ($self, %attr) = @_;
85            
86             # if no fh object is set, we default to STDERR.
87 11 50       58 if(!exists($self->{fh})) {
88 0         0 $self->{fh} = IO::Handle->new_from_fd(fileno(STDERR),'w');
89             }
90              
91 11 100 100     197 if($self->{fh}->can('autoflush') && !$self->{no_autoflush}) {
92 6         25 $self->{fh}->autoflush(1);
93             }
94            
95             # if no format is set, we default to a reasonable sane default.
96 11 100       190 if(!exists($self->{format})) {
97 9         21 $self->{format} = "[%s] %s\n";
98             }
99              
100 11 100       37 if(!exists($self->{escape})) {
101 9         35 $self->{escape} = 'none';
102             }
103             }
104              
105              
106             {
107             # setup logging methods, that simply print to the given io object.
108             my $escapere;
109             eval q# $escapere = qr/\P{ASCII}|\p{PosixCntrl}/; "test" =~ $escapere #;
110             if($@) {
111             # Older versions of perl don't have PosixCntrl.
112             # Since I need to support 5.8.8 for my own use, we have to use compatible RegExp
113 3     3   6791 $escapere = qr/\P{ASCII}/;
  3         23  
  3         41  
114             }
115              
116             foreach my $method ( Log::Any->logging_methods() ) {
117             my $logger = sub {
118 22     22   5220 my $self = shift;
119 22         61 my $message = join('',@_);
120 22 100 100     143 if($self->{escape} eq 'newline' || $self->{escape} eq 'nonascii') {
121 5         25 $message =~ s/\n/\\n/sg;
122 5         12 $message =~ s/\r/\\r/sg;
123             }
124 22 100       50 if($self->{escape} eq 'nonascii') {
125 3         52 $message =~ s/($escapere)/sprintf("\\x{%x}",ord($1))/eg;
  4         331  
126             }
127 22 50       76 if($self->{fh}) {
128 22         163 $self->{fh}->print(sprintf($self->{format}, $method, $message));
129             }
130             };
131             make_method($method, $logger);
132             }
133              
134 9     9   3109 my $true = sub { 1 };
135              
136             # In FileHandle, we log *everything*, and let the
137             # log seperation happen in external programs.
138             foreach my $method ( Log::Any->detection_methods() ) {
139             make_method($method, $true);
140             }
141             }
142              
143              
144              
145             1;