From 7fc00840744292c3c138a7dffa187b073960e5a2 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 14 May 2013 07:13:05 +0000
Subject: [PATCH] OPENDJ-858 (CR-1680) Add stats tracking to HTTP client connections

---
 opends/resource/schema/02-config.ldif                                                  |   52 +++++
 opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java           |  103 ++++++++++++
 opends/src/server/org/opends/server/loggers/TextHTTPAccessLogPublisher.java            |    8 
 opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java           |   12 -
 opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java                 |  104 +++++++++---
 opends/src/server/org/opends/server/loggers/HTTPRequestInfo.java                       |  137 ++++------------
 opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java |   20 -
 7 files changed, 276 insertions(+), 160 deletions(-)

diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 7967342..a814b19 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -3684,35 +3684,71 @@
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.121
-  NAME 'ds-mon-http-delete-requests-total-count'
+  NAME 'ds-mon-resident-time-http-requests-total-time'
   EQUALITY integerMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.122
-  NAME 'ds-mon-http-get-requests-total-count'
+  NAME 'ds-mon-http-delete-requests-total-count'
   EQUALITY integerMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.123
-  NAME 'ds-mon-http-patch-requests-total-count'
+  NAME 'ds-mon-resident-time-http-delete-requests-total-time'
   EQUALITY integerMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.124
-  NAME 'ds-mon-http-post-requests-total-count'
+  NAME 'ds-mon-http-get-requests-total-count'
   EQUALITY integerMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.125
+  NAME 'ds-mon-resident-time-http-get-requests-total-time'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.126
+  NAME 'ds-mon-http-patch-requests-total-count'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.127
+  NAME 'ds-mon-resident-time-http-patch-requests-total-time'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.128
+  NAME 'ds-mon-http-post-requests-total-count'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.129
+  NAME 'ds-mon-resident-time-http-post-requests-total-time'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.130
   NAME 'ds-mon-http-put-requests-total-count'
   EQUALITY integerMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.131
+  NAME 'ds-mon-resident-time-http-put-requests-total-time'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDJ Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler'
   SUP top
@@ -5629,11 +5665,17 @@
   ds-mon-extended-operations-total-count $
   ds-mon-resident-time-extended-operations-total-time $
   ds-mon-http-requests-total-count $
+  ds-mon-resident-time-http-requests-total-time $
   ds-mon-http-delete-requests-total-count $
+  ds-mon-resident-time-http-delete-requests-total-time $
   ds-mon-http-get-requests-total-count $
+  ds-mon-resident-time-http-get-requests-total-time $
   ds-mon-http-patch-requests-total-count $
+  ds-mon-resident-time-http-patch-requests-total-time $
   ds-mon-http-post-requests-total-count $
-  ds-mon-http-put-requests-total-count )
+  ds-mon-resident-time-http-post-requests-total-time $
+  ds-mon-http-put-requests-total-count $
+  ds-mon-resident-time-http-put-requests-total-time )
   X-ORIGIN 'OpenDJ Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.14
   NAME 'ds-cfg-pbkdf2-password-storage-scheme'
diff --git a/opends/src/server/org/opends/server/loggers/HTTPRequestInfo.java b/opends/src/server/org/opends/server/loggers/HTTPRequestInfo.java
index 5a18a7c..ea009af 100644
--- a/opends/src/server/org/opends/server/loggers/HTTPRequestInfo.java
+++ b/opends/src/server/org/opends/server/loggers/HTTPRequestInfo.java
@@ -26,131 +26,88 @@
  */
 package org.opends.server.loggers;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.servlet.http.HttpServletRequest;
-
 /**
  * Contains the information required for logging the HTTP request.
  */
-public class HTTPRequestInfo
+public interface HTTPRequestInfo
 {
 
-  /** The client's host. */
-  private final String remoteHost;
-  /** The client's address. */
-  private final String remoteAddress;
-  /** The protocol used for this request. */
-  private final String protocol;
-  /** The HTTP method/verb used for this request. */
-  private final String method;
-  /** The query issued by the client. */
-  private final String query;
-  /** The user agent used by the client. */
-  private final String userAgent;
-
-  /** The username that was used to authenticate. */
-  private String authUser;
   /**
-   * The HTTP status code returned to the client. Using 0 to say no status code
-   * was set since it is not .
-   */
-  private AtomicInteger statusCode = new AtomicInteger(0);
-  /**
-   * The unique identifier that has been assigned to the client connection for
-   * this HTTP request.
-   */
-  private long connectionID;
-
-  /**
-   * Constructor for this class.
+   * Returns the server's host.
    *
-   * @param request
-   *          The {@link HttpServletRequest} for which to log the information
-   * @param connectionID
-   *          The unique identifier that has been assigned to the client
-   *          connection for this HTTP request
+   * @return the serverAddress
    */
-  public HTTPRequestInfo(HttpServletRequest request, long connectionID)
-  {
-    this.remoteHost = request.getRemoteHost();
-    this.remoteAddress = request.getRemoteAddr();
-    this.method = request.getMethod();
-    this.query = request.getRequestURI() + "/" + request.getQueryString();
-    this.protocol = request.getProtocol();
-    this.userAgent = request.getHeader("User-Agent");
-    this.connectionID = connectionID;
-  }
+  String getServerAddress();
 
   /**
-   * Returns the client's host.
+   * Returns the server's host.
    *
-   * @return the remoteHost
+   * @return the serverHost
    */
-  public String getRemoteHost()
-  {
-    return remoteHost;
-  }
+  String getServerHost();
+
+  /**
+   * Returns the server's port.
+   *
+   * @return the serverPort
+   */
+  int getServerPort();
 
   /**
    * Returns the client's address.
    *
-   * @return the remoteAddress
+   * @return the clientAddress
    */
-  public String getRemoteAddress()
-  {
-    return remoteAddress;
-  }
+  String getClientAddress();
+
+  /**
+   * Returns the client's host.
+   *
+   * @return the clientHost
+   */
+  String getClientHost();
+
+  /**
+   * Returns the client's port.
+   *
+   * @return the clientPort
+   */
+  int getClientPort();
 
   /**
    * Returns the protocol used for this request.
    *
    * @return the protocol
    */
-  public String getProtocol()
-  {
-    return protocol;
-  }
+  String getProtocol();
 
   /**
    * Returns the HTTP method/verb used for this request.
    *
    * @return the method
    */
-  public String getMethod()
-  {
-    return method;
-  }
+  String getMethod();
 
   /**
    * Returns the query issued by the client.
    *
    * @return the query
    */
-  public String getQuery()
-  {
-    return query;
-  }
+  String getQuery();
 
   /**
    * Returns the user agent used by the client.
    *
    * @return the userAgent
    */
-  public String getUserAgent()
-  {
-    return userAgent;
-  }
+  String getUserAgent();
 
   /**
    * Returns the username that was used to authenticate.
    *
    * @return the authUser
    */
-  public String getAuthUser()
-  {
-    return authUser;
-  }
+  String getAuthUser();
 
   /**
    * Sets the username that was used to authenticate.
@@ -158,21 +115,14 @@
    * @param authUser
    *          the authUser to set
    */
-  public void setAuthUser(String authUser)
-  {
-    this.authUser = authUser;
-  }
+  void setAuthUser(String authUser);
 
   /**
    * Returns the HTTP status code returned to the client.
    *
    * @return the statusCode
    */
-  public int getStatusCode()
-  {
-    int sc = statusCode.get();
-    return sc != 0 ? sc : 200;
-  }
+  int getStatusCode();
 
   /**
    * Returns the unique identifier that has been assigned to the client
@@ -181,10 +131,7 @@
    * @return The unique identifier that has been assigned to the client
    *         connection for this HTTP request
    */
-  public long getConnectionID()
-  {
-    return this.connectionID;
-  }
+  long getConnectionID();
 
   /**
    * Logs the current request info in the HTTP access log.
@@ -192,12 +139,6 @@
    * @param statusCode
    *          the HTTP status code that was returned to the client.
    */
-  public void log(int statusCode)
-  {
-    if (this.statusCode.compareAndSet(0, statusCode))
-    { // this request was not logged before
-      HTTPAccessLogger.logRequestInfo(this);
-    }
-  }
+  void log(int statusCode);
 
 }
diff --git a/opends/src/server/org/opends/server/loggers/TextHTTPAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
index ed65dc6..f93b0ec 100644
--- a/opends/src/server/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
@@ -379,8 +379,12 @@
   public void logRequestInfo(HTTPRequestInfo ri)
   {
     final Map<String, Object> fields = new HashMap<String, Object>();
-    fields.put("cs-host", ri.getRemoteHost());
-    fields.put("c-ip", ri.getRemoteAddress());
+    fields.put("c-ip", ri.getClientAddress());
+    fields.put("cs-host", ri.getClientHost());
+    fields.put("c-port", ri.getClientPort());
+    fields.put("s-ip", ri.getServerAddress());
+    fields.put("s-computername", ri.getServerHost());
+    fields.put("s-port", ri.getServerPort());
     fields.put("cs-username", ri.getAuthUser());
     fields.put("datetime", TimeThread.getUserDefinedTime(timeStampFormat));
     fields.put("cs-method", ri.getMethod());
diff --git a/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java b/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
index a7738ea..74bf97b 100644
--- a/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
+++ b/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -66,7 +66,6 @@
 import org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory;
 import org.opends.messages.Message;
 import org.opends.server.admin.std.server.ConnectionHandlerCfg;
-import org.opends.server.loggers.HTTPRequestInfo;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.schema.SchemaConstants;
 import org.opends.server.types.AddressMask;
@@ -99,8 +98,6 @@
     private String userName;
     /** Used for the bind request when credentials are specified. */
     private String password;
-    /** Request information for logging. */
-    private HTTPRequestInfo requestInfo;
   }
 
   /**
@@ -181,7 +178,7 @@
     @Override
     public void handleResult(BindResult result)
     {
-      ctx.requestInfo.setAuthUser(ctx.userName);
+      ctx.clientConnection.setAuthUser(ctx.userName);
 
       final AuthenticationInfo authInfo =
           new AuthenticationInfo(to(resultEntry), to(resultEntry.getName()),
@@ -254,7 +251,7 @@
       @Override
       public void setStatus(int sc)
       {
-        ctx.requestInfo.log(sc);
+        ctx.clientConnection.log(sc);
         super.setStatus(sc);
       }
 
@@ -263,7 +260,7 @@
       @Override
       public void setStatus(int sc, String sm)
       {
-        ctx.requestInfo.log(sc);
+        ctx.clientConnection.log(sc);
         super.setStatus(sc, sm);
       }
     };
@@ -276,12 +273,10 @@
     this.connectionHandler.addClientConnection(clientConnection);
 
     ctx.clientConnection = clientConnection;
-    ctx.requestInfo =
-        new HTTPRequestInfo(ctx.request, clientConnection.getConnectionID());
 
     if (this.connectionHandler.keepStats()) {
       this.connectionHandler.getStatTracker().addRequest(
-          ctx.request.getMethod());
+          ctx.clientConnection.getMethod());
     }
 
     try
@@ -294,8 +289,7 @@
       // checked.
       logConnect(clientConnection);
 
-      ctx.connection =
-          new SdkConnectionAdapter(clientConnection, ctx.requestInfo);
+      ctx.connection = new SdkConnectionAdapter(clientConnection);
 
       final String[] userPassword = extractUsernamePassword(request);
       if (userPassword != null && userPassword.length == 2)
@@ -358,7 +352,7 @@
     }
     finally
     {
-      ctx.requestInfo.log(statusCode);
+      ctx.clientConnection.log(statusCode);
 
       if (ctx.asyncContext != null)
       {
@@ -390,7 +384,7 @@
     }
     finally
     {
-      ctx.requestInfo.log(ex.getCode());
+      ctx.clientConnection.log(ex.getCode());
 
       if (ctx.asyncContext != null)
       {
diff --git a/opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java b/opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java
index 97d1854..c142413 100644
--- a/opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java
@@ -37,9 +37,10 @@
 import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
-import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
 
 import org.forgerock.opendj.ldap.ErrorResultException;
 import org.forgerock.opendj.ldap.ResultHandler;
@@ -57,6 +58,8 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.SearchOperation;
+import org.opends.server.loggers.HTTPAccessLogger;
+import org.opends.server.loggers.HTTPRequestInfo;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.ldap.AddResponseProtocolOp;
 import org.opends.server.protocols.ldap.BindResponseProtocolOp;
@@ -90,7 +93,8 @@
  * connection that will be accepted by an instance of the HTTP connection
  * handler.
  */
-final class HTTPClientConnection extends ClientConnection
+final class HTTPClientConnection extends ClientConnection implements
+    HTTPRequestInfo
 {
 
   // TODO JNR Confirm with Matt that persistent searches are inapplicable to
@@ -185,9 +189,27 @@
   /** The protocol in use for this client connection. */
   private String protocol;
 
+  /** The HTTP method/verb used for this request. */
+  private final String method;
+  /** The query issued by the client. */
+  private final String query;
+  /** The user agent used by the client. */
+  private final String userAgent;
+
+  /** The username that was used to authenticate. */
+  private String authUser;
+  /**
+   * The HTTP status code returned to the client. Using 0 to say no status code
+   * was set since it is not .
+   */
+  private AtomicInteger statusCode = new AtomicInteger(0);
+
   /** The client (remote) address. */
   private String clientAddress;
 
+  /** The client (remote) host name. */
+  private String clientHost;
+
   /** The client (remote) port. */
   private int clientPort;
 
@@ -197,6 +219,9 @@
   /** The server (local) address. */
   private String serverAddress;
 
+  /** The server (local) host name. */
+  private String serverHost;
+
   /** The server (local) port. */
   private int serverPort;
 
@@ -218,13 +243,12 @@
    *          represents this client connection.
    */
   public HTTPClientConnection(HTTPConnectionHandler connectionHandler,
-      ServletRequest request)
+      HttpServletRequest request)
   {
     this.connectionHandler = connectionHandler;
 
     // memoize all the fields we need from the request before Grizzly decides to
     // recycle it
-    this.protocol = request.getProtocol();
     this.clientAddress = request.getRemoteAddr();
     this.clientPort = request.getRemotePort();
     this.serverAddress = request.getLocalAddr();
@@ -234,6 +258,10 @@
     this.isSecure = request.isSecure();
     this.securityStrengthFactor =
         calcSSF(request.getAttribute(SERVLET_SSF_CONSTANT));
+    this.method = request.getMethod();
+    this.query = request.getRequestURI() + "/" + request.getQueryString();
+    this.protocol = request.getProtocol();
+    this.userAgent = request.getHeader("User-Agent");
 
     this.statTracker = this.connectionHandler.getStatTracker();
 
@@ -249,6 +277,13 @@
 
   /** {@inheritDoc} */
   @Override
+  public String getAuthUser()
+  {
+    return this.authUser;
+  }
+
+  /** {@inheritDoc} */
+  @Override
   public long getConnectionID()
   {
     return connectionID;
@@ -277,6 +312,13 @@
 
   /** {@inheritDoc} */
   @Override
+  public String getClientHost()
+  {
+    return clientHost;
+  }
+
+  /** {@inheritDoc} */
+  @Override
   public int getClientPort()
   {
     return clientPort;
@@ -291,6 +333,13 @@
 
   /** {@inheritDoc} */
   @Override
+  public String getServerHost()
+  {
+    return serverHost;
+  }
+
+  /** {@inheritDoc} */
+  @Override
   public int getServerPort()
   {
     return serverPort;
@@ -332,6 +381,7 @@
       {
         time = operation.getProcessingTime();
       }
+      this.statTracker.updateRequestMonitoringData(getMethod(), time);
       this.statTracker.updateOperationMonitoringData(operation
           .getOperationType(), time);
     }
@@ -451,6 +501,13 @@
     throw new RuntimeException("Not implemented");
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public void setAuthUser(String authUser)
+  {
+    this.authUser = authUser;
+  }
+
   /**
    * {@inheritDoc}
    *
@@ -511,6 +568,34 @@
 
   /** {@inheritDoc} */
   @Override
+  public String getMethod()
+  {
+    return this.method;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public String getQuery()
+  {
+    return this.query;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public int getStatusCode()
+  {
+    return this.statusCode.get();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public String getUserAgent()
+  {
+    return this.userAgent;
+  }
+
+  /** {@inheritDoc} */
+  @Override
   public Collection<Operation> getOperationsInProgress()
   {
     Collection<OperationWithFutureResult> values =
@@ -772,4 +857,14 @@
   {
     return true;
   }
+
+  /** {@inheritDoc} */
+  @Override
+  public void log(int statusCode)
+  {
+    if (this.statusCode.compareAndSet(0, statusCode))
+    { // this request was not logged before
+      HTTPAccessLogger.logRequestInfo(this);
+    }
+  }
 }
diff --git a/opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java b/opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java
index be4a8f0..b40bbd5 100644
--- a/opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java
+++ b/opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java
@@ -32,6 +32,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
 
 import org.opends.server.protocols.ldap.LDAPStatistics;
 import org.opends.server.types.Attribute;
@@ -45,22 +46,34 @@
 {
 
   /**
-   * Map containing the total number of requests.
+   * Map containing the total number of requests per HTTP methods.
    * <p>
-   * key: HTTP verb => value: number of requests for that verb.
+   * key: HTTP method => value: number of requests for that method.
    * </p>
-   * Not using a ConcurrentMap implementation because the keys are static. The
-   * keys are static because they need to be listed in the schema which is
+   * Not using a ConcurrentMap implementation here because the keys are static.
+   * The keys are static because they need to be listed in the schema which is
    * static.
    */
-  private Map<String, AtomicInteger> nbRequests =
+  private Map<String, AtomicInteger> requestMethodsTotalCount =
       new HashMap<String, AtomicInteger>();
   /**
+   * Map containing the total execution time for the requests per HTTP methods.
+   * <p>
+   * key: HTTP method => value: total execution time for requests using that
+   * method.
+   * </p>
+   * Not using a ConcurrentMap implementation here because the keys are static.
+   * The keys are static because they need to be listed in the schema which is
+   * static.
+   */
+  private Map<String, AtomicLong> requestMethodsTotalTime =
+      new HashMap<String, AtomicLong>();
+  /**
    * Total number of requests. The total number may be different than the sum of
    * the supported HTTP methods above because clients could use unsupported HTTP
-   * verbs.
+   * methods.
    */
-  private AtomicInteger nbRequestsTotalCount = new AtomicInteger(0);
+  private AtomicInteger requestsTotalCount = new AtomicInteger(0);
 
   /**
    * Constructor for this class.
@@ -77,7 +90,8 @@
         Arrays.asList("delete", "get", "patch", "post", "put");
     for (String method : supportedHttpMethods)
     {
-      nbRequests.put(method, new AtomicInteger(0));
+      requestMethodsTotalCount.put(method, new AtomicInteger(0));
+      requestMethodsTotalTime.put(method, new AtomicLong(0));
     }
   }
 
@@ -85,7 +99,9 @@
   @Override
   public void clearStatistics()
   {
-    this.nbRequests.clear();
+    this.requestMethodsTotalCount.clear();
+    this.requestMethodsTotalTime.clear();
+    this.requestsTotalCount.set(0);
 
     super.clearStatistics();
   }
@@ -95,34 +111,45 @@
   public List<Attribute> getMonitorData()
   {
     // first take a snapshot of all the data as fast as possible
-    final Map<String, Integer> snapshot = new HashMap<String, Integer>();
-    for (Entry<String, AtomicInteger> entry : this.nbRequests.entrySet())
+    final int totalCount = this.requestsTotalCount.get();
+    final Map<String, Integer> totalCountsSnapshot =
+        new HashMap<String, Integer>();
+    for (Entry<String, AtomicInteger> entry : this.requestMethodsTotalCount
+        .entrySet())
     {
-      snapshot.put(entry.getKey(), entry.getValue().get());
+      totalCountsSnapshot.put(entry.getKey(), entry.getValue().get());
+    }
+    final Map<String, Long> totalTimesSnapshot = new HashMap<String, Long>();
+    for (Entry<String, AtomicLong> entry1 : this.requestMethodsTotalTime
+        .entrySet())
+    {
+      totalTimesSnapshot.put(entry1.getKey(), entry1.getValue().get());
     }
 
     // do the same with the underlying data
     final List<Attribute> results = super.getMonitorData();
 
-    // then add the snapshot data to the monitoring data
-    int total = 0;
-    for (Entry<String, Integer> entry : snapshot.entrySet())
-    {
-      final String httpMethod = entry.getKey();
-      final Integer nb = entry.getValue();
-      final String number = nb.toString();
-      // nb should never be null since we only allow supported HTTP methods
-      total += nb;
-
-      results.add(createAttribute("ds-mon-http-" + httpMethod
-          + "-requests-total-count", number));
-    }
+    addAll(results, totalCountsSnapshot, "ds-mon-http-",
+        "-requests-total-count");
+    addAll(results, totalTimesSnapshot, "ds-mon-resident-time-http-",
+        "-requests-total-time");
     results.add(createAttribute("ds-mon-http-requests-total-count", Integer
-        .toString(total)));
+        .toString(totalCount)));
 
     return results;
   }
 
+  private void addAll(final List<Attribute> results,
+      final Map<String, ?> toOutput, String prefix, String suffix)
+  {
+    for (Entry<String, ?> entry : toOutput.entrySet())
+    {
+      final String httpMethod = entry.getKey();
+      final String nb = entry.getValue().toString();
+      results.add(createAttribute(prefix + httpMethod + suffix, nb));
+    }
+  }
+
   /**
    * Adds a request to the stats using the provided HTTP method.
    *
@@ -133,12 +160,33 @@
    */
   public void addRequest(String httpMethod) throws NullPointerException
   {
-    AtomicInteger nb = this.nbRequests.get(httpMethod.toLowerCase());
+    AtomicInteger nb =
+        this.requestMethodsTotalCount.get(httpMethod.toLowerCase());
     if (nb != null)
     {
       nb.incrementAndGet();
     } // else this is an unsupported HTTP method
     // always count any requests regardless of whether the method is supported
-    this.nbRequestsTotalCount.incrementAndGet();
+    this.requestsTotalCount.incrementAndGet();
+  }
+
+  /**
+   * Adds to the total time of an HTTP request method.
+   *
+   * @param httpMethod
+   *          the method of the HTTP request to add to the stats
+   * @param time
+   *          the time to add to the total
+   * @throws NullPointerException
+   *           if the httpMethod is null
+   */
+  public void updateRequestMonitoringData(String httpMethod, long time)
+      throws NullPointerException
+  {
+    AtomicLong nb = this.requestMethodsTotalTime.get(httpMethod.toLowerCase());
+    if (nb != null)
+    {
+      nb.addAndGet(time);
+    } // else this is an unsupported HTTP method
   }
 }
diff --git a/opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java b/opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java
index 737b542..7d6e6fb 100644
--- a/opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java
+++ b/opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java
@@ -80,7 +80,6 @@
 import org.opends.server.core.SearchOperationBasis;
 import org.opends.server.core.UnbindOperation;
 import org.opends.server.core.UnbindOperationBasis;
-import org.opends.server.loggers.HTTPRequestInfo;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.protocols.ldap.AbandonRequestProtocolOp;
 import org.opends.server.protocols.ldap.AddRequestProtocolOp;
@@ -116,9 +115,6 @@
   /** The HTTP client connection being "adapted". */
   private final HTTPClientConnection clientConnection;
 
-  /** The HTTP request information to log. */
-  private final HTTPRequestInfo requestInfo;
-
   /**
    * The next message ID (and operation ID) that should be used for this
    * connection.
@@ -139,14 +135,10 @@
    *
    * @param clientConnection
    *          the HTTP client connection being "adapted"
-   * @param requestInfo
-   *          the HTTP request information to log
    */
-  public SdkConnectionAdapter(HTTPClientConnection clientConnection,
-      HTTPRequestInfo requestInfo)
+  public SdkConnectionAdapter(HTTPClientConnection clientConnection)
   {
     this.clientConnection = clientConnection;
-    this.requestInfo = requestInfo;
     this.queueingStrategy =
         new BoundedWorkQueueStrategy(clientConnection.getConnectionHandler()
             .getCurrentConfig().getMaxConcurrentOpsPerConnection());
@@ -330,7 +322,7 @@
 
     // At this point, we try to log the request with OK status code.
     // If it was already logged, it will be a no op.
-    this.requestInfo.log(HttpServletResponse.SC_OK);
+    this.clientConnection.log(HttpServletResponse.SC_OK);
 
     isClosed = true;
   }

--
Gitblit v1.10.0