@@ -240,6 +240,52 @@ sub register_metrics {
240240 };
241241}
242242
243+ =metric_method I<record_time_taken($callback, $handler, $microseconds) >
244+
245+ Record the time taken in a particular callback/handler
246+
247+ =cut
248+
249+ sub record_time_taken ($self , $callback , $handler , $microseconds ) {
250+ $self -> metric_count(' time_microseconds_total' , { ' callback' => $callback , ' handler' => $handler }, $microseconds );
251+
252+ # For extended logging
253+
254+ # setup/dequeue stages are not relevant and abort/close occur post extended logging
255+ return if $callback eq ' setup'
256+ || $callback eq ' dequeue'
257+ || $callback eq ' abort'
258+ || $callback eq ' close' ;
259+
260+ my $label = join (' .' , $callback , $handler );
261+
262+ # connect and helo stages go into c_timing (connection persist)
263+ if ($callback eq ' connect' || $callback eq ' helo' ) {
264+ $self -> {c_timing } = {} unless $self -> {c_timing };
265+ $self -> {c_timing }-> {$label } = 0 unless $self -> {c_timing }-> {$label };
266+ $self -> {c_timing }-> {$label } = $self -> {c_timing }-> {$label } + $microseconds ;
267+ } else {
268+ # remaining are envfrom rcptto header eoh body and eom addheader stages which are
269+ # email specific and go into timing
270+ $self -> {timing } = {} unless $self -> {timing };
271+ $self -> {timing }-> {$label } = 0 unless $self -> {timing }-> {$label };
272+ $self -> {timing }-> {$label } = $self -> {timing }-> {$label } + $microseconds ;
273+ }
274+ }
275+
276+ =metric_method I<get_timing_data() >
277+
278+ Return timing data for this transaction
279+
280+ =cut
281+
282+ sub get_timing_data ($self ) {
283+ my $c_timing = $self -> {c_timing } // {};
284+ my $timing = $self -> {timing } // {};
285+ my %data = ( %$c_timing , %$timing );
286+ return \%data ;
287+ }
288+
243289=callback_method I<top_dequeue_callback() >
244290
245291Top level handler for dequeue.
@@ -259,12 +305,15 @@ sub top_dequeue_callback {
259305 $self -> set_alarm( $timeout );
260306 }
261307 my $callbacks = $self -> get_callbacks( ' dequeue' );
308+
262309 foreach my $handler ( @$callbacks ) {
263310 $self -> dbgout( ' CALLBACK' , ' Dequeue ' . $handler , LOG_DEBUG );
264311 my $start_time = $self -> get_microseconds();
265- $self -> get_handler($handler )-> dequeue_callback();
312+ eval { $self -> get_handler($handler )-> dequeue_callback(); };
313+ my $error = $@ ;
266314 $self -> dbgoutwrite();
267- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' dequeue' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
315+ $self -> record_time_taken(' dequeue' , $handler , $self -> get_microseconds_since($start_time ));
316+ die $error if $error ;
268317 }
269318 $self -> set_alarm(0);
270319 };
@@ -297,8 +346,11 @@ sub top_setup_callback {
297346 foreach my $handler ( @$callbacks ) {
298347 $self -> dbgout( ' CALLBACK' , ' Setup ' . $handler , LOG_DEBUG );
299348 my $start_time = $self -> get_microseconds();
300- $self -> get_handler($handler )-> setup_callback();
301- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' setup' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
349+ eval { $self -> get_handler($handler )-> setup_callback(); };
350+ my $error = $@ ;
351+ $self -> record_time_taken(' setup' , $handler , $self -> get_microseconds_since($start_time ));
352+ die $error if $error ;
353+ # $self->metric_count( 'time_microseconds_total', { 'callback' => 'setup', 'handler' => $handler }, $self->get_microseconds_since( $start_time ) );
302354 }
303355 $self -> status(' postsetup' );
304356}
@@ -630,13 +682,14 @@ sub top_connect_callback {
630682 $self -> dbgout( ' CALLBACK' , ' Connect ' . $handler , LOG_DEBUG );
631683 my $start_time = $self -> get_microseconds();
632684 eval { $self -> get_handler($handler )-> connect_callback( $hostname , $ip ); };
633- if ( my $error = $@ ) {
685+ my $error = $@ ;
686+ $self -> record_time_taken(' connect' , $handler , $self -> get_microseconds_since($start_time ));
687+ if ($error ) {
688+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' connect' , ' handler' => $handler } );
634689 $self -> handle_exception( $error );
635690 $self -> exit_on_close( ' Connect callback error ' . $error );
636691 $self -> tempfail_on_error();
637- $self -> metric_count( ' callback_error_total' , { ' stage' => ' connect' , ' handler' => $handler } );
638692 }
639- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' connect' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
640693 $self -> check_timeout();
641694 }
642695 $self -> set_alarm(0);
@@ -713,13 +766,14 @@ sub top_helo_callback {
713766 $self -> dbgout( ' CALLBACK' , ' Helo ' . $handler , LOG_DEBUG );
714767 my $start_time = $self -> get_microseconds();
715768 eval { $self -> get_handler($handler )-> helo_callback($helo_host ); };
716- if ( my $error = $@ ) {
769+ my $error = $@ ;
770+ $self -> record_time_taken(' helo' , $handler , $self -> get_microseconds_since($start_time ));
771+ if ($error ) {
772+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' helo' , ' handler' => $handler } );
717773 $self -> handle_exception( $error );
718774 $self -> exit_on_close( ' HELO callback error ' . $error );
719775 $self -> tempfail_on_error();
720- $self -> metric_count( ' callback_error_total' , { ' stage' => ' helo' , ' handler' => $handler } );
721776 }
722- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' helo' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
723777 $self -> check_timeout();
724778 }
725779 }
@@ -771,19 +825,21 @@ sub top_envfrom_callback {
771825 delete $self -> {' pre_headers' };
772826 delete $self -> {' add_headers' };
773827 delete $self -> {' suppress_error_emails' };
828+ delete $self -> {' timing' };
774829
775830 my $callbacks = $self -> get_callbacks( ' envfrom' );
776831 foreach my $handler ( @$callbacks ) {
777832 $self -> dbgout( ' CALLBACK' , ' EnvFrom ' . $handler , LOG_DEBUG );
778833 my $start_time = $self -> get_microseconds();
779834 eval { $self -> get_handler($handler )-> envfrom_callback($env_from , @params ); };
780- if ( my $error = $@ ) {
835+ my $error = $@ ;
836+ $self -> record_time_taken(' envfrom' , $handler , $self -> get_microseconds_since($start_time ));
837+ if ($error ) {
838+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' envfrom' , ' handler' => $handler } );
781839 $self -> handle_exception( $error );
782840 $self -> exit_on_close( ' Env From callback error ' . $error );
783841 $self -> tempfail_on_error();
784- $self -> metric_count( ' callback_error_total' , { ' stage' => ' envfrom' , ' handler' => $handler } );
785842 }
786- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' envfrom' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
787843 $self -> check_timeout();
788844 }
789845 $self -> set_alarm(0);
@@ -830,13 +886,14 @@ sub top_envrcpt_callback {
830886 $self -> dbgout( ' CALLBACK' , ' EnvRcpt ' . $handler , LOG_DEBUG );
831887 my $start_time = $self -> get_microseconds();
832888 eval { $self -> get_handler($handler )-> envrcpt_callback($env_to , @params ); };
833- if ( my $error = $@ ) {
889+ my $error = $@ ;
890+ $self -> record_time_taken(' rcptto' , $handler , $self -> get_microseconds_since($start_time ));
891+ if ($error ) {
892+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' rcptto' , ' handler' => $handler } );
834893 $self -> handle_exception( $error );
835894 $self -> exit_on_close( ' Env Rcpt callback error ' . $error );
836895 $self -> tempfail_on_error();
837- $self -> metric_count( ' callback_error_total' , { ' stage' => ' rcptto' , ' handler' => $handler } );
838896 }
839- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' rcptto' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
840897 $self -> check_timeout();
841898 }
842899 $self -> set_alarm(0);
@@ -890,13 +947,14 @@ sub top_header_callback {
890947 $self -> dbgout( ' CALLBACK' , ' Header ' . $handler , LOG_DEBUG );
891948 my $start_time = $self -> get_microseconds();
892949 eval { $self -> get_handler($handler )-> header_callback( $header , $value , $original ); };
893- if ( my $error = $@ ) {
950+ my $error = $@ ;
951+ $self -> record_time_taken(' header' , $handler , $self -> get_microseconds_since($start_time ));
952+ if ($error ) {
953+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' header' , ' handler' => $handler } );
894954 $self -> handle_exception( $error );
895955 $self -> exit_on_close( ' Header callback error ' . $error );
896956 $self -> tempfail_on_error();
897- $self -> metric_count( ' callback_error_total' , { ' stage' => ' header' , ' handler' => $handler } );
898957 }
899- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' header' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
900958 $self -> check_timeout();
901959 }
902960 $self -> set_alarm(0);
@@ -941,13 +999,14 @@ sub top_eoh_callback {
941999 $self -> dbgout( ' CALLBACK' , ' EOH ' . $handler , LOG_DEBUG );
9421000 my $start_time = $self -> get_microseconds();
9431001 eval { $self -> get_handler($handler )-> eoh_callback(); };
944- if ( my $error = $@ ) {
1002+ my $error = $@ ;
1003+ $self -> record_time_taken(' eoh' , $handler , $self -> get_microseconds_since($start_time ));
1004+ if ($error ) {
1005+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' eoh' , ' handler' => $handler } );
9451006 $self -> handle_exception( $error );
9461007 $self -> exit_on_close( ' EOH callback error ' . $error );
9471008 $self -> tempfail_on_error();
948- $self -> metric_count( ' callback_error_total' , { ' stage' => ' eoh' , ' handler' => $handler } );
9491009 }
950- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' eoh' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
9511010 $self -> check_timeout();
9521011 }
9531012 $self -> set_alarm(0);
@@ -993,13 +1052,14 @@ sub top_body_callback {
9931052 $self -> dbgout( ' CALLBACK' , ' Body ' . $handler , LOG_DEBUG );
9941053 my $start_time = $self -> get_microseconds();
9951054 eval { $self -> get_handler($handler )-> body_callback( $body_chunk ); };
996- if ( my $error = $@ ) {
1055+ my $error = $@ ;
1056+ $self -> record_time_taken(' body' , $handler , $self -> get_microseconds_since($start_time ));
1057+ if ($error ) {
1058+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' body' , ' handler' => $handler } );
9971059 $self -> handle_exception( $error );
9981060 $self -> exit_on_close( ' Body callback error ' . $error );
9991061 $self -> tempfail_on_error();
1000- $self -> metric_count( ' callback_error_total' , { ' stage' => ' body' , ' handler' => $handler } );
10011062 }
1002- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' body' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
10031063 $self -> check_timeout();
10041064 }
10051065 $self -> set_alarm(0);
@@ -1045,13 +1105,14 @@ sub top_eom_callback {
10451105 $self -> dbgout( ' CALLBACK' , ' EOM ' . $handler , LOG_DEBUG );
10461106 my $start_time = $self -> get_microseconds();
10471107 eval { $self -> get_handler($handler )-> eom_callback(); };
1048- if ( my $error = $@ ) {
1108+ my $error = $@ ;
1109+ $self -> record_time_taken(' eom' , $handler , $self -> get_microseconds_since($start_time ));
1110+ if ($error ) {
1111+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' eom' , ' handler' => $handler } );
10491112 $self -> handle_exception( $error );
10501113 $self -> exit_on_close( ' EOM callback error ' . $error );
10511114 $self -> tempfail_on_error();
1052- $self -> metric_count( ' callback_error_total' , { ' stage' => ' eom' , ' handler' => $handler } );
10531115 }
1054- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' eom' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
10551116 $self -> check_timeout();
10561117 }
10571118 $self -> set_alarm(0);
@@ -1123,13 +1184,14 @@ sub top_abort_callback {
11231184 $self -> dbgout( ' CALLBACK' , ' Abort ' . $handler , LOG_DEBUG );
11241185 my $start_time = $self -> get_microseconds();
11251186 eval { $self -> get_handler($handler )-> abort_callback(); };
1126- if ( my $error = $@ ) {
1187+ $self -> record_time_taken(' abort' , $handler , $self -> get_microseconds_since($start_time ));
1188+ my $error = $@ ;
1189+ if ($error ) {
1190+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' abort' , ' handler' => $handler } );
11271191 $self -> handle_exception( $error );
11281192 $self -> exit_on_close( ' Abort callback error ' . $error );
11291193 $self -> tempfail_on_error();
1130- $self -> metric_count( ' callback_error_total' , { ' stage' => ' abort' , ' handler' => $handler } );
11311194 }
1132- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' abort' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
11331195 $self -> check_timeout();
11341196 }
11351197 $self -> set_alarm(0);
@@ -1177,13 +1239,14 @@ sub top_close_callback {
11771239 $self -> dbgout( ' CALLBACK' , ' Close ' . $handler , LOG_DEBUG );
11781240 my $start_time = $self -> get_microseconds();
11791241 eval { $self -> get_handler($handler )-> close_callback(); };
1180- if ( my $error = $@ ) {
1242+ my $error = $@ ;
1243+ $self -> record_time_taken(' close' , $handler , $self -> get_microseconds_since($start_time ));
1244+ if ($error ) {
1245+ $self -> metric_count( ' callback_error_total' , { ' stage' => ' close' , ' handler' => $handler } );
11811246 $self -> handle_exception( $error );
11821247 $self -> exit_on_close( ' Close callback error ' . $error );
11831248 $self -> tempfail_on_error();
1184- $self -> metric_count( ' callback_error_total' , { ' stage' => ' close' , ' handler' => $handler } );
11851249 }
1186- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' close' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
11871250 $self -> check_timeout();
11881251
11891252 my $handler_object = $self -> get_handler($handler );
@@ -1210,6 +1273,8 @@ sub top_close_callback {
12101273 delete $self -> {' raw_helo_name' };
12111274 delete $self -> {' c_auth_headers' };
12121275 delete $self -> {' auth_headers' };
1276+ delete $self -> {' c_timing' };
1277+ delete $self -> {' timing' };
12131278 delete $self -> {' pre_headers' };
12141279 delete $self -> {' add_headers' };
12151280 delete $self -> {' ip_object' };
@@ -1241,8 +1306,10 @@ sub top_addheader_callback {
12411306 my $callbacks = $self -> get_callbacks( ' addheader' );
12421307 foreach my $handler ( @$callbacks ) {
12431308 my $start_time = $self -> get_microseconds();
1244- $self -> get_handler($handler )-> addheader_callback($self );
1245- $self -> metric_count( ' time_microseconds_total' , { ' callback' => ' addheader' , ' handler' => $handler }, $self -> get_microseconds_since( $start_time ) );
1309+ eval { $self -> get_handler($handler )-> addheader_callback($self ); };
1310+ my $error = $@ ;
1311+ $self -> record_time_taken(' addheader' , $handler , $self -> get_microseconds_since($start_time ));
1312+ die $error if $error ;
12461313 $self -> check_timeout();
12471314 }
12481315 $self -> set_alarm(0);
@@ -2582,17 +2649,18 @@ sub add_headers {
25822649 $self -> add_auth_headers_of_type($type );
25832650 }
25842651
2585- if ($config -> {extended_log }) {
2586- my $j = JSON-> new-> canonical-> utf8;
2587- $self -> dbgout( ' ARex' ,$j -> encode($self -> {extended_log }), LOG_INFO );
2588- }
2589-
25902652 if ( my $reason = $self -> get_quarantine_mail() ) {
25912653 $self -> prepend_header( ' X-Disposition-Quarantine' , $reason );
25922654 }
25932655
25942656 $top_handler -> top_addheader_callback();
25952657
2658+ $self -> {extended_log }-> {timing } = $self -> get_timing_data;
2659+ if ($config -> {extended_log }) {
2660+ my $j = JSON-> new-> canonical-> utf8;
2661+ $self -> dbgout( ' ARex' ,$j -> encode($self -> {extended_log }), LOG_INFO );
2662+ }
2663+
25962664 if ( exists ( $top_handler -> {' pre_headers' } ) ) {
25972665 foreach my $header ( @{ $top_handler -> {' pre_headers' } } ) {
25982666 $self -> dbgout( ' PreHeader' ,
0 commit comments