This file is indexed.

/usr/share/perl5/Log/Trace.pm is in liblog-trace-perl 1.070-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
package Log::Trace;
use Carp;

#Hires times if available
eval
{
	require Time::HiRes;
};

use vars qw($VERSION @EXPORT);
@EXPORT = qw(TRACE_HERE TRACEF); # TRACE, DUMP
use strict qw(subs vars);
use Fcntl ':flock';

$VERSION = sprintf"%d.%03d", q$Revision: 1.70 $ =~ /: (\d+)\.(\d+)/;

#################################################
# Importing
#################################################

*{"_debug"} = 0 ? sub { warn __PACKAGE__ . " @_\n" } : sub {};

#Import into calling packages
sub import
{
	my $pkg = shift;
	my $callpkg = caller(0);
	my @args = @_;
	if (ref $args[1] eq 'HASH')
	{
		# e.g. 'import (print => {Verbose => 1})
		@args = ($args[0], undef, @args[1..$#args])
	}
	$pkg->_import($callpkg, @args);
}

sub deep_import # deprecated. use 'import Log::Trace {Deep => 1, ...} ...'
{
	my $pkg = shift;
	my $callpkg = caller(0);
	my $params = ref $_[0] ? shift : {};
	$params->{Deep} = 1;
	push @_, undef if @_ == 1; # deep_import 'print';
	$pkg->_import($callpkg, @_, $params);
}


sub TRACEF
{
	my $callpkg = caller();
	my $trace = *{"$callpkg\::TRACE"};
	my $params = ref $_[0] ? shift : {};
	my $format = shift;
	$trace->($params, sprintf($format, @_));
}


sub TRACE_HERE
{
	my $callpkg = caller();
	my $params = ref $_[0] ? shift : {};
	# see 'perldoc -f caller'
	# calling caller() from the DB package stores subroutine args in @DB::args
	my @caller;
	do {
		package DB;
		@caller = caller(1);
		@caller = caller(0) unless $caller[0];
	};
	my $sub = $caller[3]; # the subroutine that called TRACE_HERE
	my ($file, $line) = (caller(0))[1,2]; # the location of the TRACE_HERE
	my $trace = *{"$callpkg\::TRACE"};
	shift @DB::args if @DB::args && "$DB::args[0]" eq "$params";
	$trace->($params, "In $sub(".join(",", @DB::args).") - line $line of $file");
}


#################################################
# Exporting
#################################################

sub _import
{
	my $pkg = shift;
	my (@packages) = shift;
	my ($target, $arg, $params) = @_;
	$target = '' unless defined $target;

	if ($params->{Deep}) {
		# extend the package list
		push @packages, _deep_import_packages($params->{Everywhere});
	}
	if ($params->{AutoImport}) {
		# override the default require() to catch new modules being loaded
		_install_require($pkg, $params, $target, $arg)
	}

	# lookup: valid target > TRACE sub.  These are also closures around '$arg'
	my %import_targets = (
		'print'          => sub {_log_to_fh($arg, _log_normal(@_))},
		'print-verbose'  => sub {_log_to_fh($arg, _log_verbose(@_))},
		'print-debug'    => sub {_log_to_fh($arg, _log_debug(@_))},
		'warn'           => sub {warn _log_normal(@_)},
		'warn-verbose'   => sub {warn _log_verbose(@_)},
		'warn-debug'     => sub {warn _log_debug(@_)},
		'buffer'         => sub {$$arg .= _log_normal(@_)},
		'buffer-verbose' => sub {$$arg .= _log_verbose(@_)},
		'buffer-debug'   => sub {$$arg .= _log_debug(@_)},
		'file'           => sub {_log_to_file($arg, _log_normal(@_))},
		'file-verbose'   => sub {_log_to_file($arg, _log_verbose(@_))},
		'file-debug'     => sub {_log_to_file($arg, _log_debug(@_))},
		'log'            => sub {_log_to_file($arg, _log_debug(@_))},
		'syslog'         => sub {_log_to_syslog($arg, _log_normal(@_))},
		'syslog-verbose' => sub {_log_to_syslog($arg, _log_verbose(@_))},
		'syslog-debug'   => sub {_log_to_syslog($arg, _log_debug(@_))},
		'custom'         => $arg,
	);

	my $suffix = '';
	$params->{Verbose} = 0 unless defined $params->{Verbose};
	if ($params->{Verbose} == 1)
	{
		$suffix = '-verbose';
	}
	elsif ($params->{Verbose} == 2)
	{
		$suffix = '-debug';
	}
	$target = $import_targets{$target.$suffix} ? $target.$suffix : $target;
	_debug("Initialising target: $target");

	foreach my $export_to (@packages) {
		# Check whether to export functions to the package
		my $match = defined $params->{Match} ? $params->{Match} : '.';
		next unless $export_to =~ /$match/;
		my %exclude;
		if (my $excl = $params->{Exclude}) {
			%exclude = map {$_ => 1} ref $excl eq 'ARRAY' ? @$excl : $excl;
		}
		$exclude{+__PACKAGE__} = 1; # exclude ourselves
		next if $exclude{$export_to};

		_debug("Exporting target:$target to $export_to");
		# set up the TRACE/DUMP functions
		my ($trace, $dump);
		if ($target && $import_targets{$target})
		{
			$trace = _trace_maker($export_to, $params, $import_targets{$target});
			$dump  = _dump_maker($export_to, $params, $trace);
		}
		else
		{
			# Just export stub functions
			$trace = $dump = sub {};
			carp "$pkg imported with unknown target $target" if $target;
		}

		# Now export ...
		__replace_subroutine($export_to, 'TRACE', $trace);
		__replace_subroutine($export_to, 'DUMP', $dump);
		__replace_subroutine($export_to, 'TRACEF', \&TRACEF);
		__replace_subroutine($export_to, 'TRACE_HERE', \&TRACE_HERE);

		if ($params->{AllSubs})
		{
			# wrap all functions in package with calls to TRACE
			_debug("wrapping all functions in $export_to");
			_wrap_functions($export_to, $trace);
		}
	}
}

sub __replace_subroutine
{
	my ($package, $sub, $coderef) = @_;
	if (defined \&{"${package}::$sub"})
	{
		# quietly remove existing stub function
		# This avoids unsightly "subroutine foo redefined" warnings
		# 'no warnings "redefine"' doesn't work pre perl 5.6
		eval "undef \$${package}::{'$sub'}";
	}
	*{"${package}::$sub"} = $coderef;
}

sub _trace_maker
{
	my ($package, $params, $trace_sub) = @_;
	my $trace_level = $params->{Level};
	return sub
	{
		local $@; # in-case TRACE is called from &DESTROY
		my $rv;
		eval
		{
			my $level = shift->{Level} if ($_[0] && ref $_[0] eq 'HASH');
			return unless _evaluate_level($package, $trace_level, $level);
			$rv = 1 && $trace_sub->(@_);
		};
		if ($@)
		{
			warn __PACKAGE__ . " : $@";
		}
		return $rv;
	}
}

sub _dump_maker
{
	my ($package, $params, $trace_sub) = @_;
	my $trace_level = $params->{Level};
	return sub
	{
		# always return the dumped data regardless of level unless called in
		# void context
		my $context = wantarray();
		local $@; # in-case DUMP is called from &DESTROY
		my $rv;
		eval
		{
			return $rv = _dump($params, @_) if defined $context;

			my $level = undef;
			if ($_[0] && ref $_[0] eq 'HASH' && defined $_[0]{Level})
			{
				$level = shift->{Level};
			}
			return unless _evaluate_level($package, $trace_level, $level);
			my $dumped = _dump($params, @_);
			$rv = 1 && $trace_sub->($dumped);
		};
		if ($@)
		{
			warn __PACKAGE__ . " : $@";
		}
		return $rv;
	}
};


# returns a list of packages to export trace functions to
sub _deep_import_packages
{
	my $all_packages = shift;

	# Build the list of packages
	my @packages;
	foreach my $module (@{_list_all_packages()})
	{
		next if $module eq __PACKAGE__;
		next unless $all_packages || defined (&{"$module\::TRACE"});
		push @packages, $module;
	}
	return @packages;
}


my %_autowrap;
sub _wrap_functions {
	my ($package, $trace) = @_;

	return if $_autowrap{$package};
	$_autowrap{$package} = {} unless defined $_autowrap{$package};

	my $symbols = \%{$package . '::'};
	# wrap coderefs in the caller's symbol table
	foreach my $typeglob (keys %$symbols) {

		# skip TRACE/DUMP and other potential deep recursions
		next if $typeglob =~ /^(?:TRACE(?:F|_HERE)?|DUMP|AUTOLOAD)$/;

		# only wrap code references
		my $sub = *{$symbols->{$typeglob}}{CODE};
		next unless (defined $sub and defined &$sub);

		# skip if sub is already wrapped
		next if $_autowrap{$package}{$typeglob}++;

		# define wrapped subroutine body
		my $sub_body = <<'WRAPPED';
			my ($name) = "${package}::$typeglob";
			my ($callpkg, $file, $line) = caller(1);
			my $arg = $_[0] && ref($_[0]) ? ref($_[0]) . ', ...' : "";
			$trace->( "${name}( $arg )" );
			goto &$sub
WRAPPED

		# wrap subroutine, preserving prototypes
		my $wrapped_sub;
		if(defined (my $proto = prototype($sub)))
		{
			$wrapped_sub = eval "sub ($proto) { $sub_body }";
		}
		else
		{
			$wrapped_sub = eval "sub { $sub_body }";
		}

		__replace_subroutine($package, $typeglob, $wrapped_sub);
	}
}


# return a list of all defined packages in the symbol table
# we could use %INC, but we'd miss packages that are defined in other modules
sub _list_all_packages {
	my ($package) = @_;
	$package = '' unless defined $package;
	my @packages;

	# this is a recursive look in the symbol table:
	# %main::
	#   CGI::
	#     Cookie::
	#   Data::
	#     Dumper::
	# ...

	my %symbols = %{$package . "::"};
	foreach my $module (keys %symbols)
	{
		next unless $module =~ s/::$//;
		# ignore 'main' (deep recursion) and all invalid package names
		next if !$package && ($module eq 'main' || $module !~ /^[a-zA-Z_]\w*$/);

		my $prefix = $package ? $package . '::' : '';
		# Add this module
		push @packages, $prefix . $module;
		# and recurse to sub-packages
		push @packages, @{_list_all_packages($prefix . $module)};
	}
	return \@packages;
}


# Override the built-in require()
# This is tricky because these are treated differently by perl:
# 1. require CGI
# 2. require "CGI"
# We have no way of distinguishing the two, so we make a best guess
#
# This only works since perl 5.6.1
#
# See 'perlsub' for more information about overriding built-ins
sub _install_require
{
	my ($pkg, $params, $target, @args) = @_;

	# CORE::require has prototype(;$), but we get "bareword foo not allowed"
	# errors if we use that. prototype(*) works though
	my $require = sub (*)
	{
		local $^W;
		my $what = shift;
		return 1 if $INC{$what};
		_debug("require $what");

		my $package;
		if ($what =~ /^v?[\d_.]+$/) {
			# take advantage of UNIVERSAL->VERSION($require) for a portable
			# version check
			local $_Log::Trace::PerlVersion::VERSION = $];
			eval {_Log::Trace::PerlVersion->VERSION($what)};
			if (my $error = $@) {
				$error =~ s/_Log::Trace::PerlVersion/Perl/;
				die $error; #rethrow exception
			}
			return 1;
		} elsif ($what =~ /(.*)\.pm$/) {
			# looks like a module name, get the main package from the filename
			# (perl 5.8 & ActivePerl 5.6.1)
			($package = $1) =~ s{/}{::}g;
		} elsif ($what =~ /^[a-zA-Z_]\w*(?:::\w+)*$/i) {
			# package name: vanilla perl 5.6.1, 5.6.2
			$package = $what;
			($what = "$what.pm") =~ s{::}{/}g;
		}

		my $rv = CORE::require $what;
		if ($rv && $package)
		{
			# import Log::Trace into package
			return unless $params->{Everywhere}
				|| defined (&{"$package\::TRACE"});
			$pkg->_import($package, $target, @args, $params);
		}
		return $rv;
	};

	# Override global require, silencing "... used only once" warnings
	*CORE::GLOBAL::require = *CORE::GLOBAL::require = $require;
}


# Returns caller info for exported functions
sub __caller
{
	# We need to look several frames back, so we keep going until we find
	# something from outside this package
	my @caller;
	for (1 .. 8) {
		my @c = caller($_);
		last unless defined $c[0];
		@caller = @c;
		last unless $caller[0] eq __PACKAGE__
			|| $caller[3] =~ /^@{[__PACKAGE__]}\::/o;
	}

	# because we don't seem to get a call frame for main::__ANON__
	$caller[0] = 'main' if ($caller[0] eq __PACKAGE__);
	$caller[3] =~ s/^@{[__PACKAGE__]}\::.*/main::__ANON__/;
	return @caller;
}

#################################################
# TRACE guts
#################################################

sub _evaluate_level
{
	my ($callpkg, $imported_level, $trace_level) = @_;

	return 1 if ! defined $imported_level;

	if (ref $imported_level eq 'CODE')
	{
		return $imported_level->($callpkg, $trace_level);
	}
	elsif (ref $imported_level eq 'ARRAY')
	{
		for (@$imported_level)
		{
			return 1 if (! defined($_) && ! defined($trace_level));
			next unless defined($trace_level) && defined($_);;
			return 1 if $_ == $trace_level;
		}
	}
	elsif (!ref $imported_level)
	{
		return unless defined $trace_level;
		return $imported_level >= $trace_level;
	}
}

sub _log_normal
{
	return join(",", @_)."\n";
}

sub _log_verbose
{
	my ($pack,$file,$line,$sub) = __caller();
	return "$sub ($line) :: " . join( ", ", @_ ) . "\n";
}

sub _log_debug
{
	my ($pack,$file,$line,$sub) = __caller();
	my $timestamp = _timestamp();
	return "$file: $sub ($line) [$timestamp] " . join( ", ", @_ ) . "\n";
}

sub _log_to_fh
{
	my ($fh, @output) = @_;
	$fh = \*STDOUT unless $fh;
	print $fh @output;
}

sub _log_to_file
{
	my $filename = shift;
	my ($pack,$file,$line,$sub) = __caller();

	local *LOG_FILE;
	if (open (LOG_FILE, ">> $filename"))
	{
		if (eval {flock LOG_FILE, LOCK_EX|LOCK_NB})
		{
			print LOG_FILE @_;
			flock LOG_FILE, LOCK_UN;
			close LOG_FILE;
		}
		else
		{
			die "couldn't get lock on $filename : $!";
		}
	}
	else
	{
		die "Cannot open $filename : $!";
	}
}

sub _log_to_syslog
{
	my ($priority) = shift || 'debug';

	return unless eval {require Sys::Syslog};
	Sys::Syslog::openlog(__PACKAGE__, 'pid');
	my $rv = Sys::Syslog::syslog($priority, join ",", @_);
	Sys::Syslog::closelog();
	return $rv;
}

sub _dump
{
	my ($params, @args) = @_;

	my $msg = ref $args[0] ? '' : shift @args;
	$msg .= ": " if($msg && @args);

	my $type;
	eval
	{
		if ($params->{Dumper})
		{
			$type = 'Data::Serializer';
			require Data::Serializer;
			my $params = ref $params->{Dumper} ?
				$params->{Dumper} : { serializer => $params->{Dumper} };
			my $serialiser = Data::Serializer->new(%$params);
			for (@args)
			{
				$msg .= $serialiser->raw_serialize($_) . "\n";
			}
		}
		else
		{
			$type = 'Data::Dumper';
			require	Data::Dumper;
			# avoid 'used $var only once' warning
			local $Data::Dumper::Indent;
			local $Data::Dumper::Sortkeys;
			local $Data::Dumper::Quotekeys;
			$Data::Dumper::Indent    = 1;
			$Data::Dumper::Sortkeys  = 1;
			$Data::Dumper::Quotekeys = 0;

			$msg .= Data::Dumper::Dumper(@args);
		}
	};
	die "$type not available: $@" if $@;
	return $msg;
}

sub _gettimeofday()
{
	return Time::HiRes::gettimeofday() if $INC{'Time/HiRes.pm'};
	return (time(), undef);
}

#Provide localtime-style timestamp with microsecond resolution if Time::HiRes
#is available
sub _timestamp
{
	my ($epoch, $usec) = _gettimeofday();
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($epoch);
	$year+=1900; $mon+=1;
	my $stamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec);
	$stamp .= sprintf(".%.6d",$usec) if(defined $usec);
	return $stamp;
}

1;

=head1 NAME

Log::Trace - provides a unified approach to tracing

=head1 SYNOPSIS

	# The tracing targets
	use Log::Trace; # No output
	use Log::Trace 'print'; # print to STDOUT
	use Log::Trace log => '/var/log/foo.log'; # Output to log file
	use Log::Trace print => { Level => 3 };

	# Switch on/off logging with a constant
	use Log::Trace;
	import Log::Trace ('log' => LOGFILE) if TRACING;


	# Set up tracing for all packages that advertise TRACE
	use Foo;
	use Bar;
	use Log::Trace warn => { Deep => 1 };

	# Sets up tracing in all subpackages excluding Foo
	use Log::Trace warn => {Deep => 1, 'Exclude' => 'Foo'};


	# Exported functions
	TRACE("Record this...");
	TRACE({Level => 2}, "Only shown if tracing level is 2 or higher");
	TRACEF("A la printf: %d-%.2f", 1, 2.9999);
	TRACE_HERE();	        # Record where we are (file, line, sub, args)
	DUMP(\@loh, \%hoh);     # Trace out via Data::Dumper
	DUMP("Title", \@loh);   # Trace out via Data::Dumper
	my $dump = DUMP(@args); # Dump is returned without being traced

=head1 DESCRIPTION

A module to provide a unified approach to tracing. A script can C<use
Log::Trace qw( E<lt> mode E<gt> )> to set the behaviour of the TRACE function.

By default, the trace functions are exported to the calling package only. You
can export the trace functions to other packages with the C<Deep> option. See
L<"OPTIONS"> for more information.

All exports are in uppercase (to minimise collisions with "real" functions).

=head1 FUNCTIONS

=over 4

=item TRACE(@args)

Output a message. Where the message actually goes depends on how you imported
Log::Trace (See L<"Importing/enabling Log::Trace">)

The first argument is an optional hashref of options:

	TRACE('A simple message');

vs:

	TRACE({ Level => 2.1 }, 'A message at a specified trace level');

=item TRACEF($format, @args)

C<printf()> equivalent of TRACE. Also accepts an optional hashref:

	TRACEF('%d items', scalar @items);
	TRACEF({ Level => 5 }, '$%1.2d', $value);

=item DUMP([$message,] @args)

Serialises each of @args, optionally prepended with $message. If called in a
non-void context, DUMP will return the serialised data rather than TRACE
it. This is useful if you want to DUMP a datastructure at a specific tracing
level.

	DUMP('colours', [qw(red green blue)]);             # outputs via TRACE
	my $dump = DUMP('colours', [qw(red green blue)]);  # output returned

=item TRACE_HERE()

TRACEs the current position on the call stack (file, line number, subroutine
name, subroutine args).

	TRACE_HERE();
	TRACE_HERE({Level => 99});

=back

=head1 Importing/enabling Log::Trace

=over 4

=item import($target, [$arg], [\%params])

Controls where TRACE messages go. This method is called automatically when you
call C<'use Log::Trace;'>, but you may explicitly call this method at
runtime. Compare the following:

	use Log::Trace 'print';

which is the same as

	BEGIN {
		require Log::Trace;
		Log::Trace->import('print');
	}

Valid combinations of C<$target> and C<arg> are:

=over 4

=item print =E<gt> $filehandle

Prints trace messages to the supplied C<$filehandle>. Defaults to C<STDOUT>
if no file handle is specified.

=item warn

Prints trace messages via C<warn()>s to C<STDERR>.

=item buffer =E<gt> \$buffer

Appends trace messages to a string reference.

=item file =E<gt> $filename

Append trace messages to a file. If the file doesn't exist, it will be created.

=item log =E<gt> $filename

This is equivalent to:

	use Log::Trace file => $filename, {Verbose => 2};

=item syslog =E<gt> $priority

Logs trace messages to syslog via C<Sys::Syslog>, if available.

You should consult your syslog configuration before using this option.

The default C<$priority> is 'C<debug>', and the C<ident> is set to
C<Log::Trace>. You can configure the C<priority>, but beyond that, you can
implement your own syslogging via the C<custom> trace target.

=item custom => \&custom_trace_sub

Trace messages are processed by a custom subroutine. E.g.

	use Log::Trace custom => \&mylogger;

	sub mylogger {
		my @messages = @_;
		foreach (@messages) {
			# highly sensitive trace messages!
			tr/a-zA-Z/n-za-mN-ZA-M/;
			print;
		}
	}

=back

The import C<\%params> are optional. These two statements are functionally the
same:

	import Log::Trace print => {Level => undef};
	import Log::Trace 'print';

See L<"OPTIONS"> for more information.

B<Note:> If you use the C<custom> tracing option, you should be careful about
supplying a subroutine named C<TRACE>.

=back

=head1 OPTIONS

=over 4

=item AllSubs =E<gt> BOOL

Attaches a C<TRACE> statement to all subroutines in the package. This can be
used to track the execution path of your code. It is particularly useful when
used in conjunction with C<Deep> and C<Everywhere> options.

B<Note:> Anonymous subroutines and C<AUTOLOAD> are not C<TRACE>d.

=item AutoImport =E<gt> BOOL

By default, C<Log::Trace> will only set up C<TRACE> routines in modules that
have already been loaded. This option overrides C<require()> so that modules
loaded after C<Log::Trace> can automatically be set up for tracing.

B<Note>: This is an experimental feature. See the ENVIRONMENT NOTES
for information about behaviour under different versions of perl.

This option has no effect on perl E<lt> 5.6

=item Deep =E<gt> BOOL

Attaches C<Log::Trace> to all packages (that define a TRACE function). Any
TRACEF, DUMP and TRACE_HERE routines will also be overridden in these packages.

=item Dumper =E<gt> Data::Serializer backend

Specify a serialiser to be used for DUMPing data structures. 

This should either be a string naming a Data::Serializer backend (e.g. "YAML") 
or a hashref of parameters which will be passed to Data::Serializer, e.g.

	{
		serializer => 'XML::Dumper',
		options => {
			dtd => 'path/to/my.dtd'
		}
	}

Note that the raw_serialise() method of Data::Serializer is used.  See L<Data::Serializer>
for more information.
		
If you do not have C<Data::Serializer> installed, leave this option undefined to use the
C<Data::Dumper> natively.

Default: undef (use standalone Data::Dumper)

=item Everywhere =E<gt> BOOL

When used in conjunction with the C<Deep> option, it will override the
standard behaviour of only enabling tracing in packages that define C<TRACE>
stubs.

Default: false

=item Exclude =E<gt> STRING|ARRAY

Exclude a module or list of modules from tracing.

=item Level =E<gt> NUMBER|LIST|CODE

Specifies which trace levels to display.

If no C<Level> is defined, all TRACE statements will be output.

If the value is numeric, only TRACEs that are at the specified level or below
will be output.

If the value is a list of numbers, only TRACEs that match the specified levels
are output.

The level may also be a code reference which is passed the package name and the
TRACE level. It mst return a true value if the TRACE is to be output.

Default: undef

=item Match =E<gt> REGEX

Exports trace functions to packages that match the supplied regular
expression. Can be used in conjunction with  C<Exclude>. You can also use
C<Match> as an exclusion method if you give it a negative look-ahead.

For example:

	Match => qr/^(?!Acme::)/  # will exclude every module beginning with Acme::

and

	Match => qr/^Acme::/      # does the reverse

Default: '.' # everything

=item Verbose =E<gt> 0|1|2

You can use this option to prepend extra information to each trace message. The
levels represent increasing levels of verbosity:

	0: the default*, don't add anything
	1: adds subroutine name and line number to the trace output
	2: As [1], plus a filename and timestamp (in ISO 8601 : 2000 format)

This setting has no effect on the C<custom> or C<log> targets.

* I<the log target uses 'Verbose' level 2>

=back

=head1 ENVIRONMENT NOTES

The AutoImport feature overrides C<CORE::require()> which requires perl 5.6, but you may see unexpected errors if you aren't using at
least perl 5.8. The AutoImport option has no effect on perl E<lt> 5.6.

In mod_perl or other persistent interpreter environments, different applications could trample on each other's
C<TRACE> routines if they use Deep (or Everywhere) option.  For example application A could route all the trace output 
from Package::Foo into "appA.log" and then application B could import Log::Trace over the top, re-routing all the trace output from Package::Foo
to "appB.log" for evermore.  One way around this is to ensure you always import Log::Trace on every run in a persistent environment from all your 
applications that use the Deep option.  We may provide some more tools to work around this in a later version of C<Log::Trace>.

C<Log::Trace> has not been tested in a multi-threaded application.

=head1 DEPENDENCIES

	Carp
	Time::HiRes      (used if available)
	Data::Dumper     (used if available - necessary for meaningful DUMP output)
	Data::Serializer (optional - to customise DUMP output)
	Sys::Syslog      (loaded on demand)

=head1 RELATED MODULES

=over 4

=item Log::TraceMessages

C<Log::TraceMessages> is similar in design and purpose to C<Log::Trace>.
However, it only offers a subset of this module's functionality. Most notably,
it doesn't offer a mechanism to control the tracing output of an entire
application - tracing must be enabled on a module-by-module
basis. C<Log::Trace> also offers control over the output with the trace
levels and supports more output targets.

=item Log::Agent

C<Log::Agent> offers a procedural interface to logging. It strikes a good
balance between configurability and ease of use. It differs to C<Log::Trace> in
a number of ways. C<Log::Agent> has a concept of channels and priorities, while
C<Log::Trace> only offers levels. C<Log::Trace> also supports tracing code
execution path and the C<Deep> import option. C<Log::Trace> trades a certain
amount of configurability for increased ease-of use.

=item Log::Log4Perl

A feature rich perl port of the popular C<log4j> library for Java. It is
object-oriented and comprised of more than 30 modules. It has an impressive
feature set, but some people may be frightened of its complexity. In contrast,
to use C<Log::Trace> you need only remember up to 4 simple functions and a
handful of configuration options.

=back

=head1 SEE ALSO

L<Log::Trace::Manual> - A guide to using Log::Trace

=head1 VERSION

$Revision: 1.70 $ on $Date: 2005/11/01 11:32:59 $ by $Author: colinr $

=head1 AUTHOR

John Alden and Simon Flack with some additions by Piers Kent and Wayne Myers 
<cpan _at_ bbc _dot_ co _dot_ uk>

=head1 COPYRIGHT

(c) BBC 2005. This program is free software; you can redistribute it and/or modify it under the GNU GPL.

See the file COPYING in this distribution, or http://www.gnu.org/licenses/gpl.txt 

=cut