package io.undertow.attribute;

import io.undertow.server.HttpServerExchange;

/**
 * The response time
 *
 * This will only work if {@link io.undertow.UndertowOptions#RECORD_REQUEST_START_TIME} has been set
 */
public class ResponseTimeAttribute implements ExchangeAttribute {

    public static final String RESPONSE_TIME_SHORT = "%D";
    public static final String RESPONSE_TIME = "%{RESPONSE_TIME}";

    public static final ExchangeAttribute INSTANCE = new ResponseTimeAttribute();

    private ResponseTimeAttribute() {}

    @Override
    public String readAttribute(HttpServerExchange exchange) {
        long requestStartTime = exchange.getRequestStartTime();
        if(requestStartTime == -1) {
            return null;
        }
        return String.valueOf(System.nanoTime() - requestStartTime);
    }

    @Override
    public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
        throw new ReadOnlyAttributeException("Response Time", newValue);
    }

    public static final class Builder implements ExchangeAttributeBuilder {

        @Override
        public String name() {
            return "Response Time";
        }

        @Override
        public ExchangeAttribute build(String token) {
            if (token.equals(RESPONSE_TIME) || token.equals(RESPONSE_TIME_SHORT)) {
                return ResponseTimeAttribute.INSTANCE;
            }
            return null;
        }
    }

}

@@ -72,16 +72,55 @@
 hange;%0A%0A
+import java.util.concurrent.TimeUnit;%0A%0A
 /**%0A * T
@@ -352,24 +352,31 @@
 SPONSE_TIME_
+MILLIS_
 SHORT = %22%25D%22
@@ -425,32 +425,31 @@
 TIME
- = %22%25%7BRESPONSE_TIME%7D
+_SECONDS_SHORT = %22%25T
 %22;%0A
-%0A
     
@@ -472,72 +472,102 @@
 nal 
-ExchangeAttribute INSTANCE = new ResponseTimeAttribute()
+String RESPONSE_TIME_MILLIS = %22%25%7BRESPONSE_TIME%7D%22;%0A%0A    private final TimeUnit timeUnit
 ;%0A%0A    p
 riva
@@ -562,22 +562,21 @@
 ;%0A%0A    p
-rivate
+ublic
  Respons
@@ -590,19 +590,75 @@
 tribute(
-) %7B
+TimeUnit timeUnit) %7B%0A        this.timeUnit = timeUnit;%0A    
 %7D%0A%0A    @
@@ -895,16 +895,33 @@
 valueOf(
+timeUnit.convert(
 System.n
@@ -948,16 +948,39 @@
 tartTime
+, TimeUnit.NANOSECONDS)
 );%0A    %7D
@@ -1476,16 +1476,23 @@
 NSE_TIME
+_MILLIS
 ) %7C%7C tok
@@ -1515,16 +1515,23 @@
 SE_TIME_
+MILLIS_
 SHORT)) 
@@ -1555,16 +1555,20 @@
  return 
+new 
 Response
@@ -1584,17 +1584,174 @@
 bute
-.INSTANCE
+(TimeUnit.MILLISECONDS);%0A            %7D%0A            if (token.equals(RESPONSE_TIME_SECONDS_SHORT)) %7B%0A                return new ResponseTimeAttribute(TimeUnit.SECONDS)
 ;%0A  

Add support for different time units in the response time attribute