File Coverage

lib/Pcore/Core/Exception.pm
Criterion Covered Total %
statement 16 58 27.5
branch 3 22 13.6
condition 2 6 33.3
subroutine 5 11 45.4
pod 2 6 33.3
total 28 103 27.1


line stmt bran cond sub pod time code
1             package Pcore::Core::Exception;
2              
3 5         33 use Pcore -export => { #
4             DEFAULT => [qw[croak cluck]],
5 5     5   31 };
  5         9  
6 5     5   34 use Carp qw[];
  5         8  
  5         93  
7 5     5   1413 use Pcore::Core::Exception::Object;
  5         15  
  5         581  
8              
9             our $IGNORE_ERRORS = 1; # do not write errors to error log channel by default
10              
11             # needed to properly destruct TEMP_DIR
12             $SIG->{INT} = AE::signal INT => \&SIGINT;
13              
14             # required for properly remove TEMP_DIR
15             $SIG->{TERM} = AE::signal TERM => \&SIGTERM;
16              
17             $SIG{__DIE__} = \&SIGDIE; ## no critic qw[Variables::RequireLocalizedPunctuationVars]
18              
19             $SIG{__WARN__} = \&SIGWARN; ## no critic qw[Variables::RequireLocalizedPunctuationVars]
20              
21             # we don't need stacktrace from Error::TypeTiny exceptions
22             $Error::TypeTiny::StackTrace = 0;
23              
24             # redefine Carp::longmess, Carp::shotmess, disable stack trace
25             {
26 5     5   37 no warnings qw[redefine];
  5         7  
  5         4095  
27              
28             *Carp::longmess = *Carp::shortmess = sub {
29 0 0   0   0 if ( defined $_[0] ) {
30 0         0 return $_[0];
31             }
32             else {
33 0         0 return q[];
34             }
35             };
36             }
37              
38             sub SIGINT {
39 0     0 0 0 exit 128 + 2;
40             }
41              
42             sub SIGTERM {
43 0     0 0 0 exit 128 + 15;
44             }
45              
46             # SIGNALS
47             sub SIGDIE {
48 9     9 1 1729 my $e = Pcore::Core::Exception::Object->new( $_[0], level => 'ERROR', skip_frames => 1, with_trace => 1 );
49              
50             # error in AE callback
51 9 50 33     301 if ( $^S && $e->{is_ae_cb_error} ) {
    50 33        
52             {
53 0         0 local $@;
  0         0  
54              
55 0         0 eval { $e->sendlog('FATAL') };
  0         0  
56             }
57              
58 0         0 return CORE::die $e; # set $@ to $e
59             }
60              
61             # ERROR, !defined $^S - parsing module, eval, or main program, true - executing an eval
62             elsif ( !defined $^S || $^S ) {
63 9 50       34 if ( !$IGNORE_ERRORS ) {
64 0         0 local $@;
65              
66 0         0 eval { $e->sendlog('ERROR') };
  0         0  
67             }
68              
69 9         68 return CORE::die $e; # set $@ to $e
70             }
71              
72             # FATAL
73             else {
74             {
75 0           local $@;
  0            
76              
77 0           eval { $e->sendlog('FATAL') };
  0            
78             }
79              
80 0           exit $e->exit_code;
81             }
82             }
83              
84             sub SIGWARN {
85              
86             # skip AE callback error warning
87 0 0   0 1   return if $_[0] =~ /\AEV: error in callback/sm;
88              
89 0           my $e = Pcore::Core::Exception::Object->new( $_[0], level => 'WARN', skip_frames => 1, with_trace => 1 );
90              
91             {
92 0           local $@;
  0            
93              
94 0           $e->sendlog('WARN');
95             }
96              
97 0           return; # skip standard warn behaviour
98             }
99              
100             # die without trace
101             sub croak {
102 0     0 0   my $msg;
103              
104 0 0         if (@_) {
    0          
105 0 0         if ( @_ > 1 ) {
106 0           $msg = join q[], @_;
107             }
108             else {
109 0           $msg = $_[0];
110             }
111             }
112             elsif ($@) {
113 0           $msg = $@ . ' ...propagated';
114             }
115             else {
116 0           $msg = 'Died';
117             }
118              
119 0           my $e = Pcore::Core::Exception::Object->new( $msg, level => 'ERROR', skip_frames => 1, with_trace => 0 );
120              
121 0           return CORE::die $e;
122             }
123              
124             # warn without trace
125             sub cluck {
126 0     0 0   my $msg;
127              
128 0 0         if (@_) {
    0          
129 0 0         if ( @_ > 1 ) {
130 0           $msg = join q[], @_;
131             }
132             else {
133 0           $msg = $_[0];
134             }
135             }
136             elsif ($@) {
137 0           $msg = $@ . ' ...caught';
138             }
139             else {
140 0           $msg = q[Warning: something's wrong];
141             }
142              
143 0           my $e = Pcore::Core::Exception::Object->new( $msg, level => 'WARN', skip_frames => 1, with_trace => 0 );
144              
145 0           return CORE::warn $e;
146             }
147              
148             1;
149             ## -----SOURCE FILTER LOG BEGIN-----
150             ##
151             ## PerlCritic profile "pcore-script" policy violations:
152             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
153             ## | Sev. | Lines | Policy |
154             ## |======+======================+================================================================================================================|
155             ## | 3 | 53, 64, 75, 92 | Variables::RequireInitializationForLocalVars - "local" variable not initialized |
156             ## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
157             ## | 3 | 55, 66, 77 | ErrorHandling::RequireCheckingReturnValueOfEval - Return value of eval not tested |
158             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
159             ##
160             ## -----SOURCE FILTER LOG END-----
161             __END__
162             =pod
163              
164             =encoding utf8
165              
166             =head1 Pcore::Core::Exception
167              
168             Pharaoh::Core::Sig - signals management for Pharaoh::Core.
169              
170             This package is part of Pharaoh::Core.
171              
172             =head1 EXPORTS
173              
174             =head2 CORE::GLOBAL::exit
175              
176             Common exit() family functions behaviour:
177              
178             =over
179              
180             =item * threads->exit() and CORE::exit() is unhandled in threads and perform exit according to threads->set_thread_exit_only;
181              
182             =item * CORE::exit() is unhandled;
183              
184             =back
185              
186             =head1 SIGNALS
187              
188             =head2 SIGDIE
189              
190             Standart $SIG{__DIE__} exceptions handler. Use following code to redefined callback:
191              
192             local $SIG{__DIE__}; # Redefine handler locally, no callback defined, $SIG{__DIE__} will be ignored
193             local $SIG{__DIE__} = sub { # Ditto with callback defined
194             ...do something...
195             };
196              
197             =over
198              
199             =item * C<$SIG{__DIE__}> called from eval block produce ERROR log with stack trace and returns;
200              
201             =item * C<$SIG{__DIE__}> called from NOT eval block produce FATAL log with stack trace and exit from process / thread;
202              
203             =item * C<__ALRM__> exception from eval ignored;
204              
205             =item * C<__ALRM__> exception from NOT eval block produce FATAL exception;
206              
207             =item * C<__EXIT__> exception is ignored totally and can be processed in your code. See CORE::GLOBAL::exit for example;
208              
209             =item * Calling die() in $SIG{__DIE__} will overwrite $@ and exit $SIG{__DIE__} immidiately;
210              
211             =item * Overriding die will only catch actual calls to die, not run-time errors;
212              
213             =back
214              
215             =head2 SIGWARN
216              
217             Standart $SIG{__WARN__} handler. Produce standart log event on WARN level with stack backtace. To avoid call use following in your code:
218              
219             local $SIG{__WARN__} = sub { }; # Redefine callback locally
220             local $SIG{__WARN__} = undef; # Restore standart behaviour in current block
221              
222             =head2 SIGALRM
223              
224             Standart $SIG{ALRM} handler. Produce C<__ALRM__> exception. To redefine callback use following in your code:
225              
226             local $SIG{ALRM} = sub { }; # Redefine callback locally
227              
228             or use this alarm - safe code:
229              
230             my $orig_alarm = 0;
231             eval{
232             $orig_alarm = alarm 5; # Store previous alarm() timer internally
233             ...some code here...
234             };
235             alarm $orig_alarm; # Restore previous timer
236              
237             if($@ =~ /^__ALRM__/){
238             ...do something on alarm...
239             }
240              
241             NOTES
242              
243             =over
244              
245             =item * If $SIG{ALRM} not defined - process will killed on alarm. SIG{__DIE__} don't handle alarm exception;
246              
247             =item * Alarm - safe code must restore previous alarm timer at the end of execution. We can't control bad written code in other modules, so be ready that you alarm timers will not work if you use not alarm - safe modules;
248              
249             =item * alarm() works on MSWin and in threads as expected;
250              
251             =item * You must remove alarm timer immidiately after end of eval block (not in block), because if evaluated code will die - eval block will be broken and your alarm will not be removed;
252              
253             =item * alarm() call on MSWin didn't return amount of time remaining for previous timer. So chained timers on MSWin NOT WORKED.
254              
255             =back
256              
257             =cut