This scratched an itch for me, no guarantees.
use warnings::colored; warn "warning"; # yellow system "non-existant-command"; # red say "test"; # none eval { die "caught" }; # none say $@; # none die "died"; # red
And the implementation:
package warnings::colored; use strict; use warnings; use Term::ANSIColor; # Color die and warn messages. # NOTE: Doesn' play well with Carp::Always because it replaces our die + and # warn sighandlers. $ENV{NO_COLOR} = 1 if ! exists $ENV{NO_COLOR} and (! -t STDIN or ! -t STDERR); BEGIN { my $died; *CORE::GLOBAL::die = sub { $died = 1, print STDERR color('bold red') if @_ and ! $^S; END { $died && print STDERR color('reset') } $] >= 5.016 && goto &CORE::die; CORE::die @_; }; *CORE::GLOBAL::warn = sub { unshift @_, color('bold yellow'); # $SIG{__WARN__} will print the reset sequence. $] >= 5.016 && goto &CORE::warn; CORE::warn @_; }; } # Unintentional warning messages should display with high severity. # E.g.`system 'nonexistent-command'`. $SIG{__WARN__} = sub { my $msg = shift; if ($] < 5.016 and __FILE__ eq (caller)[1]) { my ($file, $line) = (caller(1))[1, 2]; $msg =~ s/( at .*? line \d+\.$)/ at $file line $line/m; } CORE::warn color('bold red'), $msg; print STDERR color('reset'); }; $SIG{__DIE__} = sub { my $msg = shift; if (__FILE__ eq (caller)[1]) { my ($file, $line) = (caller(1))[1, 2]; $msg =~ s/( at .*? line \d+\.$)/ at $file line $line/m; die $msg; } } if $] < 5.016 ; 1;

Replies are listed 'Best First'.
Re: Color die and warn messages
by dbuckhal (Chaplain) on Mar 02, 2024 at 06:28 UTC

    Hey, just silly thought I had regarding your "NOTE"

    # NOTE: Doesn' play well with Carp::Always because it replaces our die

    Since you are colorizing, instead of "die", use "dye" to prevent clobbering.

    Otherwise, cool concept!

    ... I really hope Anonymous Monk gets this response ...
      Your quote is incomplete: "it replaces our die and warn sighandlers". The point of the code is to be drop-in and not require any other changes in your code. In fact, it would be better to call it in an eval so if it's not installed, it doesn't break anything: BEGIN { eval 'use warnings::colored' };.

      Changing die to dye would require you to change any code that uses it, and also it wouldn't then work on anything that internally called die or warn, like the example: system 'nonexistent-command'.

      If the %SIG entries could be tied variables, then it might be possible to make this play nice with Carp::Always. I haven't looked into that because it works fine enough as it is for me. That's why I released it anonymously and not to CPAN. If somebody wants to improve on it and deal with the edge cases, feel free to release it.

        In fact, it would be better to call it in an eval so if it's not installed, it doesn't break anything: BEGIN { eval 'use warnings::colored' };.
        Better yet, invoke it using an environment variable: PERL5OPT="-M5;BEGIN{eval{require warnings::colored)}}" as mentioned here: Re: Is it possible load optional modules from PERL5OPT?.
Re: Color die and warn messages
by Anonymous Monk on Jul 31, 2025 at 22:00 UTC
Re: Color die and warn messages
by Anonymous Monk on Aug 01, 2025 at 07:20 UTC
    Doesn't work with Carp. croak calls CORE::die internally so the coloring would need to be done in the die handler, and carp is colored red even though internally it doesn't call CORE::warn, but somehow the CORE::GLOBAL::warn override is bypassed.
      Carp overrides the die handler so that won't work. What about using a tied handle to STDERR: Perl Programming 4.4. Tying Filehandles. But I don't think it would be possible to distinguish fatal messages.
Re: Color die and warn messages
by Anonymous Monk on Mar 05, 2025 at 01:05 UTC
    i tried using it and noticed occasionally when there is much output, the reset isn't set properly, so all remaining output is colored, even if not from warn/die. sorry, i couldn't figure out a minimal test case to demonstrate.
      It's probably because something is messing with STDERR and putting it into line-buffered mode. I've seen some modules do that. This could probably be fixed using IO::Handle::printflush to print the terminal reset sequence.
        Indeed, that did work. printflush() prevents writes to stderrr and stdout from intermingling.