diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml
index 7d532702245..1ff13985a4e 100644
--- a/docs/manual/mod/core.xml
+++ b/docs/manual/mod/core.xml
@@ -1761,6 +1761,9 @@ ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M"
%{u}t |
The current time including micro-seconds |
+ %{m}t |
+ The current time including milliseconds |
+
%{cu}t |
The current time in ISO 8601 extended format (compact), including
micro-seconds |
diff --git a/include/util_time.h b/include/util_time.h
index 1ba6353c025..c149e52166a 100644
--- a/include/util_time.h
+++ b/include/util_time.h
@@ -49,6 +49,8 @@ extern "C" {
#define AP_CTIME_OPTION_COMPACT 0x2
/* Add timezone offset from GMT ([+-]hhmm) */
#define AP_CTIME_OPTION_GMTOFF 0x4
+/* Add sub second timestamps with millisecond resolution */
+#define AP_CTIME_OPTION_MSEC 0x8
/**
diff --git a/server/log.c b/server/log.c
index 91dcf2c3eb0..af746ae1d37 100644
--- a/server/log.c
+++ b/server/log.c
@@ -584,10 +584,14 @@ static int log_ctime(const ap_errorlog_info *info, const char *arg,
if (arg) {
if (arg[0] == 'u' && !arg[1]) { /* no ErrorLogFormat (fast path) */
option |= AP_CTIME_OPTION_USEC;
- }
- else if (!ap_strchr_c(arg, '%')) { /* special "%{cuz}t" formats */
+ } else if (arg[0] == 'm' && !arg[1]){ /* no ErrorLogFormat (fast path) - msec */
+ option |= AP_CTIME_OPTION_MSEC;
+ } else if (!ap_strchr_c(arg, '%')) { /* special "%{mcuz}t" formats */
while (*arg) {
switch (*arg++) {
+ case 'm':
+ option |= AP_CTIME_OPTION_MSEC;
+ break;
case 'u':
option |= AP_CTIME_OPTION_USEC;
break;
diff --git a/server/util_time.c b/server/util_time.c
index 8dcf2fb293f..f0092e09688 100644
--- a/server/util_time.c
+++ b/server/util_time.c
@@ -24,6 +24,11 @@
* */
#define AP_CTIME_USEC_LENGTH 7
+/* Number of characters needed to format the millisecond part of a timestamp.
+ * Milliseconds have 3 digits plus one separator character makes 4.
+ * */
+#define AP_CTIME_MSEC_LENGTH 4
+
/* Length of ISO 8601 date/time (including trailing '\0') */
#define AP_CTIME_COMPACT_LEN 20
@@ -183,6 +188,8 @@ AP_DECLARE(apr_status_t) ap_recent_ctime_ex(char *date_str, apr_time_t t,
if (option & AP_CTIME_OPTION_USEC) {
needed += AP_CTIME_USEC_LENGTH;
+ } else if (option & AP_CTIME_OPTION_MSEC){
+ needed += AP_CTIME_MSEC_LENGTH;
}
if (option & AP_CTIME_OPTION_GMTOFF) {
@@ -244,11 +251,16 @@ AP_DECLARE(apr_status_t) ap_recent_ctime_ex(char *date_str, apr_time_t t,
*date_str++ = ':';
*date_str++ = xt.tm_sec / 10 + '0';
*date_str++ = xt.tm_sec % 10 + '0';
- if (option & AP_CTIME_OPTION_USEC) {
+ if (option & (AP_CTIME_OPTION_USEC|AP_CTIME_OPTION_MSEC)) {
int div;
int usec = (int)xt.tm_usec;
*date_str++ = '.';
- for (div=100000; div>0; div=div/10) {
+ div = 100000;
+ if (!(option & AP_CTIME_OPTION_USEC)){
+ usec = usec / 1000;
+ div = 100;
+ }
+ for (; div>0; div=div/10) {
*date_str++ = usec / div + '0';
usec = usec % div;
}