File Coverage

blib/lib/Log/Log4perl/Layout/PatternLayout/Redact.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 32 32 100.0


line stmt bran cond sub pod time code
1             package Log::Log4perl::Layout::PatternLayout::Redact;
2              
3 3     3   277219 use strict;
  3         479  
  3         126  
4 3     3   17 use warnings;
  3         6  
  3         664  
5              
6             # Due to circularities in module uses inside Log::Log4perl, loading
7             # Log::Log4perl seems to pre-load the whole distribution in the correct order
8             # and makes "use base 'Log::Log4perl::Layout::PatternLayout'" work instead of
9             # dieing with a "Cannot find new() on Log::Log4perl::Layout::PatternLayout".
10             # It's unfortunate, but this is why "use Log::Log4perl" is the first thing in
11             # this file.
12 3     3   1462 use Log::Log4perl;
  3         72667  
  3         22  
13              
14 3     3   185 use base 'Log::Log4perl::Layout::PatternLayout';
  3         5  
  3         382  
15              
16 3     3   19 use Carp;
  3         7  
  3         319  
17 3     3   3120 use Carp::Parse::Redact;
  3         60365  
  3         102  
18 3     3   32 use Data::Validate::Type;
  3         7  
  3         104  
19 3     3   2864 use Try::Tiny;
  3         5283  
  3         1641  
20              
21              
22             =head1 NAME
23              
24             Log::Log4perl::Layout::PatternLayout::Redact - Add stack traces without sensitive information in Log::Log4perl logs.
25              
26              
27             =head1 DESCRIPTION
28              
29             C offers the ability to add stack traces to layouts using I<%T>
30             in pattern layouts (see C).
31              
32             However, stack traces contain a list of arguments, and those arguments can
33             be sensitive data like passwords or credit card data. This module redacts the
34             sensitive information, replacing them with '[redacted]' so that the stack traces
35             can be PCI-compliant.
36              
37              
38             =head1 VERSION
39              
40             Version 1.2.2
41              
42             =cut
43              
44             our $VERSION = '1.2.2';
45              
46             our $SENSITIVE_ARGUMENT_NAMES = undef;
47             our $SENSITIVE_REGEXP_PATTERNS = undef;
48             our $MESSAGE_REDACTION_CALLBACK = undef;
49              
50             =head1 SYNOPSIS
51              
52             use Log::Log4perl::Layout::PatternLayout::Redact;
53              
54             =head2 Redacting stack traces
55              
56             Here's an example of log4perl configuration that outputs a redacted trace
57             (use I<%E> instead of I<%T>) :
58              
59             log4perl.logger = WARN, logfile
60             log4perl.appender.logfile = Log::Log4perl::Appender::File
61             log4perl.appender.logfile.filename = $file_name
62             log4perl.appender.logfile.layout = Log::Log4perl::Layout::PatternLayout::Redact
63             log4perl.appender.logfile.layout.ConversionPattern = %d %p: (%X{host}) %P %F:%L %M - %m{chomp}%E
64             log4perl.appender.logfile.recreate = 1
65             log4perl.appender.logfile.mode = append
66              
67             To set your own list of arguments to redact, rather than use the defaults in C,
68             you need to set a localized version of $SENSITIVE_ARGUMENT_NAMES:
69              
70             $Log::Log4perl::Layout::PatternLayout::Redact::SENSITIVE_ARGUMENT_NAMES =
71             [
72             'password',
73             'luggage_combination',
74             'favorite_pony',
75             ];
76              
77             And hash keys in the stack trace that match these names will have their values replaced with '[redacted]'.
78              
79             To set your own list of regexes to use for redaction, rather than use the
80             defaults in C, you need to set a localized version of
81             $SENSITIVE_REGEXP_PATTERNS:
82              
83             $Log::Log4perl::Layout::PatternLayout::Redact::SENSITIVE_REGEXP_PATTERNS =
84             [
85             qr/^\d{16}$/,
86             ]
87              
88             And any argument in the stack trace that matches one of the regexes provided
89             will be replaced with '[redacted]'.
90              
91             Be sure to do the localizations of the package variables after you have
92             initialized your logger.
93              
94             =head2 Redacting messages
95              
96             Here's an example of log4perl configuration that outputs a redacted message
97             (use I<%e> instead of I<%m>) :
98              
99             log4perl.logger = WARN, logfile
100             log4perl.appender.logfile = Log::Log4perl::Appender::File
101             log4perl.appender.logfile.filename = $file_name
102             log4perl.appender.logfile.layout = Log::Log4perl::Layout::PatternLayout::Redact
103             log4perl.appender.logfile.layout.ConversionPattern = %d %p: (%X{host}) %P %F:%L %M - %e
104             log4perl.appender.logfile.recreate = 1
105             log4perl.appender.logfile.mode = append
106              
107             To redact the message, you will need to write your own redaction subroutine as
108             follows:
109              
110             $Log::Log4perl::Layout::PatternLayout::Redact::MESSAGE_REDACTION_CALLBACK = sub
111             {
112             my ( $message ) = @_;
113            
114             # Do replacements on the messages to redact sensitive information.
115             $message =~ s/(password=")[^"]+(")/$1\[redacted\]$2/g;
116            
117             return $message;
118             };
119              
120             Be sure to do the localizations of the package variable after you have
121             initialized your logger.
122              
123             =cut
124              
125             # Add '%E' to the list of options available for the Log4perl layout.
126             # This offers a redacted stack trace.
127             Log::Log4perl::Layout::PatternLayout::add_global_cspec(
128             'E',
129             sub
130             {
131             my $trace = Carp::longmess();
132             chomp( $trace );
133            
134             my $redacted_stack_trace = Carp::Parse::Redact::parse_stack_trace(
135             $trace,
136             sensitive_argument_names => $SENSITIVE_ARGUMENT_NAMES,
137             sensitive_regexp_patterns => $SENSITIVE_REGEXP_PATTERNS,
138             );
139            
140             # For each line of the stack trace, replace the original arguments with the
141             # newly redacted ones.
142             my $lines = [];
143             my $bubbled_to_log4perl = 0;
144             foreach my $caller_information ( @{ $redacted_stack_trace || [] } )
145             {
146             # This caller is inside Log::Log4perl, skip it.
147             if ( $caller_information->get_line() =~ /^\s*Log::Log4perl/ )
148             {
149             # But not after indicating that we've bubbled up to Log::Log4perl.
150             $bubbled_to_log4perl = 1 if !$bubbled_to_log4perl;
151             next;
152             }
153             # This caller is below Log::Log4perl, skip it.
154             next if !$bubbled_to_log4perl;
155            
156             push( @$lines, $caller_information->get_redacted_line() );
157             }
158            
159             my $redacted_trace = join( "\n", @$lines );
160            
161             return "\n" . $redacted_trace;
162             }
163             );
164              
165             # Add '%e' to the list of options available for the Log4perl layout.
166             # This offers a redacted message.
167             Log::Log4perl::Layout::PatternLayout::add_global_cspec(
168             'e',
169             sub
170             {
171             my ( $self, $message ) = @_;
172            
173             return $message
174             if !defined( $MESSAGE_REDACTION_CALLBACK );
175            
176             my $redacted_message;
177             try
178             {
179             Carp::croak('the message redaction callback is not a valid code reference')
180             if !Data::Validate::Type::is_coderef( $MESSAGE_REDACTION_CALLBACK );
181            
182             $redacted_message = $MESSAGE_REDACTION_CALLBACK->( $message );
183             }
184             catch
185             {
186             my $error = $_;
187             Carp::carp("Failed to redact message: $error");
188             return $message;
189             };
190            
191             return $redacted_message;
192             }
193             );
194              
195              
196             =head1 AUTHOR
197              
198             Kate Kirby, C<< >>.
199              
200             Guillaume Aubert, C<< >>.
201              
202              
203             =head1 BUGS
204              
205             Please report any bugs or feature requests to C, or through
206             the web interface at L.
207             I will be notified, and then you'll automatically be notified of progress on
208             your bug as I make changes.
209              
210              
211             =head1 SUPPORT
212              
213             You can find documentation for this module with the perldoc command.
214              
215             perldoc Log::Log4perl::Layout::PatternLayout::Redact
216              
217              
218             You can also look for information at:
219              
220             =over 4
221              
222             =item * RT: CPAN's request tracker
223              
224             L
225              
226             =item * AnnoCPAN: Annotated CPAN documentation
227              
228             L
229              
230             =item * CPAN Ratings
231              
232             L
233              
234             =item * Search CPAN
235              
236             L
237              
238             =back
239              
240              
241             =head1 ACKNOWLEDGEMENTS
242              
243             Thanks to ThinkGeek (L) and its corporate overlords
244             at Geeknet (L), for footing the bill while we eat pizza
245             and write code for them!
246              
247              
248             =head1 COPYRIGHT & LICENSE
249              
250             Copyright 2012 Kate Kirby & Guillaume Aubert.
251              
252             This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
253              
254             This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
255              
256             You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/
257              
258             =cut
259              
260             1;