cannot be zero. This is the combination of %I and %O.<br />
Available in Apache 2.4.7 and later</td></tr>
+ <tr><td><code>%^FU</code></td>
+ <td>Delay in microseconds between when the request arrived and the
+ last byte of the request body was read (finished upload).
+ Only available if <directive>LogIOTrackTTFU</directive> is set to
+ ON.<br />
+ Available in Apache 2.4.34 and later</td></tr>
+
<tr><td><code>%^FB</code></td>
<td>Delay in microseconds between when the request arrived and the
first byte of the response headers are written. Only available if
</dl>
</section>
+<directivesynopsis>
+<name>LogIOTrackTTFU</name>
+<description>Enable tracking of time to last request byte (TTFU = time to finish
+upload)</description>
+<syntax>LogIOTrackTTFU ON|OFF</syntax>
+<default>LogIOTrackTTFU OFF</default>
+<contextlist><context>server config</context><context>virtual host</context>
+<context>directory</context><context>.htaccess</context></contextlist>
+<override>All</override>
+<compatibility>Apache HTTP Server 2.4.34 and later</compatibility>
+
+<usage>
+ <p>This directive configures whether this module tracks the delay
+ between the request being read and the last byte of the request
+ body being read (finished upload). The resulting value may be logged
+ with the <code>%^FU</code> format.</p>
+</usage>
+</directivesynopsis>
+
<directivesynopsis>
<name>LogIOTrackTTFB</name>
-<description>Enable tracking of time to first byte (TTFB)</description>
+<description>Enable tracking of time to first byte (TTFB = time to first byte)
+</description>
<syntax>LogIOTrackTTFB ON|OFF</syntax>
<default>LogIOTrackTTFB OFF</default>
<contextlist><context>server config</context><context>virtual host</context>
module AP_MODULE_DECLARE_DATA logio_module;
static const char logio_filter_name[] = "LOG_INPUT_OUTPUT";
+static const char logio_ttfu_filter_name[] = "LOGIO_TTFU_IN";
static const char logio_ttfb_filter_name[] = "LOGIO_TTFB_OUT";
/*
} logio_config_t;
typedef struct logio_dirconf_t {
+ unsigned int track_ttfu:1;
+ unsigned int track_ttfu_set:1;
unsigned int track_ttfb:1;
+ unsigned int track_ttfb_set:1;
} logio_dirconf_t;
typedef struct logio_req_t {
+ apr_time_t ttfu;
apr_time_t ttfb;
} logio_req_t;
return apr_off_t_toa(r->pool, cf->bytes_out + cf->bytes_in);
}
+static const char *log_ttfu(request_rec *r, char *a)
+{
+ logio_req_t *rconf = ap_get_module_config(r->request_config,
+ &logio_module);
+
+ if (!rconf || !rconf->ttfu) {
+ return "-";
+ }
+
+ return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, rconf->ttfu - r->request_time);
+}
+
static const char *log_ttfb(request_rec *r, char *a)
{
logio_req_t *rconf = ap_get_module_config(r->request_config,
log_pfn_register(p, "I", log_bytes_in, 0);
log_pfn_register(p, "O", log_bytes_out, 0);
log_pfn_register(p, "S", log_bytes_combined, 0);
+ log_pfn_register(p, "^FU", log_ttfu, 0);
log_pfn_register(p, "^FB", log_ttfb, 0);
}
return OK;
}
+static apr_status_t logio_ttfu_filter(ap_filter_t *f,
+ apr_bucket_brigade *bb,
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ apr_off_t length;
+ apr_status_t status;
+
+ status = ap_get_brigade(f->next, bb, mode, block, readbytes);
+
+ apr_brigade_length(bb, 0, &length);
+
+ if (length > 0) {
+ request_rec *r = f->r;
+ logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config,
+ &logio_module);
+ if (conf && conf->track_ttfu) {
+ logio_req_t *rconf = ap_get_module_config(r->request_config,
+ &logio_module);
+ if (rconf == NULL) {
+ rconf = apr_pcalloc(r->pool, sizeof(logio_req_t));
+ ap_set_module_config(r->request_config, &logio_module, rconf);
+ }
+ rconf->ttfu = apr_time_now();
+ }
+ }
+ return status;
+}
+
static apr_status_t logio_ttfb_filter(ap_filter_t *f, apr_bucket_brigade *b)
{
request_rec *r = f->r;
&logio_module);
if (rconf == NULL) {
rconf = apr_pcalloc(r->pool, sizeof(logio_req_t));
- rconf->ttfb = apr_time_now() - r->request_time;
ap_set_module_config(r->request_config, &logio_module, rconf);
}
+ if (rconf->ttfb == 0) {
+ rconf->ttfb = apr_time_now() - r->request_time;
+ }
}
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, b);
{
logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config,
&logio_module);
+ if (conf->track_ttfu) {
+ ap_add_input_filter(logio_ttfu_filter_name, NULL, r, r->connection);
+ }
if (conf->track_ttfb) {
ap_add_output_filter(logio_ttfb_filter_name, NULL, r, r->connection);
}
}
+static const char *logio_track_ttfu(cmd_parms *cmd, void *in_dir_config, int arg)
+{
+ logio_dirconf_t *dir_config = in_dir_config;
+ dir_config->track_ttfu = arg;
+ dir_config->track_ttfu_set = 1;
+ return NULL;
+}
+
static const char *logio_track_ttfb(cmd_parms *cmd, void *in_dir_config, int arg)
{
logio_dirconf_t *dir_config = in_dir_config;
dir_config->track_ttfb = arg;
+ dir_config->track_ttfb_set = 1;
return NULL;
}
}
+static void *merge_logio_dirconf(apr_pool_t *p, void *basev, void *addv)
+{
+ logio_dirconf_t *new = (logio_dirconf_t *) apr_pcalloc(p, sizeof(logio_dirconf_t));
+ const logio_dirconf_t *add = (logio_dirconf_t *) addv;
+ const logio_dirconf_t *base = (logio_dirconf_t *) basev;
+
+ new->track_ttfu = add->track_ttfu_set ? add->track_ttfu : base->track_ttfu;
+ new->track_ttfu_set = add->track_ttfu_set || base->track_ttfu_set;
+ new->track_ttfb = add->track_ttfb_set ? add->track_ttfb : base->track_ttfb;
+ new->track_ttfb_set = add->track_ttfb_set || base->track_ttfb_set;
+
+ return new;
+}
+
+
static const command_rec logio_cmds[] = {
+ AP_INIT_FLAG ("LogIOTrackTTFU", logio_track_ttfu, NULL, OR_ALL,
+ "Set to 'ON' to enable tracking time to finish upload"),
AP_INIT_FLAG ("LogIOTrackTTFB", logio_track_ttfb, NULL, OR_ALL,
"Set to 'ON' to enable tracking time to first byte"),
{NULL}
AP_FTYPE_NETWORK - 1);
ap_hook_insert_filter(logio_insert_filter, NULL, NULL, APR_HOOK_LAST);
+ ap_register_input_filter(logio_ttfu_filter_name, logio_ttfu_filter, NULL,
+ AP_FTYPE_RESOURCE);
ap_register_output_filter(logio_ttfb_filter_name, logio_ttfb_filter, NULL,
AP_FTYPE_RESOURCE);
{
STANDARD20_MODULE_STUFF,
create_logio_dirconf, /* create per-dir config */
- NULL, /* merge per-dir config */
+ merge_logio_dirconf, /* merge per-dir config */
NULL, /* server config */
NULL, /* merge server config */
logio_cmds, /* command apr_table_t */