1## no critic (Modules::ProhibitExcessMainComplexity) 2use strict; 3use warnings; 4 5use Test::More 0.96; 6use Test::Fatal; 7 8use File::Spec; 9use File::Temp qw( tempdir ); 10use Module::Runtime qw( use_module ); 11use Try::Tiny; 12 13use Log::Dispatch; 14 15my %tests; 16 17BEGIN { 18 local $@ = undef; 19 for (qw( MailSend MIMELite MailSendmail MailSender )) { 20 ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval) 21 eval "use Log::Dispatch::Email::$_"; 22 $tests{$_} = !$@; 23 $tests{$_} = 0 if $ENV{LD_NO_MAIL}; 24 } 25} 26 27my %TestConfig; 28if ( my $email_address = $ENV{LOG_DISPATCH_TEST_EMAIL} ) { 29 %TestConfig = ( email_address => $email_address ); 30} 31 32my @syswrite_strs; 33 34BEGIN { 35 if ( $] >= 5.016 ) { 36 my $syswrite = \&CORE::syswrite; 37 *CORE::GLOBAL::syswrite = sub { 38 my ( $fh, $str, @other ) = @_; 39 push @syswrite_strs, $_[1]; 40 41 return $syswrite->( $fh, $str, @other ); 42 }; 43 } 44} 45 46use Log::Dispatch::File; 47use Log::Dispatch::Handle; 48use Log::Dispatch::Null; 49use Log::Dispatch::Screen; 50 51use IO::File; 52 53my $tempdir = tempdir( CLEANUP => 1 ); 54 55subtest( 56 'Test Log::Dispatch::File', 57 sub { 58 my $dispatch = Log::Dispatch->new; 59 ok( $dispatch, 'created Log::Dispatch object' ); 60 61 my $emerg_log = File::Spec->catdir( $tempdir, 'emerg.log' ); 62 63 $dispatch->add( 64 Log::Dispatch::File->new( 65 name => 'file1', 66 min_level => 'emerg', 67 filename => $emerg_log 68 ) 69 ); 70 71 $dispatch->log( level => 'info', message => "info level 1\n" ); 72 $dispatch->log( level => 'emerg', message => "emerg level 1\n" ); 73 74 my $debug_log = File::Spec->catdir( $tempdir, 'debug.log' ); 75 76 $dispatch->add( 77 Log::Dispatch::File->new( 78 name => 'file2', 79 min_level => 'debug', 80 syswrite => 1, 81 filename => $debug_log 82 ) 83 ); 84 85 my %outputs = map { $_->name() => ref $_ } $dispatch->outputs(); 86 is_deeply( 87 \%outputs, { 88 file1 => 'Log::Dispatch::File', 89 file2 => 'Log::Dispatch::File', 90 }, 91 '->outputs() method returns all output objects' 92 ); 93 94 $dispatch->log( level => 'info', message => "info level 2\n" ); 95 $dispatch->log( level => 'emerg', message => "emerg level 2\n" ); 96 97 # This'll close them filehandles! 98 undef $dispatch; 99 100 ## no critic (InputOutput::RequireBriefOpen) 101 open my $emerg_fh, '<', $emerg_log 102 or die "Can't read $emerg_log: $!"; 103 open my $debug_fh, '<', $debug_log 104 or die "Can't read $debug_log: $!"; 105 106 my @log = <$emerg_fh>; 107 is( 108 $log[0], "emerg level 1\n", 109 q{First line in log file set to level 'emerg' is 'emerg level 1'} 110 ); 111 112 is( 113 $log[1], "emerg level 2\n", 114 q{Second line in log file set to level 'emerg' is 'emerg level 2'} 115 ); 116 117 @log = <$debug_fh>; 118 is( 119 $log[0], "info level 2\n", 120 q{First line in log file set to level 'debug' is 'info level 2'} 121 ); 122 123 is( 124 $log[1], "emerg level 2\n", 125 q{Second line in log file set to level 'debug' is 'emerg level 2'} 126 ); 127 128 close $emerg_fh or die $!; 129 close $debug_fh or die $!; 130 131 SKIP: 132 { 133 ## no critic (ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions) 134 skip 'This test requires Perl 5.16+', 1 135 unless $] >= 5.016; 136 is_deeply( 137 \@syswrite_strs, 138 [ 139 "info level 2\n", 140 "emerg level 2\n", 141 ], 142 'second LD object used syswrite', 143 ); 144 } 145 } 146); 147 148subtest( 149 'max_level', 150 sub { 151 my $max_log = File::Spec->catfile( $tempdir, 'max.log' ); 152 153 my $dispatch = Log::Dispatch->new; 154 $dispatch->add( 155 Log::Dispatch::File->new( 156 name => 'file1', 157 min_level => 'debug', 158 max_level => 'crit', 159 filename => $max_log 160 ) 161 ); 162 163 $dispatch->log( level => 'emerg', message => "emergency\n" ); 164 $dispatch->log( level => 'crit', message => "critical\n" ); 165 166 undef $dispatch; # close file handles 167 168 open my $fh, '<', $max_log 169 or die "Can't read $max_log: $!"; 170 my @log = <$fh>; 171 close $fh or die $!; 172 173 is( 174 $log[0], "critical\n", 175 q{First line in log file with a max level of 'crit' is 'critical'} 176 ); 177 } 178); 179 180subtest( 181 'Handle output', 182 sub { 183 my $handle_log = File::Spec->catfile( $tempdir, 'handle.log' ); 184 185 my $fh = IO::File->new( $handle_log, 'w' ) 186 or die "Can't write to $handle_log: $!"; 187 188 my $dispatch = Log::Dispatch->new; 189 $dispatch->add( 190 Log::Dispatch::Handle->new( 191 name => 'handle', 192 min_level => 'debug', 193 handle => $fh 194 ) 195 ); 196 197 $dispatch->log( level => 'notice', message => "handle test\n" ); 198 199 # close file handles 200 undef $dispatch; 201 undef $fh; 202 203 open $fh, '<', $handle_log 204 or die "Can't open $handle_log: $!"; 205 206 my @log = <$fh>; 207 208 close $fh or die $!; 209 210 is( 211 $log[0], "handle test\n", 212 q{Log::Dispatch::Handle created log file should contain 'handle test\\n'} 213 ); 214 } 215); 216 217subtest( 218 'Email::MailSend output', 219 sub { 220 SKIP: 221 { 222 skip 'Cannot do MailSend tests', 1 223 unless $tests{MailSend} && $TestConfig{email_address}; 224 225 my $dispatch = Log::Dispatch->new; 226 227 $dispatch->add( 228 Log::Dispatch::Email::MailSend->new( 229 name => 'Mail::Send', 230 min_level => 'debug', 231 to => $TestConfig{email_address}, 232 subject => 'Log::Dispatch test suite' 233 ) 234 ); 235 236 $dispatch->log( 237 level => 'emerg', 238 message => 239 "Mail::Send test - If you can read this then the test succeeded (PID $$)" 240 ); 241 242 diag( 243 "Sending email with Mail::Send to $TestConfig{email_address}.\nIf you get it then the test succeeded (PID $$)\n" 244 ); 245 undef $dispatch; 246 247 ok( 1, 'sent email via MailSend' ); 248 } 249 } 250); 251 252subtest( 253 'Email::MailSendmail output', 254 sub { 255 SKIP: 256 { 257 skip 'Cannot do MailSendmail tests', 1 258 unless $tests{MailSendmail} && $TestConfig{email_address}; 259 260 my $dispatch = Log::Dispatch->new; 261 262 $dispatch->add( 263 Log::Dispatch::Email::MailSendmail->new( 264 name => 'Mail::Sendmail', 265 min_level => 'debug', 266 to => $TestConfig{email_address}, 267 subject => 'Log::Dispatch test suite' 268 ) 269 ); 270 271 $dispatch->log( 272 level => 'emerg', 273 message => 274 "Mail::Sendmail test - If you can read this then the test succeeded (PID $$)" 275 ); 276 277 diag( 278 "Sending email with Mail::Sendmail to $TestConfig{email_address}.\nIf you get it then the test succeeded (PID $$)\n" 279 ); 280 undef $dispatch; 281 282 ok( 1, 'sent email via MailSendmail' ); 283 } 284 } 285); 286 287subtest( 288 'Email::MIMELite output', 289 sub { 290 SKIP: 291 { 292 293 skip 'Cannot do MIMELite tests', 1 294 unless $tests{MIMELite} && $TestConfig{email_address}; 295 296 my $dispatch = Log::Dispatch->new; 297 298 $dispatch->add( 299 Log::Dispatch::Email::MIMELite->new( 300 name => 'Mime::Lite', 301 min_level => 'debug', 302 to => $TestConfig{email_address}, 303 subject => 'Log::Dispatch test suite' 304 ) 305 ); 306 307 $dispatch->log( 308 level => 'emerg', 309 message => 310 "MIME::Lite - If you can read this then the test succeeded (PID $$)" 311 ); 312 313 diag( 314 "Sending email with MIME::Lite to $TestConfig{email_address}.\nIf you get it then the test succeeded (PID $$)\n" 315 ); 316 undef $dispatch; 317 318 ok( 1, 'sent mail via MIMELite' ); 319 } 320 } 321); 322 323subtest( 324 'Email::MailSender output', 325 sub { 326 SKIP: 327 { 328 skip 'Cannot do MailSender tests', 1 329 unless $tests{MailSender} && $TestConfig{email_address}; 330 331 my $dispatch = Log::Dispatch->new; 332 333 $dispatch->add( 334 Log::Dispatch::Email::MailSender->new( 335 name => 'Mail::Sender', 336 min_level => 'debug', 337 smtp => 'localhost', 338 to => $TestConfig{email_address}, 339 subject => 'Log::Dispatch test suite' 340 ) 341 ); 342 343 $dispatch->log( 344 level => 'emerg', 345 message => 346 "Mail::Sender - If you can read this then the test succeeded (PID $$)" 347 ); 348 349 diag( 350 "Sending email with Mail::Sender to $TestConfig{email_address}.\nIf you get it then the test succeeded (PID $$)\n" 351 ); 352 undef $dispatch; 353 354 ok( 1, 'sent email via MailSender' ); 355 } 356 } 357); 358 359subtest( 360 'Log::Dispatch::Output->accepted_levels', 361 sub { 362 my $l = Log::Dispatch::Screen->new( 363 name => 'foo', 364 min_level => 'warning', 365 max_level => 'alert', 366 stderr => 0 367 ); 368 369 my @expected = qw(warning error critical alert); 370 my @levels = $l->accepted_levels; 371 372 is_deeply( 373 \@expected, 374 \@levels, 375 'accepted_levels matches what is expected' 376 ); 377 } 378); 379 380subtest( 381 'Log::Dispatch single callback', 382 sub { 383 my $reverse = sub { my %p = @_; return reverse $p{message}; }; 384 my $dispatch = Log::Dispatch->new( callbacks => $reverse ); 385 386 my $string; 387 $dispatch->add( 388 Log::Dispatch::String->new( 389 name => 'foo', 390 string => \$string, 391 min_level => 'warning', 392 max_level => 'alert', 393 ) 394 ); 395 396 $dispatch->log( level => 'warning', message => 'esrever' ); 397 398 is( 399 $string, 'reverse', 400 'callback to reverse text' 401 ); 402 } 403); 404 405subtest( 406 'Log::Dispatch multiple callbacks', 407 sub { 408 my $reverse = sub { my %p = @_; return reverse $p{message}; }; 409 my $uc = sub { my %p = @_; return uc $p{message}; }; 410 411 my $dispatch = Log::Dispatch->new( callbacks => [ $reverse, $uc ] ); 412 413 my $string; 414 $dispatch->add( 415 Log::Dispatch::String->new( 416 name => 'foo', 417 string => \$string, 418 min_level => 'warning', 419 max_level => 'alert', 420 ) 421 ); 422 423 $dispatch->log( level => 'warning', message => 'esrever' ); 424 425 is( 426 $string, 'REVERSE', 427 'callback to reverse and uppercase text' 428 ); 429 430 is_deeply( 431 [ $dispatch->callbacks() ], 432 [ $reverse, $uc ], 433 '->callbacks() method returns all of the callback subs' 434 ); 435 436 my $clone = $dispatch->clone(); 437 is_deeply( 438 $clone, 439 $dispatch, 440 'clone is a shallow clone of the original object' 441 ); 442 443 $clone->add( 444 Log::Dispatch::Screen->new( 445 name => 'screen', 446 min_level => 'debug', 447 ) 448 ); 449 my @orig_outputs = map { $_->name() } $dispatch->outputs(); 450 my @clone_outputs = map { $_->name() } $clone->outputs(); 451 isnt( 452 scalar(@orig_outputs), 453 scalar(@clone_outputs), 454 'clone is not the same as original after adding an output' 455 ); 456 457 $clone->add_callback( sub { return 'foo' } ); 458 my @orig_cb = $dispatch->callbacks(); 459 my @clone_cb = $clone->callbacks(); 460 isnt( 461 scalar(@orig_cb), 462 scalar(@clone_cb), 463 'clone is not the same as original after adding a callback' 464 ); 465 } 466); 467 468subtest( 469 'Log::Dispatch::Output single callback', 470 sub { 471 my $reverse = sub { my %p = @_; return reverse $p{message}; }; 472 473 my $dispatch = Log::Dispatch->new; 474 475 my $string; 476 $dispatch->add( 477 Log::Dispatch::String->new( 478 name => 'foo', 479 string => \$string, 480 min_level => 'warning', 481 max_level => 'alert', 482 callbacks => $reverse 483 ) 484 ); 485 486 $dispatch->log( level => 'warning', message => 'esrever' ); 487 488 is( 489 $string, 'reverse', 490 'Log::Dispatch::Output callback to reverse text' 491 ); 492 } 493); 494 495subtest( 496 'Log::Dispatch::Output multiple callbacks', 497 sub { 498 my $reverse = sub { my %p = @_; return reverse $p{message}; }; 499 my $uc = sub { my %p = @_; return uc $p{message}; }; 500 501 my $dispatch = Log::Dispatch->new; 502 503 my $string; 504 $dispatch->add( 505 Log::Dispatch::String->new( 506 name => 'foo', 507 string => \$string, 508 min_level => 'warning', 509 max_level => 'alert', 510 callbacks => [ $reverse, $uc ] 511 ) 512 ); 513 514 $dispatch->log( level => 'warning', message => 'esrever' ); 515 516 is( 517 $string, 'REVERSE', 518 'Log::Dispatch::Output callbacks to reverse and uppercase text' 519 ); 520 } 521); 522 523subtest( 524 'level parameter to callbacks', 525 sub { 526 my $level = sub { my %p = @_; return uc $p{level}; }; 527 528 my $dispatch = Log::Dispatch->new( callbacks => $level ); 529 530 my $string; 531 $dispatch->add( 532 Log::Dispatch::String->new( 533 name => 'foo', 534 string => \$string, 535 min_level => 'warning', 536 max_level => 'alert', 537 stderr => 0 538 ) 539 ); 540 541 $dispatch->log( level => 'warning', message => 'esrever' ); 542 543 is( 544 $string, 'WARNING', 545 'Log::Dispatch callback to uppercase the level parameter' 546 ); 547 } 548); 549 550subtest( 551 'level name methods', 552 sub { 553 my %levels = map { $_ => $_ } 554 (qw( debug info notice warning error critical alert emergency )); 555 @levels{qw( warn err crit emerg )} 556 = (qw( warning error critical emergency )); 557 558 for my $allowed_level ( 559 qw( debug info notice warning error critical alert emergency )) { 560 my $dispatch = Log::Dispatch->new; 561 562 my $string; 563 $dispatch->add( 564 Log::Dispatch::String->new( 565 name => 'foo', 566 string => \$string, 567 min_level => $allowed_level, 568 max_level => $allowed_level, 569 ) 570 ); 571 572 for my $test_level ( 573 qw( debug info notice warn warning err 574 error crit critical alert emerg emergency ) 575 ) { 576 $string = q{}; 577 $dispatch->$test_level( $test_level, 'test' ); 578 579 if ( $levels{$test_level} eq $allowed_level ) { 580 my $expect = join $", $test_level, 'test'; 581 is( 582 $string, $expect, 583 qq{Calling $test_level method should send message '$expect'} 584 ); 585 } 586 else { 587 ok( 588 !length $string, 589 "Calling $test_level method should not log anything" 590 ); 591 } 592 } 593 } 594 } 595); 596 597subtest( 598 'argument variations to name method', 599 sub { 600 my $string; 601 my $dispatch = Log::Dispatch->new( 602 outputs => [ 603 [ 604 'String', 605 name => 'string', 606 string => \$string, 607 min_level => 'debug', 608 ], 609 ], 610 ); 611 612 $dispatch->debug( 'foo', 'bar' ); 613 is( 614 $string, 615 'foo bar', 616 'passing multiple elements to ->debug stringifies them like an array' 617 ); 618 619 $string = q{}; 620 $dispatch->debug( sub {'foo'} ); 621 is( 622 $string, 623 'foo', 624 'passing single sub ref to ->debug calls the sub ref' 625 ); 626 627 } 628); 629 630subtest( 631 'Log::Dispatch->level_is_valid method', 632 sub { 633 for my $l ( 634 qw( debug info notice warning err error 635 crit critical alert emerg emergency ) 636 ) { 637 ok( Log::Dispatch->level_is_valid($l), "$l is valid level" ); 638 } 639 640 for my $l (qw( debu inf foo bar )) { 641 ok( !Log::Dispatch->level_is_valid($l), "$l is not valid level" ); 642 } 643 644 # Provide calling line if level missing 645 my $string; 646 my $dispatch = Log::Dispatch->new( 647 outputs => [ 648 [ 649 'String', 650 name => 'string', 651 string => \$string, 652 min_level => 'debug', 653 ], 654 ], 655 ); 656 657 like( 658 exception { $dispatch->log( msg => 'Message' ) }, 659 qr/Logging level was not provided at .* line \d+./, 660 'Provide calling line if level not provided' 661 ); 662 } 663); 664 665subtest( 666 'Log::Dispatch->would_log method', 667 sub { 668 my $string; 669 my $dispatch = Log::Dispatch->new( 670 outputs => [ 671 [ 672 'String', 673 name => 'string', 674 string => \$string, 675 min_level => 'debug', 676 ], 677 ], 678 ); 679 680 is( 681 $dispatch->would_log('debug'), 682 1, 683 'Would log works with level name' 684 ); 685 686 is( 687 $dispatch->would_log(0), 688 1, 689 'Would log works with level number' 690 ); 691 } 692); 693 694subtest( 695 'File output mode=write', 696 sub { 697 my $mode_log = File::Spec->catfile( $tempdir, 'mode.log' ); 698 699 my $f1 = Log::Dispatch::File->new( 700 name => 'file', 701 min_level => 1, 702 filename => $mode_log, 703 mode => 'write', 704 ); 705 $f1->log( 706 level => 'emerg', 707 message => "test2\n" 708 ); 709 710 undef $f1; 711 712 open my $fh, '<', $mode_log 713 or die "Cannot read $mode_log: $!"; 714 my $data = do { local $/ = undef; <$fh> }; 715 close $fh or die $!; 716 717 like( $data, qr/^test2/, 'test write mode' ); 718 } 719); 720 721subtest( 722 'Log::Dispatch->dispatch by name', 723 sub { 724 my $dispatch = Log::Dispatch->new; 725 726 $dispatch->add( 727 Log::Dispatch::Screen->new( 728 name => 'yomama', 729 min_level => 'alert' 730 ) 731 ); 732 733 ok( 734 $dispatch->output('yomama'), 735 'yomama output should exist' 736 ); 737 738 ok( 739 !$dispatch->output('nomama'), 740 'nomama output should not exist' 741 ); 742 } 743); 744 745subtest( 746 'File output close_after_writer & permissions', 747 sub { 748 my $dispatch = Log::Dispatch->new; 749 750 my $close_log = File::Spec->catfile( $tempdir, 'close.log' ); 751 752 ## no critic (ValuesAndExpressions::ProhibitLeadingZeros) 753 $dispatch->add( 754 Log::Dispatch::File->new( 755 name => 'close', 756 min_level => 'info', 757 filename => $close_log, 758 permissions => 0777, 759 close_after_write => 1 760 ) 761 ); 762 763 $dispatch->log( level => 'info', message => "info\n" ); 764 765 open my $fh, '<', $close_log 766 or die "Can't read $close_log: $!"; 767 my @log = <$fh>; 768 close $fh or die $!; 769 770 is( 771 $log[0], "info\n", 772 q{First line in log file should be 'info\\n'} 773 ); 774 775 my $mode = ( stat $close_log )[2] 776 or die "Cannot stat $close_log: $!"; 777 778 my $mode_string = sprintf( '%04o', $mode & 07777 ); 779 780 if ( $^O =~ /win32/i ) { 781 ok( 782 $mode_string eq '0777' || $mode_string eq '0666', 783 'Mode should be 0777 or 0666' 784 ); 785 } 786 elsif ( $^O =~ /cygwin|msys/i ) { 787 ok( 788 $mode_string eq '0777' || $mode_string eq '0644', 789 'Mode should be 0777 or 0644' 790 ); 791 } 792 else { 793 is( 794 $mode_string, 795 '0777', 796 'Mode should be 0777' 797 ); 798 } 799 } 800); 801 802subtest( 803 'File output chmod calls', 804 sub { 805 my $dispatch = Log::Dispatch->new; 806 807 my $chmod_log = File::Spec->catfile( $tempdir, 'chmod.log' ); 808 809 open my $fh, '>', $chmod_log 810 or die "Cannot write to $chmod_log: $!"; 811 close $fh or die $!; 812 813 chmod 0777, $chmod_log 814 or die "Cannot chmod 0777 $chmod_log: $!"; 815 816 my @chmod; 817 ## no critic (TestingAndDebugging::ProhibitNoWarnings) 818 no warnings 'once'; 819 local *CORE::GLOBAL::chmod = sub { @chmod = @_; warn @chmod }; 820 821 ## no critic (ValuesAndExpressions::ProhibitLeadingZeros) 822 $dispatch->add( 823 Log::Dispatch::File->new( 824 name => 'chmod', 825 min_level => 'info', 826 filename => $chmod_log, 827 permissions => 0777, 828 ) 829 ); 830 831 $dispatch->warning('test'); 832 833 ok( 834 !scalar @chmod, 835 'chmod() was not called when permissions already matched what was specified' 836 ); 837 } 838); 839 840subtest( 841 'File output binmode', 842 sub { 843 SKIP: 844 { 845 ## no critic (ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions) 846 skip "Cannot test utf8 files with this version of Perl ($])", 1 847 unless $] >= 5.008; 848 849 my $dispatch = Log::Dispatch->new; 850 851 my $utf8_log = File::Spec->catfile( $tempdir, 'utf8.log' ); 852 853 $dispatch->add( 854 Log::Dispatch::File->new( 855 name => 'utf8', 856 min_level => 'info', 857 filename => $utf8_log, 858 binmode => ':encoding(UTF-8)', 859 ) 860 ); 861 862 my @warnings; 863 864 { 865 local $SIG{__WARN__} = sub { push @warnings, @_ }; 866 $dispatch->warning("\x{999A}"); 867 } 868 869 ok( 870 !scalar @warnings, 871 'utf8 binmode was applied to file and no warnings were issued' 872 ); 873 } 874 } 875); 876 877subtest( 878 'Log::Dispatch->would_log', 879 sub { 880 my $dispatch = Log::Dispatch->new; 881 882 $dispatch->add( 883 Log::Dispatch::Null->new( 884 name => 'null', 885 min_level => 'warning', 886 ) 887 ); 888 889 ok( 890 !$dispatch->would_log('foo'), 891 q{will not log 'foo'} 892 ); 893 894 ok( 895 !$dispatch->would_log('debug'), 896 q{will not log 'debug'} 897 ); 898 899 ok( 900 !$dispatch->is_debug(), 901 'is_debug returns false' 902 ); 903 904 ok( 905 $dispatch->is_warning(), 906 'is_warning returns true' 907 ); 908 909 ok( 910 $dispatch->would_log('crit'), 911 q{will log 'crit'} 912 ); 913 914 ok( 915 $dispatch->is_crit, 916 q{will log 'crit'} 917 ); 918 } 919); 920 921subtest( 922 'messages as coderefs are only called as needed', 923 sub { 924 my $dispatch = Log::Dispatch->new; 925 926 $dispatch->add( 927 Log::Dispatch::Null->new( 928 name => 'null', 929 min_level => 'info', 930 max_level => 'critical', 931 ) 932 ); 933 934 my $called = 0; 935 my $message = sub { $called = 1 }; 936 937 $dispatch->log( level => 'debug', message => $message ); 938 ok( 939 !$called, 940 'subref is not called if the message would not be logged' 941 ); 942 943 $called = 0; 944 $dispatch->log( level => 'warning', message => $message ); 945 ok( $called, 'subref is called when message is logged' ); 946 947 $called = 0; 948 $dispatch->log( level => 'emergency', message => $message ); 949 ok( 950 !$called, 951 'subref is not called when message would not be logged' 952 ); 953 } 954); 955 956subtest( 957 'passing coderef to ->log', 958 sub { 959 my $string; 960 my $dispatch = Log::Dispatch->new; 961 $dispatch->add( 962 Log::Dispatch::String->new( 963 name => 'handle', 964 string => \$string, 965 min_level => 'debug', 966 ) 967 ); 968 969 $dispatch->log( 970 level => 'debug', 971 message => sub {'this is my message'}, 972 ); 973 974 is( 975 $string, 'this is my message', 976 'message returned by subref is logged' 977 ); 978 } 979); 980 981subtest( 982 'newline parameter to output', 983 sub { 984 my $string; 985 my $dispatch = Log::Dispatch->new; 986 $dispatch->add( 987 Log::Dispatch::String->new( 988 name => 'handle', 989 string => \$string, 990 min_level => 'debug', 991 newline => 1, 992 ) 993 ); 994 $dispatch->debug('hello'); 995 $dispatch->debug('goodbye'); 996 997 is( $string, "hello\ngoodbye\n", 'added newlines' ); 998 } 999); 1000 1001subtest( 1002 'log_and_die method', 1003 sub { 1004 my $string; 1005 my $dispatch = Log::Dispatch->new; 1006 $dispatch->add( 1007 Log::Dispatch::String->new( 1008 name => 'handle', 1009 string => \$string, 1010 min_level => 'debug', 1011 ) 1012 ); 1013 1014 my $e = exception { 1015 _log_and_die( 1016 $dispatch, 1017 level => 'error', 1018 message => 'this is my message', 1019 ); 1020 }; 1021 1022 ok( $e, 'died when calling log_and_die()' ); 1023 like( $e, qr{this is my message}, 'error contains expected message' ); 1024 like( $e, qr{basic\.t line 50\d\d}, 'error croaked' ); 1025 1026 is( $string, 'this is my message', 'message is logged' ); 1027 1028 undef $string; 1029 1030 try { 1031 Croaker::croak($dispatch) 1032 } 1033 catch { 1034 $e = $_; 1035 }; 1036 1037 ok( $e, 'died when calling log_and_croak()' ); 1038 like( $e, qr{croaking a message}, 'error contains expected message' ); 1039 like( 1040 $e, qr{basic\.t line 100\d\d}, 1041 'error croaked from perspective of caller' 1042 ); 1043 1044 is( $string, 'croaking a message', 'message is logged' ); 1045 } 1046); 1047 1048subtest( 1049 'adding and removing callbacks in output', 1050 sub { 1051 my $string; 1052 my $dispatch = Log::Dispatch->new; 1053 $dispatch->add( 1054 Log::Dispatch::String->new( 1055 name => 'handle', 1056 string => \$string, 1057 min_level => 'debug', 1058 ) 1059 ); 1060 1061 $dispatch->log( level => 'debug', message => 'foo' ); 1062 is( $string, 'foo', 'first test w/o callback' ); 1063 1064 my $cb = sub { return 'bar' }; 1065 $string = q{}; 1066 $dispatch->add_callback($cb); 1067 $dispatch->log( level => 'debug', message => 'foo' ); 1068 is( $string, 'bar', 'second call, callback overrides message' ); 1069 1070 $string = q{}; 1071 $dispatch->remove_callback($cb); 1072 $dispatch->log( level => 'debug', message => 'foo' ); 1073 is( $string, 'foo', 'third call, callback is removed' ); 1074 } 1075); 1076 1077subtest( 1078 'adding and removing callbacks in Log::Dispatch', 1079 sub { 1080 my $string; 1081 my $dispatch = Log::Dispatch->new( 1082 callbacks => sub { return 'baz' }, 1083 ); 1084 $dispatch->add( 1085 Log::Dispatch::String->new( 1086 name => 'handle', 1087 string => \$string, 1088 min_level => 'debug', 1089 ) 1090 ); 1091 1092 $dispatch->log( level => 'debug', message => 'foo' ); 1093 is( $string, 'baz', 'first test gets orig callback result' ); 1094 1095 my $cb = sub { return 'bar' }; 1096 $string = q{}; 1097 $dispatch->add_callback($cb); 1098 $dispatch->log( level => 'debug', message => 'foo' ); 1099 is( $string, 'bar', 'second call, callback overrides message' ); 1100 1101 $string = q{}; 1102 $dispatch->remove_callback($cb); 1103 $dispatch->log( level => 'debug', message => 'foo' ); 1104 is( $string, 'baz', 'third call, output callback is removed' ); 1105 } 1106); 1107 1108subtest( 1109 'callback in output can overwrite message', 1110 sub { 1111 my $string; 1112 my $dispatch = Log::Dispatch->new; 1113 $dispatch->add( 1114 Log::Dispatch::String->new( 1115 name => 'handle', 1116 string => \$string, 1117 min_level => 'debug', 1118 ) 1119 ); 1120 1121 $dispatch->log( level => 'debug', message => 'foo' ); 1122 is( $string, 'foo', 'first test w/o callback' ); 1123 1124 $string = q{}; 1125 $dispatch->add_callback( sub { return 'bar' } ); 1126 $dispatch->log( level => 'debug', message => 'foo' ); 1127 is( $string, 'bar', 'second call, callback overrides message' ); 1128 } 1129); 1130 1131subtest( 1132 'callback in Log::Dispatch can overwrite message', 1133 sub { 1134 my $string; 1135 my $dispatch = Log::Dispatch->new( 1136 callbacks => sub { return 'baz' }, 1137 ); 1138 $dispatch->add( 1139 Log::Dispatch::String->new( 1140 name => 'handle', 1141 string => \$string, 1142 min_level => 'debug', 1143 ) 1144 ); 1145 1146 $dispatch->log( level => 'debug', message => 'foo' ); 1147 is( $string, 'baz', 'first test gets orig callback result' ); 1148 1149 $string = q{}; 1150 $dispatch->add_callback( sub { return 'bar' } ); 1151 $dispatch->log( level => 'debug', message => 'foo' ); 1152 is( $string, 'bar', 'second call, callback overrides message' ); 1153 } 1154); 1155 1156subtest( 1157 'default output name', 1158 sub { 1159 1160 # Test defaults 1161 my $dispatch = Log::Dispatch::Null->new( min_level => 'debug' ); 1162 like( $dispatch->name, qr/anon/, 'generated anon name' ); 1163 is( $dispatch->max_level, 'emergency', 'max_level is emergency' ); 1164 } 1165); 1166 1167subtest( 1168 'callbacks get correct level', 1169 sub { 1170 my $level; 1171 my $record_level = sub { 1172 my %p = @_; 1173 $level = $p{level}; 1174 return %p; 1175 }; 1176 1177 my $dispatch = Log::Dispatch->new( 1178 callbacks => $record_level, 1179 outputs => [ 1180 [ 1181 'Null', 1182 name => 'null', 1183 min_level => 'debug', 1184 ], 1185 ], 1186 ); 1187 1188 $dispatch->warn('foo'); 1189 is( 1190 $level, 1191 'warning', 1192 'level for call to ->warn is warning' 1193 ); 1194 1195 $dispatch->err('foo'); 1196 is( 1197 $level, 1198 'error', 1199 'level for call to ->err is error' 1200 ); 1201 1202 $dispatch->crit('foo'); 1203 is( 1204 $level, 1205 'critical', 1206 'level for call to ->crit is critical' 1207 ); 1208 1209 $dispatch->emerg('foo'); 1210 is( 1211 $level, 1212 'emergency', 1213 'level for call to ->emerg is emergency' 1214 ); 1215 } 1216); 1217 1218subtest( 1219 'Code output', 1220 sub { 1221 my @calls; 1222 my $log = Log::Dispatch->new( 1223 outputs => [ 1224 [ 1225 'Code', 1226 min_level => 'error', 1227 code => sub { push @calls, {@_} }, 1228 ], 1229 ] 1230 ); 1231 1232 $log->error('foo'); 1233 $log->info('bar'); 1234 $log->critical('baz'); 1235 1236 is_deeply( 1237 \@calls, 1238 [ 1239 { 1240 level => 'error', 1241 message => 'foo', 1242 }, { 1243 level => 'critical', 1244 message => 'baz', 1245 }, 1246 ], 1247 'code received the expected messages' 1248 ); 1249 } 1250); 1251 1252subtest( 1253 'passing level as name or integer', 1254 sub { 1255 my $dispatch = Log::Dispatch->new; 1256 my $log = File::Spec->catdir( $tempdir, 'emerg.log' ); 1257 1258 $dispatch->add( 1259 Log::Dispatch::File->new( 1260 name => 'file1', 1261 min_level => 3, 1262 filename => $log, 1263 ) 1264 ); 1265 1266 $dispatch->log( level => 'info', message => "info level 1\n" ); 1267 $dispatch->log( level => 'emerg', message => "emerg level 1\n" ); 1268 $dispatch->log( level => 'warn', message => "warn level 1\n" ); 1269 $dispatch->log( level => 3, message => "bug 106495 1\n" ); 1270 $dispatch->log( level => 4, message => "bug 106495 2\n" ); 1271 $dispatch->log( level => 1, message => "bug 106495 3\n" ); 1272 1273 open my $fh, '<', $log or die $!; 1274 my @log = <$fh>; 1275 close $fh or die $!; 1276 1277 is( $log[0], "emerg level 1\n", 'at level 3, emerg works' ); 1278 is( $log[1], "warn level 1\n", 'at level 3, warn works' ); 1279 is( 1280 $log[2], "bug 106495 1\n", 1281 'level as integer works with min_level 3 and level 3' 1282 ); 1283 is( 1284 $log[3], "bug 106495 2\n", 1285 'level as integer works with min_level 3 and level 4' 1286 ); 1287 is( 1288 $log[4], undef, 1289 'using integer level works with min_level 3 and level 1' 1290 ); 1291 } 1292); 1293 1294subtest( 1295 'more levels as integers', 1296 sub { 1297 my $dispatch = Log::Dispatch->new; 1298 my $log = File::Spec->catdir( $tempdir, 'emerg.log' ); 1299 1300 $dispatch->add( 1301 Log::Dispatch::File->new( 1302 name => 'file1', 1303 min_level => 0, 1304 filename => $log, 1305 ) 1306 ); 1307 1308 $dispatch->log( level => 0, message => "bug 106495 0\n" ); 1309 $dispatch->log( level => 1, message => "bug 106495 1\n" ); 1310 $dispatch->log( level => 2, message => "bug 106495 2\n" ); 1311 $dispatch->log( level => 3, message => "bug 106495 3\n" ); 1312 $dispatch->log( level => 4, message => "bug 106495 4\n" ); 1313 $dispatch->log( level => 5, message => "bug 106495 5\n" ); 1314 $dispatch->log( level => 6, message => "bug 106495 6\n" ); 1315 $dispatch->log( level => 7, message => "bug 106495 7\n" ); 1316 1317 open my $fh, '<', $log or die $!; 1318 my @log = <$fh>; 1319 close $fh or die $!; 1320 1321 is( $log[0], "bug 106495 0\n", 'at level 0, int works' ); 1322 is( $log[1], "bug 106495 1\n", 'at level 1, int works' ); 1323 is( $log[2], "bug 106495 2\n", 'at level 2, int works' ); 1324 is( $log[3], "bug 106495 3\n", 'at level 3, int works' ); 1325 is( $log[4], "bug 106495 4\n", 'at level 4, int works' ); 1326 is( $log[5], "bug 106495 5\n", 'at level 5, int works' ); 1327 is( $log[6], "bug 106495 6\n", 'at level 6, int works' ); 1328 is( $log[7], "bug 106495 7\n", 'at level 7, int works' ); 1329 } 1330); 1331 1332done_testing(); 1333 1334## no critic (Modules::ProhibitMultiplePackages) 1335{ 1336 package Log::Dispatch::String; 1337 1338 use strict; 1339 1340 use Log::Dispatch::Output; 1341 1342 use base qw( Log::Dispatch::Output ); 1343 1344 sub new { 1345 my $proto = shift; 1346 my $class = ref $proto || $proto; 1347 my %p = @_; 1348 1349 my $self = bless { string => $p{string} }, $class; 1350 1351 $self->_basic_init(%p); 1352 1353 return $self; 1354 } 1355 1356 sub log_message { 1357 my $self = shift; 1358 my %p = @_; 1359 1360 ${ $self->{string} } .= $p{message}; 1361 } 1362} 1363 1364#line 5000 1365sub _log_and_die { 1366 shift->log_and_die(@_); 1367} 1368 1369{ 1370#line 10000 1371 package Croaker; 1372 1373 sub croak { 1374 shift->log_and_croak( 1375 level => 'error', 1376 message => 'croaking a message' 1377 ); 1378 } 1379} 1380