474888 - HttpClient JMX support.

This commit is contained in:
Simone Bordet 2015-08-13 15:16:14 +02:00
parent 4c7d5f661e
commit 69b90ef59b
10 changed files with 90 additions and 13 deletions

View File

@ -31,10 +31,13 @@ import org.eclipse.jetty.io.SelectChannelEndPoint;
import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.io.SelectorManager;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ManagedObject
public abstract class AbstractHttpClientTransport extends ContainerLifeCycle implements HttpClientTransport public abstract class AbstractHttpClientTransport extends ContainerLifeCycle implements HttpClientTransport
{ {
protected static final Logger LOG = Log.getLogger(HttpClientTransport.class); protected static final Logger LOG = Log.getLogger(HttpClientTransport.class);
@ -59,6 +62,12 @@ public abstract class AbstractHttpClientTransport extends ContainerLifeCycle imp
this.client = client; this.client = client;
} }
@ManagedAttribute(value = "The number of selectors", readonly = true)
public int getSelectors()
{
return selectors;
}
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
{ {

View File

@ -33,12 +33,15 @@ import org.eclipse.jetty.client.api.Destination;
import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Sweeper; import org.eclipse.jetty.util.thread.Sweeper;
@ManagedObject("The connection pool")
public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
{ {
protected static final Logger LOG = Log.getLogger(ConnectionPool.class); protected static final Logger LOG = Log.getLogger(ConnectionPool.class);
@ -60,11 +63,24 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
this.activeConnections = new BlockingArrayQueue<>(maxConnections); this.activeConnections = new BlockingArrayQueue<>(maxConnections);
} }
@ManagedAttribute(value = "The number of connections", readonly = true)
public int getConnectionCount() public int getConnectionCount()
{ {
return connectionCount.get(); return connectionCount.get();
} }
@ManagedAttribute(value = "The number of idle connections", readonly = true)
public int getIdleConnectionCount()
{
return idleConnections.size();
}
@ManagedAttribute(value = "The number of active connections", readonly = true)
public int getActiveConnectionCount()
{
return activeConnections.size();
}
public BlockingQueue<Connection> getIdleConnections() public BlockingQueue<Connection> getIdleConnections()
{ {
return idleConnections; return idleConnections;

View File

@ -62,6 +62,8 @@ import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.SocketAddressResolver;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -106,6 +108,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
* }); * });
* </pre> * </pre>
*/ */
@ManagedObject("The HTTP client")
public class HttpClient extends ContainerLifeCycle public class HttpClient extends ContainerLifeCycle
{ {
private static final Logger LOG = Log.getLogger(HttpClient.class); private static final Logger LOG = Log.getLogger(HttpClient.class);
@ -503,11 +506,13 @@ public class HttpClient extends ContainerLifeCycle
} }
else else
{ {
addManaged(destination);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Created {}", destination); LOG.debug("Created {}", destination);
} }
if (!isRunning()) if (!isRunning())
destinations.remove(origin); removeDestination(destination);
} }
} }
@ -516,6 +521,7 @@ public class HttpClient extends ContainerLifeCycle
protected boolean removeDestination(HttpDestination destination) protected boolean removeDestination(HttpDestination destination)
{ {
removeBean(destination);
return destinations.remove(destination.getOrigin()) != null; return destinations.remove(destination.getOrigin()) != null;
} }
@ -594,6 +600,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the max time, in milliseconds, a connection can take to connect to destinations * @return the max time, in milliseconds, a connection can take to connect to destinations
*/ */
@ManagedAttribute("The timeout, in milliseconds, for connect() operations")
public long getConnectTimeout() public long getConnectTimeout()
{ {
return connectTimeout; return connectTimeout;
@ -634,6 +641,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the max time, in milliseconds, a connection can be idle (that is, without traffic of bytes in either direction) * @return the max time, in milliseconds, a connection can be idle (that is, without traffic of bytes in either direction)
*/ */
@ManagedAttribute("The timeout, in milliseconds, to close idle connections")
public long getIdleTimeout() public long getIdleTimeout()
{ {
return idleTimeout; return idleTimeout;
@ -688,6 +696,7 @@ public class HttpClient extends ContainerLifeCycle
* @return whether this {@link HttpClient} follows HTTP redirects * @return whether this {@link HttpClient} follows HTTP redirects
* @see Request#isFollowRedirects() * @see Request#isFollowRedirects()
*/ */
@ManagedAttribute("Whether HTTP redirects are followed")
public boolean isFollowRedirects() public boolean isFollowRedirects()
{ {
return followRedirects; return followRedirects;
@ -753,6 +762,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the max number of connections that this {@link HttpClient} opens to {@link Destination}s * @return the max number of connections that this {@link HttpClient} opens to {@link Destination}s
*/ */
@ManagedAttribute("The max number of connections per each destination")
public int getMaxConnectionsPerDestination() public int getMaxConnectionsPerDestination()
{ {
return maxConnectionsPerDestination; return maxConnectionsPerDestination;
@ -777,6 +787,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the max number of requests that may be queued to a {@link Destination}. * @return the max number of requests that may be queued to a {@link Destination}.
*/ */
@ManagedAttribute("The max number of requests queued per each destination")
public int getMaxRequestsQueuedPerDestination() public int getMaxRequestsQueuedPerDestination()
{ {
return maxRequestsQueuedPerDestination; return maxRequestsQueuedPerDestination;
@ -803,6 +814,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the size of the buffer used to write requests * @return the size of the buffer used to write requests
*/ */
@ManagedAttribute("The request buffer size")
public int getRequestBufferSize() public int getRequestBufferSize()
{ {
return requestBufferSize; return requestBufferSize;
@ -819,6 +831,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return the size of the buffer used to read responses * @return the size of the buffer used to read responses
*/ */
@ManagedAttribute("The response buffer size")
public int getResponseBufferSize() public int getResponseBufferSize()
{ {
return responseBufferSize; return responseBufferSize;
@ -853,6 +866,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return whether TCP_NODELAY is enabled * @return whether TCP_NODELAY is enabled
*/ */
@ManagedAttribute(value = "Whether the TCP_NODELAY option is enabled", name = "tcpNoDelay")
public boolean isTCPNoDelay() public boolean isTCPNoDelay()
{ {
return tcpNoDelay; return tcpNoDelay;
@ -900,6 +914,7 @@ public class HttpClient extends ContainerLifeCycle
* @return whether request events must be strictly ordered * @return whether request events must be strictly ordered
* @see #setStrictEventOrdering(boolean) * @see #setStrictEventOrdering(boolean)
*/ */
@ManagedAttribute("Whether request/response events must be strictly ordered")
public boolean isStrictEventOrdering() public boolean isStrictEventOrdering()
{ {
return strictEventOrdering; return strictEventOrdering;
@ -940,6 +955,7 @@ public class HttpClient extends ContainerLifeCycle
* @return whether destinations that have no connections should be removed * @return whether destinations that have no connections should be removed
* @see #setRemoveIdleDestinations(boolean) * @see #setRemoveIdleDestinations(boolean)
*/ */
@ManagedAttribute("Whether idle destinations are removed")
public boolean isRemoveIdleDestinations() public boolean isRemoveIdleDestinations()
{ {
return removeIdleDestinations; return removeIdleDestinations;
@ -965,6 +981,7 @@ public class HttpClient extends ContainerLifeCycle
/** /**
* @return whether {@code connect()} operations are performed in blocking mode * @return whether {@code connect()} operations are performed in blocking mode
*/ */
@ManagedAttribute("Whether the connect() operation is blocking")
public boolean isConnectBlocking() public boolean isConnectBlocking()
{ {
return connectBlocking; return connectBlocking;

View File

@ -36,12 +36,15 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
public abstract class HttpDestination implements Destination, Closeable, Dumpable @ManagedObject
public abstract class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Dumpable
{ {
protected static final Logger LOG = Log.getLogger(HttpDestination.class); protected static final Logger LOG = Log.getLogger(HttpDestination.class);
@ -130,12 +133,14 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl
} }
@Override @Override
@ManagedAttribute(value = "The destination scheme", readonly = true)
public String getScheme() public String getScheme()
{ {
return origin.getScheme(); return origin.getScheme();
} }
@Override @Override
@ManagedAttribute(value = "The destination host", readonly = true)
public String getHost() public String getHost()
{ {
// InetSocketAddress.getHostString() transforms the host string // InetSocketAddress.getHostString() transforms the host string
@ -144,11 +149,18 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl
} }
@Override @Override
@ManagedAttribute(value = "The destination port", readonly = true)
public int getPort() public int getPort()
{ {
return origin.getAddress().getPort(); return origin.getAddress().getPort();
} }
@ManagedAttribute(value = "The number of queued requests", readonly = true)
public int getQueuedRequestCount()
{
return exchanges.size();
}
public Origin.Address getConnectAddress() public Origin.Address getConnectAddress()
{ {
return proxy == null ? origin.getAddress() : proxy.getAddress(); return proxy == null ? origin.getAddress() : proxy.getAddress();

View File

@ -19,14 +19,17 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Collections;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.thread.Sweeper; import org.eclipse.jetty.util.thread.Sweeper;
@ManagedObject
public abstract class PoolingHttpDestination<C extends Connection> extends HttpDestination implements Callback public abstract class PoolingHttpDestination<C extends Connection> extends HttpDestination implements Callback
{ {
private final ConnectionPool connectionPool; private final ConnectionPool connectionPool;
@ -35,6 +38,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
{ {
super(client, origin); super(client, origin);
this.connectionPool = newConnectionPool(client); this.connectionPool = newConnectionPool(client);
addBean(connectionPool);
Sweeper sweeper = client.getBean(Sweeper.class); Sweeper sweeper = client.getBean(Sweeper.class);
if (sweeper != null) if (sweeper != null)
sweeper.offer(connectionPool); sweeper.offer(connectionPool);
@ -45,6 +49,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this); return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this);
} }
@ManagedAttribute(value = "The connection pool", readonly = true)
public ConnectionPool getConnectionPool() public ConnectionPool getConnectionPool()
{ {
return connectionPool; return connectionPool;
@ -195,7 +200,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
public void dump(Appendable out, String indent) throws IOException public void dump(Appendable out, String indent) throws IOException
{ {
super.dump(out, indent); super.dump(out, indent);
ContainerLifeCycle.dump(out, indent, Arrays.asList(connectionPool)); ContainerLifeCycle.dump(out, indent, Collections.singletonList(connectionPool));
} }
@Override @Override

View File

@ -27,7 +27,9 @@ import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject("The HTTP/1.1 client transport")
public class HttpClientTransportOverHTTP extends AbstractHttpClientTransport public class HttpClientTransportOverHTTP extends AbstractHttpClientTransport
{ {
public HttpClientTransportOverHTTP() public HttpClientTransportOverHTTP()

View File

@ -18,9 +18,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import static java.nio.file.StandardOpenOption.CREATE;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -33,6 +30,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -124,8 +122,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest
client.stop(); client.stop();
Assert.assertEquals(0, client.getDestinations().size()); Assert.assertEquals(0, client.getDestinations().size());
Assert.assertEquals(0, connectionPool.getIdleConnections().size()); Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
Assert.assertEquals(0, connectionPool.getActiveConnections().size()); Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
Assert.assertFalse(connection.getEndPoint().isOpen()); Assert.assertFalse(connection.getEndPoint().isOpen());
} }
@ -543,10 +541,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest
start(new RespondThenConsumeHandler()); start(new RespondThenConsumeHandler());
// Prepare a big file to upload // Prepare a big file to upload
Path targetTestsDir = testdir.getEmptyDir().toPath(); Path targetTestsDir = testdir.getEmptyPathDir();
Files.createDirectories(targetTestsDir); Files.createDirectories(targetTestsDir);
Path file = Paths.get(targetTestsDir.toString(), "http_client_conversation.big"); Path file = Paths.get(targetTestsDir.toString(), "http_client_conversation.big");
try (OutputStream output = Files.newOutputStream(file, CREATE)) try (OutputStream output = Files.newOutputStream(file, StandardOpenOption.CREATE))
{ {
byte[] kb = new byte[1024]; byte[] kb = new byte[1024];
for (int i = 0; i < 10 * 1024; ++i) for (int i = 0; i < 10 * 1024; ++i)
@ -813,7 +811,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
}); });
} }
assertTrue(latch.await(10, TimeUnit.SECONDS)); Assert.assertTrue(latch.await(10, TimeUnit.SECONDS));
} }
@Test @Test
@ -1119,7 +1117,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest
} }
}); });
final Exchanger<Response> ex = new Exchanger<Response>(); final Exchanger<Response> ex = new Exchanger<>();
BufferingResponseListener listener = new BufferingResponseListener() BufferingResponseListener listener = new BufferingResponseListener()
{ {
@Override @Override

View File

@ -30,7 +30,10 @@ import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject("The FastCGI/1.0 client transport")
public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport
{ {
private final boolean multiplexed; private final boolean multiplexed;
@ -53,6 +56,7 @@ public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport
return multiplexed; return multiplexed;
} }
@ManagedAttribute(value = "The scripts root directory", readonly = true)
public String getScriptRoot() public String getScriptRoot()
{ {
return scriptRoot; return scriptRoot;

View File

@ -33,8 +33,11 @@ import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ManagedObject("The HTTP/2 client transport")
public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport
{ {
private final HTTP2Client client; private final HTTP2Client client;
@ -46,6 +49,12 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
this.client = client; this.client = client;
} }
@ManagedAttribute(value = "The number of selectors", readonly = true)
public int getSelectors()
{
return client.getSelectors();
}
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
{ {

View File

@ -26,6 +26,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.Scheduler;
@ -48,6 +50,7 @@ public interface SocketAddressResolver
/** /**
* <p>Creates {@link SocketAddress} instances synchronously in the caller thread.</p> * <p>Creates {@link SocketAddress} instances synchronously in the caller thread.</p>
*/ */
@ManagedObject("The synchronous address resolver")
public static class Sync implements SocketAddressResolver public static class Sync implements SocketAddressResolver
{ {
@Override @Override
@ -91,6 +94,7 @@ public interface SocketAddressResolver
* }); * });
* </pre> * </pre>
*/ */
@ManagedObject("The asynchronous address resolver")
public static class Async implements SocketAddressResolver public static class Async implements SocketAddressResolver
{ {
private static final Logger LOG = Log.getLogger(SocketAddressResolver.class); private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
@ -124,6 +128,7 @@ public interface SocketAddressResolver
return scheduler; return scheduler;
} }
@ManagedAttribute(value = "The timeout, in milliseconds, to resolve an address", readonly = true)
public long getTimeout() public long getTimeout()
{ {
return timeout; return timeout;