@@ -265,6 +265,14 @@ typedef struct {
265265 char * condition_var ;
266266} config_log_state ;
267267
268+ /*
269+ * log_request_state holds request specific log data that is not
270+ * part of the request_rec.
271+ */
272+ typedef struct {
273+ apr_time_t request_end_time ;
274+ } log_request_state ;
275+
268276/*
269277 * Format items...
270278 * Note that many of these could have ap_sprintfs replaced with static buffers.
@@ -555,50 +563,130 @@ typedef struct {
555563 unsigned t_validate ;
556564} cached_request_time ;
557565
566+ #define TIME_FMT_CUSTOM 0
567+ #define TIME_FMT_CLF 1
568+ #define TIME_FMT_ABS_SEC 2
569+ #define TIME_FMT_ABS_MSEC 3
570+ #define TIME_FMT_ABS_USEC 4
571+ #define TIME_FMT_ABS_MSEC_FRAC 5
572+ #define TIME_FMT_ABS_USEC_FRAC 6
573+
558574#define TIME_CACHE_SIZE 4
559575#define TIME_CACHE_MASK 3
560576static cached_request_time request_time_cache [TIME_CACHE_SIZE ];
561577
578+ static apr_time_t get_request_end_time (request_rec * r )
579+ {
580+ log_request_state * state = (log_request_state * )ap_get_module_config (r -> request_config ,
581+ & log_config_module );
582+ if (state -> request_end_time == 0 ) {
583+ state -> request_end_time = apr_time_now ();
584+ }
585+ return state -> request_end_time ;
586+ }
587+
588+
562589static const char * log_request_time (request_rec * r , char * a )
563590{
564591 apr_time_exp_t xt ;
592+ apr_time_t request_time = r -> request_time ;
593+ int fmt_type = TIME_FMT_CUSTOM ;
594+ char * fmt = a ;
595+
596+ if (fmt && * fmt ) {
597+ if (!strncmp (fmt , "begin" , 5 )) {
598+ fmt += 5 ;
599+ if (!* fmt ) {
600+ fmt_type = TIME_FMT_CLF ;
601+ }
602+ else if (* fmt == ':' ) {
603+ fmt ++ ;
604+ a = fmt ;
605+ }
606+ }
607+ else if (!strncmp (fmt , "end" , 3 )) {
608+ fmt += 3 ;
609+ if (!* fmt ) {
610+ request_time = get_request_end_time (r );
611+ fmt_type = TIME_FMT_CLF ;
612+ }
613+ else if (* fmt == ':' ) {
614+ fmt ++ ;
615+ a = fmt ;
616+ request_time = get_request_end_time (r );
617+ }
618+ }
619+ if (!strncmp (fmt , "msec" , 4 )) {
620+ fmt += 4 ;
621+ if (!* fmt ) {
622+ fmt_type = TIME_FMT_ABS_MSEC ;
623+ }
624+ else if (!strcmp (fmt , "_frac" )) {
625+ fmt_type = TIME_FMT_ABS_MSEC_FRAC ;
626+ }
627+ }
628+ else if (!strncmp (fmt , "usec" , 4 )) {
629+ fmt += 4 ;
630+ if (!* fmt ) {
631+ fmt_type = TIME_FMT_ABS_USEC ;
632+ }
633+ else if (!strcmp (fmt , "_frac" )) {
634+ fmt_type = TIME_FMT_ABS_USEC_FRAC ;
635+ }
636+ }
637+ else if (!strcmp (fmt , "sec" )) {
638+ fmt_type = TIME_FMT_ABS_SEC ;
639+ }
640+ else if (!* fmt ) {
641+ fmt_type = TIME_FMT_CLF ;
642+ }
643+ }
644+ else {
645+ fmt_type = TIME_FMT_CLF ;
646+ }
565647
566- /* ### I think getting the time again at the end of the request
567- * just for logging is dumb. i know it's "required" for CLF.
568- * folks writing log parsing tools don't realise that out of order
569- * times have always been possible (consider what happens if one
570- * process calculates the time to log, but then there's a context
571- * switch before it writes and before that process is run again the
572- * log rotation occurs) and they should just fix their tools rather
573- * than force the server to pay extra cpu cycles. if you've got
574- * a problem with this, you can set the define. -djg
575- */
576- if (a && * a ) { /* Custom format */
648+ if (fmt_type >= TIME_FMT_ABS_SEC ) { /* Absolute (micro-/milli-)second time
649+ * or msec/usec fraction
650+ */
651+ char * buf = apr_palloc (r -> pool , 20 );
652+ switch (fmt_type ) {
653+ case TIME_FMT_ABS_SEC :
654+ apr_snprintf (buf , 20 , "%" APR_TIME_T_FMT , apr_time_sec (request_time ));
655+ break ;
656+ case TIME_FMT_ABS_MSEC :
657+ apr_snprintf (buf , 20 , "%" APR_TIME_T_FMT , apr_time_as_msec (request_time ));
658+ break ;
659+ case TIME_FMT_ABS_USEC :
660+ apr_snprintf (buf , 20 , "%" APR_TIME_T_FMT , request_time );
661+ break ;
662+ case TIME_FMT_ABS_MSEC_FRAC :
663+ apr_snprintf (buf , 20 , "%03" APR_TIME_T_FMT , apr_time_msec (request_time ));
664+ break ;
665+ case TIME_FMT_ABS_USEC_FRAC :
666+ apr_snprintf (buf , 20 , "%06" APR_TIME_T_FMT , apr_time_usec (request_time ));
667+ break ;
668+ default :
669+ return "-" ;
670+ }
671+ return buf ;
672+ }
673+ else if (fmt_type == TIME_FMT_CUSTOM ) { /* Custom format */
577674 /* The custom time formatting uses a very large temp buffer
578675 * on the stack. To avoid using so much stack space in the
579676 * common case where we're not using a custom format, the code
580677 * for the custom format in a separate function. (That's why
581678 * log_request_time_custom is not inlined right here.)
582679 */
583- #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
584- ap_explode_recent_localtime (& xt , apr_time_now ());
585- #else
586- ap_explode_recent_localtime (& xt , r -> request_time );
587- #endif
680+ ap_explode_recent_localtime (& xt , request_time );
588681 return log_request_time_custom (r , a , & xt );
589682 }
590- else { /* CLF format */
683+ else { /* CLF format */
591684 /* This code uses the same technique as ap_explode_recent_localtime():
592685 * optimistic caching with logic to detect and correct race conditions.
593686 * See the comments in server/util_time.c for more information.
594687 */
595688 cached_request_time * cached_time = apr_palloc (r -> pool ,
596689 sizeof (* cached_time ));
597- #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
598- apr_time_t request_time = apr_time_now ();
599- #else
600- apr_time_t request_time = r -> request_time ;
601- #endif
602690 unsigned t_seconds = (unsigned )apr_time_sec (request_time );
603691 unsigned i = t_seconds & TIME_CACHE_MASK ;
604692 * cached_time = request_time_cache [i ];
@@ -635,14 +723,14 @@ static const char *log_request_time(request_rec *r, char *a)
635723
636724static const char * log_request_duration (request_rec * r , char * a )
637725{
638- apr_time_t duration = apr_time_now ( ) - r -> request_time ;
726+ apr_time_t duration = get_request_end_time ( r ) - r -> request_time ;
639727 return apr_psprintf (r -> pool , "%" APR_TIME_T_FMT , apr_time_sec (duration ));
640728}
641729
642730static const char * log_request_duration_microseconds (request_rec * r , char * a )
643731{
644732 return apr_psprintf (r -> pool , "%" APR_TIME_T_FMT ,
645- (apr_time_now ( ) - r -> request_time ));
733+ (get_request_end_time ( r ) - r -> request_time ));
646734}
647735
648736/* These next two routines use the canonical name:port so that log
@@ -1021,6 +1109,12 @@ static int multi_log_transaction(request_rec *r)
10211109 config_log_state * clsarray ;
10221110 int i ;
10231111
1112+ /*
1113+ * Initialize per request state
1114+ */
1115+ log_request_state * state = apr_pcalloc (r -> pool , sizeof (log_request_state ));
1116+ ap_set_module_config (r -> request_config , & log_config_module , state );
1117+
10241118 /*
10251119 * Log this transaction..
10261120 */
0 commit comments